Generating A 16-Bit CRC

Goeytex

Senior Member
This Picaxe Code generates a 16-Bit CRC as used in the MODBUS protocol & other applications.

This is not my code. I found it in another thread and thought it might be useful to others.
This was a collaborative effort of Kermit, Westaust55, & Hippy. I have reformatted it a bit.
http://www.picaxeforum.co.uk/showthread.php?16954-CRC-16-Saga/

The process is relatively slow as each bit of each byte must be processed. At 16mhz it takes
approx 15ms to process each byte.

Code:
symbol crc = W2
symbol polynomial = W3
symbol  k = W4
symbol  i =  B0
symbol data_byte = B1

MAIN:
DO
GOSUB GENERATE_CRC
DEBUG  ' See result
PAUSE 5000
LOOP

GENERATE_CRC:
crc = $FFFF
polynomial = $A001 

data_byte = $F2   : GOSUB CrcAdd   'Four bytes of data to generate CRC on 
data_byte = $1C   : GOSUB CrcAdd   ' This can be  more or less
data_byte = $33   : GOSUB CrcAdd
data_byte = $c2   : GOSUB CrcAdd

return   'To main

	CrcAdd:
           For i = 0 To 7
    	   k = data_byte ^ crc & $01 * Polynomial
    	   crc = crc / 2 ^ k
    	   data_byte = data_byte / 2
   	   next
           return
 

hippy

Technical Support
Staff member
With more program memory these days there's an opportunity to unroll the FOR-NEXT loop. If you reassign symbols, put the databyte in 'b0' and 'crc' in 'w1', you can increase the speed with -

CrcAdd:
k = bit0 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit1 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit2 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit3 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit4 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit5 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit6 ^ bit16 * Polynomial : crc = crc / 2 ^ k
k = bit7 ^ bit16 * Polynomial : crc = crc / 2 ^ k
Return

On X2's you can gain even more changing "/ 2" to ">> 1". On a 28X2 at 8MHz, calling 'GENERATE_CRC' ...

Original with FOR-NEXT : 86ms
Unrolled FOR-NEXT : 65ms
Using >> 1 : 50ms
Getting rid of the multiply would be nice, and if anyone can find a fast conversion of %0 => $0000 and %1 => $FFFF that would help. My first attempt was ...

k = bit0 ^ bit16 ^ 1 - 1 & Polynomial : crc = crc >> 1 ^ k

And we can save the ^ 1 in eight lines if we invert b0 at the start giving ...

b0 = b0 ^ $FF
k = bit0 ^ bit16 - 1 & Polynomial : crc = crc >> 1 ^ k

But those were 55ms and 53ms respectively, the extra tokens adding more overhead than we're saving in multiplying.
 

Goeytex

Senior Member
Nice work Hippy,

Here is the code as modified by Hippy for use with a Picaxe X2.
It runs considerably faster.

Code:
;*****************************************
'* Generate 16-bit CRC on Picaxe X2 ONlY *
'* running at 16mhz.                     *   
'***************************************** 

symbol crc = W1
symbol polynomial = W2
symbol  k = W3
symbol data_byte = B0
setfreq m16

MAIN:
DO
GOSUB GENERATE_CRC
DEBUG  ' See result
PAUSE 5000
LOOP

GENERATE_CRC:
crc = $FFFF
polynomial = $A001 

data_byte = $F2   : GOSUB CrcAdd   'Four bytes of data to generate CRC on 
data_byte = $1C   : GOSUB CrcAdd   ' This can be  more or less
data_byte = $33   : GOSUB CrcAdd
data_byte = $c2   : GOSUB CrcAdd
return   'To main

	CrcAdd:
	
	k = bit0 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit1 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit2 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit3 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit4 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit5 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit6 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit7 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	Return
 

westaust55

Moderator
Great work to speed to code up by Goeytex and hippy.

Further to hippy's comment, the "Shift Right" command >> is also available on the X1 parts
so albeit that the X1 has only 25% of the program space of an X2 chip and most folks will now likely purchase an X2 over an X1 part,
for those with an X1 part the same routine will also work.
 

