ARM Programming: ใช้งาน CRC module ของ STM32

microcontroller ตระกูล STM32 หลายๆ ตัวจะมีฮาร์ดแวร์สำหรับช่วยคำนวณค่า CRC มาด้วย (อยากรู้ว่า CRC คืออะไรดูที่นี่ Wikipedia Cyclic_redundancy_check) แต่ความสามารถของ CRC module ของ microcontroller แต่ละตัวจะมีไม่เท่ากัน ในรุ่นเล็กๆ อย่าง STM32F030 จะคำนวณได้เฉพาะ CRC32 เท่านั้น ไม่สามารถเปลี่ยนให้คำนวณค่า CRC แบบอื่นได้ ในขณะที่รุ่นใหญ่กว่าเช่น STM32F072 และ F3 F4 จะสามารถเปลี่ยนให้คำนวณค่า CRC แบบอื่นได้

เริ่มใช้ CRC module อย่างไร

ถ้าเขียนโปรแกรมที่ใช้ HAL ก็ใช้ STM32CubeMX สร้าง code ขึ้นมาก่อนได้

STM32CubeMX crc

เมื่อเปิด code ใน ide แล้วให้ดูใน MX_CRC_INIT() ส่วนนี้จะเป็นการตั้งค่าสำหรับ CRC module รายละเอียดของการตั้งค่าสามารถดูได้จากเอกสาร UM1785 User Manual Description of STM32F0 HAL and low-layer drivers UM1725 User Manual Description of STM32F4 HAL and LL drivers หรือเอกสารแบบเดียวกันสำหรับ STM32 ตระกูลอื่นๆ

ด้านล่างนี้เป็นตัวอย่างสำหรับการคำนวณ CRC16 สำหรับ protocol Modbus

#define MODBUS_CRC_POLY 0x8005

// คำนวณ CRC
uwCRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t *)&commsBuffer, 0x09);

static void MX_CRC_Init(void)
{
    hcrc.Instance = CRC;
    hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
    hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
    hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
    hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
    hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;

    hcrc.Init.GeneratingPolynomial = MODBUS_CRC_POLY;
    hcrc.Init.CRCLength = CRC_POLYLENGTH_16B;
    hcrc.Init.InitValue = 0xFFFF;

    if (HAL_CRC_Init(&hcrc) != HAL_OK)
    {
        Error_Handler();
    }
}

การตั้งค่าสำหรับ CRC แบบอื่นนั้นหาได้จากเอกสารของ CRC นั้น หรือที่ผมใช้ก็มาจากเอกสารของ crcmod ที่เป็น library สำหรับคำนวณ CRC สำหรับ Python

crc calculation method

CRC algorithm สำหรับ modbus

Name Polynomial Reversed? Init value XOR out Check
CRC-16 modbus 0x18005 True 0xFFFF 0x0000 0x4B37

เวลานำไปตั้งค่าในโปรแกรม polynomial ตัด 1 ข้างหน้าออก เหลือเพียง 0x8005 ส่วน reversed ก็ enable input/output inversion กำหนด initial value เป็น 0xFFFF ส่วน check คือค่า CRC เมื่อ Input เป็น “123456789” หรือ {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39}

เปรียบเทียบกับการคำนวณด้วย software

กรณีที่ต้องการใช้ software คำนวณ CRC16(modbus) เมื่อจำเป็นต้องใช้งานกับ mcu ที่รองรับเฉพาะ CRC32 ที่ https://community.st.com/thread/15006 มีตัวอย่างการคำนวณ CRC หลายๆ แบบอยู่ ซึ่งสำหรับ CRC16 modbus ก็มีอยู่ 3 วิธี เขาเรียกว่าแบบ Slow Quick และ Fast แบบ slow เป็นการคำนวณทีละบิต แบบ Quick จะใช้ lookup table ขนาด 4 บิต ส่วนแบบ fast จะใช้ lookup table ขนาด 8 บิต

เปรียบเทียบความเร็ว ในการคำนวณ modbus CRC ขนาดของ data คือ 9 ไบต์ จำนวน 100,000 ครั้ง บนบอร์ด STM32F072B-Discovery

Type 1/1000 s
hardware CRC 622
fast 629
quick 759
slow 2475