STM32的CRC32 軟件實現代碼


對於STM32的32位CRC,如果假定它的一個主要目的是為了校驗往內部FLASH存儲數據的可靠性,那么(余數)初值是全1當然是比較合理的。
由於STM32的32位CRC是純32位,即每次必須輸入32位的數,所以如果數據不到32位,應該往低位用1來填充比較合理;

另外,如果輸入數據是 "1234"-0x31 0x32 0x33 0x34,

那么輸入的CRC數據是 0011-0100 0011-0011 0011-0010 0011-0001 :: 0x34333231

由於STM32的32位CRC是純32位且STM32是按小端對齊(little endian)的,這也是合理的。

輸入數據緩沖區:0x31 0x32 0x33 0x34

輸入STM32 CRC : 0x34333231

CRC->DR 是個 32 位寄存器,如果寫入數據不夠32位,要自行補足,但關鍵是要跟PC機一致即可。一般是補 1,如:

CRC->DR = 0x5AFFFFFF ;

 

不太清楚這個Reflect()的作用,現在在網上找到一個資料,里面介紹了這個Reflect()的由來,不知道正確與否,拿出來給大家分享評判:

資料地址:A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS

所有CRC的計算都是按照數據的高位在先的原則進行,上述這份資料(11節)中說因為UART是先發送字節的最低位,

因此設計UART的工程師按照傳輸線上數據位的順序,設計了CRC的計算電路。

如果這樣的計算方式只是局限在芯片的硬件層次,不會產生什么問題,但后來到了與計算機通信時發生了數據位反轉的問題,

結果就出現了這個Reflect()函數,並被引入了CRC的軟件算法中。

從所有對CRC計算的文字描述來看,顯然都沒有這個Reflect()的操作,因此上述的說法是有一定的可信度的。

我從網上也下載了一個號稱是WinZIP使用的CRC算法,在里面我也看到了這個Reflect()的操作;

這再次讓我相信WinZIP的實現只是CRC實現的一個個案,而不具有普遍的代表性。

前述資料的作者來自於澳大利亞阿德萊德大學,他也認為這種REFLECTED算法引起了不少的混亂,我相信這種混亂也包括我們這里的討論。

 

在任何“左移CRC”中,當選初值為0x00000000時,若輸入為0x00000000時,CRC結果為0x00000000。

若輸入為0xFFFFFFFF時,CRC結果為權。

所以,CRC32選擇了初值非0x00000000。

 

 

感覺stm32與主流實例差別有2點:

1、每個字節的位序相反。stm32f是按32位,高位在先。而主流實例每字節里面是從低位起的。
2、結果出來后,主流實例與0xffffffff異或了。而 stm32 沒有。

處理方法:

1、數據輸入到STM32之前使用 RBIT 對數據反向。
2、結果出來后,與0xffffffff 進行異或。

結果同樣需要用 RBIT 對數據反向。 

計算96位UID作來產品的序列號來顯示, 原始序列號: 39006C065834313149670543 分成三個32位數。

每一個32位按位倒置,然后給STM32計算CRC,結果跟0xffffffff異或運算后,再把32位的結果按位倒置。

39006C06     58343131     49670543

39006C06=00111001000000000110110000000110 : 按位倒置后 01100000001101100000000010011100 = 6036009C
58343131=01011000001101000011000100110001 : 按位倒置后 10001100100011000010110000011010 = 8C8C2C1A
49670543=01001001011001110000010101000011 : 按位倒置后 11000010101000001110011010010010 = C2A0E692

STM32的CRC結果為

FFAA5C5F=11111111101010100101110001011111 : 按位倒置后 11111010001110100101010111111111=FA3A55FF

__asm u32 RBIT(u32 value) //用到的32位位倒置程序
{
    rbit r0, r0
    bx lr
}
{ 
  u32 Device_Serial, Device_Serial0, Device_Serial1, Device_Serial2;
Device_Serial0
= *(u32*)(0x1FFFF7E8); Device_Serial0 = RBIT(Device_Serial0);
Device_Serial1
= *(u32*)(0x1FFFF7EC); Device_Serial1 = RBIT(Device_Serial1);
Device_Serial2
= *(u32*)(0x1FFFF7F0); Device_Serial2 = RBIT(Device_Serial2);
CRC_ResetDR(); Device_Serial
= CRC_CalcCRC(Device_Serial0); Device_Serial = CRC_CalcCRC(Device_Serial1); Device_Serial = CRC_CalcCRC(Device_Serial2);
Device_Serial
^= 0xFFFFFFFF;
Device_Serial
= RBIT(Device_Serial); }

看了很多朋友貼出了CRC的計算代碼,還是不明白CRC怎么算,這不重要了,可用就行。

在此帖上碼表和查表法,代碼經過驗證,和STM32的CRC結果一致。

uint32 Crc32Table[ 256 ] =
{
  0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
  0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
  0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
  0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
  0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
  0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
  0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
  0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
  0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
  0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
  0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
  0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
  0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
  0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
  0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
  0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
  0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
  0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
  0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
  0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
  0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
  0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
  0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
  0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
  0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
  0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
  0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
  0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
  0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
  0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
  0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
  0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
  0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
  0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
  0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
  0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
  0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
  0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
  0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
  0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
  0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
  0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
  0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 };
//查表法 uint32 CRC32Software( uint8 *pData, uint16 Length ) { uint32 nReg; //CRC寄存器 uint32 nTemp = 0; uint16 i, n; nReg = 0xFFFFFFFF; // for ( n = 0; n < Length; n++ ) { nReg ^= (uint32) pData[ n ]; for ( i = 0; i < 4; i++ ) { nTemp = Crc32Table[ ( uint8 )( ( nReg >> 24 ) & 0xff ) ]; //取一個字節,查表 nReg <<= 8; //丟掉計算過的頭一個BYTE nReg ^= nTemp; //與前一個BYTE的計算結果異或 } } return nReg; }
//STM32的CRC uint32 CRC32( uint8 *pBuf, uint16 nSize ) { uint32 index = 0; CRC_ResetDR( ); //復位CRC for ( index = 0; index < nSize; index++ ) { CRC->DR = (uint32) pBuf[ index ]; } return ( CRC->DR ); }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM