Close

Modbus CRC using an STM32 controller

oaolsenO.A.Olsen wrote 10/26/2025 at 20:10 • 1 min read • Like

The Modbus RTU protocol calls for the calculation of the CRC for each message transmitted. 

From the perspective of an STM32 controller the CRC calculation properties are  : 

  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
  hcrc.Init.GeneratingPolynomial = 32773;
  hcrc.Init.CRCLength = CRC_POLYLENGTH_16B;
  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;

 In hexadecimal notation the polynomial value is 0x8005. Equivalent to using  this polynomial in the MX configurator : X15+X2+X0. The CRC can be calculated by the hardware CRC block by using this function:

uint16_t hwCalcCrc(uint8_t *d, int bytes) 
{
    int i;
    hcrc.Instance->CR |= 1;// Reset the calculator
    for (i=0; i<bytes; i++)
     *(__IO uint8_t *)(__IO void *)(&hcrc.Instance->DR) = d[i];
    return hcrc.Instance->DR;
}

 The C pre-processor  replaces volatile for the __IO macro. So, this is a trick to keep  the compiler from optimizing out repeated writes to the same static register.

// WORKS:
*(__IO uint8_t *)(__IO void *)(&hcrc.Instance->DR) = d[i];

// DOESN'T WORK
hcrc.Instance->DR = d[i]; 

Test message: 

The CRC of 

[ 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x02, 0xAA, 0xAA]

 is 0x8f58.

Like

Discussions