開發(fā)環(huán)境:
MDK:Keil 5.30
開發(fā)板:GD32F207I-EVAL
MCU:GD32F207IK
1 CRC的校驗(yàn)原理
__循環(huán)冗余校驗(yàn)(CRC)計(jì)算單元是根據(jù)固定的生成多項(xiàng)式得到任一32位全字的CRC計(jì)算結(jié)果。__在其他的應(yīng)用中, CRC技術(shù)主要應(yīng)用于核實(shí)數(shù)據(jù)傳輸或者數(shù)據(jù)存儲(chǔ)的正確性和完整性。標(biāo)準(zhǔn)EN/IEC 60335-1即提供了一種核實(shí)閃存存儲(chǔ)器完整性的方法。 CRC計(jì)算單元可以在程序運(yùn)行時(shí)計(jì)算出軟件的標(biāo)識(shí),之后與在連接時(shí)生成的參考標(biāo)識(shí)比較,然后存放在指定的存儲(chǔ)器空間。那么首先來看看CRC校驗(yàn)原理。
1.1基本原理
CRC檢驗(yàn)原理實(shí)際上就是在一個(gè)p位二進(jìn)制數(shù)據(jù)序列之后附加一個(gè)r位二進(jìn)制檢驗(yàn)碼(序列),從而構(gòu)成一個(gè)總長為n=p+r位的二進(jìn)制序列;附加在數(shù)據(jù)序列之后的這個(gè)檢驗(yàn)碼與數(shù)據(jù)序列的內(nèi)容之間存在著某種特定的關(guān)系。如果因干擾等原因使數(shù)據(jù)序列中的某一位或某些位發(fā)生錯(cuò)誤,這種特定關(guān)系就會(huì)被破壞。因此,通過檢查這一關(guān)系,就可以實(shí)現(xiàn)對數(shù)據(jù)正確性的檢驗(yàn)。
- 幾個(gè)基本概念
1、幀檢驗(yàn)序列FCS(Frame Check Sequence):為了進(jìn)行差錯(cuò)檢驗(yàn)而添加的冗余碼。
2、多項(xiàng)式模2運(yùn)行:實(shí)際上是按位異或(Exclusive OR)運(yùn)算,即相同為0,相異為1,也就是不考慮進(jìn)位、借位的二進(jìn)制加減運(yùn)算。如:10011011 + 11001010 = 01010001。
3、生成多項(xiàng)式(generator polynomial):當(dāng)進(jìn)行CRC檢驗(yàn)時(shí),發(fā)送方與接收方需要事先約定一個(gè)除數(shù),即生成多項(xiàng)式,一般記作G(x)。生成多項(xiàng)式的最高位與最低位必須是1。常用的CRC碼的生成多項(xiàng)式有:
每一個(gè)生成多項(xiàng)式都可以與一個(gè)代碼相對應(yīng),如CRC8對應(yīng)代碼:100110001。
1.2 CRC檢驗(yàn)碼的計(jì)算
設(shè)信息字段為K位,校驗(yàn)字段為R位,則碼字長度為N(N=K+R)。設(shè)雙方事先約定了一個(gè)R次多項(xiàng)式g(x),則CRC碼:
V(x)=A(x)g(x)=xRm(x)+r(x)
其中: m(x)為K次信息多項(xiàng)式, r(x)為R-1次校驗(yàn)多項(xiàng)式。
這里r(x)對應(yīng)的代碼即為冗余碼,加在原信息字段后即形成CRC碼。
r(x)的計(jì)算方法為:在K位信息字段的后面添加R個(gè)0,再除以g(x)對應(yīng)的代碼序列,得到的余數(shù)即為r(x)對應(yīng)的代碼(應(yīng)為R-1位;若不足,而在高位補(bǔ)0)。
計(jì)算示例:
設(shè)需要發(fā)送的信息為M = 1010001101,產(chǎn)生多項(xiàng)式對應(yīng)的代碼為P = 110101,R=5。在M后加5個(gè)0,然后對P做模2除法運(yùn)算,得余數(shù)r(x)對應(yīng)的代碼:01110。故實(shí)際需要發(fā)送的數(shù)據(jù)是101000110101110。
1.3 錯(cuò)誤檢測
當(dāng)接收方收到數(shù)據(jù)后,用收到的數(shù)據(jù)對P(事先約定的)進(jìn)行模2除法,若余數(shù)為0,則認(rèn)為數(shù)據(jù)傳輸無差錯(cuò);若余數(shù)不為0,則認(rèn)為數(shù)據(jù)傳輸出現(xiàn)了錯(cuò)誤,由于不知道錯(cuò)誤發(fā)生在什么地方,因而不能進(jìn)行自動(dòng)糾正,一般的做法是丟棄接收的數(shù)據(jù)。
【注】幾點(diǎn)說明:
1、CRC是一種常用的檢錯(cuò)碼,并不能用于自動(dòng)糾錯(cuò)。
2、只要經(jīng)過嚴(yán)格的挑選,并使用位數(shù)足夠多的除數(shù) P,那么出現(xiàn)檢測不到的差錯(cuò)的概率就很小很小。
3、僅用循環(huán)冗余檢驗(yàn) CRC 差錯(cuò)檢測技術(shù)只能做到無差錯(cuò)接受(只是非常近似的認(rèn)為是無差錯(cuò)的),并不能保證可靠傳輸。
2 GD32中的CRC
所有的GD32芯片都內(nèi)置了一個(gè)硬件的CRC計(jì)算模塊,可以很方便地應(yīng)用到需要進(jìn)行通信的程序中,這個(gè)CRC計(jì)算模塊使用常見的、在以太網(wǎng)中使用的計(jì)算多項(xiàng)式:
寫成16進(jìn)制就是:0x04C11DB7
使用這個(gè)內(nèi)置CRC模塊的方法非常簡單,既首先復(fù)位CRC模塊(設(shè)置CRC_CR=0x01),這個(gè)操作把CRC計(jì)算的余數(shù)初始化為0xFFFFFFFF;然后把要計(jì)算的數(shù)據(jù)按每32位分割為一組數(shù)據(jù)字,并逐個(gè)地把這組數(shù)據(jù)字寫入CRC_DR寄存器(既下圖中的綠色框),寫完所有的數(shù)據(jù)字后,就可以從CRC_DR寄存器(既下圖中的蘭色框)讀出計(jì)算的結(jié)果。
下面是用C語言描述的這個(gè)計(jì)算模塊的算法,大家可以把它放在通信的另一端,對通信的正確性進(jìn)行驗(yàn)證:
DWORD dwPolynomial = 0x04c11db7;
DWORD cal_crc(DWORD *ptr, int len)
{
DWORD xbit;
DWORD data;
DWORD CRC = 0xFFFFFFFF; // init
while (len--) {
xbit = 1 << 31;
data = *ptr++;
for (int bits = 0; bits < 32; bits++) {
if (CRC & 0x80000000) {
CRC <<= 1;
CRC ^= dwPolynomial;
}
else
CRC <<= 1;
if (data & xbit)
CRC ^= dwPolynomial;
xbit >>= 1;
}
}
return CRC;
}
有幾點(diǎn)需要說明:
1)上述算法中變量CRC,在每次循環(huán)結(jié)束包含了計(jì)算的余數(shù),它始終是向左移位(既從最低位向最高位移動(dòng)),溢出的數(shù)據(jù)位被丟棄。
2)輸入的數(shù)據(jù)始終是以32位為單位,如果原始數(shù)據(jù)少于32位,需要在低位補(bǔ)0,當(dāng)然也可以高位補(bǔ)0。
3)假定輸入的DWORD數(shù)組中每個(gè)分量是按小端存儲(chǔ)。
4)輸入數(shù)據(jù)是按照最高位最先計(jì)算,最低位最后計(jì)算的順序進(jìn)行。
例如:
如果輸入0x44434241,內(nèi)存中按字節(jié)存放的順序是:0x41, 0x42, 0x43, 0x44。計(jì)算的結(jié)果是:0xCF534AE1
如果輸入0x41424344,內(nèi)存中按字節(jié)存放的順序是:0x44, 0x43, 0x42, 0x41。計(jì)算的結(jié)果是:0xABCF9A63
3 CRC寄存器描述
- 數(shù)據(jù)寄存器(CRC_DRTA)
CRC_DATA用于接收待計(jì)算的新數(shù)據(jù),直接將其寫入即可。剛寫入的數(shù)據(jù)不能被讀出來,因?yàn)樽x取該寄存器得到的是上次CRC計(jì)算的結(jié)果。
- 獨(dú)立數(shù)據(jù)寄存器(CRC_FDATA)
注:此寄存器不參與CRC計(jì)算,可以存放任何數(shù)據(jù)。
- 控制寄存器(CRC_CTL)
CRC_CTL用來復(fù)位CRC_DATA寄存器,設(shè)置其值為0xFFFFFFFF,然后該位被硬件自動(dòng)清零。該位對CRC_FDATA寄存器沒有影響。
4 CRC具體代碼實(shí)現(xiàn)
代碼很簡單。
brief main function
param[in] none
param[out] none
retval none
*/
int main(void)
{
//systick init
sysTick_init();
//usart init 115200 8-N-1
com_init(COM1, 115200, 0, 1);
printf("CRC Test \\n");
/* Enable CRC clock */
rcu_periph_clock_enable(RCU_CRC);
/* Compute the CRC of "DataBuffer" */
CRCValue = crc_block_data_calculate((uint32_t *)DataBuffer, BUFFER_SIZE);
printf("\\r\\n32-bit CRC check code : 0x%X\\n", CRCValue);
while(1)
{
delay_ms(1000);
}
}
就使用了crc_block_data_calculate()函數(shù),傳入一個(gè)要計(jì)算的數(shù)據(jù)和大小,就得到了計(jì)算的CRC值。
5 實(shí)驗(yàn)現(xiàn)象
將編譯好的程序下載到板子中,通過串口助手可以看到如下現(xiàn)象。
然后使用CRC計(jì)算工具來計(jì)算。
可以看到和軟件計(jì)算的一致。
值得注意的是,STM32的硬件CRC的結(jié)果異或值是0x00000000。
【注】關(guān)于CRC的更多內(nèi)容可以自行查閱相關(guān)資料,筆者這里推薦一篇文章A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS
,感興趣的朋友自己去看看吧。
-
CRC校驗(yàn)
+關(guān)注
關(guān)注
0文章
84瀏覽量
15533 -
Cortex-M
+關(guān)注
關(guān)注
2文章
230瀏覽量
30263 -
GD32
+關(guān)注
關(guān)注
7文章
419瀏覽量
25227
發(fā)布評論請先 登錄
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第1章 開發(fā)環(huán)境搭建
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第4章 GD32啟動(dòng)流程詳解(Keil版)
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第7章 定時(shí)器
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第8章 定時(shí)器
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第12章 ADC
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第14章 內(nèi)部溫度傳感器
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第15章 低功耗
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第16章 RTC
GD32開發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第17章 看門狗
【圖書分享】《STM32庫開發(fā)實(shí)戰(zhàn)指南》
《GD32 MCU原理及固件庫開發(fā)指南》 + 初讀感悟
《GD32 MCU原理及固件庫開發(fā)指南》+讀后感
PIC32系列中文參考手冊—第60章 32位可編程循環(huán)冗余校驗(yàn) (CRC)
---GD32 MCU---SPI硬件CRC校驗(yàn)失敗

評論