CRC-16 Saga

kermet

New Member
Hi I've looked through the threads on this subject but all the code i've found and tried don't seem to giv me the correct CRC calculation.


here's what i've tried, all using either polynomial's $A001, $8005, $1021 and clearing the CRC to $0000 and $FFFF but they don't give me the correct calc's any help here would be much appreciated.

trial 1:

SYMBOL crc = w0
SYMBOL k = w1
SYMBOL bite = b4
SYMBOL i = b5

crc = $ffff

bite = $16:GOSUB CrcAdd
bite = $06:GOSUB CrcAdd
bite = $63:GOSUB CrcAdd
bite = $0a:GOSUB CrcAdd
bite = $1d:GOSUB CrcAdd
bite = $61:GOSUB CrcAdd
;bite = $00:GOSUB CrcAdd
' ** CRC-16 is $7B80 **

DEBUG crc
END

CrcAdd:

FOR i = 0 TO 7
k = bite ^ crc & $01 ' original code was "k = bite ^ crc & 1" which didn't compile???
IF k = 0 THEN CrcAdd1
k = $a001
CrcAdd1:
crc = crc / 2 ^ k
bite = bite / 2
NEXT
RETURN


trial 2:

SYMBOL DataFlags = b0
SYMBOL data_bit = bit0
SYMBOL SR_lsb = bit1
SYMBOL FB_bit = bit2

SYMBOL line = b16
SYMBOL bbyte = b17
SYMBOL data_back = b18
SYMBOL check = b19
SYMBOL EEdata = b20
SYMBOL Checkbyte = b3

SYMBOL CRC16 = w11
SYMBOL CRC16Check = w12

SYMBOL Poly16Mask = $8005 ;1021 ;A001
;
; ---------------------------------------------------------------------------

Try_again:
pause 1000
GOSUB CRC_Check
end

; ---------------------------------------------------------------------------
;
CRC_Check:
CRC16Check = $ffff
CheckByte = $16 : GOSUB CRC_Calc
CheckByte = $06 : GOSUB CRC_Calc
CheckByte = $63 : GOSUB CRC_Calc
CheckByte = $0A : GOSUB CRC_Calc
CheckByte = $1D : GOSUB CRC_Calc
CheckByte = $61 : GOSUB CRC_Calc
;CRC16Check = 65535 - CRC16Check
RETURN
;
;
CRC_Calc:
FOR line = 0 to 7
data_bit = CheckByte AND $01
SR_lsb = CRC16Check AND $01
FB_bit = data_bit XOR SR_lsb AND $01
CRC16Check = CRC16Check / 2
IF FB_bit = 1 THEN
CRC16Check = CRC16Check XOR Poly16Mask
ENDIF
CheckByte = CheckByte / 2
NEXT Line
RETURN


Thanks Robert
 

hippy

Technical Support
Staff member
Calculating CRC has a lot of variations; polynomial, starting value, final inversion, shifting left or right so can be hard to guess what you need.

Can you tell us what this CRC is ultimately used for, point to examples which show it in use and point to examples of what a correct CRC calculation would be ?
 

kermet

New Member
I'm wanting to make a custom room temperature sensor to inferface with a Siemens fan coil unit controller (TEC), if captured the code between the siemens software and controller and have broken it down to the individual packets needed.

to read the temp setpoint value from the controller id send the device a hex code like

$16 $06 $63 $0A $0D $61 $71 $C8

$16 = Start byte
$06 $63 $0A= common read command bytes
$0D = Setpoint byte address
$61 = End byte
$71 $C8 = CRC calculated off all previous bytes above

the CRC $71 $C8 equates to the CRC calculated using the following CRC calculator on the net

http://www.lammertbies.nl/comm/info/crc-calculation.html

the device responds with the byte's rewuested value as follows

$16 $0D $63 $06 $0D $47 $00 $8D $07 $00 $0D $47 $00 $DF $B7

$16 = Start byte
$0D $63 $06 = common response bytes
$0D = Setpoint byte address
$47 $00 = Setpoint value (dec 71)
$8D = Setpoint status byte address
$07 $00 = Setpoint status value (bits specific)
$0D = Setpoint byte address repeated
$47 $00 = Setpoint value (dec 71) repeated
$DF $B7 = CRC calculated off all previous bytes above

hope this explains it better

Robert
 

hippy

Technical Support
Staff member
$16 $06 $63 $0A $0D $61 $71 $C8

$16 = Start byte
$06 $63 $0A= common read command bytes
$0D = Setpoint byte address
$61 = End byte
$71 $C8 = CRC calculated off all previous bytes above

the CRC $71 $C8 equates to the CRC calculated using the following CRC calculator on the net

