硬汉嵌入式论坛

 找回密码
 立即注册
查看: 537|回复: 13
收起左侧

[STM32H7] stm32h743的硬件crc,能用来做modbus的crc16的计算吗?

  [复制链接]

3

主题

21

回帖

30

积分

新手上路

积分
30
发表于 2025-12-18 21:16:35 | 显示全部楼层 |阅读模式
如题,求教。AI有的说可以,有的说不可以。如果真的可以的话,哪位高手能分享一下代码不?
回复

使用道具 举报

0

主题

5

回帖

5

积分

新手上路

积分
5
发表于 2025-12-19 09:40:27 | 显示全部楼层
之前用过,你自己要验证以下。

HWCRC.h

1.08 KB, 下载次数: 9

HWCRC.c

3.21 KB, 下载次数: 10

crc.c

2.39 KB, 下载次数: 14

回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120448
QQ
发表于 2025-12-19 10:34:51 | 显示全部楼层
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2025-12-19 11:37:38 | 显示全部楼层
没必要使用,moudus就两百多字节,软件算也费不了多少时间,使用软件算还方便移植。
回复

使用道具 举报

1

主题

23

回帖

26

积分

新手上路

积分
26
发表于 2025-12-19 16:10:49 | 显示全部楼层
可以的,我在G4系列上测试过,H7跟G4类似,CRC都是多项式、宽度可配置的,应该也是可以的
[C] 纯文本查看 复制代码

struct crc_info_t
{
    MOL_CRC_Width_T width;
    uint32_t        poly;
    uint32_t        init;
    uint32_t        xor_out;
    bool            ref_in;
    bool            ref_out;
};


enum class MOL_CRC_Type_T
{
    CRC32_MPEG2 = 0,
    CRC32_HDLC,
    CRC32_ISCSI,
    CRC32_CKSUM,
    CRC32_BZIP2,
    CRC32_AUTOSAR,
    CRC16_XMODEM,
    CRC16_MODBUS,
    CRC8_SMBUS,
    CRC8_AUTOSAR,
    CRC8_BLUETOOTH,
    LENGTH
};


namespace
{
    crc_info_t crc_info[static_cast<uint32_t>(MOL_CRC_Type_T::LENGTH)] = {
            {MOL_CRC_Width_T::Width_32bit, 0x04C11DB7, 0xFFFFFFFF, 0x00000000, false, false},
            {MOL_CRC_Width_T::Width_32bit, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true, true},
            {MOL_CRC_Width_T::Width_32bit, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true, true},
            {MOL_CRC_Width_T::Width_32bit, 0x04C11DB7, 0x00000000, 0xFFFFFFFF, false, false},
            {MOL_CRC_Width_T::Width_32bit, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, false, false},
            {MOL_CRC_Width_T::Width_32bit, 0xF4ACFB13, 0xFFFFFFFF, 0xFFFFFFFF, true, true},
            {MOL_CRC_Width_T::Width_16bit, 0x1021, 0x0000, 0x0000, false, false},
            {MOL_CRC_Width_T::Width_16bit, 0x8005, 0xFFFF, 0x0000, true, true},
            {MOL_CRC_Width_T::Width_8bit, 0x07, 0x00, 0x00, false, false},
            {MOL_CRC_Width_T::Width_8bit, 0x2F, 0xFF, 0xFF, false, false},
            {MOL_CRC_Width_T::Width_8bit, 0xA7, 0x00, 0x00, true, true},
    };
}


[C] 纯文本查看 复制代码
class MOL_CRC_T
{
    static constexpr crc_info_t const* info_tbl = crc_info;

    MOL_CRC_Type_T type;

    crc_info_t crc_cfg;

public:
    MOL_CRC_T() = default;

    ~MOL_CRC_T() = default;

