循环冗余校验技术以及在STM32中的一些具体使用体会

在嵌入式产品的应用中,经常需要处理系统数据在存储或传输过程中的完整性问题。完整性是指数据在其生命周期中的准确性和一致性。这些数据可能存储在EEPROM/FLASH中,或者基于通信协议传输,它们可能会因外部干扰、程序错误甚至系统入侵而损坏。如果在使用前没有验证这些数据,产品功能可能无效。在某些特定领域,在严重的情况下,它可能会危及用户财产甚至他们的生命。本文将谈谈在STM32中广泛使用的循环冗余校验技术和一些具体的经验。所谓CRC:循环冗余校验(CRC)是一种错误检测算法,通常用于通信协议或存储设备中,检测原始数据的意外变化。可以简单理解为,按照一定的算法计算出有用数据后,提取一个特征值,附加到有用数据上。在应用中,将根据特定算法从有用数据中提取的特征值与预先存储的特征值进行比较,如果相等,则验证通过,否则验证失败,从而识别数据是否异常。

为什么要验证数据完整性?

数据存储和传输过程中可能会发生变化。以数据通信应用场景为例,常见错误大致有两种故障模式:

单比特错误:只有一个数据比特有错误,如图所示:

BurstError:码流中有两个或两个以上的数据位有错误,如图:

为什么可能出现这些位错误?对于电子系统通信,涉及物理层、链路层、通信介质等。其中物理层主要以一定的编解码原理对原始二进制数据进行调制,然后通过发送电路将调制后的信号传输到传输介质上,接收端用接收电路接收并解调信息,将信息恢复为二进制码流。在这个过程中,介质可能受到干扰,接收电路、发射电路、调制电路和解调电路都可能由于一些干扰原因而无法工作,产生误码。这时,如果没有一个好的机制来保证数据的正确性,比如某个飞控系统中的一些控制命令,某个车载系统中的CAN报文数据,系统就会直接利用这些错误数据来控制被控对象(比如电机、发动机),严重时会造成无法估量的生命财产灾难。

存储系统中的数据是相同的。一般来说,系统在开机时会从物理存储介质中加载系统参数,如一些校准数据。如果介质的某些位损坏,或者软件bug导致数据误操作,没有数据完整性检测,这样的数据会直接应用到系统控制中,也会造成安全隐患。

因此,数据完整性检测的重要性不言而喻。常见的数据完整性算法有很多,如简单的异或校验、CRC循环冗余校验、FEC前向纠错算法等。循环冗余校验广泛应用于嵌入式系统中,如通信协议制定、数据存储、压缩和解压缩算法等。

循环冗余校验(CRC)使用二进制除法作为算法原理,具有强大的错误检测机制。二进制除法可以用几个硬件逻辑电路实现。对于软件代码的实现,有两种思路和策略:查表法和移位计算法。查表法以空间换时间,移位计算法以时间换空间。

什么是循环冗余校验?

循环冗余校验的核心数学算法原理是基于循环码,在不增加原始数据信息的情况下扩充信息,以最小的存储代价存储其冗余特征。该算法是W. Wesley Peterson在1961年发明的。

这里,n位二进制数据是有效载荷。(可能是用于传输或存储的有用信息)

M位冗余码是根据CRC算法计算出来的,也就是根据这个CRC校验多项式结合CRC算法从之前的有效数据中提取特征冗余码,这才是真正意义上的冗余。

实际传输或存储的是n m位二进制数据。

这就引出了一个概念:多项式,在CRC算法中可以这样理解和表达:

它的本质是多系统的数学表示,这里是二进制,所以x是2。

基本算法处理过程如下:

假设要发送的有效数据是二元多项式M(x),校验多项式P(x)是发送方和接收方双方约定的,双方都知道,这里下面简单介绍几个多项式的含义和相关的处理流程:

接收器在接收到数据后执行CRC校验。余数为0,检查通过。

其实CRC的本质是二元多项式除法获得冗余码的计算过程。无论是软件查表法、移位计算法还是纯硬件逻辑电路实现,本质都是一样的。对数字逻辑电路使用移位运算更有利,因为它几乎不占用CPU时间。

常见CRC校验多项式

常见的CRC校验多项式运算符有哪些?

除了复杂度上的差异,从应用的角度来看,不同的校验多项式有什么区别?从应用来看,主要体现在误诊断率上。看看CRC-16和CRC-CCITT的检错效果:

它可以完全检测单比特和双比特错误。

奇数位错误

它可以检测长度为16位和小于16位的突发错误。

可以以99.997%的概率检测到长度为17位或更长的错误。

选择不同的校验多项式算子,误码诊断的成功率不同,当然计算代价也不同。让查看权威的IEC标准。下图取自《IEC61508-7》。

从上面可以看出,CRC-8可以诊断99.6%的误码概率,而CRC-16可以提高到99.998%。

注:IEC61508是国际电工委员会电气/电子/可编程电子安全相关系统的功能安全。