http://www.lammertbies.nl/comm/info/crc-calculation.html
Thanks. Entering "16 06 63 0A 0D 61", selecting hex, and clicking calculate shows the "CRC-16" as 0xC871.

Now just a matter of determining what that site means by "CRC-16". Will have to dig further but it appears the polynomial is 0x8005. The actual calculations are 'hidden' in a separate .php application.
 

kermet

New Member
yeah all the CRC i've checked appear byte swaped in the calculator.
i've tried swapping the bytes around in the words (instead of putting in $16 $06.... putting in $06 $16...) but still no success.

tried reversing polynomial bytes and still no go. Man and my next project is a hand held modbus master device to allow easy connect and test to PLC's etc when intergrating to the Siemens Building Automation processors so there's another CRC calculation.
 

kermet

New Member
Sorry not wireless but interested modules, will keep in mind for further applications.

Attached is what i believe the site calculator's C++ program, only thing is i'm not familiar with C that much and have had some difficulty trying to implement it in the Picaxe.

anyone able to break it down?
 

Attachments

kermet

New Member
Arghhhh, man i feel so stupid. The code works and always has, it's just that the simulation function doesn't calculate the CRC correct.

I've been running the code through the simulator before loading it in a chip for the past couple of days tearing my hair out and getting little sleep thinking what could be the problem.
Today day i thought I'll try it in a chip just out of interest and the code works fine no problems at all it calculates the CRC correctly every time, argh.

the code for CRC-16 is;

SYMBOL crc = w0
SYMBOL k = w1
SYMBOL bite = b4
SYMBOL i = b5

crc = $0000

bite = $16:GOSUB CrcAdd
bite = $06:GOSUB CrcAdd
bite = $63:GOSUB CrcAdd
bite = $0A:GOSUB CrcAdd
bite = $0D:GOSUB CrcAdd
bite = $61:GOSUB CrcAdd


DEBUG crc
END

CrcAdd:

FOR i = 0 TO 7
k = bite ^ crc & $01
IF k = 0 THEN CrcAdd1
k = $A001
CrcAdd1:
crc = crc / 2 ^ k
bite = bite / 2
NEXT
RETURN


code for Modbus CRC-16 is;

SYMBOL crc = w0
SYMBOL k = w1
SYMBOL bite = b4
SYMBOL i = b5

crc = $FFFF

bite = $16:GOSUB CrcAdd
bite = $06:GOSUB CrcAdd
bite = $63:GOSUB CrcAdd
bite = $0A:GOSUB CrcAdd
bite = $0D:GOSUB CrcAdd
bite = $61:GOSUB CrcAdd


DEBUG crc
END

CrcAdd:

FOR i = 0 TO 7
k = bite ^ crc & $01
IF k = 0 THEN CrcAdd1
k = $A001
CrcAdd1:
crc = crc / 2 ^ k
bite = bite / 2
NEXT
RETURN


difference between CRC-16 and Modbus CRC-16 is the CRC set value of $0000 to $FFFF

got to love it when it comes together in the end.

Rob
 

hippy

Technical Support
Staff member
Arghhhh, man i feel so stupid. The code works and always has, it's just that the simulation function doesn't calculate the CRC correct.
Glad you have got it sorted but I'm a bit unclear; are you saying that the code simulated was wrong ( crc = $FFFF should have been crc = $0000 ) or there is a problem with the simulator when running that code ?
 

westaust55

Moderator
great to read you have it working.


having crc = $0000 at the beginning is more usual.

by way of example here is an extract of CRC16 code I wrote earlier this year for 1-Wire devices:
Code:
SYMBOL line 	 = b16
SYMBOL bbyte	 = b17
SYMBOL data_back	 = b18
SYMBOL check	 = b19
SYMBOL EEdata	 = b20
SYMBOL Checkbyte	 = b21

SYMBOL CRC16	 = w11	; 16 bit CRC code as read back from the DS2406
SYMBOL  CRC16_Lo	    = b22
SYMBOL  CRC16_Hi	    = b23

SYMBOL CRC16Check  = w12	; w12=b24:b25 = 16 bit CRC code as calculated in the program for checking



SYMBOL Poly16Mask = $A001  ; $8005 and $C002 are alternative) non Maxim values



;
; ---------------------------------------------------------------------------
;
CRC_Check:
	CRC16Check = 0                              		 ; clear the CRC value ready to start check
	CheckByte = command : GOSUB CRC_Calc	; paa each byte one at a time via CheckByte variable for inclusion in the CRC16 calc
	CheckByte = TA1  : GOSUB CRC_Calc
	CheckByte = TA2  : GOSUB CRC_Calc
	CheckByte = EEdata  : GOSUB CRC_Calc
	CRC16Check = 65535 - CRC16Check			 ;   invert the data to match with DS2406 CRC16 response
	RETURN
