• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

CRC Calculate Code Help

Suraj143

Active Member
I'm doing a modbus project & needs to read some data from a PIC driven driver.I'm confused with the CRC routine.I'm not getting the correct CRC values from PC simulator (Hyper terminal). like in the top comment the correct CRC values are "77" & "03".I'm not getting it. I get some other values :(
May be I'm doing wrong.

Code:
;==================================================================
Modbus RTU request for the content of analog output holding registers #40108 to #40110 from the slave device with address 21.
;15 03 00 6B 00 03 77 03   
           
                ;movlw        0xFF
                ;movwf        crcL
                ;movwf        crcH
                ;
                movlw        0x15
                call        CRC_16_Upd
                movlw        0x03
                call        CRC_16_Upd
                movlw        0x00
                call        CRC_16_Upd
                movlw        0x6B
                call        CRC_16_Upd
                movlw        0x00
                call        CRC_16_Upd
                movlw        0x03
                call        CRC_16_Upd
                ;               
                ;send higher CRC to PC Terminal               
                swapf        crcH,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC
                movf        crcH,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC               
                movlw        .10        ;LF
                call        TX_RS232_PC
                movlw        .13        ;CR
                call        TX_RS232_PC
               
                ;send lower CRC to PC Terminal
                swapf        crcL,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC
                movf        crcL,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC
                movlw        .10        ;LF
                call        TX_RS232_PC
                movlw        .13        ;CR
                call        TX_RS232_PC
                ;
Wait_Here        nop
                goto        Wait_Here
               
;John Paysons CRC Routine
CRC_16_Upd        xorwf      crcH,F
                ; Compute the LSB first [based upon MSB]
                   movlw      .0
                   btfsc      crcH,0
                xorlw     .33
                   btfsc      crcH,1
                xorlw     .66
                   btfsc      crcH,2
                xorlw     .132
                   btfsc      crcH,3
                xorlw     .8
                   btfsc      crcH,4
                xorlw     .49
                   btfsc      crcH,5
                xorlw     .98
                   btfsc      crcH,6
                xorlw     .196
                   btfsc      crcH,7
                xorlw     .136
                ; Swap crcL with W
                   xorwf      crcL,f
                   xorwf      crcL,w
                   xorwf      crcL,f
                ; Next compute the MSB [note W holds old LSB]
                   btfsc      crcH,0
                xorlw     .16
                   btfsc      crcH,1
                xorlw     .32
                   btfsc      crcH,2
                xorlw     .64
                   btfsc      crcH,3
                xorlw     .129
                   btfsc      crcH,4
                xorlw     .18
                   btfsc      crcH,5
                xorlw     .36
                   btfsc      crcH,6
                xorlw     .72
                   btfsc      crcH,7
                xorlw     .145
                   movwf      crcH   
                   return               

;========================================================               
Ascii_Table        addwf        PCL,F
                retlw        '0'
                retlw        '1'
                retlw        '2'
                retlw        '3'
                retlw        '4'
                retlw        '5'
                retlw        '6'
                retlw        '7'
                retlw        '8'
                retlw        '9'
                retlw        'A'
                retlw        'B'
                retlw        'C'
                retlw        'D'
                retlw        'E'
                retlw        'F'
 

rjenkinsgb

Well-Known Member
Most Helpful Member
There are many different versions of CRC16 using different polynomials - in effect, different combinations of "taps" in the shift register, if you look at a diagram in shift register form.


The CRC routine you are using is written for a version of the CCITT CRC, which uses the polynomial 0x1021

Modbus uses the polynomial 0x8005, from what I can see.

I've found the exact version you are using here:


The John Payson version seems to have the polynomial constant encoded in all the XOR bytes, I have no idea offhand how they are derived.

The conventional bit-shift version at the start of the page can easily have different polynomial constants in place of the 0x1021, the two bytes are defined at the start.

I'd use that instead, or there are faster (but much larger) CRC routines that use a lookup table.

eg. A table-based version for modbus, though it's in C and would need modifying for assembler:
 

Suraj143

Active Member
There are many different versions of CRC16 using different polynomials - in effect, different combinations of "taps" in the shift register, if you look at a diagram in shift register form.


The CRC routine you are using is written for a version of the CCITT CRC, which uses the polynomial 0x1021

Modbus uses the polynomial 0x8005, from what I can see.

I've found the exact version you are using here:


The John Payson version seems to have the polynomial constant encoded in all the XOR bytes, I have no idea offhand how they are derived.

The conventional bit-shift version at the start of the page can easily have different polynomial constants in place of the 0x1021, the two bytes are defined at the start.

I'd use that instead, or there are faster (but much larger) CRC routines that use a lookup table.

eg. A table-based version for modbus, though it's in C and would need modifying for assembler:
Many thanks for the information.That helped me a lot.Actually I don't know what are polynomials...
Anyway I changed the CRC routine to more generic type one that you mentioned.Also initialized the CRC Values to FFFF before the first call.But my CRC value are still incorrect :(

Code:
;==================================================================
Modbus RTU request for the content of analog output holding registers #40108 to #40110 from the slave device with address 21.
;15 03 00 6B 00 03 77 03    
            
                movlw        0xFF
                movwf        crcL
                movwf        crcH
                ;
                movlw        0x15
                call        CRC_16_Upd
                movlw        0x03
                call        CRC_16_Upd
                movlw        0x00
                call        CRC_16_Upd
                movlw        0x6B
                call        CRC_16_Upd
                movlw        0x00
                call        CRC_16_Upd
                movlw        0x03
                call        CRC_16_Upd
                ;                
                ;send higher CRC to PC Terminal                
                swapf        crcH,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC
                movf        crcH,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC                
                movlw        .10        ;LF
                call        TX_RS232_PC
                movlw        .13        ;CR
                call        TX_RS232_PC
                
                ;send lower CRC to PC Terminal
                swapf        crcL,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC
                movf        crcL,W
                andlw        b'00001111'
                call        Ascii_Table
                call        TX_RS232_PC
                movlw        .10        ;LF
                call        TX_RS232_PC
                movlw        .13        ;CR
                call        TX_RS232_PC
                ;
Wait_Here        nop
                goto        Wait_Here
                
                
;poly0               equ     0x05
;poly1               equ     0x80                
                
CrcUpd              movwf       saved           ; j = W
                    movlw       d'8'            ; W = 8
                    movwf       i               ; i = W
_loop               movfw       crcH
                    movwf       oldcch          ; temporary save
                    clrc                           ; clear carry for rlf
                    rlf         crcL,F          ; crc << 1
                    rlf         crcH,F
                    movfw       saved           ; the char read
                    xorwf       oldcch,F        ; test with old high
                    btfss       oldcch,7        ; if bit set, apply mask
                    goto           _notset         ; otherwise skip
                    movlw       poly0
                    xorwf       crcL,F
                    movlw       poly1
                    xorwf       crcH,F
_notset             clrc                        ; for rlf
                    rlf         saved,F         ; next bit of saved
                    decfsz      i,F
                    goto           _loop
                    return

;========================================================                
Ascii_Table        addwf        PCL,F
                retlw        '0'
                retlw        '1'
                retlw        '2'
                retlw        '3'
                retlw        '4'
                retlw        '5'
                retlw        '6'
                retlw        '7'
                retlw        '8'
                retlw        '9'
                retlw        'A'
                retlw        'B'
                retlw        'C'
                retlw        'D'
                retlw        'E'
                retlw        'F'
 

rjenkinsgb

Well-Known Member
Most Helpful Member
What results are you actually getting?

I have done a bit more research via the official modbus specifications (the top link in this page http://www.modbus.org/tech.php ) then the new serial or TCP/IP docs.

The serial line one uses CCITT (A0 01) and the TCP/IP appears to be 32 bit..

However, a lot of resources online say it's the 0x8005 one, and you test string verifies to that using an online CRC checker, here: https://www.lammertbies.nl/comm/info/crc-calculation.html

Entering the full string 15 03 00 6B 00 03 77 03 in hex mode gives 0000 result or leaving off the last two bytes gives 0377 result.


Just found more info - the CRC register needs to be initialised to 0 for the 8005 algorithm, not FF.

eg.
Code:
    movlw 0x00
    movwf crcL
    movwf crcH

Try that. The only possibility I can see is that the bit ordering within bytes is wrong and needs reversing in the CRC algorithm.
 

Suraj143

Active Member
Thank you very much for the ideas. I also think the serial line one uses CCITT (A0 01).I'll give a try.

Many Thanks for the help.
 

EE World Online Articles

Loading

 
Top