0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

嵌入式USB开发 来源:嵌入式USB开发 作者:嵌入式USB开发 2023-06-08 11:00 次阅读

本文转自公众号,欢迎关注

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_16Bit


CRC_WrBlock_16Bit


CRC_WrOctet_16Bit


CRC_Close_16Bit


CRC_Open_32Bit


CRC_WrBlock_32Bit


CRC_WrOctet_32Bit


CRC_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 < stdio.h >
#include < stdint.h >
#include "edc_crc.h"
uint8_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部分测试以及相应的原理讲解,在理解的基础上可以将代码集成到自己的项目中使用。

审核编辑:汤梓红

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

    关注

    5056

    文章

    18955

    浏览量

    301671
  • NAND
    +关注

    关注

    16

    文章

    1664

    浏览量

    135919
  • crc
    crc
    +关注

    关注

    0

    文章

    199

    浏览量

    29413
  • Micrium
    +关注

    关注

    1

    文章

    7

    浏览量

    11737
收藏 人收藏

    评论

    相关推荐

    Micrium全家uC-FS: 0x02 NAND FTL算法原理详解

    uC-FS的NAND驱动实现基于一篇论文:《KAST: K-Associative Sector Translation for NAND Flash Memory in Real-Time Systems》所以有必要先介绍下该论文的内容,以便后面理解代码的实现。
    的头像 发表于 06-08 10:55 1505次阅读
    <b class='flag-5'>Micrium</b><b class='flag-5'>全家</b><b class='flag-5'>桶</b><b class='flag-5'>之</b><b class='flag-5'>uC</b>-FS: <b class='flag-5'>0x02</b> NAND FTL算法原理详解

    Micrium全家uC-FS: 0x01 NAND FTL

    这一篇我们来讲讲Micrium全家uC-FS。文件系统是一个比较庞大的组件,我们以从下往上的顺序介绍,即先以一个具体的设备:NAND为例,讲其FTL的原理和实现,然后再讲FS部分。
    的头像 发表于 06-08 10:58 1657次阅读
    <b class='flag-5'>Micrium</b><b class='flag-5'>全家</b><b class='flag-5'>桶</b><b class='flag-5'>之</b><b class='flag-5'>uC</b>-FS: <b class='flag-5'>0x</b>01 NAND FTL

    Micrium全家uC-CRC: 0x01 ECC

    我们这一篇来讲讲Micrium全家uC-CRC。该代码库提供了CRC算法进行错误检测EDC,使用HAMMING算法实现ECC错误纠正。E
    的头像 发表于 06-08 11:04 1124次阅读
    <b class='flag-5'>Micrium</b><b class='flag-5'>全家</b><b class='flag-5'>桶</b><b class='flag-5'>之</b><b class='flag-5'>uC-CRC</b>: <b class='flag-5'>0x</b>01 ECC

    STM32的CRC外设如何设置

    本文中将介绍的就是如何配置IAR的CRC参数,使与STM32的CRC硬件模块保持一致。本文中的例子都基于STM32F072进行。
    的头像 发表于 09-28 06:05 1.7w次阅读

    CRC的LSB表示方式该如何计算?

    的结果是011000111B=0xC7,都和格西CRC计算器结果0x02不一致。那么到底在对LSB表示的CRC该如何计算?还是说我的计算过程有问题?
    发表于 03-05 11:34

    CRC的LSB表示方式该如何计算?

    的结果是011000111B=0xC7,都和格西CRC计算器结果0x02不一致。那么到底在对LSB表示的CRC该如何计算?还是说我的计算过程有问题?
    发表于 03-05 13:59

    从M24SR通过i2c发送和接收字节时无法计算CRC

    命令来读取CC文件长度,我将如何计算CRC?起始位0xAC 0x02 0x00 0xB0 0x0
    发表于 07-17 08:15

    CRC校验源码分析

    CRC根据权(即多项表达式)的不同而相应的源代码也有稍许不同。以下是各种常用的权: CRA8 =X8+X5+X4+1 CRC-CCITT =X16+X12+X5+1
    发表于 04-07 20:49 117次下载

    STM32软件CRC和硬件CRC速度测试

    软件提前生成CRC表,用于查询。分别使用软件CRC算法和硬件CRC外设对一个缓存进行计算,目的是从该缓存中找到同步头。同步头共11字节,前两个字节为后九个字节的CRC校验值。通过迭代算
    发表于 05-09 11:45 6383次阅读
    STM32<b class='flag-5'>之</b>软件<b class='flag-5'>CRC</b>和硬件<b class='flag-5'>CRC</b>速度测试

    CRC算法原理和CRC编码的实现方式与使用Verilog对CRC编码进行描述

    CRC 校验是一种在数据通信系统和其它串行传输系统中广泛使用的错误检测手段。通用的CRC 标准有CRC-8、CRC-16、CRC-32、
    发表于 08-06 16:39 36次下载
    <b class='flag-5'>CRC</b>算法原理和<b class='flag-5'>CRC</b>编码的实现方式与使用Verilog对<b class='flag-5'>CRC</b>编码进行描述

    CRC校验 、STM32中CRC计算单元、 CRC应用

    CRC校验、STM32中CRC计算单元、CRC应用
    的头像 发表于 03-04 13:54 5984次阅读

    用于单片机的CRC数据校验方法

    方法也够用了。二、代码实现1.CRC表格crc table:static const u16 ccitt_table[256] = { 0x0000, 0x1021,
    发表于 12-17 18:35 3次下载
    用于单片机的<b class='flag-5'>CRC</b>数据校验方法

    FPGA学习CRC校验

    其中有的CRC寄存器初始值设置为全1,如以太网的CRC32,目的就是为了能检测出数据前面的0的个数。1234算出来的CRC,跟01234算出来的,不一样,这就能应对前面带
    发表于 08-26 14:11 2297次阅读

    讲讲Micrium全家uC-CRC算法

    我们这一篇来讲讲Micrium全家uC-CRC。该代码库提供了CRC算法进行错误检测EDC,使用HAMMING算法实现ECC错误纠正。
    的头像 发表于 05-04 10:47 796次阅读
    讲讲<b class='flag-5'>Micrium</b><b class='flag-5'>全家</b><b class='flag-5'>桶</b>的<b class='flag-5'>uC-CRC</b>算法

    这个CRC计算单元是如何基于固定的生成多项式(0x4C11DB7)来获取给定数据缓冲区的CRC码的?

    这个CRC计算单元是如何基于固定的生成多项式(0x4C11DB7)来获取给定数据缓冲区的CRC码的?
    的头像 发表于 05-16 16:06 667次阅读