RunningCRC

Purpose: Calculate the next CRC WORD given the prior CRC WORD and the next BYTE in the sequence.
Assumes: The CRC generator polynomial is x15 + x13 + x0 (which is the value 0xA001 or 1010000000000001.)
Passed:    R25:R24  WORD  wPriorCRC the previous 16-bit CRC value (i.e., its accrued value so far)
R22  BYTE bNewByte  the next data BYTE to include in the CRC
Returns: R25:R24  WORD wCRC the new 16-bit CRC value, with bNewByte included
Alters: No Registers (i.e., only the R25:R24 value returned and the FLAGS)
Example: 
.ORG 0x1000

CRCOverAnyType:
   ADIW    R26, 0               ; If the buffer pointer is NULL, there is
   BREQ    ACRCOverAny_Ret      ;  nothing to do, so just exit immediately
   MOVW    R24, R26             ; Only need to point R25:R24 at the buffer
   CALL    AParseValue          ; The ULONG result is in R25:R24:R23:R22
   SBRS    R21, BIT_PV_VALID    ; Done if a value could not be parsed from it
   RJMP    ACRCOverAny_Ret      ; (could read param #2 here as the BYTE count)

   LDI     R27, -1              ; Maintain the CRC in R27:R26; initialize it
   LDI     R26, -1              ;  to 0xFFFF
   MOVW    R30, R22             ; Save the target address: the R23:R22 portion
   LDI     R19, '='             ; For PrintDescAndHexBYTE & PrintDescAndHexWORD
   MOV     R21, R24             ; BYTE 3 selects the data source (1 is EEPROM,
   CPI     R21, 3               ;  2 = FLASH, any other SRAM), so if it is 3 or
   BRLO    ACRCOverAny_Loop     ;  above, set it to zero, thereby limiting the
   LDI     R21, 0               ;  values to only 0, 1, or 2

CRCOverAny_Loop:
   LD      R22, Z               ; Assuming the value is in SRAM, read it
   CPI     R21, 0               ; If it is, in fact in SRAM, we've got the new
   BREQ    ACRCOverAny_Check    ;  data byte
   MOVW    R24, R30             ; Move the 'Z' pointer to the common parameter
   SBRS    R21, 1               ;  which both ReadEEPROM... and ReadPGM...
   CALL    AReadEEPROM_BYTE     ;  share, then call one or the other of them,
   SBRC    R21, 1               ;  based on whether R21 is B00000010 or not
   CALL    AReadPGM_BYTE
   MOV     R22, R24             ; Move the EEPROM or FLASH data BYTE into R22

CRCOverAny_Check:
   CPI     R22, 0xFF            ; If the new data BYTE is 0xFF, we're done
   BREQ    ACRCOverAny_Ret

   MOVW    R24, R26             ; Place the prior accrued CRC in R25:R24
   CALL    ARunningCRC          ; Call to calculate the CRC; R22 is retained
   MOVW    R26, R24             ; Save the new CRC back into R27:R26
   LDI     R25, ACSZ_New >> 8
   LDI     R24, ACSZ_New & 0xFF ; "New BYTE = 0x--"
   CALL    APrintDescAndHexBYTE
   LDI     R25, ACSZ_CRC >> 8
   LDI     R24, ACSZ_CRC & 0xFF ; "; new CRC = 0x----"
   MOVW    R22, R26
   CALL    APrintDescAndHexWORD ; Print the string and the value
   CALL    APrintNewLine        ; Print a Carriage Return and Line Feed
   ADIW    R30, 1               ; Advance the address to the next BYTE
   RJMP    ACRCOverAny_Loop     ; Loop back to read the next BYTE

CRCOverAny_Ret:
   RET

Leading0s: .LONG    0

CSZ_New:   .STRING  "New BYTE"
CSZ_CRC:   .STRING  "; new CRC"
Test it:
m>DP+ 0x1000 0x80
FLASH (program memory) contents:
1000:  10 96 59 F1 CD 01 0E 94-6D 30 50 FF 26 C0 BF EF  ..Y.....m0P.&...
1010:  AF EF FB 01 3D E3 58 2F-53 30 08 F0 50 E0 60 81  ....=.X/S0..P.`.
1020:  50 30 41 F0 CF 01 51 FF-0E 94 21 30 51 FD 0E 94  P0A...Q...!0Q...
1030:  2C 30 68 2F 6F 3F 89 F0-CD 01 0E 94 1A 30 DC 01  ,0h/o?.......0..
1040:  90 E1 80 E6 0E 94 62 30-90 E1 89 E6 BD 01 0E 94  ......b0........
1050:  63 30 0E 94 5B 30 31 96-E2 CF 08 95 00 00 00 00  c0..[01.........
1060:  4E 65 77 20 42 59 54 45-00 3B 20 6E 65 77 20 43  New BYTE.; new C
1070:  52 43 00 FF FF FF FF FF-FF FF FF FF FF FF FF FF  RC..............
m>@ 0x1000 0x2106F   ; The '2' selects FLASH and address = 0x106F
New BYTE = 0x43; new CRC = 0xB1FE
New BYTE = 0x52; new CRC = 0x7DB1
New BYTE = 0x43; new CRC = 0x85FC
New BYTE = 0x00; new CRC = 0x4185
m>DES
EEPROM contents:
0000:  10 3C 00 9F 01 00 84 FF-04 00 FF FF 28 3C 50 FF  .<..........(.P.
0010:  C0 00 3F FF 40 08 03 67-FF 25 74 FF FF FF FF FF  ..?.@..g.%t.....
0020:  24 28 05 00 FF FF 2A FF-FF 14 30 20 00 30 FF FF  $(....*...0 .0..
0030:  80 16 FF FF FF FF FF FF-60 00 B0 00 90 01 FF FF  ........`.......
0040:  FF FF FF FF FF FF 00 2F-FF FF FF FF FF FF FF FF  ......./........
m>@ 0x1000 0x10000   ; The '1' selects EEPROM and address = 0
New BYTE = 0x10; new CRC = 0x8CBE
New BYTE = 0x3C; new CRC = 0x610C
New BYTE = 0x00; new CRC = 0x0561
New BYTE = 0x9F; new CRC = 0x8084
New BYTE = 0x01; new CRC = 0xA341
New BYTE = 0x00; new CRC = 0x3063
New BYTE = 0x84; new CRC = 0x4A70
m>                                                                              
Notes: When a CRC WORD is initialized to 0xFFFF, changes in blocks that begin with runs of zeros can be detected. When the initial CRC is 0x0000, they cannot be detected.
Refer to the CRC System Function for more general information about CRCs. More more information is available online.
The CRC System Function calculates a 16-bit CRC over a block of SRAM
 
Dropin: 
(setup
code)
;   Setup for the CRC() call:
; Passed:  R25:R24 WORD wPriorCRC the existing CRC value accrued so far
;              R22 BYTE bNewByte the next data BYTE to combine into the CRC
; Returns: R25:R24 WORD wCRC the new 16-bit CRC value, including the new byte
; Alters:  R24, R25 and the FLAGS (R25:R24 has the return value)
Also see:  The CRC System Function.