If you need to send small data packets over a serial interface or the like, the CRC-16-CCITT checksum offers a good trade-off among performance, size and robustness.
This is a straightforward implementation in AVR assembler:
; ----------------------------
; r23 = new data byte to add to the CRC-16 checksum.
; The 16-bit variable crc16_accumulator (see below) holds the checksum,
; you should initialise its value to 0xFFFF before the first call to this routine.
;
; r18, r19, r24 and r25 are overwritten.
accumulate_crc16:
/* Algorithm: CRC-16-CCITT, x16 + x12 + x5 + 1, 0x1021 / 0x8408 / 0x8810
Steps in C to update a running CRC with a new byte in ser_data:
unsigned char ser_data;
unsigned int crc; -> accumulated CRC to update, initial value 0xFFFF
crc = (unsigned char)(crc >> 8) | (crc << 8);
crc ^= ser_data;
crc ^= (unsigned char)(crc & 0xff) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0xff) << 4) << 1;
Note that there are faster table-based implementations, but they
consume more program space.
*/
; r18: CRC low
; r19: CRC high
; Load the last CRC value, but swapped (low <-> high)
lds r18, crc16_accumulator+1
lds r19, crc16_accumulator
; First XOR
eor r18, r23
; Second XOR
mov r25, r18
; These 2 instructions are faster than executing 4 times "lsr 4".
swap r25
andi r25, 0x0F
eor r18, r25
; Third XOR
mov r25, r18
; These 2 instructions are faster than executing 4 times "lsr 4".
swap r25
andi r25, 0xF0
eor r19, r25
; Fourth XOR
mov r25, r18
swap r25
mov r24, r25
andi r25, 0xF0
andi r24, 0x0F
lsl r25
rol r24
eor r18, r25
eor r19, r24
sts crc16_accumulator , r18
sts crc16_accumulator+1, r19
ret
.dseg
crc16_accumulator: .dw 0
.cseg |