Author Topic: Rant[+solution]: STM32F0 CRC engine  (Read 3548 times)

0 Members and 1 Guest are viewing this topic.

Offline poorchavaTopic starter

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Rant[+solution]: STM32F0 CRC engine
« on: March 22, 2017, 08:03:53 am »
Hi, so I have this device that used STM32F030. I did use its CRC module before, but it was being verified against crc also generated by the MCU itself (user setting integrity checks and such).

This time i wanted to use this to verify firmware image uploaded via a custom bootloader. Obviously the CRC is being calculated on PC. Since The datasheet claims to use standard Ethernet CRC, I thought i was golden. Boy was I wrong.

I've downloaded some CRC32 code for c# and generated a CRC from few random bytes from this and from the MCU. No match.

I've checked several other implementations for the PC program as well as online calculators and they all aggreed, result from MCU is different.

4 hour of  |O |O |O |O |O |O |O |O |O |O later, I couldn't find any set of settings for the MCU CRC engine that would generate remotely similar result.

I then started brute-forcing all the combinations of all possible CRC engine settings. To no avail. And then I tried the same thing, but also reversing all the bits in the output ( xor 0xffffffff). One combination worked. :wtf: :wtf:

How to make it work?
-set input inversion to 8/16/32 bits, which one it doesn;t matter as long as you're doing byte-wise CRC. No idea about 16- or 32 bits at a time, only that they produce different output.
-set output inversion to enabled
-flip all the bits in the resulting CRC, the output will match the commonly available algorithms

<rant>

What the f** were they thinking. If they needed to implement the algorithm in some f**ed up way, they could've just published an appnote saying "do this, in order to convert out weird crc into something standard".

 :-- :-- :-- :--

</rant>


I love the smell of FR4 in the morning!
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4228
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #1 on: March 22, 2017, 08:25:50 am »
It's pretty common to find that line protocols which use a CRC don't transmit it using the byte ordering and/or bit sense that you're expecting. There's almost certainly nothing wrong, odd or unusual about the STM32 CRC engine.

IIRC I found exactly the same thing when implementing a serial HDLC controller in FPGA. The generator polynomial was well known. Less well known was the fact that the bytes in the CRC were transmitted with the bit ordering reversed (or something... it was a long time ago and I forget the exact details) compared to the data bytes they related to.

Consider it a fun little cryptography challenge. Expect bit and byte ordering to be changed, and spend half an hour working out what you need to do to make your code match a known sample.

Offline bktemp

  • Super Contributor
  • ***
  • Posts: 1616
  • Country: de
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #2 on: March 22, 2017, 08:40:46 am »
I have the same problems with most CRCs. Giving the polynomial isn't enought, because there are so many variants how to apply this polynomial. I can't understand why manufacturers just don't put some example C code next to the polynomial.
I used this code and it gave me the correct results for STM32F0:
https://community.st.com/thread/21851
 

Offline dgtl

  • Regular Contributor
  • *
  • Posts: 183
  • Country: ee
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #3 on: March 22, 2017, 09:26:34 am »
There are so many different CRCs, that it is not suprising they do not use the same. I like to keep the protocols standard CRC32, so I'm doing the conversions on the uc side. You'll need to reverse bit order of all words and invert the output to get standard CRC32. This means that you'll have to use sw and can't use DMA. There is ARM ASM instruction RBIT for that, use CMSIS macro __RBIT. (Some newer parts have the bit order reversal configuration in hw, too).
There are much more difficult issues:
1) Calculating CRC of data that is not multiple of 4 bytes long. A bit of math helps in this case.
2) Setting the CRC value back to a pre-defined value (in case I need to calculate 2 CRCs interleaved). Some more math to write the correct value to get the required start state in data register.
3) For some unknown reason, the reset of the CRC fails if there is high DMA load on both DMA controllers (at least on F107). The rest works, so I'll just use the math in 2) to set the data register to required state.

The best I've come up so far is following code. I used this thread as reference: https://community.st.com/message/49784
Code: [Select]
static uint32_t crc32_step(uint32_t crc, uint8_t data) {  // single byte
    crc = ~crc ^ data;
    CRC->DR = (~CRC->DR) ^ __RBIT(~(crc << 24));
    return (crc >> 8) ^ ~__RBIT(CRC->DR);
}

