Search code examples
stm32endiannesscrcdma

STM32G030 / CRC_DR / how to use 32bit writes?


Somehow I do not get 0xD0FA with 0x12345678 and 16bit POLY 0x1021, when I use word access for CRC_DR.

exempli gratia: pseudo code:

RCC.CRCEN=1; CRC_CR.POLYSIZE=0b01; CRC_POL=0x1021; CRC_INIT=0; CRC_CR.RESET=1;
CRC_DR=0x12345678;
CRC_DR contains 0x0000B42C but my own CRC routine says 0xD0FA.

but this works fine:

RCC.CRCEN=1; CRC_CR.POLYSIZE=0b01; CRC_POL=0x1021; CRC_INIT=0; CRC_CR.RESET=1;
CRC_DR=0x78563412;

none of the REV* bits help me (i tried all 8 combinations...). I wonder in which case the REV* bits could help... It is much more likely that the endianness needs adjustment... e.g.:

char word[4] = {'b','i','r','d'};
The 'b' should be fed first to the CRC unit...

I would prefer to use the word access with DMA, because: That is more than twice as fast compared to DMA-1-byte and 25% faster than my hand-crafted assembler routine...


Solution

  • The STM32 CRC unit inexplicably feeds starting with the Most-Significant-Byte, which - as you've already noticed - is in conflict with the whole rest of this mcu being little-endian. So, if you have in memory bytes 0x12 0x34 0x56 0x78 and you read them as a word, they are read as 0x78563412 and the CRC unit feeds them in as 0x78 0x56 0x34 0x12, whereas if you'd read byte by byte and feed so to CRC they would be in order 0x12 0x34 0x56 0x78 - and this of course leads to different results. The latter method is the usual one with the vast majority of communication and storage protocols, that's why most users are confused by the STM32 CRC unit (including me).

    The REV_xx bits in the newer STM32 CRC_CR won't help with this, as they perform bitwise reversals, they don't swap bytes. Bitwise reversals are needed because some CRC incarnations are simply defined like this. At the end of the day, CRC is just a shift register with feedback taps, and the shift register can be designed to go either direction. This, together with initial/final xor and some other rarely used obscure features, makes CRC as an algorithm parametrizable to a painful extent.

    Now if you feed the CRC using the processor (as opposed to DMA, where only bytewise feed is feasible but given it works autonomously it's not that painful), after reading the word from memory and before feeding it into CRC, you can use the REV instruction to swap bytes. In C, you can use the CMSIS intrinsics __REV().