Full Version : How to Calculate a CRC (AVR ASM)
avr >>ASSMBLER ROUTINES >>How to Calculate a CRC (AVR ASM)


AVR_Admin- 05-17-2006
How to Calculate a CRC (AVR ASM)

CODE

;**** A P P L I C A T I O N   N O T E   A V R 236 ************************
;*
;* Title:  CRC check of program memory
;* Version:  1.3
;* Last updated: 11.11.2004
;* Target:  AT90Sxxx, ATtinyxxx, ATmegaxxx
;*    (All AVR Devices with LPM instr, not AT90S1200)
;*
;* Support E-mail: avr@atmel.com
;*
;* NOTE: Always check out Atmels web site, www.atmel.com for the latest and updated
;* version of the software.
;*
;* DESCRIPTION
;* This application note describes how to perform CRC computation
;* of code memory contents using a simple algoritm.
;* To generate CRC checksum load the register "status" with 00 and call the routine
;* "crc_gen". The resulting checksum is placed in the registers
;* byte_2(low byte) and byte_3(high byte).
;*
;* To check the CRC checksum load the register "status" with FF and call the routine
;* "crc_gen". The resulting checksum is placed in the registers
;* byte_2(low byte) and byte_3(high byte). If the checksum is 00 the program code is
;* correct, if the checksum is non-zero an error has been introduced in the program code
;**************************************************************************


.include "8515def.inc"

;***** Constants

.equ  LAST_PROG_ADDR = 0x1FFF; Last program memory address(byte address)
.equ  CR = 0x8005; CRC divisor value

;**************************************************************************
;*
;*      PROGRAM START - EXECUTION STARTS HERE
;*
;**************************************************************************

;        .cseg

.org $0000
rjmp RESET     ;Reset handle


;***************************************************************************
;*
;* "crc_gen" - Generation and checking of CRC checksum
;*
;* This subroutine generates the checksum for the program code.
;* 32 bits are loaded into 4 register, the upper 16 bits are XORed
;* with the divisor value each time a 1 is shifted into the carry flag
;* from the MSB.
;*
;* If the status byte is 0x00,the routine will generate new checksum:
;* After the computing the code 16 zeros are
;* appended to the code and the checksum is calculated.
;*
;* If the status byte is different from 0X00, the routine will check if the current checksum is valid.
;* After the computing the code the original checksum are
;* appended to the code and calculated. The result is zero if no errors occurs
;* The result is placed in registers byte_2 and byte_3
;*  
;* Number of words :44 + return
;* Number of cycles :program memory size(word) * 175(depending on memory contens)
;* Low registers used :6 (byte_0,byte_1,byte_2,byte_3)
;* High registers used  :7 (sizel,sizeh,crdivl,crdivh,count,status,zl,zh)
;*
;***************************************************************************

;***** Subroutine Register Variables

.def byte_0 = r0 ; Lower byte of lower word
.def byte_1 = r1 ; Upper byte of lower word
.def byte_2 = r2 ; Lower byte of upper word
.def byte_3 = r3 ; Upper byte of upper word
.def crc  = r4 ; CRC checksum low byte
.def crch  = r5 ; CRC checksum high byte
.def sizel  = r17; Program code size register
.def sizeh  = r18
.def crdivl = r19; CRC divisor register
.def crdivh = r20
.def count = r21; Bit counter
.def status = r22; Status byte: generate(0) or check(1)

crc_gen:
ldi  sizel,low(LAST_PROG_ADDR) ;Load last program memory address
ldi  sizeh,high(LAST_PROG_ADDR)
clr  zl  ;Clear Z pointer
clr  zh    
ldi  crdivh,high(CR);Load divisor value
ldi crdivl,low(CR)
lpm   ;Load first memory location
mov byte_3,byte_0;Move to highest byte
adiw zl,0x01 ;Increment Z pointer
lpm   ;Load second memory location
mov byte_2,byte_0  

next_byte:
cp zl,sizel ;Loop starts here
cpc zh,sizeh ;Check for end of code
brge end  ;Jump if end of code
adiw zl,0x01  
lpm   ;Load high byte
mov byte_1,byte_0;Move to upper byte
adiw zl,0x01 ;Increment Z pointer
lpm   ;Load program memory location
rcall  rot_word;Call the rotate routine
rjmp next_byte

