STM32F10x 學(xué)習(xí)筆記4(CRC計(jì)算單元 續(xù))
下面先給個(gè)crc32的計(jì)算函數(shù),這個(gè)函數(shù)計(jì)算的結(jié)果與STM32F單片機(jī)上硬件單元的計(jì)算結(jié)果相同。
- uint32_tcrc32(uint32_t*addr,intnum,uint32_tcrc)
- {
- inti;
- for(;num>0;num--)
- {
- crc=crc^(*addr++);
- for(i=0;i<32;i++)
- {
- if(crc&0x80000000)
- crc=(crc<<1)^POLY;
- else
- crc<<=1;
- }
- crc&=0xFFFFFFFF;
- }
- return(crc);
- }
在我寫的文章《寫給嵌入式程序員的循環(huán)冗余校驗(yàn)(CRC)算法入門引導(dǎo)》(http://blog.csdn.net/liyuanbhu/article/details/7882789)中給了個(gè)利用查表法計(jì)算crc的程序。那個(gè)程序稍微修改一點(diǎn)就能計(jì)算CRC32。下面給出改動(dòng)后的程序。
- //crc32.h
- #ifndefCRC32_H_INCLUDED
- #defineCRC32_H_INCLUDED
- #ifdef__cplusplus
- #if__cplusplus
- extern"C"{
- #endif
- #endif/*__cplusplus*/
- #include
- /*
- *TheCRCparameters.CurrentlyconfiguredforCRC32.
- *CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0
- */
- #definePOLYNOMIAL0x04C11DB7
- #defineINITIAL_REMAINDER0xFFFFFFFF
- #defineFINAL_XOR_VALUE0x00000000
- /*
- *ThewidthoftheCRCcalculationandresult.
- *Modifythetypedefforan8or32-bitCRCstandard.
- */
- typedefuint32_twidth_t;
- #defineWIDTH(8*sizeof(width_t))
- #defineTOPBIT(1<<(WIDTH-1))
- /**
- *InitializetheCRClookuptable.
- *ThistableisusedbycrcCompute()tomakeCRCcomputationfaster.
- */
- voidcrcInit(void);
- /**
- *ComputetheCRCchecksumofabinarymessageblock.
- *@paramessage,用來計(jì)算的數(shù)據(jù)
- *@paranBytes,數(shù)據(jù)的長(zhǎng)度
- *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
- *firsttoinitializetheCRClookuptable.
- */
- width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder);
- #ifdef__cplusplus
- #if__cplusplus
- }
- #endif
- #endif/*__cplusplus*/
- #endif//CRC32_H_INCLUDED
對(duì)應(yīng)的C程序如下:
- #include"crc32.h"
- /*
- *Anarraycontainingthepre-computedintermediateresultforeach
- *possiblebyteofinput.Thisisusedtospeedupthecomputation.
- */
- staticwidth_tcrcTable[256];
- /**
- *InitializetheCRClookuptable.
- *ThistableisusedbycrcCompute()tomakeCRCcomputationfaster.
- */
- voidcrcInit(void)
- {
- width_tremainder;
- width_tdividend;
- intbit;
- /*Performbinarylongdivision,abitatatime.*/
- for(dividend=0;dividend<256;dividend++)
- {
- /*Initializetheremainder.*/
- remainder=dividend<<(WIDTH-8);
- /*ShiftandXORwiththepolynomial.*/
- for(bit=0;bit<8;bit++)
- {
- /*Trytodividethecurrentdatabit.*/
- if(remainder&TOPBIT)
- {
- remainder=(remainder<<1)^POLYNOMIAL;
- }
- else
- {
- remainder=remainder<<1;
- }
- }
- /*Savetheresultinthetable.*/
- crcTable[dividend]=remainder;
- }
- }/*crcInit()*/
- /**
- *ComputetheCRCchecksumofabinarymessageblock.
- *@paramessage,用來計(jì)算的數(shù)據(jù)
- *@paranBytes,數(shù)據(jù)的長(zhǎng)度
- *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
- *firsttoinitializetheCRClookuptable.
- */
- width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder)
- {
- unsignedintoffset;
- unsignedcharbyte;
- //width_tremainder=INITIAL_REMAINDER;
- /*Dividethemessagebythepolynomial,abyteatatime.*/
- for(offset=0;offset
- {
- byte=(remainder>>(WIDTH-8))^message[offset];
- remainder=crcTable[byte]^(remainder<<8);
- }
- /*ThefinalremainderistheCRCresult.*/
- return(remainder^FINAL_XOR_VALUE);
- }/*crcCompute()*/
不過用這個(gè)程序直接計(jì)算得到的CRC值與STM32給出的并不相同。之所以會(huì)這樣是因?yàn)樽止?jié)序的原因。可以舉個(gè)例子來說明這個(gè)問題。比如我們有一片內(nèi)存區(qū)域要計(jì)算CRC值。這片內(nèi)存區(qū)域的起始地址是0x1000,共有8個(gè)字節(jié)。用crcCompute()函數(shù)計(jì)算時(shí)是按照地址順序依次傳入各個(gè)字節(jié)。也就是先計(jì)算0x1000處的字節(jié),再計(jì)算0x0001處的字節(jié),以此類推最后計(jì)算0x1007地址處的字節(jié)。而STM32的硬件CRC單元是以32位的字為單位計(jì)算的。我們知道CRC實(shí)際上是個(gè)多項(xiàng)式的除法運(yùn)算,而除法運(yùn)算是從高位算起的。也就是相當(dāng)于它是按照0x1003、0x1002、0x1001、0x1000這個(gè)順序計(jì)算第一個(gè)字,然后按照0x1007、0x1006、0x1005、x1004的順序計(jì)算第二個(gè)字。因此。我們要是預(yù)先將字節(jié)序調(diào)換一下得到結(jié)果就沒有問題了。這就有了下面的改造。其中remainder傳入0xffffffff。因?yàn)镾TM32中的CRC余數(shù)初始值為0xffffffff。
- uint32_tstm32crc32(uint32_t*message,unsignedintnWords,uint32_tremainder)
- {
- unsignedintoffset;
- unsignedcharbyte;
- unsignedchar*p=(unsignedchar*)message;
- //width_tremainder=INITIAL_REMAINDER;
- /*Dividethemessagebythepolynomial,abyteatatime.*/
- for(offset=0;offset
- {
- byte=(remainder>>(WIDTH-8))^p[3];
- remainder=crcTable[byte]^(remainder<<8);
- byte=(remainder>>(WIDTH-8))^p[2];
- remainder=crcTable[byte]^(remainder<<8);
- byte=(remainder>>(WIDTH-8))^p[1];
- remainder=crcTable[byte]^(remainder<<8);
- byte=(remainder>>(WIDTH-8))^p[0];
- remainder=crcTable[byte]^(remainder<<8);
- p+=4;
- }
- /*ThefinalremainderistheCRCresult.*/
- return(remainder);
- }/*crcCompute()*/
大家可以驗(yàn)證這個(gè)函數(shù)的計(jì)算結(jié)果與STM32上的結(jié)果完全一樣。
寫到這里本該就結(jié)束了,不過我要多說一句,之所以要這么麻煩的調(diào)換字節(jié)序,都是小端(littleendian)惹的禍。要是都采用大端格式就沒這些麻煩的轉(zhuǎn)換了。
評(píng)論