本文轉(zhuǎn)自公眾號(hào),歡迎關(guān)注
Micrium全家桶之uC-CRC: 0x02 CRC (qq.com)
前言
前一篇我們講了Micrium全家桶之uC-CRC: 0x01 ECC:https://mp.weixin.qq.com/s/FKVvzwL7wzxLJCkx3gOdJQ。ECC常用于NAND進(jìn)行誤碼校正。而CRC一般用于錯(cuò)誤檢測(cè),比如鏡像,協(xié)議的正確完備性檢測(cè)。
這一篇我們來講講uC-CRC組件的CRC部分,老規(guī)矩先代碼用起來,然后再講講原理,理論結(jié)合實(shí)踐。
使用
可以從https://github.com/qinyunti/uC-CRC.git下載代碼,該版本在原版本基礎(chǔ)上進(jìn)行了修改,刪除了其他依賴,可以單獨(dú)使用,方便移植,也可以參考https://mp.weixin.qq.com/s/FKVvzwL7wzxLJCkx3gOdJQ。
有了上一篇基礎(chǔ)我們不再詳細(xì)介紹如何集成該代碼,直接進(jìn)入測(cè)試環(huán)節(jié)。
文件
如果只使用CRC的話只需要crc_cfg.h和edc_crc.c,edc_crc.h即可。
配置
其中cec_cfg.h的宏EDC_CRC_CFG_OPTIMIZE_ASM_EN配置是否使用匯編代碼實(shí)現(xiàn),默認(rèn)為DEF_DISABLED.
以下宏配置是否使能對(duì)應(yīng)的算法和反轉(zhuǎn)查找表
其中前面4個(gè)宏使能了4種算法,后面4個(gè)宏定義是否支持位反轉(zhuǎn)模式,如果是則會(huì)定義對(duì)應(yīng)的CRC查找表,比如EDC_CRC_CFG_CRC32_REF_EN使能則使用CRC_TblCRC32_ref,EDC_CRC_CFG_CRC32_EN使能則使用CRC_TblCRC32。
所謂的位反轉(zhuǎn)就是bit7和bit0交換,bit6和bit1交換...,通過查表法空間換時(shí)間加快速度。有些場(chǎng)景需要位翻轉(zhuǎn),所以有這個(gè)實(shí)現(xiàn)。
#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位的
流式操作,結(jié)果存在結(jié)構(gòu)體參數(shù)種 只支持查表法
CRC_Open_16Bit()->
CRC_WrBlock_16Bit()-> 一次寫多個(gè)字節(jié)
CRC_WrOctet_16Bit()-> 一次寫一個(gè)字節(jié)
CRC_Close_16Bit()->
32位的類似
CRC_Open_32Bit->
CRC_WrBlock_32Bit->
CRC_WrOctet_32Bit->
CRC_Close_32Bit->
這里提供這幾個(gè)位反轉(zhuǎn)接口,最后結(jié)果再調(diào)用這些接口進(jìn)行位反轉(zhuǎn)。
CRC_Reflect_08Bit 查表法實(shí)現(xiàn)8位數(shù)據(jù)位反轉(zhuǎn) 查表是CRC_ReflectTbl
CRC_Reflect_16Bit 查表法實(shí)現(xiàn)16位數(shù)據(jù)位反轉(zhuǎn)
CRC_Reflect_32Bit 查表法實(shí)現(xiàn)32位數(shù)據(jù)位反轉(zhuǎn)
還提供兩個(gè)接口直接計(jì)算,立即返回計(jì)算值,支持查表和不查表
CRC_ChkSumCalc_16Bit
CRC_ChkSumCalc_32Bit
所以以上有幾種配置:使用查表還是不使用查表,使用位反轉(zhuǎn)還是不使用
p_model->Reflect == DEF_YES 則使用位反轉(zhuǎn)
p_model->TblPtr == (const CPU_INT16U *)0則不使用查表
測(cè)試
以CRC_ChkSumCalc_16Bit為例
CPU_INT16U crc = CRC_ChkSumCalc_16Bit((CRC_MODEL_16*)&CRC_ModelCRC16_8005,(void*)p_datap,strlen(p_datap),&err);
第一個(gè)參數(shù)傳入默認(rèn)配置好的
const CRC_MODEL_16 CRC_ModelCRC16_8005 = {
0x8005u,
0x0000u,
DEF_NO,
0x0000u,
&CRC_TblCRC16_8005[0]
};
即多項(xiàng)式為0x8005,初始值為0x0000,不進(jìn)行位反轉(zhuǎn),不進(jìn)行異或輸出,查表為CRC_TblCRC16_8005。
測(cè)試代碼如下
#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下列舉的測(cè)試用例結(jié)果一致
* ------------------------------------------------------------------
* | 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 |