EmbDev.net

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.
 
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
webmaster@embdev.netContactAdvertising on EmbDev.net