techElder

Well-known member
I know this is an old thread but I have a question that seems pertinent to the code above by Goeytex.

In looking over the MODBUS spec sheet referencing serial line comms, I was researching CRC creation for MODBUS.

One thing I noticed different between the code by Goeytex and the written and diagrammed algorithm in the document is loop step 4 that checks Least Significant Bit (LSB) equal to zero and redoes the shift in step 3 if so.

I didn't specifically see this in the original code. Did I miss something important? Wouldn't this make a significant difference in the CRC?

Relavant paragraph in the document titled "Modbus_over_serial_line_V1_02.pdf" located on page 39 "6.2.2 CRC Generation".

A procedure for generating a CRC is:

1. Load a 16–bit register with FFFF hex (all 1’s). Call this the CRC register.

2. Exclusive OR the first 8–bit byte of the message with the low–order byte of the 16–bit CRC register, putting the result in the CRC register.

3. Shift the CRC register one bit to the right (toward the LSB), zero–filling the MSB. Extract and examine the LSB.

4. (If the LSB was 0): Repeat Step 3 (another shift). (If the LSB was 1): Exclusive OR the CRC register with the polynomial value 0xA001 (1010 0000 0000 0001).

5. Repeat Steps 3 and 4 until 8 shifts have been performed. When this is done, a complete 8–bit byte will have been processed.

6. Repeat Steps 2 through 5 for the next 8–bit byte of the message. Continue doing this until all bytes have been processed.

7. The final content of the CRC register is the CRC value.

8. When the CRC is placed into the message, its upper and lower bytes must be swapped as described below.

View attachment Modbus_over_serial_line_V1_02.pdf
 

hippy

Technical Support
Staff member
One thing I noticed different between the code by Goeytex and the written and diagrammed algorithm in the document is loop step 4 that checks Least Significant Bit (LSB) equal to zero and redoes the shift in step 3 if so.
You are right, the spec seems to suggest a double-shift when lsb is zero and the code given only does a single shift regardless of zero or one.

I think it is perhaps ambiguous wording in the spec; when zero I think it should be read as 'continue with step 3 for the next bit' rather than 'another shift then continue for next bit'. This would reflect the earlier "This process is repeated until eight shifts have been performed", that is, only one shift for each bit.

Just a single shift per bit is also what's shown in the flowchart on page 40.

The best way to check is with a known legitimate MODBUS message. If the PICAXE algorithm is wrong then it won't generate the same and correct CRC for that message.
 

techElder

Well-known member
In other words, if the bit is zero there's a requirement not to "... Exclusive OR the CRC register with the polynomial value ..."

Whereas, in the algorithm presented above by Goeytex, that zero bit would not be detected and the CRC register would again be XORed.

Seems that not detecting the zero bit would affect the CRC.

I don't really need MODBUS for the current iteration of my project, but was seeking compliance for future additions / addons without redesign.

As they say in American football, "punt it" and see where it lands.

Thanks, Hippy.
 

techElder

Well-known member
I've never seen "CRC16_CCITT" in the MODBUS specs.

Actually, I don't remember seeing this spec for CRC anywhere but in the "serial line specification" mentioned above. Makes sense, though.
 

hippy

Technical Support
Staff member
In other words, if the bit is zero there's a requirement not to "... Exclusive OR the CRC register with the polynomial value ..."
That is correct as I see it. We check lsb before shifting rather than shifting then checking carry as we don't have carry on the PICAXE -

If lsb = 0 : shift CRC
If lsb = 1 : shift CRC then XOR polynomial

Whereas, in the algorithm presented above by Goeytex, that zero bit would not be detected and the CRC register would again be XORed.
"k" is the polynomial to XOR but is zeroed if the lsb is zero, so we are effectively doing -

If lsb = 0 : shift CRC then XOR k (zero)
If lsb = 1 : shift CRC then XOR k (polynomial)

