• Modbus CRC using an STM32 controller

    10/26/2025 at 20:10 0 comments

    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.