cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H725 possible bug in CRC peripheral with input data reflection

MStra.6
Associate

During porting by code from STM32F3 to STM32H7 i had the problem, that the calculated crc of my firmware was not computed correctly.

I found out, that on STM32H7 the reflection of the crc peripheral works not correctly if writing data smaller then 4 bytes into the data register of the crc unit.

So in my example, i write a single byte into data register. To get the correct result on STM32H7, i have to reconfigure the reflection to byte-wise instead of word-wise reflection like on STM32F3.

// result is wrong on STM32H7 and correct with STM32F3
hcrc->Instance->CR = CRC_CR_REV_OUT | CRC_CR_REV_IN_0 | CRC_CR_REV_IN_1;
hcrc->Instance->CR |= CRC_CR_RESET;
*(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = (uint8_t)data;
 
// if configure input reflection byte-wise on STM32H7, then the result is equal to STM32F3
hcrc->Instance->CR = CRC_CR_REV_OUT | CRC_CR_REV_IN_0 ;
hcrc->Instance->CR |= CRC_CR_RESET;
*(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = (uint8_t)data;

Can anyone share his experiences with the crc unit on STM32H725?

4 REPLIES 4
simosilva
Senior

Looking at your shippet code, seem like the inversion was by default on half-word, 16 bit perhaps.

#define CRC_INPUTDATA_INVERSION_NONE               0x00000000U     /*!< No input data inversion            */
#define CRC_INPUTDATA_INVERSION_BYTE               CRC_CR_REV_IN_0 /*!< Byte-wise input data inversion     */
#define CRC_INPUTDATA_INVERSION_HALFWORD           CRC_CR_REV_IN_1 /*!< HalfWord-wise input data inversion */
#define CRC_INPUTDATA_INVERSION_WORD               CRC_CR_REV_IN   /*!< Word-wise input data inversion     */

For sure, stm crc default evaluation has changed in time with different families, I encountered same type of problems changing from F series to H series.

Application notes usually have good hints on how the hardware CRC is evaluated and how to solve problems, for example AN4187 at page 5 and later explain CRC on STM32 F series.

MStra.6
Associate

No. In my code snippet the reflection is set to word-wise in line 2. And in line 7 it is set to byte-wise. I also checked this in the register in debugging mode.

The ST HAL function also calculate a wrong crc if it is configured with byte input type and byte-wise reflection. So i changed the HAL code in the following snippet and everything is fine. (The original HAL code combine 4 bytes for optimization, so the byte-wise reflection does not work if a word is written in the data register)

static uint32_t CRC_Handle_8(CRC_HandleTypeDef *hcrc, uint8_t pBuffer[], uint32_t BufferLength)
{
  uint32_t i; /* input data buffer index */
  uint16_t data;
  __IO uint16_t *pReg;
 
  for (i = 0U; i < (BufferLength); i++)
  {
     *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[i];         /* Derogation MisraC2012 R.11.5 */
  }
  
//  /* Processing time optimization: 4 bytes are entered in a row with a single word write,
//   * last bytes must be carefully fed to the CRC calculator to ensure a correct type
//   * handling by the peripheral */
//  for (i = 0U; i < (BufferLength / 4U); i++)
//  {
//    hcrc->Instance->DR = ((uint32_t)pBuffer[4U * i] << 24U) | \
//                         ((uint32_t)pBuffer[(4U * i) + 1U] << 16U) | \
//                         ((uint32_t)pBuffer[(4U * i) + 2U] << 8U)  | \
//                         (uint32_t)pBuffer[(4U * i) + 3U];
//  }
//  /* last bytes specific handling */
//  if ((BufferLength % 4U) != 0U)
//  {
//    if ((BufferLength % 4U) == 1U)
//    {
//      *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[4U * i];         /* Derogation MisraC2012 R.11.5 */
//    }
//    if ((BufferLength % 4U) == 2U)
//    {
//      data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
//      pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
//      *pReg = data;
//    }
//    if ((BufferLength % 4U) == 3U)
//    {
//      data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U];
//      pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR);                    /* Derogation MisraC2012 R.11.5 */
//      *pReg = data;
//
//      *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[(4U * i) + 2U];  /* Derogation MisraC2012 R.11.5 */
//    }
//  }
 
  /* Return the CRC computed value */
  return hcrc->Instance->DR;
}

AZorn.1
Associate III

Hello,

this issue is also reproduce-able on STM32H747.

If you need inputdata-reflektion to calculate your CRC, you can not use the HAL. Especially if your data has odd size (no multiple of four)

In my opinion the HAL is wrong, because depending on the crc-computing size (4Byte or 2Byte or 1Byte) you must reconfigure the reflect-configuration on demand. Or another solution is to always calculate Byte-wise, like in you example above.

Using the original HAL implementation on H7 MCU will cause wrong CRC calculations. This makes the HAL not usable in case of CRC Calcualtions.

best regards

AZorn.1
Associate III

The following code snippet is my optimized solution to calculate the ETH-Crc with ability to have odd data length.

uint32_t STM32H735IGK6_crc32::calculate(uint8_t *dataPtr, const size_t len)
{
   uint32_t crc32 = 0;

      if (len / 4) {
         // configure the peripheral to calculate WordWise (32Bit)
         this->refHcrc.Instance = CRC;
         this->refHcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
         this->refHcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
         this->refHcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_WORD;
         this->refHcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
         this->refHcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_WORDS;
         HAL_CRC_Init(&this->refHcrc);

         crc32 = HAL_CRC_Calculate(&this->refHcrc, (uint32_t*)dataPtr, len / 4);
      }

      if (len % 4) {
         // the rest is calculated byte-wise with the prior crc as init value
         this->refHcrc.Instance = CRC;
         this->refHcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
         this->refHcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
         this->refHcrc.Init.InitValue = __RBIT(crc32);
         this->refHcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
         this->refHcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
         this->refHcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
         HAL_CRC_Init(&this->refHcrc);

         dataPtr += (len / 4) * 4;
         crc32 = HAL_CRC_Calculate(&this->refHcrc, (uint32_t*)dataPtr, len % 4);
      }

      // XOR Out
      crc32 = crc32 ^ 0xFFFFFFFF;

   return crc32;
}