With an "XOR zero" being a no effect operation.
 

techElder

Well-known member
There is a 'C' function on page 42 that does a lookup into a LO and HI table of all possible CRC values. Claims to be quicker than the calculation.
 

techElder

Well-known member
Perhaps the specification added the "test for zero" branch just to save the XOR operation?

As I understand your explanation of the algorithm, since "XOR zero" has no effect, any "test for zero" would add more overhead to the routine for no possible gain.
 

srnet

Senior Member
I've never seen "CRC16_CCITT" in the MODBUS specs.

Actually, I don't remember seeing this spec for CRC anywhere but in the "serial line specification" mentioned above. Makes sense, though.
I mentioned it as its one of the CRC formats supported by the RFM22B radio transceiver for CRC checked data packets, its also used by high altitude balloon guys for checking the NMEA style FSK RTTY data that they transmit.

There is some working PICAXE code for it, I checked it out, it does work and takes about 1.5 seconds to do the CRC on a 50 character string.
 

hippy

Technical Support
Staff member
There is a 'C' function on page 42 that does a lookup into a LO and HI table of all possible CRC values. Claims to be quicker than the calculation.
Might be and it is usually argued that doing it once for a byte is quicker than doing it eight times for each bit.

That does however depend on what the overhead for a byte and per bit is. The amount of written code in C doesn't necessarily reflect what's done under the hood. The PICAXE doesn't have the same under the hood functionality as C so arrays have to be explicitly implemented for PICAXE and what may be 'faster in C' may well be slower for a PICAXE.

I would guess it is probably faster for a PICAXE but never tried it. It needs 512 bytes of data (DATA and TABLE) and we only had DATA when the CRC algorithms were originally developed so it wasn't a feasible algorithm then. Using LOOKUP would have been far slower than doing it per bit.

Perhaps the specification added the "test for zero" branch just to save the XOR operation?
Could be. I think it's just poorly worded in the text part.

As I understand your explanation of the algorithm, since "XOR zero" has no effect, any "test for zero" would add more overhead to the routine for no possible gain.
That's right. Rather then 'determine if needed', 'if needed', 'do it' ( 2 or 3 operations, 2.5 on average ) it's just as easy to do it regardless and have the affect 'do nothing' and hope each case is going to be 2.5 or less.

For a PICAXE, execution time is proportionate to the number of tokens and this uses fewer than the alternative, and hopefully saves enough to more than offset the cost of a multiply. Not sure I ever tested that though.

Even if it were slower it uses less code space, looks quite elegant and compact so just went with it. Speed wasn't really a primary objective and code size was more important back then than now.
 

techElder

Well-known member
That time is interesting as my project will think that is a "very long time." Thanks!

...There is some working PICAXE code for it, I checked it out, it does work and takes about 1.5 seconds to do the CRC on a 50 character string.
 

techElder

Well-known member
Thanks for y'alls help. Hopefully, this will get a real world test. At the moment I'm settling on a 28X2 so should be a good test.
 

hippy

Technical Support
Staff member
The PICAXE doesn't have the same under the hood functionality as C so arrays have to be explicitly implemented for PICAXE and what may be 'faster in C' may well be slower for a PICAXE.
But perhaps not and I might have been selling the PICAXE a bit short there. Arrays for data (EEPROM/DATA and TABLE) are quite efficiently handled in PICAXE basic (READ and READTABLE) and with a bit of optimisation the code for doing it a byte at a time isn't that complicated.

For a four byte packet, at 8MHz;

60.61ms doing it bit-wise as per spec, only XOR'ing when needed (CrcSpec)
52.45ms doing it the optimised bit-wise way (CrcBits)
13.01ms doing it byte-wise (CrcByte)

Code:
#Picaxe 20X2
#Terminal 9600

Symbol crc        = w1
Symbol polynomial = w2
Symbol k          = w3
Symbol data_byte  = b0

Symbol crc.lsb    = b2
Symbol crc.msb    = b3

