Hexmate has several algorithms that implement the
robust cyclic redundancy checks (CRC). There is a choice of two algorithms that
correspond to the selector values 5 and -5 in the algorithm suboption to
-mchecksum
and that implement a CRC calculation and reflected CRC
calculation, respectively. The reflected algorithm works on the least significant bit of
the data first.
The polynomial to be used and the initial value can be specified in the option. Hexmate will automatically store the CRC result in the HEX file at the address specified in the checksum option.
Some devices implement a CRC module in hardware that can be used to calculate a CRC at
runtime. These modules can stream data read from program memory using a Scanner module.
To ensure that the order of the bytes processed by Hexmate and the CRC/Scanner module
are identical, you must specify a reserve word width of 2 using the suboption
revword=2
. This will read each 2-byte word in the HEX file in
order, but process the bytes within those words in reverse order.
The function shown below can be customized to work with any result width
(resultType
). It calculates a CRC hash value using the polynomial
specified by the POLYNOMIAL
macro.
typedef unsigned int resultType;
#define POLYNOMIAL 0x1021
#define WIDTH (8 * sizeof(resultType))
#define MSb ((resultType)1 << (WIDTH - 1))
resultType
crc(const unsigned char * data, unsigned n, resultType remainder) {
unsigned pos;
unsigned char bitp;
for (pos = 0; pos != n; pos++) {
remainder ^= ((resultType)data[pos] << (WIDTH - 8));
for (bitp = 8; bitp > 0; bitp--) {
if (remainder & MSb) {
remainder = (remainder << 1) ^ POLYNOMIAL;
} else {
remainder <<= 1;
}
}
}
return remainder;
}
The resultType
type definition should be adjusted to suit
the result width. When using MPLAB XC8 and for a size of 1, use a
char
type; for a size of 4, use a long
type, etc., or consider using the exact-width types provided by
<stdint.h>
.
Here is how this function might be used when, for example, a 2-byte-wide
CRC hash value is to be calculated values over the address range 0x0 to 0xFF, starting
with an initial value of 0xFFFF. The result is to be stored at 0x100 and 0x101 in little
endian format. The following option is specified when building the project. In MPLAB X
IDE, only enter the information to the right of the first =
in the
Checksum field in the Additional
options Option category in the XC8
Linker category.
-mchecksum=0-FF@100,offset=0xFFFF,algorithm=5,width=-2,polynomial=0x1021
In your project, add the following code snippet which calls
crc()
and compares the runtime hash result with that stored by Hexmate at compile time.
extern const unsigned char ck_range[0x100] __at(0x0);
extern const resultType hexmate __at(0x100);
resultType result;
result = crc(ck_range, sizeof(ck_range), 0xFFFF);
if(result != hexmate){
// something’s not right, take appropriate action
ck_failure();
}
// data verifies okay, continue with the program
The reflected CRC result can be calculated by reflecting the input data
and final result, or by reflecting the polynomial. The functions shown below can be
customized to work with any result width (resultType
). The
crc_reflected_IO()
function calculates a reflected CRC hash value by
reflecting the data stream bit positions. Alternatively, the
crc_reflected_poly()
function does not adjust the data stream but
reflects instead the polynomial, which in both functions is specified by the
POLYNOMIAL
macro. Both functions use the reflect()
function to perform bit reflection.
typedef unsigned int resultType;
typedef unsigned char readType;
typedef unsigned int reflectWidth;
// This is the polynomial used by the CRC-16 algorithm we are using.
#define POLYNOMIAL 0x1021
#define WIDTH (8 * sizeof(resultType))
#define MSb ((resultType)1 << (WIDTH - 1))
#define LSb (1)
#define REFLECT_DATA(X) ((readType) reflect((X), 8))
#define REFLECT_REMAINDER(X) (reflect((X), WIDTH))
reflectWidth
reflect(reflectWidth data, unsigned char nBits)
{
reflectWidth reflection = 0;
reflectWidth reflectMask = (reflectWidth)1 << nBits - 1;
unsigned char bitp;
for (bitp = 0; bitp != nBits; bitp++) {
if (data & 0x01) {
reflection |= reflectMask;
}
data >>= 1;
reflectMask >>= 1;
}
return reflection;
}
resultType
crc_reflected_IO(const unsigned char * data, unsigned n, resultType remainder) {
unsigned pos;
unsigned char reflected;
unsigned char bitp;
for (pos = 0; pos != n; pos++) {
reflected = REFLECT_DATA(data[pos]);
remainder ^= ((resultType)reflected << (WIDTH - 8));
for (bitp = 8; bitp > 0; bitp--) {
if (remainder & MSb) {
remainder = (remainder << 1) ^ POLYNOMIAL;
} else {
remainder <<= 1;
}
}
}
remainder = REFLECT_REMAINDER(remainder);
return remainder;
}
resultType
crc_reflected_poly(const unsigned char * data, unsigned n, resultType remainder) {
unsigned pos;
unsigned char bitp;
resultType rpoly;
rpoly = reflect(POLYNOMIAL, WIDTH);
for (pos = 0; pos != n; pos++) {
remainder ^= data[pos];
for (bitp = 8; bitp > 0; bitp--) {
if (remainder & LSb) {
remainder = (remainder >> 1) ^ rpoly;
} else {
remainder >>= 1;
}
}
}
return remainder;
}
Here is how this function might be used when, for example, a 2-byte-wide reflected CRC result is to be calculated over the address range 0x0 to 0xFF, starting with an initial value of 0xFFFF. The result is to be stored at 0x100 and 0x101 in little endian format. The following option is specified when building the project (Note the algorithm selected is negative 5 in this case).
-mchecksum=0-FF@100,offset=0xFFFF,algorithm=-5,width=-2,polynomial=0x1021
In your project, call either the crc_reflected_IO()
or
crc_reflected_poly()
functions, as shown previously.