浅析YTM32的循环冗余校验CRC外设模块

电子说

1.3w人已加入

描述

引言

在串行通信帧中,为了保证数据在传输过程中的完整性,通常采用一种指定的算法对原始数据进行计算,得出的一个校验值。接收方接收到数据时,采用同样的校验算法对原始数据进行计算,若计算结果和接收到的 校验值一致 ,说明数据校验正确,该帧数据可用,若不一致,说明传输过程中出现了差错,丢弃该帧数据,请求重发。常用的校验算法有奇偶校验、校验和、CRC,还有LRC、BCC等不常用的校验算法。

在诸多检错手段中,CRC是最著名的一种。CRC的全称是循环冗余校验,其特点是:检错能力强,开销小,易于用编码器及检测威廉希尔官方网站 实现。从其检错能力来看,它所不能发现的错误的几率仅为0.0047%以下。从性能上和开销上考虑,均远远优于奇偶校验及算术和校验等方式。因而,在数据存储和数据通讯领域,CRC无处不在:著名的通讯协议X.25的FCS(帧检错序列)采用的是CRC-CCITT,WinRAR、NERO、ARJ、LHA等压缩工具软件采用的是CRC32,磁盘驱动器的读写采用了CRC16,通用的图像存储格式GIF、TIFF等也都用CRC作为检错手段。

YTM32B1ME微控制器中提供了硬件的CRC计算引擎,用以加速和简化用户程序中的CRC运算。值得注意的是,YTM32B1ME微控制器中还集成了SENT通信外设,SENT通信协议中也用到了CRC校验。可以想见,在具体应用中,CRC外设可以配合SENT外设,或者其他在协议中使用CRC校验算法的通信过程提供硬件计算引擎的支持。

YTM32的硬件CRC外设模块,用户通过AHB总线向CRC外设送数参与计算,然后通过AHB总线送出实时的计算结果。CRC外设内部实现了CRC4(CRC-ITU)、CRC16(CRC-CCITT)、CRC32(CRC-ethernet)等多项算式的计算引擎,并可配置输出和输出数据的位交换,通过8b、16b、32b等带宽方式,向CRC计算引擎送数。如图x所示。

编码器

图x CRC外设系统框图

原理与机制

CRC算法简介

CRC的全称是循环冗余校验(Cyclic Redundancy Check),其目的是保证数据的完整性,具体应用方法,是在发送数据的后面再补充若干位的数据,使得接收方使用同样的CRC计算方法,检查接收到的数据的CRC计算结果是否为0,从而判定接收数据的完整性。

CRC的核心算法,就是通过一串“发送数据”,来计算“需要补充的若干数据”。CRC的计算过程是用除法求余数。不同于十进制的除法运算,CRC用的是 2进制的除法运算 ,2进制的除法运算,属于 模2运算 ,模2运算的特点是: 没有进位

  • 模2加法:0+0=0,0+1=1,1+0=1,1+1=0。
  • 模2减法:0-0=0,0-1=1,1-0=1,1-1=0。模2加减法实际上就是异或操作,这也是CRC很容易在实际中应用的数学基础。
  • 模2乘法:0x0=0,0x1=0,1x0=0,1x1=1。
  • 模2除法:是模2乘法的逆运算,参见下图示例。

编码器

图x 模2除法

通过除法算式可以形象地想见,当将一串输入数据,再在右侧补入N个空位,作为被除数,除以CRC多项式所表示的N位除数时,若不能除尽,则在除法竖式的最后一个环节,在最右边产生一个同补入空位同位宽的余数,那这个余数就是CRC的计算结果。此处用一个例子说明CRC的计算过程。如图x所示。

编码器

图x CRC8计算用例

在这个算例中:

  • CRC8的多项式是x8+x2+x+1,对应的除数就是二进制数100000111
  • 被除数是0x1C,转化成二进制就是00011100
  • CRC8为8位,被除数后面补8个0,也同时对应CRC计算的结果也是8位
  • 最后的计算结果是0x54

在CRC解算时,若将CRC计算的结果换入补充的空位,在进行CRC计算,相当于是将之前CRC计算的余数同自己相加,根据CRC计算的加法中0+0=11+1=0的规则,刚好可以得到0的计算结果,从而验证数据在传输过程的完整性。

使用在线的计算器,也能算得同样的结果。如图x所示。

编码器

图x 使用在线CRC计算器

细心的读者可能看到了,这里面还有 初始值结果异或值输入数据反转输出数据反转 ,这些名词都是指什么呢?

  • 初始值,是给CRC计算前提供一个初始值(Offset,预计算值),大部分情况下设定为0,也可以根据选定的特定算法指定其他值,有时也被称为CRC计算的种子(Seed)。结果异或值,是把计算结果再异或某一个值。使用初始值和结果异或值,的目的是防止在某个计算环节中,算得全0的中间结果,导致后续的CRC余数一直为0。
  • 输入数据反转,是指输入数据以字节为单位按位逆序处理;输出数据反转,是指CRC计算结果整体按位逆序处理;这么做的目的(一个合理的解释)是右移比左移更容易计算,效率高,它跟大小端无关。

特别注意,最基本的计算过程大多不需要额外设定这些参数(配置成false或者0即可),但有些面向典型应用的场景,会对应一些特别配置组合(典型配置),产生了不同的算法。如图x所示。

编码器

图x 多种不同的CRC计算配置

从CRC算法到CRC硬件外设