    explicit MOL_CRC_T(MOL_CRC_Type_T _type)
    {
        this->type = _type;

        crc_cfg = info_tbl[static_cast<uint32_t>(_type)];

        SET_BIT(RCC->AHB1ENR, RCC_AHB1ENR_CRCEN);

        LL_CRC_SetPolynomialSize(CRC, static_cast<uint32_t>(crc_cfg.width));

        LL_CRC_SetInitialData(CRC, crc_cfg.init);

        LL_CRC_SetPolynomialCoef(CRC, crc_cfg.poly);

        // 根据ref_in配置输入数据反转模式
        if (crc_cfg.ref_in)
        {
            LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_BYTE);
        }
        else
        {
            LL_CRC_SetInputDataReverseMode(CRC, LL_CRC_INDATA_REVERSE_NONE);
        }

        // 根据ref_out配置输出数据反转模式
        if (crc_cfg.ref_out)
        {
            LL_CRC_SetOutputDataReverseMode(CRC, LL_CRC_OUTDATA_REVERSE_BIT);
        }
        else
        {
            LL_CRC_SetOutputDataReverseMode(CRC, LL_CRC_OUTDATA_REVERSE_NONE);
        }
    }

    uint32_t clac_w_reset(uint32_t start_addr, uint32_t len)
    {
        LL_CRC_ResetCRCCalculationUnit(CRC);

        return clac_wo_reset(start_addr, len);
    }


    uint32_t clac_wo_reset(uint32_t start_addr, uint32_t len)
    {
        auto ptr = reinterpret_cast<uint8_t*>(start_addr);

        for (uint32_t i = 0; i < len; i++)
        {
            LL_CRC_FeedData8(CRC, ptr[i]);
        }

        uint32_t result = 0;
        if (crc_cfg.width == MOL_CRC_Width_T::Width_32bit)
        {
            result = LL_CRC_ReadData32(CRC);
        }
        else if (crc_cfg.width == MOL_CRC_Width_T::Width_16bit)
        {
            result = LL_CRC_ReadData16(CRC);
        }
        else if (crc_cfg.width == MOL_CRC_Width_T::Width_8bit)
        {
            result = LL_CRC_ReadData8(CRC);
        }
        else
        {
            result = LL_CRC_ReadData7(CRC);
        }

        // 应用XOR_OUT
        return result ^ crc_cfg.xor_out;
    }
};


这些都验证测试过,三方验证,MCU计算,网页计算,python计算,还验证出python中AutoSAR的计算有特殊之处要用一个专用的库才行
回复

使用道具 举报

7

主题

364

回帖

385

积分

高级会员

积分
385
发表于 2025-12-19 21:26:43 | 显示全部楼层
我几乎没看到过MCU直接支持modbus-crc的,所以用查表算法是最快的了。
回复

使用道具 举报

3

主题

