1

Working on a SPI communication bus between an array of SAMD MCUs.

I have an incoming packet which is something like { 0x00, 0xFF, 0x00, 0xFF }. The receiver chip performs CRC16 check on the incoming packet.

Since I am expecting the exact same packet every time, I want to have zero CRC checksum when the packet is valid and not zero checksum when there is a transfer error.

I know that I can add the calculated CRC16 to the end of the packet when sending it and on the receiver side the CRC check will output 0, but in this case it is impossible to add a CRC16 checksum to the packet since the packet is constructed by multiple sender chips on the SPI line and each chip only fills its own two bytes from the entire packet.

I need to load an initial CRC checksum on the receiver side, so after the incoming packet is checked, the resulting CRC equals to zero (if packet is intact).

The answer here on SO is actually what I am looking for, but it is for CRC32 format and I don't actually understand the principle of the code, so I can't rewrite if for CRC16 format.

Any help would be greatly appreciated!

Regards, Niko

NikoDiYana
  • 31
  • 9

2 Answers2

2

The solution is simply to use a look-up table based CRC. If you can't append the checksum (aka the Frame Check Sequence, FCS) to the package, then do the table look-up first and then simply compare that one against the expected sequence for your fixed data.

Please note that "CRC 16" could mean anything, there are multiple versions and (non)standards. The most common one is perhaps the one called "CRC-16-CCITT" with 1021h poly and initial value FFFFh, but even for that one there's multiple algorithms out there - some are correct, some are broken. Your biggest challenge will be to find a trustworthy CRC algorithm.

However, I actually think SAMD specifically uses hardware-generated CRC-16-CCITT on-chip, for DMA purposes. Since this is SPI, it should be DMA-able, so perhaps investigate if you can use that one somehow.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Yes, you are right, indeed the SAMD hardware CRC16 version which I am using is CRC-16-CCITT with polynomial 0x1021. A DMA channel which reads the SPI frames is used for calculating it. Regarding the look-up table, this is the way I am doing right now, knowing all the possible states of the incoming packet, I have a LUT to compare the checksums. However I am also receiving "conventional" packets with an added FCS, so I need to pre-load a state before the transfer to know what checksum to expect. And I want to avoid this by just checking the checksum against zero for all the packets. – NikoDiYana Apr 23 '20 at 08:39
  • @NikoDiYana I'm not sure how you expect to solve that. Will the packages have different sizes with or without FCS appended, or how can you tell the difference? – Lundin Apr 23 '20 at 08:44
  • The SPI master chip sends a byte number request to the slaves. This is how it knows what packet to expect. On the next transaction the slaves respond. – NikoDiYana Apr 23 '20 at 08:53
  • @NikoDiYana Is enabling/disabling the hardware CRC check an option then? Depending on what you expect. – Lundin Apr 23 '20 at 09:39
  • Yes, but I still need to check the contents of the incoming packet. If a chip on the line is not responding, its slot in the packet will be 0x00. I perfectly realise that I can do this with a LUT or a loop, but the thing is that the master is doing a computation meanwhile and a quick check against zero can be done in the receive data interrupt and not break the main loop. – NikoDiYana Apr 23 '20 at 10:15
0

I found a solution, thanks to the advice of Bastian Molkenthin, who did this great online CRC calculator.

He advised trying a brute force calculation of all the 2^16 values of a CRC16 initial value. Indeed, after a few lines of code and few microseconds later the SAMD51 found an initial value, which matches a zero CRC value for the given buffer.

Dharman
  • 30,962
  • 25
  • 85
  • 135
NikoDiYana
  • 31
  • 9