開發環境:
MDK:Keil 5.30
開發板:GD32F207I-EVAL
MCU:GD32F207IK
1 CRC的校驗原理
__循環冗余校驗(CRC)計算單元是根據固定的生成多項式得到任一32位全字的CRC計算結果。__在其他的應用中, CRC技術主要應用于核實數據傳輸或者數據存儲的正確性和完整性。標準EN/IEC 60335-1即提供了一種核實閃存存儲器完整性的方法。 CRC計算單元可以在程序運行時計算出軟件的標識,之后與在連接時生成的參考標識比較,然后存放在指定的存儲器空間。那么首先來看看CRC校驗原理。
1.1基本原理
CRC檢驗原理實際上就是在一個p位二進制數據序列之后附加一個r位二進制檢驗碼(序列),從而構成一個總長為n=p+r位的二進制序列;附加在數據序列之后的這個檢驗碼與數據序列的內容之間存在著某種特定的關系。如果因干擾等原因使數據序列中的某一位或某些位發生錯誤,這種特定關系就會被破壞。因此,通過檢查這一關系,就可以實現對數據正確性的檢驗。
- 幾個基本概念
1、幀檢驗序列FCS(Frame Check Sequence):為了進行差錯檢驗而添加的冗余碼。
2、多項式模2運行:實際上是按位異或(Exclusive OR)運算,即相同為0,相異為1,也就是不考慮進位、借位的二進制加減運算。如:10011011 + 11001010 = 01010001。
3、生成多項式(generator polynomial):當進行CRC檢驗時,發送方與接收方需要事先約定一個除數,即生成多項式,一般記作G(x)。生成多項式的最高位與最低位必須是1。常用的CRC碼的生成多項式有:
每一個生成多項式都可以與一個代碼相對應,如CRC8對應代碼:100110001。
1.2 CRC檢驗碼的計算
設信息字段為K位,校驗字段為R位,則碼字長度為N(N=K+R)。設雙方事先約定了一個R次多項式g(x),則CRC碼:
V(x)=A(x)g(x)=xRm(x)+r(x)
其中: m(x)為K次信息多項式, r(x)為R-1次校驗多項式。
這里r(x)對應的代碼即為冗余碼,加在原信息字段后即形成CRC碼。
r(x)的計算方法為:在K位信息字段的后面添加R個0,再除以g(x)對應的代碼序列,得到的余數即為r(x)對應的代碼(應為R-1位;若不足,而在高位補0)。
計算示例:
設需要發送的信息為M = 1010001101,產生多項式對應的代碼為P = 110101,R=5。在M后加5個0,然后對P做模2除法運算,得余數r(x)對應的代碼:01110。故實際需要發送的數據是101000110101110。
1.3 錯誤檢測
當接收方收到數據后,用收到的數據對P(事先約定的)進行模2除法,若余數為0,則認為數據傳輸無差錯;若余數不為0,則認為數據傳輸出現了錯誤,由于不知道錯誤發生在什么地方,因而不能進行自動糾正,一般的做法是丟棄接收的數據。
【注】幾點說明:
1、CRC是一種常用的檢錯碼,并不能用于自動糾錯。
2、只要經過嚴格的挑選,并使用位數足夠多的除數 P,那么出現檢測不到的差錯的概率就很小很小。
3、僅用循環冗余檢驗 CRC 差錯檢測技術只能做到無差錯接受(只是非常近似的認為是無差錯的),并不能保證可靠傳輸。
2 GD32中的CRC
所有的GD32芯片都內置了一個硬件的CRC計算模塊,可以很方便地應用到需要進行通信的程序中,這個CRC計算模塊使用常見的、在以太網中使用的計算多項式:
寫成16進制就是:0x04C11DB7
使用這個內置CRC模塊的方法非常簡單,既首先復位CRC模塊(設置CRC_CR=0x01),這個操作把CRC計算的余數初始化為0xFFFFFFFF;然后把要計算的數據按每32位分割為一組數據字,并逐個地把這組數據字寫入CRC_DR寄存器(既下圖中的綠色框),寫完所有的數據字后,就可以從CRC_DR寄存器(既下圖中的蘭色框)讀出計算的結果。
下面是用C語言描述的這個計算模塊的算法,大家可以把它放在通信的另一端,對通信的正確性進行驗證:
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;
}
有幾點需要說明:
1)上述算法中變量CRC,在每次循環結束包含了計算的余數,它始終是向左移位(既從最低位向最高位移動),溢出的數據位被丟棄。
2)輸入的數據始終是以32位為單位,如果原始數據少于32位,需要在低位補0,當然也可以高位補0。
3)假定輸入的DWORD數組中每個分量是按小端存儲。
4)輸入數據是按照最高位最先計算,最低位最后計算的順序進行。
例如:
如果輸入0x44434241,內存中按字節存放的順序是:0x41, 0x42, 0x43, 0x44。計算的結果是:0xCF534AE1
如果輸入0x41424344,內存中按字節存放的順序是:0x44, 0x43, 0x42, 0x41。計算的結果是:0xABCF9A63
3 CRC寄存器描述
- 數據寄存器(CRC_DRTA)
CRC_DATA用于接收待計算的新數據,直接將其寫入即可。剛寫入的數據不能被讀出來,因為讀取該寄存器得到的是上次CRC計算的結果。
- 獨立數據寄存器(CRC_FDATA)
注:此寄存器不參與CRC計算,可以存放任何數據。
- 控制寄存器(CRC_CTL)
CRC_CTL用來復位CRC_DATA寄存器,設置其值為0xFFFFFFFF,然后該位被硬件自動清零。該位對CRC_FDATA寄存器沒有影響。
4 CRC具體代碼實現
代碼很簡單。
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()函數,傳入一個要計算的數據和大小,就得到了計算的CRC值。
5 實驗現象
將編譯好的程序下載到板子中,通過串口助手可以看到如下現象。
然后使用CRC計算工具來計算。
可以看到和軟件計算的一致。
值得注意的是,STM32的硬件CRC的結果異或值是0x00000000。
【注】關于CRC的更多內容可以自行查閱相關資料,筆者這里推薦一篇文章A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS
,感興趣的朋友自己去看看吧。
-
CRC校驗
+關注
關注
0文章
84瀏覽量
15188 -
Cortex-M
+關注
關注
2文章
227瀏覽量
29726 -
GD32
+關注
關注
7文章
403瀏覽量
24219
發布評論請先 登錄
相關推薦
評論