cancel
Showing results for 
Search instead for 
Did you mean: 

How to calc CRC16 for Modbus?

sdianoff
Associate II

My controller is STM32L462. I need to compute CRC16 for Modbus application. There is CRC initialization function:

void MX_CRC_Init_CRC16(void)
{
  hcrc.Instance = CRC;
  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
  hcrc.Init.GeneratingPolynomial = 0xa001;
  hcrc.Init.InitValue = 0xffff;
  hcrc.Init.CRCLength = CRC_POLYLENGTH_16B;
  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
  if (HAL_CRC_Init(&hcrc) != HAL_OK)
  {
    Error_Handler();
  }
}

There is function to calc CRC16 by software. It works correct.

uint16_t calc(uint8_t *packet, uint8_t size)
{
    uint16_t crc_polynome = 0xa001;
    uint16_t crc = 0xffff;
    for (uint8_t j = 0; j < size; j++)
    {
        crc ^= packet[j];
        for (uint8_t i = 0; i < 8; i++)
        {
            if (crc & 0x1)
            {
                crc >>= 1; 
                crc ^= crc_polynome;
            } 
            else 
            { 
                crc >>= 1;
            }
        }
    }
    return crc;
}

Now I compare CRC16 values calculated by hardware and software:

TEST(CRC, CRC16)
{
    uint8_t buf[] = {0x10, 0x04, 0x00, 0x0c, 0x00, 0x01}; //Modbus CRC=0xF288
    //uint8_t buf[] = {0, 1, 2, 3, 4, 5, 6, 7};
    MX_CRC_Init_CRC16();
    uint16_t hardCrc = static_cast<uint16_t>(HAL_CRC_Calculate(&hcrc, reinterpret_cast<uint32_t*>(buf), sizeof buf));
    uint16_t softCrc = calc(buf, sizeof buf);
    TEST_ASSERT_EQUAL(hardCrc, softCrc);
}

I studied this question https://community.st.com/s/question/0D53W00000RRw3fSAD/cant-seem-to-get-correct-results-from-crc-hardware and found that my software calculated CRC16 doesn't match CRC calculated by code of last answer. Does Modbus use different CRC16 algorythm? Can it be implemented in STM32L462 CRC unit?

2 REPLIES 2

I wrote this many years back (F3 SPL days), I had to reverse the polynomial for the hardware computation.

https://community.st.com/s/contentdocument/0690X0000060JWXQA2

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

uint16_t crc_485(unsigned char len,unsigned char *buffer)
{
CRC_TypeDef copiacrc;
//Save old state
copiacrc.POL = CRC->POL;
copiacrc.CR = CRC->CR;
copiacrc.INIT = CRC->INIT;
LL_CRC_SetPolynomialSize(CRC, LL_CRC_POLYLENGTH_16B);
LL_CRC_ResetCRCCalculationUnit(CRC);
LL_CRC_SetInitialData(CRC, 0xffff);
LL_CRC_SetPolynomialCoef(CRC, 0x8005);// 0xa001
LL_CRC_SetInputDataReverseMode(CRC,LL_CRC_INDATA_REVERSE_HALFWORD);
LL_CRC_SetOutputDataReverseMode(CRC,CRC_CR_REV_OUT);
for (uint8_t i=0 ; i<len ; i++)
LL_CRC_FeedData8(CRC,buffer[i]);
copiacrc.DR = LL_CRC_ReadData16(CRC);
//restore old state
CRC->POL = copiacrc.POL;
CRC->CR = copiacrc.CR;
CRC->INIT = copiacrc.INIT ;
return copiacrc.DR;
}