Skip to main content
stucmath
Associate II
August 22, 2019
Question

STM32f42xx CRC stop/resume

  • August 22, 2019
  • 9 replies
  • 4511 views

Hello

Since the STM32f42xx series has no intial value for the CRC I'm wondering if there is a way to stop a crc calculation (store the DR value) and resume it by writing the DR register with the stored value and some calculation??

Something like this:

crcvalue1 = HAL_CRC_Calculate(&CRCType, &byte_array_hex[0], 37000);
__HAL_CRC_DR_RESET(&CRCType);
CRCType.Instance->DR = crcvalue1;
crcvalue2 = HAL_CRC_Accumulate(&CRCType, &byte_array_hex[37000], 13000);

The goal is to interrupt a ongoing CRC calculaton with a higher prioritized calculation and afterwards resume to the lower priority again.

Kind regards

Mathias

This topic has been closed for replies.

9 replies

waclawek.jan
Super User
August 22, 2019

@Community member​ is the expert in the field; see for examle https://community.st.com/s/question/0D50X00009XkbxTSAR/crc-calculation-unit-initialize (misformatting courtesy of failed forum software conversions).

JW

Tesla DeLorean
Guru
August 22, 2019

The F4 lacks access to the register, setting 0xFFFFFFFF or 0x00000000 is relatively easy/cheap, other values require a computation.

Bit of a design oversight in my opinion, could have been implemented trivially.

I can probably generate a more efficient table driven version.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
stucmath
stucmathAuthor
Associate II
August 23, 2019

Wow, that's amazing thank you very much!

stucmath
stucmathAuthor
Associate II
August 23, 2019

Since you ar the expert on this topic.

Is there a way to convert a CRC32b to CRC32 value?

My problem is: With the STM32F4 I have to get the same CRC value as the Fujitsu FM3 CRC (MB9BF416N) calculates (for retro compatibilty).

Configuration of the Fujitsu FM3 CRC:

void CRC_crcInit()
{
 bFM3_CRC_CRCCR_FXOR = 1; // XOR Result : 0 = None, 1 = Yes
 bFM3_CRC_CRCCR_CRCLSF = LSB_FIRST; // Result Bitorder : 0 = MSB First, 1 = LSB First
 bFM3_CRC_CRCCR_CRCLTE = LITTLE_ENDIAN; // Result Byteorder : 0 = Big endian, 1 = Little Endian
 bFM3_CRC_CRCCR_LSBFST = LSB_FIRST; // Input Bit-order : 0 = MSB First, 1 = LSB First
 bFM3_CRC_CRCCR_LTLEND = LITTLE_ENDIAN; // Input Byteorder : 0 = Big endian, 1 = Little Endian
 bFM3_CRC_CRCCR_CRC32 = 1; // Mode : 0 = CRC16, 1 = CRC32
}

I calculated the CRC on both uC.

Input value: 0x12345678

STM result: 0xdf8a8a2b

Fujitsu result: 0xaf6d87d2

I think the STM uC works with the CRC32b algorithm while the Fujitsu works with the CRC32.

What do you think? Is there a chance to get the same result without changing the CRC settings from the fujitsu controller?

Kind regards

Mathias

Tesla DeLorean
Guru
August 23, 2019

The CRC on the STM32 (F1/F2/F4) is fixed and awkward, done 32-bit at a time, with the wrong endianess.

Later STM32 designs had a programmable CRC peripheral, but the design could have been executed far better.

The FM3 seems to use the same polynomial (0x04C11DB7), the byte order is probably correct.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
August 23, 2019

 crc = Crc32(0xFFFFFFFF, revbit(0x12345678));

 crc = ~revbit(crc); // 0xAF6D87D2

 printf("%08X\n", crc);

Intrinsic is __RBIT

uint32_t revbit(uint32_t data) // IAR
{
 asm("rbit r0,r0");
 return data;
}
 
__asm uint32_t revbit(uint32_t data) // KEIL
{
 rbit r0, r0
 bx lr
}
 
uint32_t revbit(uint32_t data) // C
{
 int i;
 uint32_t rev = 0;
 
 for(i=0; i<32; i++)
 rev |= ((data >> i) & 1) << (31 - i);
 
 return rev;
}
 
uint32_t CalcCRC32FM3(uint32_t *buffer, uint32_t count) // sourcer32@gmail.com
{
 while(count--)
 CRC->DR = revbit(*buffer++); // rbit r0,r0
 
 return(~revbit(CRC->DR));
}

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
stucmath
stucmathAuthor
Associate II
August 23, 2019

Yes thats right, the FM3 has the same polynomial.

I did some testing with the FM3 uC. I changed the CRC Input Byteorder from little endian to big endian and I received this crc value:

