2018-09-04 08:55 AM
If LL_CRC_INDATA_REVERSE_WORD is set and 8-bit data is provided via LL_CRC_FeedData8(), the resulting CRC is not what is expected. It appears the combination of word-reversal and byte-submission mangles the submitted data in some way, when I had expected it to fall back to byte reversal.
The datasheet does not indicate this is a concern, and the HAL code freely mixes word, half-word, and byte sizes, giving results that do not match third party calculators when dealing with data that isn't a multiple of 4 bytes in length. For example, these three all give correct results (22C644CD):
uint8_t data8[8] = {0x1F, 0x52, 0x41, 0x9C, 0xB6, 0xAF, 0, 0};
uint16_t * data16 = (uint16_t *)data8;
uint32_t * data32 = (uint32_t *)data8;
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_BYTE);
LL_CRC_ResetCRCCalculationUnit(CRC);
LL_CRC_FeedData8(CRC, data8[0]);
LL_CRC_FeedData8(CRC, data8[1]);
LL_CRC_FeedData8(CRC, data8[2]);
LL_CRC_FeedData8(CRC, data8[3]);
LL_CRC_FeedData8(CRC, data8[4]);
LL_CRC_FeedData8(CRC, data8[5]);
crc = ~LL_CRC_ReadData32(CRC);
printf("rev by byte: %08lX\n", crc);
LL_CRC_ResetCRCCalculationUnit(CRC);
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_WORD);
LL_CRC_FeedData32(CRC, data32[0]);
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_HALFWORD);
LL_CRC_FeedData16(CRC, data16[2]);
crc = ~LL_CRC_ReadData32(CRC);
printf("rev by word/halfword: %08lX\n", crc);
LL_CRC_ResetCRCCalculationUnit(CRC);
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_WORD);
LL_CRC_FeedData32(CRC, data32[0]);
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_BYTE);
LL_CRC_FeedData8(CRC, data8[4]);
LL_CRC_FeedData8(CRC, data8[5]);
crc = ~LL_CRC_ReadData32(CRC);
printf("rev by word/byte: %08lX\n", crc);
The HAL code does the equivalent of this, which gives incorrect results (B1C2A1A3):
LL_CRC_ResetCRCCalculationUnit(CRC);
LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_WORD);
LL_CRC_FeedData32(CRC, data32[0]);
LL_CRC_FeedData8(CRC, data8[4]);
LL_CRC_FeedData8(CRC, data8[5]);
crc = ~LL_CRC_ReadData32(CRC);
printf("rev by word: %08lX\n", crc);
LL_CRC_INDATA_REVERSE_NONE only gives the correct results if the bytes are reversed before sending to the CRC hardware. The HAL code appears to be quite broken when handling bytes: CRC_Handle_8()'s byte ordering requires bit reversal on input, but its mixing of data sizes without changing the reversal settings requires unreversed input.
2024-02-22 02:37 AM
Thanks for the follow up!
The MCU is STM32F767.
Not much to the code, but here it is: It works on the F7 if you are on 4-byte boundary (ie the first branch only). If you get down to byte access the calculation fails.
Cube MX settings:
Code (I could not figure out how to format this better). Sorry for the sloppy indentations.
u16_t Crc_Pfm_CalcCrc(u8_t *pu8_buf, u32_t u32_len)
{
u16_t u16_crc = K_NUM_START_CRC;
if (pu8_buf)
{
CRC->INIT = u16_crc;
u32_t u32_i = 0;
/* The crc dr register can handle multiple bytes in the form of a u32. You have to be
* very specific about the access. Hence all of the typecasting around the set */
while (u32_len >= 4)
{
(*((volatile u32_t *)(&(CRC->DR)))) = *(u32_t *)(&(pu8_buf[u32_i]));
u32_len -= 4;
u32_i += 4;
}
while (u32_len >= 2)
{
(*((volatile u16_t *)(&(CRC->DR)))) = *(u16_t *)(&(pu8_buf[u32_i]));
u32_len -= 2;
u32_i += 2;
}
while (u32_len >= 1)
{
(*((volatile u8_t *)(&(CRC->DR)))) = *(u8_t *)(&(pu8_buf[u32_i]));
u32_len--;
u32_i++;
}
u16_crc = CRC->DR;
}
else
{
/* null pointer */
}
return u16_crc;
}
2024-02-22 04:22 AM
Ok, so an 0x8005 polynomial, left shifting
Yes, I'd expect you'd need to change how it handles the byte-endian switching for half-words. Or perhaps writing half-words at CRC->DR + 2
The memory read via the pointer is little-endian, and the CRC is ingesting big-endian
On an MCU level the use of REV or REV16 might be simpler to manage than the peripheral
2024-02-22 04:38 AM
Are you suggesting I change the CRC->DR to a (u8 *) and do a +2 for u16 and +3 for u8? If you think that might work, I'll give it a shot.
The software implementation I have works fine, but using the peripheral is much, much faster. I took some measurements on the G0 calculating a CRC of a small array at 64MHz actually. See below:
Times reflect each test was ran at a multiple of 100 | |||
Test | Min (µs) | Max (µs) | Avg (µs) |
Software CRC | 4583 | 4607 | 4585 |
Hardware CRC | 607 | 627 | 609 |