;
;
CRC_Calc:
  	  FOR line = 0 to 7                            ; for each bit of the current byte
   	    data_bit = CheckByte AND $01       ; extract the next lsb from one-wire sn input stream 
  	    SR_lsb = CRC16Check AND $01              ; extract the lsb from the CRC shift register
  	    FB_bit = data_bit XOR SR_lsb AND $01 ; feedback = XOR of the latest input bit (data_bit) with lsb of the shift register
  	    CRC16Check = CRC16Check / 2                  ; move the current CRC shift register value right 1 bit
  	    IF FB_bit = 1 THEN                 ; if the feedback bit is currently 1 then          
    		CRC16Check = CRC16Check XOR Poly16Mask     ; apply the 16-bit CRC polynomial mask to the present intermediate shift register value
  	      ENDIF                              ; otherwise if the feedback = 0 we just . . .
  	    CheckByte = CheckByte / 2        ; shift the current byte right read to exctart the next input bit		
  	  NEXT Line                              ; loop until all bits of the current byte are used
	RETURN
;
; ---------------------------------------------------------------------------
;
 

kermet

New Member
Nothing wrong with the code when run in hardware, the simulator has a problem running the code. the simulator is completely out of wak when running the code. Gutted i didn't try it in the hardware sooner.

as for the comment of CRC = $0000 or CRC = $FFFF, this is the difference between a standard CRC-16 and a Modbus CRC=16 CRC starting value before calculating the CRC value. Also the Polynomial is $A001

hope that of help
 

hippy

Technical Support
Staff member
Nothing wrong with the code when run in hardware, the simulator has a problem running the code. the simulator is completely out of wak when running the code.
Which version of Programming Editor are you using ? I cannot find any discrepency between hardware and 3.5.1 simulation running both sets of code in Post #9.
 

kermet

New Member
i'm running version 5.2.7. Attached is a couple of print screens showing the difference between the simulation and hardware calculations.

Has anyone else had this problem with the simulator?
 

Attachments

Last edited:

kermet

New Member
Fare enough i've upgraded now and simulation works fine.

thanks for the help guy's and great to have it sorted finally now i'll carry on with the project. i've learnt a lot trying to nut out the CRC code opened my eye's to different ways of code that'll make thing's easier.

gotta love Picaxe!
 
Last edited:

westaust55

Moderator
@kermit,

while you code works, there is some room for improvement.

for the code:
Code:
CrcAdd:

FOR i = 0 TO 7
k = bite ^ crc & $01
IF k = 0 THEN CrcAdd1
[COLOR="Red"]k = $A001[/COLOR]
CrcAdd1:
crc = crc / 2 ^ k
bite = bite / 2
NEXT
RETURN
the line
k = $A001​
does not need to be within the FOR...NEXT loop.
but moving it will involve the use of an additional variable. Alternatively give the value a SYBMOL name / assignment and dont use a variable for that value at all

While the repetitions here are small and not a lot of time is lost, if that line is put above the FOR...NEXT loop it is only executed once and saves some time. In a program where there are many repetitions of the loop and it is called many times, this can add up to a more considerable time delay/saving depending upton the locaiton of fixed assignments.
 

kermet

New Member
thanks, can't say i wrote the program though, although i wish i did. this was from a previous topic.

As for moving the line out of the for...next loop the value of k wouldn't reset to the polynomial. maybe i'm missing something?
 

hippy

Technical Support
Staff member
It's the structure of the code, written for earlier versions of the Programming Editor whcih is clouding teh issue a little. This may make it much clearer ...

Code:
CrcAdd:
  For i = 0 To 7
    k = bite ^ crc & $01
    If k <> 0 Then
      k = $A001
    End If
    crc = crc / 2 ^ k
    bite = bite / 2
  Next
  Return
The could probably be optimised (untested) to ...

Code:
CrcAdd:
  For i = 0 To 7
    k = bite ^ crc & $01 * $A001
    crc = crc / 2 ^ k
    bite = bite / 2
  Next
  Return
 
Last edited:

kermet

New Member
Makes sense, multiply the true or false result by the Polynomial duh.

Kinda funny how i've been writing programs for BMS controls over 10 years, using their development tools (Block diagram and PPCL) and still when i come to C language i can over look the obvious. Math math math

by the way it works, thanks hippy.
 

westaust55

Moderator
Makes sense, multiply the true or false result by the Polynomial duh.

Kinda funny how i've been writing programs for BMS controls over 10 years, using their development tools (Block diagram and PPCL) and still when i come to C language i can over look the obvious. Math math math

by the way it works, thanks hippy.
PICAXE programming is a variant of BASIC (Beginners All-purpose Symbolic Instruction Code). it is not a variant of the C programming language
 
Top