0x4A090E98

On the STM uC I did an XOR calculation the the result value:

0xDF8A8A2B^0xFFFFFFFF = 0x207575D4

Then I check these two values with an online CRC calculator (https://crccalc.com)

0690X00000AAD43QAH.png

But I have no Idea what the difference between these two calculations are.

Is there a way to get from one to the other value with a calculation?

waclawek.jan
Super User
August 23, 2019
 static const uint32_t testArray[] = {0x12345678, };
 static volatile uint32_t result;
 
 CRC->CR = CRC_CR_RESET;
 __asm("nop \n\t nop \n\t nop"); // to avoid the HW bug described in https://community.st.com/s/feed/0D50X00009XkW6NSAV
 
 uint32_t i;
 for (i = 0; i < sizeof(testArray) / sizeof(testArray[0]); i++) {
 CRC->DR = __RBIT(testArray[i]);
 }
 
 result = __RBIT(CRC->DR) ^ 0xFFFFFFFF;
 // (gdb) p /x result
 // $14 = 0xaf6d87d2

JW

stucmath
stucmathAuthor
Associate II
August 26, 2019

Once again an awesome solution. Thank you very much!

Now I have to figure out how to use this solution with DMA.

Do you maybe have an idea how I could do that?

Is it possible to change the dma data before every transfer?

Tesla DeLorean
Guru
August 26, 2019

DMA can't do bit manipulation. HW CRC unit not that well thought out. Newer parts offer additional options.​

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
August 27, 2019

+1 to what Clive said, no option to do this with DMA.

The other side appears to have more flexibility; I'd expect you can pull this out with a bit of experimentation.\

JW

stucmath
stucmathAuthor
Associate II
August 27, 2019

Yes, there is no way to do that with DMA.

But what do you mean with "the other side appears to have more flexibility"?

waclawek.jan
Super User
August 29, 2019

> But what do you mean with "the other side appears to have more flexibility"?

I was under the impression you need to communicate between STM32 and FM3 (then the latter would be the "other side"), but upon second reading I now see you need backwards compatibility rather. Sorry for the confusion.

JW

stucmath
stucmathAuthor
Associate II
August 29, 2019

@Community member​ Do you have some sort of mathematic derivation how the reverse crc calculaton works?

Tesla DeLorean
Guru
August 29, 2019

I have a more mechanical understanding of the method/process. The other threads show the bit level reversal method, and the table driven versions are pulled from that. You can move the polynomial backward and forward in time.

These CRC/LFSR implementations have historically been used for error detection/correction. Fire codes were an early use of these. When the checksum fails you wind it backward, applying the bits in the reverse order, and shifting in the opposite direction, and you can determine where a couple of bits are wrong, and fix them. Basically approaching a discontinuity from both directions. In the context here, I'm using those techniques to compute a value that will undo itself when applied to a specific starting value.

Neal Glover Fire Codes http://www.bitsavers.org/components/cirrusLogic/Practical_Error-Correction_Design_For_Engineers_2ed_1991.pdf

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Guru
August 29, 2019
DWORD Crc32(DWORD Crc, DWORD Data)
{
 int i;
 
 Crc = Crc ^ Data; // Data applied first, cheaper to apply XOR here than 1-bit at a time
 
 for(i=0; i<32; i++)
 if (Crc & 0x80000000)
 Crc = (Crc << 1) ^ 0x04C11DB7; // Polynomial used in STM32
 else
 Crc = (Crc << 1); // Shifts left in forward direction
 
 return(Crc);
}
 
 
DWORD Crc32Rev(DWORD CurrentCrc, DWORD DesiredCrc)
{
 DWORD Data;
 int i;
 
 for(i=0; i<32; i++)
 if (DesiredCrc & 0x00000001)
#if 1
 DesiredCrc = ((DesiredCrc ^ 0x04C11DB7) >> 1) | 0x80000000; // Long form
#else // or
 DesiredCrc = (DesiredCrc >> 1) ^ 0x82608EDB; // Back feeding polynomial
#endif
 else
 DesiredCrc = (DesiredCrc >> 1); // Shifts right in the reverse direction
 
 Data = DesiredCrc ^ CurrentCrc; // Data removed last
 
 return(Data); // Data Pattern to get Desired CRC from Current CRC
}
 
The polynomial is 33-bits long in reality, in the form x**32 + .. + 1
We play games here with left/right alignment so it fits within the 32-bits
afforded by the machine.
 
0x04C11DB7 -> 1 0000 0100 1100 0001 0001 1101 1011 0111
 
0x82608EDB -> 1000 0010 0110 0000 1000 1110 1101 1011 1

@Community member​  the forum is screwy, you have to click "Previous Answers" due to the node you replied too

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..