STM32 HAL CRC:强制类型转换写寄存器与直接赋值结果差异问题
STM32 HAL CRC逐字节写入与32位直接赋值结果不一致问题
STM32 HAL库的CRC驱动中,当待计算CRC的数据长度不是4的倍数时,会通过逐字节/半字写入CRC数据寄存器(CRC_DR)来处理剩余数据,对应核心代码如下:
if ((BufferLength % 4U) != 0U) { if ((BufferLength % 4U) == 1U) { *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[4U * i]; /* Derogation MisraC2012 R.11.5 */ } if ((BufferLength % 4U) == 2U) { data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U]; pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR); /* Derogation MisraC2012 R.11.5 */ *pReg = data; } if ((BufferLength % 4U) == 3U) { data = ((uint16_t)(pBuffer[4U * i]) << 8U) | (uint16_t)pBuffer[(4U * i) + 1U]; pReg = (__IO uint16_t *)(__IO void *)(&hcrc->Instance->DR); /* Derogation MisraC2012 R.11.5 */ *pReg = data; *(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[(4U * i) + 2U]; /* Derogation MisraC2012 R.11.5 */ } }
其中pBuffer是指向uint8_t数组的指针;CRC_DR为32位宽度,官方文档明确:每次向CRC_DR写入数据时,外设会将当前CRC_DR中的值与新写入的数据结合,根据写入操作的总线宽度(字节/半字/字)执行对应的CRC计算逻辑。
测试现象
- 执行单字节写入操作
*(__IO uint8_t *)(__IO void *)(&hcrc->Instance->DR) = pBuffer[4U * i];时,CRC_DR的值从0x651F2550变为0x340BC6D9。 - 尝试用32位直接赋值模拟该操作(假设大端模式,将字节放在最高位):
结果CRC_DR变为_hcrc.Instance->DR = ncrc & ((((uint32_t)pBuffer[4U * i]) << 24) | 0x00FFFFFF);0x1D87D8BB,与预期不符。 - 再假设小端模式,将字节放在最低位:
结果CRC_DR变为_hcrc.Instance->DR = ncrc & (0xFFFFFF00 | ((uint32_t)pBuffer[4U * i]));0xEBCF331F,仍不匹配。
问题原因
核心误区是误解了STM32 CRC外设的工作逻辑:
- 字节写入触发字节级CRC计算:当通过
uint8_t指针写入CRC_DR时,外设会将这个单字节作为独立输入,按照CRC多项式的位顺序(如LSB优先或MSB优先,取决于外设配置),与当前CRC_DR中的值进行迭代计算,最终更新CRC_DR。这个过程是外设硬件执行的CRC算法迭代,不是简单的位运算拼接。 - 32位写入触发字级CRC计算:直接对CRC_DR做32位赋值时,外设会把整个32位数据当作新的输入字,执行32位宽度的CRC计算——此时你拼接的"原CRC值+目标字节"的32位数据,会被外设当作全新的输入,和字节写入的计算路径完全不同,结果自然无法匹配。
另外,CRC_DR的"端序"不是指寄存器存储的端序,而是外设处理输入字节时的位顺序,不能用简单的位拼接来模拟字节写入的硬件计算过程。
结论
无法通过32位直接赋值的方式模拟字节/半字写入的CRC计算结果,必须遵循HAL库的实现方式,通过对应宽度的指针写入剩余数据,因为不同宽度的写入操作触发的CRC硬件计算逻辑完全不同。
内容的提问来源于stack exchange,提问作者lazba
相关产品推荐
相关产品推荐