end:
;ret;uncomment this line if checksum is stored in last flash memory address.
ldi count,0x11  
cpi status,0x00  
brne check
clr byte_0 ;Append 16 bits(0x0000) to
clr byte_1 ;the end of the code for CRC generation
rjmp gen
check:
mov byte_0,crc ;Append the original checksum to
mov byte_1,crch    ;the end of the code for CRC checking
gen:
rcall rot_word;Call the rotate routine
mov crc,byte_2  
mov crch,byte_3
ret   ;Return to main prog

rot_word:
ldi count,0x11
rot_loop:
dec  count ;Decrement bit counter
breq stop  ;Break if bit counter = 0
lsl byte_0 ;Shift zero into lowest bit
rol byte_1 ;Shift in carry from previous byte
rol byte_2 ;Preceede shift
rol byte_3  
brcc rot_loop ;Loop if MSB = 0  
eor  byte_2,crdivl
eor  byte_3,crdivh;XOR high word if MSB = 1
rjmp rot_loop
stop:
ret

;***************************************************************************
;*
;* EERead_seq
;*
;* This routine reads the
;* EEPROM into the global register variable "temp".
;*
;* Number of words :4+ return
;* Number of cycles :8 + return
;* High Registers used :4 (temp,eeadr,eeadrh,eedata)
;*
;***************************************************************************

.def temp  = r16
.def eeadr = r23
.def eeadrh = r24
.def eedata = r25

;***** Code

eeread:
out EEARH,eeadrh;output address high byte
out EEARL,eeadr;output address low byte
sbi EECR,EERE ;set EEPROM Read strobe
in eedata,EEDR;get data
ret

;***************************************************************************
;*
;* EEWrite
;*
;* This subroutine waits until the EEPROM is ready to be programmed, then
;* programs the EEPROM with register variable "EEdwr" at address "EEawr"
;*
;* Number of words :7 + return
;* Number of cycles :13 + return (if EEPROM is ready)
;* Low Registers used :None
;* High Registers used:;4 (temp,eeadr,eeadr,eedata)
;*
;***************************************************************************

.def temp  = r16
.def eeadr = r23
.def eeadrh = r24
.def eedata = r25

eewrite:
sbic EECR,EEWE;If EEWE not clear
rjmp EEWrite ;    Wait more
out EEARH,eeadrh;Output address high byte
out EEARL,eeadr;Output address low byte
out EEDR,eedata;Output data
sbi EECR,EEMWE
sbi EECR,EEWE ;Set EEPROM Write strobe
ret

;************************************************************************
;*
;*  Start Of Main Program
;*
.cseg
.def crc  = r4 ;Low byte of checksum to be returned
.def crch  = r5 ;High byte of checksum to be returned
.def temp  = r16  
.def status = r22;Status byte: generate(0) or check(1)
.def eeadr = r23
.def eeadrh = r24
.def eedata = r25

RESET:
ldi r16,high(RAMEND);Initialize stack pointer
out SPH,r16  ;High byte only required if
ldi r16,low(RAMEND);RAM is bigger than 256 Bytes
out SPL,r16

ldi  temp,0xff
out  DDRB,temp ;Set PORTB as output
out  PORTB,temp;Write 0xFF to PORTB
clr  status ;Clear status register, prepare for CRC generation
rcall  crc_gen

ldi  eeadr,0x01;Set address low byte for EEPROM write
ldi  eeadrh,0x00;Set address high byte for EEPROM write
mov  eedata,crc;Set CRC low byte in EEPROM data
rcall eewrite ;Write EEPROM

ldi  eeadr,0x02;Set address low byte for EEPROM write
ldi  eeadrh,0x00;Set address high byte for EEPROM write
mov  eedata,crch;Set CRC high byte in EEPROM data
rcall eewrite ;Write EEPROM

out  PORTB,crc;Output CRC low value to PORTB

mainloop:
sbic EECR,EEWE;If EEWE not clear
rjmp mainloop;    Wait more

;********** Insert program code here *************

ldi  eeadr,0x01;Set address low byte for EEPROM read
ldi  eeadrh,0x00;Set address high byte for EEPROM read
rcall eeread ;Read EEPROM
mov  crc,eedata;Read CRC low byte from EEPROM

ldi  eeadr,0x02;Set address low byte for EEPROM read
ldi  eeadrh,0x00;Set address high byte for EEPROM read
rcall eeread ;Read EEPROM
mov  crch,eedata;Read CRC low byte from EEPROM

ser status ;Set status register, prepare for CRC checking
rcall  crc_gen

loop:
out PORTB,crc;Output CRC low value to PORTB
rjmp loop

.exit




Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.