Do
  Gosub CrcSpec : SerTxd("Spec = ", #crc, CR, LF         )
  Gosub CrcBits : SerTxd("Bits = ", #crc, CR, LF         )
  Gosub CrcByte : SerTxd("Byte = ", #crc, CR, LF, CR, LF )
  Pause 5000
Loop

CrcSpec:
  crc        = $FFFF
  polynomial = $A001
  data_byte  = $F2  : Gosub CrcSpecAdd
  data_byte  = $1C  : Gosub CrcSpecAdd
  data_byte  = $33  : Gosub CrcSpecAdd
  data_byte  = $C2  : Gosub CrcSpecAdd
  Return
CrcSpecAdd:
  k = bit0 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit1 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit2 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit3 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit4 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit5 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit6 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  k = bit7 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If
  Return

CrcBits:
  crc        = $FFFF
  polynomial = $A001
  data_byte  = $F2  : Gosub CrcBitsAdd
  data_byte  = $1C  : Gosub CrcBitsAdd
  data_byte  = $33  : Gosub CrcBitsAdd
  data_byte  = $C2  : Gosub CrcBitsAdd
  Return
CrcBitsAdd:
  k = bit0 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit1 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit2 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit3 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit4 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit5 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit6 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  k = bit7 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
  Return

CrcByte:
  crc        = $FFFF
  polynomial = $A001
  data_byte  = $F2  : Gosub CrcByteAdd
  data_byte  = $1C  : Gosub CrcByteAdd
  data_byte  = $33  : Gosub CrcByteAdd
  data_byte  = $C2  : Gosub CrcByteAdd
  Return
CrcByteAdd:
  data_byte = data_byte ^ crc.lsb : Read      data_byte, crc.lsb
  crc.lsb   = crc.lsb   ^ crc.msb : ReadTable data_byte, crc.msb
  Return

  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $01,$C0,$80,$41,$00,$C1,$81,$40,$00,$C1,$81,$40,$01,$C0,$80,$41 )
  Eeprom ( $00,$C1,$81,$40,$01,$C0,$80,$41,$01,$C0,$80,$41,$00,$C1,$81,$40 )

  Table  ( $00,$C0,$C1,$01,$C3,$03,$02,$C2,$C6,$06,$07,$C7,$05,$C5,$C4,$04 )
  Table  ( $CC,$0C,$0D,$CD,$0F,$CF,$CE,$0E,$0A,$CA,$CB,$0B,$C9,$09,$08,$C8 )
  Table  ( $D8,$18,$19,$D9,$1B,$DB,$DA,$1A,$1E,$DE,$DF,$1F,$DD,$1D,$1C,$DC )
  Table  ( $14,$D4,$D5,$15,$D7,$17,$16,$D6,$D2,$12,$13,$D3,$11,$D1,$D0,$10 )
  Table  ( $F0,$30,$31,$F1,$33,$F3,$F2,$32,$36,$F6,$F7,$37,$F5,$35,$34,$F4 )
  Table  ( $3C,$FC,$FD,$3D,$FF,$3F,$3E,$FE,$FA,$3A,$3B,$FB,$39,$F9,$F8,$38 )
  Table  ( $28,$E8,$E9,$29,$EB,$2B,$2A,$EA,$EE,$2E,$2F,$EF,$2D,$ED,$EC,$2C )
  Table  ( $E4,$24,$25,$E5,$27,$E7,$E6,$26,$22,$E2,$E3,$23,$E1,$21,$20,$E0 )
  Table  ( $A0,$60,$61,$A1,$63,$A3,$A2,$62,$66,$A6,$A7,$67,$A5,$65,$64,$A4 )
  Table  ( $6C,$AC,$AD,$6D,$AF,$6F,$6E,$AE,$AA,$6A,$6B,$AB,$69,$A9,$A8,$68 )
  Table  ( $78,$B8,$B9,$79,$BB,$7B,$7A,$BA,$BE,$7E,$7F,$BF,$7D,$BD,$BC,$7C )
  Table  ( $B4,$74,$75,$B5,$77,$B7,$B6,$76,$72,$B2,$B3,$73,$B1,$71,$70,$B0 )
  Table  ( $50,$90,$91,$51,$93,$53,$52,$92,$96,$56,$57,$97,$55,$95,$94,$54 )
  Table  ( $9C,$5C,$5D,$9D,$5F,$9F,$9E,$5E,$5A,$9A,$9B,$5B,$99,$59,$58,$98 )
  Table  ( $88,$48,$49,$89,$4B,$8B,$8A,$4A,$4E,$8E,$8F,$4F,$8D,$4D,$4C,$8C )
  Table  ( $44,$84,$85,$45,$87,$47,$46,$86,$82,$42,$43,$83,$41,$81,$80,$40 )
 

hippy

Technical Support
Staff member
Interesting though. 60.61ms with ...

k = bit0 ^ bit16 : crc = crc >> 1 : If k <> 0 Then : crc = crc ^ polynomial : End If

But 51.98ms with an optimisation ...

k = bit0 : crc = crc >> 1 : If k <> bit16 Then : crc = crc ^ polynomial : End If

So that is faster than the 52.45ms 'optimised bit-wise version' !
 

Goeytex

Senior Member
Sorry, but I missed all of the discussion past Post# 4.

The CRC-16 routine in post #3 of this thread was used successfully (as-is) to communicate with a Cal 3300 PID Controller via MODBUS-RTU Protocol. (RS-232)
 

HOJ

New Member
modbus CRC works, but I need CRC16 CCITT

I got your Modbus CRC below to work. But my project needs CCITT CRC16 xFFFF
How can I modify the code to generate a CCITT compatible CRC16?

The polynomial I used is 0x1021 and the initial value is 0xFFFF. But I didnt get the right results.

a little help...thx!


Nice work Hippy,

Here is the code as modified by Hippy for use with a Picaxe X2.
It runs considerably faster.

Code:
;*****************************************
'* Generate 16-bit CRC on Picaxe X2 ONlY *
'* running at 16mhz.                     *   
'***************************************** 

symbol crc = W1
symbol polynomial = W2
symbol  k = W3
symbol data_byte = B0
setfreq m16

MAIN:
DO
GOSUB GENERATE_CRC
DEBUG  ' See result
PAUSE 5000
LOOP

GENERATE_CRC:
crc = $FFFF
polynomial = $A001 

data_byte = $F2   : GOSUB CrcAdd   'Four bytes of data to generate CRC on 
data_byte = $1C   : GOSUB CrcAdd   ' This can be  more or less
data_byte = $33   : GOSUB CrcAdd
data_byte = $c2   : GOSUB CrcAdd
return   'To main

	CrcAdd:
	
	k = bit0 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit1 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit2 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit3 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit4 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit5 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit6 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	k = bit7 ^ bit16 * Polynomial : crc = crc >> 1 ^ k
	Return
 

hippy

Technical Support
Staff member
How can I modify the code to generate a CCITT compatible CRC16?
Hard to say without some example data and what CRC you are expecting that to have. What someone calls CCITT CRC16 might not be what you want.

If you can provide details of what the CRC would be for a single byte message of value $01 that will usually help, as will any pointers to online calculators which give the results you are expecting.

The code at the link below uses a polynomial of $8408, inverts bits and then swaps bytes of the CRC at the end. Details of what results you get and what was wanted will help decide if just a simple change is needed or a more complicated one.

http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926
 

hippy

Technical Support
Staff member
This generates the expected $6E20 CRC for the "THE,QUICK,BROWN,FOX,0123456789" example given on the above Dr Dobbs link ...

Code:
[color=Green];*****************************************
'* Generate CCITT CRC16 on Picaxe X2 ONlY *
'* running at 16mhz.                     *   
'***************************************** [/color]

[color=Blue]symbol [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]W1[/color]
[color=Blue]symbol [/color][color=Purple]crc[/color][color=Black].lsb [/color][color=DarkCyan]= [/color][color=Purple]B2[/color]
[color=Blue]symbol [/color][color=Purple]crc.msb [/color][color=DarkCyan]= [/color][color=Purple]B3[/color]
[color=Blue]symbol [/color][color=Purple]polynomial [/color][color=DarkCyan]= [/color][color=Purple]W2[/color]
[color=Blue]symbol [/color][color=Purple]k [/color][color=DarkCyan]= [/color][color=Purple]W3[/color]
[color=Blue]symbol [/color][color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Purple]B0[/color]
[color=Blue]setfreq m16[/color]

[color=Black]MAIN:[/color]
[color=Blue]GOSUB [/color][color=Black]GENERATE_CRC[/color]
[color=Blue]DEBUG  [/color][color=Green]' See result[/color]
[color=Blue]DO[/color][color=Black]:[/color][color=Blue]LOOP[/color]

[color=Black]GENERATE_CRC:[/color]
[color=Purple]crc [/color][color=DarkCyan]= [/color][color=Navy][b]$FFFF[/b][/color]
[color=Purple]polynomial [/color][color=DarkCyan]= [/color][color=Navy][b]$8408 [/b][/color]

[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"T"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"H"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"E"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]","   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"Q"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"U"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"I"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"C"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"K"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]","   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"B"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"R"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"O"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"W"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"N"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]","   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"F"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"O"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"X"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]","   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"0"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"1"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"2"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"3"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"4"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"5"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"6"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"7"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"8"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]
[color=Purple]data_byte [/color][color=DarkCyan]= [/color][color=Red]"9"   [/color][color=Black]: [/color][color=Blue]GOSUB [/color][color=Black]CrcAdd[/color]