static uint32_t crc32_4(uint32_t crc, const uint32_t *data, uint32_t cnt) { // word-wise
    if (cnt == 0) return crc;
    CRC->DR = (~CRC->DR) ^ __RBIT(*data++ ^ crc);
    cnt--;
    while(cnt--) {
    CRC->DR = __RBIT(*data++);
    }
    return ~__RBIT(CRC->DR);
}

uint32_t crc32(uint32_t crc, const void *data, uint32_t cnt) {
uint8_t* d = (uint8_t*) data;
__CRC_CLK_ENABLE();
// handle first bytes until the buffer gets word-aligned
while((((uint32_t)d) & 3) != 0 && cnt > 0) {
crc = crc32_step(crc, *d++);
cnt--;
}

// handle the 4-byte words
uint32_t cnt4 = cnt / 4;
crc = crc32_4(crc, (const uint32_t *)d, cnt4);
cnt4 = cnt4 * 4;
d += cnt4;
cnt -= cnt4;

// handle the rest of the bytes
while(cnt) {
crc = crc32_step(crc, *d++);
cnt--;
}
    return crc;
}
 

Offline poorchavaTopic starter

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #4 on: March 22, 2017, 01:45:28 pm »
I have tried __RBIT, but it appears, that CM0 does not support that instruction (ie. cmsis headers make it available only on M3/M4/M7).

I remember having used the CRC on some F4 for the same exact purpose, and it was pretty painful.

Still, since Ethernet variant of CRC32 is really popular and well documented, they could've gone to the effort of implementing it properly.

Not so long ago I was implementing similar stuff using TMS320's built in CRC engine and I was able to coerce it into generating standard CRC16-CCITT without much problem. And this is considering that TI has a reputation for implementing stuff ass-backwards

I love the smell of FR4 in the morning!
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 2365
  • Country: de
    • Frank Buss
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #5 on: March 22, 2017, 03:03:46 pm »
Hi, so I have this device that used STM32F030. I did use its CRC module before, but it was being verified against crc also generated by the MCU itself (user setting integrity checks and such).

This time i wanted to use this to verify firmware image uploaded via a custom bootloader. Obviously the CRC is being calculated on PC. Since The datasheet claims to use standard Ethernet CRC, I thought i was golden. Boy was I wrong.

Testing a bootloader is not time critical, I probably would have implemented it in software, would be no problem for the 48 MHz ARM core. You could even implement the bitwise algorithm without a lookup table, if code size is a problem. Might be less code all in all than using the hardware CRC engine.
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline dgtl

  • Regular Contributor
  • *
  • Posts: 183
  • Country: ee
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #6 on: March 22, 2017, 05:01:23 pm »
I have tried __RBIT, but it appears, that CM0 does not support that instruction (ie. cmsis headers make it available only on M3/M4/M7).
Correct, CM0 and CM0+ do not have RBIT. Missed that in your post ;)

I remember having used the CRC on some F4 for the same exact purpose, and it was pretty painful.
Still, since Ethernet variant of CRC32 is really popular and well documented, they could've gone to the effort of implementing it properly.
Not so long ago I was implementing similar stuff using TMS320's built in CRC engine and I was able to coerce it into generating standard CRC16-CCITT without much problem. And this is considering that TI has a reputation for implementing stuff ass-backwards
At least they seem to have changed it in newer parts. A more common CRC would have been much more useful; theirs looks like the MPEG2 variant with the same polynomial but different bit order.

In case of M0, it is either use it as-is (change the other end to the same as you did) or use software CRC. Reversing bit order in software is too slow.
 

Offline poorchavaTopic starter

  • Super Contributor
  • ***
  • Posts: 1672
  • Country: pl
  • Troll Cave Electronics!
Re: Rant[+solution]: STM32F0 CRC engine
« Reply #7 on: March 22, 2017, 08:08:53 pm »
As far as i understand reversing the bit order is done by setting configuration bits in CRC control register, so no software overhead is involved. The only software operation required seems to be the xor at the end.

On the other hand i've made a comparison between setting bit-reverse options in the control register, and not setting them, but reversing the input data manually instead - the results were different.
I love the smell of FR4 in the morning!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf