Skip to main content
sdianoff
Associate II
June 2, 2021
Question

How to calc CRC16 for Modbus?

  • June 2, 2021
  • 2 replies
  • 4993 views

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?

This topic has been closed for replies.

2 replies

Tesla DeLorean
Guru
June 2, 2021

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 VenmoUp vote any posts that you find helpful, it shows what's working..
roberto239955_stm1_stmicro
Associate
July 21, 2023

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;
}