2022-06-07 02:34 AM
How do I calculate the SPI CRC-16 in C? I have an STM32F429 sending me SPI data.
These are the SPI settings:
How do I implement a CRC-16 check implemented in C (not using STM32)?
It is 16-bit data with LSB first. Polynomial X1+X3
Solved! Go to Solution.
2022-06-08 03:08 AM
Thank you (I thought this solved it but no). I need more help. Possible STM32 bug.
I tried your example with polynomial 5, I got CRC = 0x9D68 on my logic analyzer and the same on the CRC calculator page:
But when I change to polynomial 10 it doesn't work. I got CRC = 0x1692 on my logic analyzer but 0x3ADA on the CRC page:
I tried it also with another polynomial 0xed2f and that one worked also. Got CRC = 0xD087 on the logic analyzer and on the CRC page:
My theory is that the CRC unit has a bug when the lower bit in the polynomial is not set to 1?
I have also tested the CRC in Python and got the same results as on the CRC page.
I found this later:
2022-06-07 03:29 AM
Ross N. Williams's article is the go-to:
http://www.ross.net/crc/download/crc_v3.txt
via: https://blog.mbedded.ninja/programming/general/crcs-cyclic-redundancy-checks/
2022-06-07 04:06 AM
Is the polynomial X1+X3 same as x^16+x^3+x^1. And what about initial value? What byte order should I input the 16-bit data? Should I reverse the bits?
2022-06-07 10:33 AM
All good questions, CRC's are complicate, and detail specific. There's a whole bunch of shift direction, and endian ordering considerations.
Do you have a collection of good test patterns for the specific application you're using? Ideally ones from a standards document, and definitely ones from the device, or a device, that's compliant and working.
Notionally the polynomial is 0x10009 or 0x12001
The STM32 SPI implementation is also super awkward, in generation you have to manage the CRC bytes/word after the data. In a ideal would the CRC reception should be a feed-thru, where the remainder/residual goes to zero as it divides thru itself.
2022-06-07 03:53 PM
To get the CRC samples, just set up that SPI as master, and then play with it in the debugger:
(gdb) set SPI2->CRCPR=0x5 // is this the poly you are after?
(gdb) set SPI2->CR1=0x2b44 // LSB bit = 0, i.e. MSB first, master 16-bit, CRC enabled
(gdb) p /x *SPI2 // checking - note TXCRCR = 0, that's the initial value
$37 = {CR1 = 0x2b44, CR2 = 0x0, SR = 0x2, DR = 0xffff, CRCPR = 0x5,
RXCRCR = 0x0, TXCRCR = 0x0, I2SCFGR = 0x0, I2SPR = 0x2}
(gdb) set SPI2->DR=0x1234 // just Tx something
(gdb) p /x *SPI2
$38 = {CR1 = 0x2b44, CR2 = 0x0, SR = 0x3, DR = 0xffff, CRCPR = 0x5,
RXCRCR = 0xc, TXCRCR = 0x5ae4, I2SCFGR = 0x0, I2SPR = 0x2}
compare TXCRC=0x5ae4 to calculation on web calculator:
Now let's try the same thing just LSB first:
(gdb) set SPI2->CR1=0 // switch off SPI
(gdb) p /x *SPI2
$39 = {CR1 = 0x0, CR2 = 0x0, SR = 0x2, DR = 0xffff, CRCPR = 0x5,
RXCRCR = 0xc, TXCRCR = 0x5ae4, I2SCFGR = 0x0, I2SPR = 0x2}
(gdb) set SPI2->CR1=0x2bc4 // same setup except LSB set
(gdb) p /x *SPI2
$40 = {CR1 = 0x2bc4, CR2 = 0x0, SR = 0x2, DR = 0xffff, CRCPR = 0x5,
RXCRCR = 0x0, TXCRCR = 0x0, I2SCFGR = 0x0, I2SPR = 0x2}
(gdb) set SPI2->DR=0x1234 // same data
(gdb) p /x *SPI2
$41 = {CR1 = 0x2bc4, CR2 = 0x0, SR = 0x3, DR = 0xffff, CRCPR = 0x5,
RXCRCR = 0xc, TXCRCR = 0x9d68, I2SCFGR = 0x0, I2SPR = 0x2}
(gdb)
Note, that now we had to reverse both bit order and bytes order (the web-calculator feeds byte-wise):
JW
2022-06-08 03:08 AM
Thank you (I thought this solved it but no). I need more help. Possible STM32 bug.
I tried your example with polynomial 5, I got CRC = 0x9D68 on my logic analyzer and the same on the CRC calculator page:
But when I change to polynomial 10 it doesn't work. I got CRC = 0x1692 on my logic analyzer but 0x3ADA on the CRC page:
I tried it also with another polynomial 0xed2f and that one worked also. Got CRC = 0xD087 on the logic analyzer and on the CRC page:
My theory is that the CRC unit has a bug when the lower bit in the polynomial is not set to 1?
I have also tested the CRC in Python and got the same results as on the CRC page.
I found this later: