CRC-16-CCITT in AVR Assembler
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.
/* 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
.dseg crc16_accumulator: .dw 0 .cseg </c>