[color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]^ [/color][color=Navy][b]$FFFF[/b][/color]
[color=Blue]Swap [/color][color=Purple]crc.msb[/color][color=Black], [/color][color=Purple]crc[/color][color=Black].lsb[/color]
[color=Blue]return   [/color][color=Green]'To main

      [/color][color=Black]CrcAdd:
      
      [/color][color=Purple]k [/color][color=DarkCyan]= [/color][color=Purple]bit0 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit1 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit2 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit3 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit4 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit5 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit6 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      k [/color][color=DarkCyan]= [/color][color=Purple]bit7 [/color][color=DarkCyan]^ [/color][color=Purple]bit16 [/color][color=DarkCyan]* [/color][color=Purple]Polynomial [/color][color=Black]: [/color][color=Purple]crc [/color][color=DarkCyan]= [/color][color=Purple]crc [/color][color=DarkCyan]>> [/color][color=Navy][b]1 [/b][/color][color=DarkCyan]^ [/color][color=Purple]k
      [/color][color=Blue]Return[/color]
 

HOJ

New Member
CRC16 CCITT xFFFF Poly x1021

this code works for me. Pulled from another thread. But its not as fast as your code.
Correct result is 0x3DDB.


SYMBOL crc = w0 ' b0/b1
SYMBOL k = w1 ' b2/b3
SYMBOL byte_ = b4
SYMBOL bit_ = b5
symbol word2 = w12

SYMBOL POLYNOMIAL = $1021

crc = $FFFF

put 1,$00
put 2,$03 '
put 3,$80
put 4,$00
put 5,$11
put 6,$03

for b14 = 1 to 6

get b14,b15

byte_ = b15 : GOSUB Crc16Add2:

next
crc = crc ^ $0000

Crc16Add2:

word2 = byte_ << 8
crc = crc ^ word2

for byte_ = 0 to 7

word2 = crc & 0x8000
if word2 > 0 then
crc = crc << 1
crc = crc ^ 0x1021
else
crc = crc << 1
endif

next
return
 

HOJ

New Member
Running the above program yields: 0xF1D1
Same as the online calculator I referenced above.

Your program above yields 0x05B5 (using 0x1021 polynomial)

Any ideas?

Thanks
 
Top