示例CRC计算的过程中,使用的是1个8位的数作为被除数,但实际计算数据帧的数据大多是一个数组,这个扩展过程,可以理解为将整个数据帧的一串数据并排放在一起,当成一个大数进行计算。实际上,CRC的除法计算,也是一个串行移位的计算过程,可以从左边算到右边。在使用CRC硬件外设进行计算时,对应可以逐个向CRC_DATA寄存器中送数,CRC会使用上次计算结果和新送入的数据位,得到本次计算的结果,并继续参与后续的计算。CRC硬件外设的CRC_DATA寄存器,支持用户已8位、16位、32位的位宽向CRC计算引擎送数。

YTM32的硬件CRC支持三种算式:

编码器

CRC硬件外设可以配置初始值(种子,寄存器CRC_INIT),支持输入和数据的位序反转,不支结果持异或计算,但支持结果位翻转。通过结果寄存器CRC_RESULT可以读取实时计算的结果。

需要注意的是,YTM32手册上列写的支持CRC多项式的名字,主要还是描述算子,硬件还是使用基本算法执行计算。若需要使用某些具体算法配套特定的位序反转、初始值等,还是需要用户自行配置CRC硬件外设。

应用要点(软件)

arm-mcu-sdk软件仓库中,为ytm_crc_0驱动设计的样例工程crc_basic中,设计了计算CRC-16和CRC-32的演示用例。

CRC16 用例

crc16_test用例中,实现计算数列{0x1234, 0x5678, 0x5A5A, 0xA5A5}的CRC16值,有源码如下 :

CRC_Init_Type crc16_ccitt =   
{  
    .EnableOutputBitInv = false,  
    .EnableOutputBitSwap = false,  
    .EnableInputBitSwap = false,  
    .CalcMode = CRC_CalcMode_Crc16,  
    .InitData = 0x0000  
};  
  
#define CRC_DATA_LEN  4u  
const uint16_t crc16_data_arr[CRC_DATA_LEN] = {0x1234, 0x5678, 0x5A5A, 0xA5A5};  
#define CRC16_RESULT 0x4BDCu  /* The result CRC calculator with CCITT 32 bits standard. */  
  
void crc16_test(void)  
{  
    /* setup the crc calculator. */  
 CRC_Init(BOARD_CRC_PORT, &crc16_ccitt);  
   
 for (uint32_t i = 0u; i < CRC_DATA_LEN; i++)  
 {  
     CRC_SetData16b(BOARD_CRC_PORT, crc16_data_arr[i]);  
 }  
   
 printf("crc16_test ... ");  
 if (CRC16_RESULT == CRC_GetResult(BOARD_CRC_PORT))  
 {  
  printf("succ.");  
 }  
 else  
 {  
  printf("fail.");  
 }  
 printf("rn");  
}

使用在线的CRC计算器计算,可以得到相同的计算结果。如图x所示。

编码器

图x CRC在线计算器计算CRC16

这里要注意,CRC在线计算器中定义的CRC-16/CCITT是输入数据反转和输出数据反转的,而样例代码中指定的crc16_ccitt配置参数,实际对应CRC在线计算器的CRC-16/XMODEM计算配置。如果在样例代码中,设定配置参数.EnableOutputBitSwap = true.EnableInputBitSwap = true,也可以得到同CRC在线计算器定义的CRC-16/CCITT算式相同的计算结果。

这里显然对算式的名字存在了误解。开发者如果不确定各名字预设的配置,也可以使用“自定义”的参数模型,此时可人为指定各参数。如图x所示。

编码器

图x 配置CRC在线计算式使用自定义的参数模型

CRC32 用例

crc32_test用例中,实现计算数列{0x12345678, 0x56781234, 0x55AA55AA, 0xA5A5A5A5}的CRC32值,有源码如下 :

CRC_Init_Type crc32_enet  =  
{  
    .EnableOutputBitInv = false,  
    .EnableOutputBitSwap = false,  
    .EnableInputBitSwap = false,  
    .CalcMode = CRC_CalcMode_Crc32,  
    .InitData = 0xffffffff  
};  
  
#define CRC_DATA_LEN  4u  
const uint32_t crc32_data_arr[CRC_DATA_LEN] = {0x12345678, 0x56781234, 0x55AA55AA, 0xA5A5A5A5};  
#define CRC32_RESULT   (0x57738169U) /* The result CRC calculator with CRC-32 standard. */  
  
void crc32_test(void)  
{  
    /* setup the crc calculator. */  
 CRC_Init(BOARD_CRC_PORT, &crc32_enet);  
   
 for (uint32_t i = 0u; i < CRC_DATA_LEN; i++)  
 {  
     CRC_SetData(BOARD_CRC_PORT, crc32_data_arr[i]);  
 }  
   
 printf("crc32_test ... ");  
 if (CRC32_RESULT == CRC_GetResult(BOARD_CRC_PORT))  
 {  
  printf("succ.");  
 }  
 else  
 {  
  printf("fail.");  
 }  
 printf("rn");  
}

使用在线的CRC计算器计算,可以得到相同的计算结果。如图x所示。

编码器

图x CRC在线计算器计算CRC16

总结

YTM32的CRC硬件外设模块能够执行CRC计算,同在线CRC计算器的结果能够对应上。

YTM32的手册中描述的CRC16-CCITTCRC32-ENET等对CRC计算典型配置的别称,实际可不必参考。CRC硬件外设的中CRC计算引擎还是执行基本CRC计算,典型配置实际可通过配置相关计算寄存器位的实现,最终可以支持各种各样的CRC典型算式。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分