2019-08-21 10:26 PM
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
2019-08-22 05:44 AM
@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
2019-08-22 06:18 AM
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.
2019-08-22 10:34 AM
Ok, there was a restartable table driven version too
https://community.st.com/s/global-search/0x82608EDB
crcvalue1 = HAL_CRC_Calculate(&CRCType, &byte_array_hex[0], 37000);
//...
__HAL_CRC_DR_RESET(&CRCType);
//...
if (CRCType.Instance->DR != crcvalue1) // ... Some Time Later
CRCType.Instance->DR = ReverseCRC32(CRCType.Instance->DR, crcvalue1);
crcvalue2 = HAL_CRC_Accumulate(&CRCType, &byte_array_hex[37000], 13000);
static uint32_t ReverseCRC32(uint32_t currentCRC, uint32_t desiredCRC)
{
static const uint32_t CrcTable[16] = { // For 0x04C11DB7 Reverse Polynomial sourcer32@gmail.com
0x00000000, 0xB2B4BCB6, 0x61A864DB, 0xD31CD86D, 0xC350C9B6, 0x71E47500, 0xA2F8AD6D, 0x104C11DB,
0x82608EDB, 0x30D4326D, 0xE3C8EA00, 0x517C56B6, 0x4130476D, 0xF384FBDB, 0x209823B6, 0x922C9F00 };
if (desiredCRC == 0) // Optimization, applying CRC to self will clear
return(currentCRC);
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
desiredCRC = (desiredCRC >> 4) ^ CrcTable[desiredCRC & 0x0F];
return(desiredCRC ^ currentCRC);
}
2019-08-22 10:36 PM
Wow, that's amazing thank you very much!
2019-08-23 07:57 AM
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
2019-08-23 08:35 AM
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.
2019-08-23 08:52 AM
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)
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?
2019-08-23 09:17 AM
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));
}
2019-08-23 10:22 AM
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