21

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2025-12-19 21:40:10 | 显示全部楼层
Dravince 发表于 2025-12-19 16:10
可以的,我在G4系列上测试过,H7跟G4类似,CRC都是多项式、宽度可配置的,应该也是可以的
[mw_shl_code=c, ...

感觉也好复杂,估计和查表差别不大了吧,有测试过和软件查表的差别有多大吗?
回复

使用道具 举报

3

主题

21

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2025-12-19 21:40:30 | 显示全部楼层
xxx1234567890 发表于 2025-12-19 09:40
之前用过,你自己要验证以下。

感觉也好复杂,估计和查表差别不大了吧,有测试过和软件查表的差别有多大吗?
回复

使用道具 举报

3

主题

21

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2025-12-19 21:42:15 | 显示全部楼层
fxyc87 发表于 2025-12-19 21:26
我几乎没看到过MCU直接支持modbus-crc的,所以用查表算法是最快的了。

感觉没有想象中的快,如果有想象中的快,用硬件的还是很划算的。因为通讯十几mS一次,感觉CPU的大部分时间都浪费在计算crc上了。
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2025-12-22 10:09:19 | 显示全部楼层
我用的是H723,里面的CRC可以自定义多项式,不知道H743可以不?
用CubeMX生成的话,改一下默认设置就可以计算CRC16-modbus.
Screenshot 2025-12-22 100601.png
回复

使用道具 举报

3

主题

21

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2025-12-22 13:05:48 | 显示全部楼层
netbeans2006 发表于 2025-12-22 10:09
我用的是H723,里面的CRC可以自定义多项式,不知道H743可以不?
用CubeMX生成的话,改一下默认设置就可以 ...

计算的部分是怎样的呢?和楼上的几位兄弟提供的一样吗?
回复

使用道具 举报

4

主题

190

回帖

202

积分

高级会员

积分
202
发表于 2025-12-22 15:52:02 | 显示全部楼层
支持的,HAL非常简单,只需要把多项式cubemx配置上就行,然后调用HAL_CRC_Calculate就行了,用了很多年了。

[C] 纯文本查看 复制代码
void MX_CRC_Init(void)
{

  /* USER CODE BEGIN CRC_Init 0 */
  /* 多项式0x8005,初值0xfff, crc16-modbus正序 x16-x15-x2-x0 */
  /* USER CODE END CRC_Init 0 */

  /* USER CODE BEGIN CRC_Init 1 */

  /* USER CODE END CRC_Init 1 */
  hcrc.Instance = CRC;
  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
  hcrc.Init.GeneratingPolynomial = 32773;
  hcrc.Init.CRCLength = CRC_POLYLENGTH_16B;
  hcrc.Init.InitValue = 0xffff;
  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
  if (HAL_CRC_Init(&hcrc) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CRC_Init 2 */

  /* USER CODE END CRC_Init 2 */
}
//使用如下;
u16 crc_check(u8 *pData, u16 nDataLen)
{
	#if 1
	return (u16)HAL_CRC_Calculate(&hcrc, (uint32_t *)pData, nDataLen);
	#else
	return CRC16_Modbus(pData, nDataLen);
	#endif
}
回复

使用道具 举报

0

主题

5

回帖

5

积分

新手上路

积分
5
发表于 2025-12-22 16:25:28 | 显示全部楼层
贴一个stm32h563的代码,验证过的。
[C] 纯文本查看 复制代码
/**
 * @brief Initialize CRC peripheral for Modbus CRC16 calculation
 * 
 * Modbus uses CRC16-IBM standard:
 * - Polynomial: 0xA001 (reverse of 0x8005)
 * - Initial value: 0xFFFF
 * - Data inversion: Both input and output are inverted
 */
void hardwareCRCInit( void )
{
    // Ensure CRC peripheral is reset
    __HAL_RCC_CRC_FORCE_RESET();
    __HAL_RCC_CRC_RELEASE_RESET();

    // Configure CRC parameters
    hcrc.Instance = CRC;
    hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE;
    hcrc.Init.GeneratingPolynomial = 0x8005;                                    // Polynomial 0x8005 (hardware handles inversion automatically)
    hcrc.Init.CRCLength = CRC_POLYLENGTH_16B; // 16-bit CRC
    hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
    hcrc.Init.InitValue = 0xFFFF;           // Initial value 0xFFFF
    hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE; // Byte inversion
    hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE; // Output inversion

    HAL_CRC_Init( &hcrc );
}

/**
 * @brief Calculate Modbus CRC16 using hardware CRC
 *
 * @param data Pointer to data buffer for CRC calculation
 * @param length Length of data in bytes
 *
 * @return Calculated CRC16 value
 */
uint16_t hardwareCRCMBCrcCalcaulate( uint8_t *ucpData, uint32_t uiLen )
{
    uint32_t uiCRCResult  = 0;
    
    // Calculate CRC
    uiCRCResult = HAL_CRC_Calculate( &hcrc, (uint32_t *)ucpData, uiLen );
  
    // Return 16-bit result
    return (uint16_t)uiCRCResult;
}
1.png
回复

使用道具 举报

3

主题

21

回帖

30

积分

新手上路

积分
30
 楼主| 发表于 2025-12-22 20:28:09 | 显示全部楼层
确实可以,感谢楼上各位兄弟。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-1-10 17:36 , Processed in 0.077802 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表