Micrium全家桶之uC-CRC: 0x02 CRC

本文转自公众号,欢迎关注
micrium全家桶之uc-crc: 0x02 crc (qq.com)
前言前一篇我们讲了micrium全家桶之uc-crc: 0x01 ecc:https://mp.weixin.qq.com/s/fkvvzwl7wzxljckx3godjq。ecc常用于nand进行误码校正。而crc一般用于错误检测,比如镜像,协议的正确完备性检测。
这一篇我们来讲讲uc-crc组件的crc部分,老规矩先代码用起来,然后再讲讲原理,理论结合实践。
使用可以从https://github.com/qinyunti/uc-crc.git下载代码,该版本在原版本基础上进行了修改,删除了其他依赖,可以单独使用,方便移植,也可以参考https://mp.weixin.qq.com/s/fkvvzwl7wzxljckx3godjq。有了上一篇基础我们不再详细介绍如何集成该代码,直接进入测试环节。文件如果只使用crc的话只需要crc_cfg.h和edc_crc.c,edc_crc.h即可。配置其中cec_cfg.h的宏edc_crc_cfg_optimize_asm_en配置是否使用汇编代码实现,默认为def_disabled.
以下宏配置是否使能对应的算法和反转查找表
其中前面4个宏使能了4种算法,后面4个宏定义是否支持位反转模式,如果是则会定义对应的crc查找表,比如edc_crc_cfg_crc32_ref_en使能则使用crc_tblcrc32_ref,edc_crc_cfg_crc32_en使能则使用crc_tblcrc32。
所谓的位反转就是bit7和bit0交换,bit6和bit1交换...,通过查表法空间换时间加快速度。有些场景需要位翻转,所以有这个实现。
#define edc_crc_cfg_crc16_1021_en def_enabled /* see note #3. */#define edc_crc_cfg_crc16_8005_en def_enabled#define edc_crc_cfg_crc16_8048_en def_enabled#define edc_crc_cfg_crc32_en def_enabled#define edc_crc_cfg_crc16_1021_ref_en def_enabled#define edc_crc_cfg_crc16_8005_ref_en def_enabled#define edc_crc_cfg_crc16_8048_ref_en def_enabled#define edc_crc_cfg_crc32_ref_en def_enabled接口crc提供了以下接口
crc_open_16bitcrc_wrblock_16bitcrc_wroctet_16bitcrc_close_16bitcrc_open_32bitcrc_wrblock_32bitcrc_wroctet_32bitcrc_close_32bit提供了两组接口16位的和32位的
流式操作,结果存在结构体参数种 只支持查表法
crc_open_16bit()->
crc_wrblock_16bit()-> 一次写多个字节
crc_wroctet_16bit()-> 一次写一个字节
crc_close_16bit()->
32位的类似
crc_open_32bit->
crc_wrblock_32bit->
crc_wroctet_32bit->
crc_close_32bit->
这里提供这几个位反转接口,最后结果再调用这些接口进行位反转。
crc_reflect_08bit 查表法实现8位数据位反转 查表是crc_reflecttbl
crc_reflect_16bit 查表法实现16位数据位反转
crc_reflect_32bit 查表法实现32位数据位反转
还提供两个接口直接计算,立即返回计算值,支持查表和不查表
crc_chksumcalc_16bit
crc_chksumcalc_32bit
所以以上有几种配置:使用查表还是不使用查表,使用位反转还是不使用
p_model->reflect == def_yes 则使用位反转
p_model->tblptr == (const cpu_int16u *)0则不使用查表
测试以crc_chksumcalc_16bit为例
cpu_int16u crc = crc_chksumcalc_16bit((crc_model_16*)&crc_modelcrc16_8005,(void*)p_datap,strlen(p_datap),&err);第一个参数传入默认配置好的
const crc_model_16 crc_modelcrc16_8005 = {0x8005u,0x0000u,def_no,0x0000u,&crc_tblcrc16_8005[0]};即多项式为0x8005,初始值为0x0000,不进行位反转,不进行异或输出,查表为crc_tblcrc16_8005。
测试代码如下
#include #include #include edc_crc.huint8_t s_buffer[33];int crc_main(int argc, char* argv[]){ const char* p_datap=123456789; edc_err err; cpu_int16u crc = crc_chksumcalc_16bit((crc_model_16*)&crc_modelcrc16_8005,(void*)p_datap,strlen(p_datap),&err); if(edc_crc_err_none != err) { printf(err\\r\\n); } else { printf(crc = %#x\\r\\n,crc); } return 0;}打印值如下
crc = 0xfee8和edc_crc.h下列举的测试用例结果一致
* ------------------------------------------------------------------* | poly | reflect? | init val | comp. out? | crc |* -------------+------------+------------+------------+-------------* | 0x1021 | no | 0x0000 | no | 0x31c3 |* | 0x1021 | no | 0x0000 | yes | 0xce3c |* | 0x1021 | no | 0x1d0f | no | 0xe5cc |* | 0x1021 | no | 0xffff | no | 0x29b1 |* | 0x1021 | no | 0xffff | yes | 0xd64e |* -------------+------------+------------+------------+-------------* | 0x1021 | yes | 0x0000 | no | 0x2189 |* | 0x1021 | yes | 0x0000 | yes | 0xde76 |* | 0x1021 | yes | 0xffff | no | 0x6f91 |* | 0x1021 | yes | 0xffff | yes | 0x906e |* -------------+------------+------------+------------+-------------* | 0x8005 | no | 0x0000 | no | 0xfee8 |* | 0x8005 | no | 0x0000 | yes | 0x0117 |* | 0x8005 | no | 0xffff | no | 0xaee7 |* | 0x8005 | no | 0xffff | yes | 0x5118 |* -------------+------------+------------+------------+-------------* | 0x8005 | yes | 0x0000 | no | 0xbb3d |* | 0x8005 | yes | 0x0000 | yes | 0x44c2 |* | 0x8005 | yes | 0xffff | no | 0x4b37 |* | 0x8005 | yes | 0xffff | yes | 0xb4c8 |* -------------+------------+------------+------------+-------------* | 0x8048 | no | 0x0000 | no | 0x80a0 |* | 0x8048 | no | 0x0000 | yes | 0x7f5f |* | 0x8048 | no | 0xffff | no | 0xe8e0 |* | 0x8048 | no | 0xffff | yes | 0x171f |* -------------+------------+------------+------------+-------------* | 0x8048 | yes | 0x0000 | no | 0x1506 |* | 0x8048 | yes | 0x0000 | yes | 0xeaf9 |* | 0x8048 | yes | 0xffff | no | 0x1710 |* | 0x8048 | yes | 0xffff | yes | 0xe8ef |* -------------+------------+------------+------------+-------------* | 0x04c11db7 | no | 0x00000000 | no | 0x89a1897f |* | 0x04c11db7 | no | 0x00000000 | yes | 0x765e7680 |* | 0x04c11db7 | no | 0xffffffff | no | 0x0376e6e7 |* | 0x04c11db7 | no | 0xffffffff | yes | 0xfc891918 |* -------------+------------+------------+------------+-------------* | 0x04c11db7 | yes | 0x00000000 | no | 0x2dfd2d88 |* | 0x04c11db7 | yes | 0x00000000 | yes | 0xd202d277 |* | 0x04c11db7 | yes | 0xffffffff | no | 0x340bc6d9 |* | 0x04c11db7 | yes | 0xffffffff | yes | 0xcbf43926 |* -------------+------------+------------+------------+-------------crc原理参考
https://www.iar.com/knowledge/support/technical-notes/general/checksum-generation/
https://ecomputernotes.com/computernetworkingnotes/communication-networks/cyclic-redundancy-check
crc即cyclic redundancy check循环冗余校验码,用来进行错误检测,我们对数据进行crc计算得到一个校验码,校验码和数据一起发送,接收时再对数据计算crc和收到的校验码比对,如果校验值一样则认为数据正确。其根本原理还是奇偶校验,只是可以认为是花式奇偶校验,源数据反转一个bit会对应到crc值的1位变化,但是源数据多位改变则有可能crc不变。
所以crc的校验能力并不是很强,但是比奇偶校验和求和校验强,且好在简单计算快,所以以太网等数据传输,一些传感器数据,底层总线信号包等都使用crc校验。
从另一个角度crc是基于二进制除法(modulo arithmetic)的算法,要传输的数据单元被一个预定的除数(二进制数)除以得到余数。这个余数称为crc。crc比除数小1位。这意味着如果crc为n位,则除数为n+ 1位。发送方将这个crc附加到数据单元的末尾,这样得到的数据单元就可以被预定的除数完全整除,即余数变为零。在目的地,输入的数据单元(即数据+ crc)被相同的数字(预定的二进制除数)所除,如果能整除就说明数据正确。
过程如下
先选择除数(即二进制值),即对应的我们所说的多项式,比如选1011则对应多项式x^3+x^1+x^0,位数为4.
然后在源数据的后面添上4-1个0.比如源数据是1001则变为了1001000,然后这个值除以1011
注意这里除法有一点不一样,看最左边的一位如果余数最左边是0则商0,否则商1,另外做减法时不需要借位,只需要满足0-1=1 0-0=0 1-1=0 1-0=1
以上运算最终得到余数110所以,所以接到数据后就是1001110
接收端检测时用1001110除以1011,如果余数为0说明数据正确
总结一下
l除数(多项式的位数)是crc值的位数+1,比如对于8位crc,其多项式的最高位为x^8,包括常数项就是9位。
lcrc可以检测到所有影响奇数位的突发错误,偶数位不保证
l选择的多项式决定了检测错误的能力和类型,所以才有了那些标准的多项式
比如
除数和多项式的关系如下,最高次项始终是1,次数和crc位数一样.
用多项式的角度看除法就是如下图,注意减法时不需要借位,系数满足1bit的减法。
而crc的计算一般都采用了查表法。
crc计算工具https://crccalc.com/?crc=01020304&method=crc32&datatype=hex
http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
https://www.lammertbies.nl/comm/info/crc-calculation.html
总结以上进行了uc-crc的crc部分测试以及相应的原理讲解,在理解的基础上可以将代码集成到自己的项目中使用。


美国会不会彻底卡断我国芯片的脖子?
Energous与Veea合作,针对工业、物流和零售应用中的大规模物联网部署进行实时资产跟踪
LMS自适应滤波器的仿真与实现
荣耀双11战报:智慧生活产品表现亮眼
简述半导体的导电机理
Micrium全家桶之uC-CRC: 0x02 CRC
华硕发布首款Wi-Fi6桌面无线网卡 最高速度超3Gbps
Java将如何促进主流区块链的采用
PLC在馈电开关控制系统中的应用和分析
华为愿意将5G技术独家授权给美国公司
汇总解读华为麒麟960六大创新之处
佳恩半导体再次完成数千万A轮融资
基于多功能实用遥控插座的设计方案
无服务器架构的基本概念及运维
OpenI启智MindSpore集结号第二期活动正式启动
python中eval的用法和作用
马云:未来城市的发展将取决于谁的数据更丰富
对于消防巡检柜而言,它到底该如何正确的接线
为什么加密货币领域也必须要执行KYC规则
小米6最新消息:频现问题的小米6、三星S8都是高通骁龙835手机,到底能不能买?