到目前为止,各行各业已经使用了大量不同的校验多项式生成器。以下是来自维基百科的截图,供大家参考:

STM32的CRC硬件外设

如下图所示,STM32内置CRC-32硬件计算单元,实现了固定多项式0x4c11db7(十六进制表示),可应用于以太网报文校验码的计算。

所有STM32产品都有CRC外设,为CRC计算提供硬件支持,节省应用代码的存储空间。CRC值可以用来验证数据在传输中的正确性,也可以用来检查数据存储的完整性。在IEC60335,闪存的完整性也由CRC检查。在FLASH完整性校验的应用中,需要预先计算整个FLASH的CRC校验值(不包括保存CRC值的最后一个字节),放在FLASH的末尾。在程序启动或运行过程中,用同样的方法再次计算整个FLASH的CRC校验值,然后与FLASH末尾地址空间中存储的CRC值进行比较。

EWARM从v5.5开始支持STM32芯片的CRC计算,计算整个FLASH的CRC校验值并在FLASH结束时保存的过程可以在IAR中完成。通过配置EWARM的CRC计算参数,自动对整个FLASH空间进行CRC计算,计算结果放在内部FLASH空间的末尾。

你可能会问,这有什么应用价值?以基于单片机程序的升级为例。在代码升级的过程中,如果你不检查bootloader升级接口传输的二进制程序文件,可以不能及时发现升级过程中的代码错误。相反,如果在原代码中添加了校验码,升级程序在收到升级文件后会进行校验计算,并与待升级文件末尾的校验码进行比较。如果没有匹配,就会放弃升级,以免将无效甚至潜在的安全代码写入芯片。

修改链接文件,指定校验和在FLASH中的存储位置,并在链接文件中添加以下语句。

placeatendofom _ region { rose section . checksum };

该语句指定CRC值应放在闪存空间的末尾。是整个FLASH空间的结束,而不是应用代码的结束。这样,CRC值的位置是固定的,不会随着码长而改变。

配置校验和页面的参数

Iachecksum页面描述(6.4及以上版本)

IAR 的校验和页分为两部分:

红线圈出的部分:定义要计算的CRC的范围和FLASH中空闲字节的填充值。

设置部分校验和计算参数:校验和大小:选择校验和对齐的大小(字节数):指定校验和的对齐方式。如果留空,默认为2字节对齐。

算法:选择校验和的算法。

补码:是否需要补码计算。选择照原样意味着没有补码计算。

位顺序:位输出的顺序。MSB优先,每个字节的高位优先。LSB优先,每个字节的低位优先。

反转字内字节顺序:对于输入数据,反转字内每个字节的顺序。

InitialValue:由校验和计算的初始化值

校验和单元大小:选择要迭代的单元大小,按照8位、16位或32位迭代。

STM32 CRC外设使用默认配置时的IAR配置

STM32CRC外设的配置:

POLY=0x4C11DB7(CRC32)

Initial_Crc=0Xffffffff

输入/输出数据不反转。

数据输入:0x08000000~0x0801FFFB。(最后4个字节用于存放计算出的CRC值)

在实验过程中,发现对齐似乎对计算的CRC值没有影响。然而,反转word 中的字节顺序与校验和单位大小。如果后者选择32位,则前者无法检查;相反,如果后者选择8位,反转word 中的字节顺序必须检查。也可以参考下图进行设置:

没有校验和单位大小IAR v6.4及以下版本的选项。请参考以下配置:

代码怎么写?

如上所述,该应用程序可用于检查Flash中的数据,参考代码如下:

CrcHandle。Instance=CRCcrchandle . init . default polynomial=default _ polynomial _ enable;crchandle . init . defaultinitvalueuse=default _ init _ value _ enable;crchandle . init . input data inversion mode=CRC _ input data _ inversion _ none;crchandle . init . output data inversion mode=CRC _ output data _ inversion _ disabled;crchandle . input data format=CRC _ input data _ format _ words;if (HAL_CRC_Init(CrcHandle)!=HAL_OK) {Error _ Handler();} pdata=(uint 32 _ t *)ROM _ START;UWCRCVALUE=HAL _ CRC _ Calculate(CRC Handle,PDATA,ROM _ size in words);

总结

对于CRC应用,纯软件方案也可以按照多项式算子编写,网上有很多现成的代码。其基本思想无非是查表法和移位计算法。区别在于,一个为了计算效率牺牲存储空间,一个为了节省存储空间牺牲计算时间。至于如何选择,根据设计的系统综合考虑,一般根据应用场景。

利用CRC算法计算块数据的冗余码,一些文章和标准称此为冗余码签名。在实践中,通过计算有效数据获得的校验码与预存的校验码进行比较。如果它们相等,则检查通过,否则检查失败。当然,原始数据和存储的校验码也可以传递到校验算法中。如果结果为0,检查将通过,否则将失败。

对于数据通信,通常在消息的末尾添加有效数据的校验码,然后接收方检查接收到的消息的数据完整性。