标签:
Everyone knows that STM32F1xx, STM32F2xx, STM32F4xx have a hardware unit
with a polynomial CRC32 0x04C11DB7.
And he, in general, work.
But only a checksum for some reason does not coincide with that calculated softvarno.
The Google usually 2 types of questions:
Moreover, the answer to the first question is negative everywhere.
Is it so? Try to understand.
Software CRC32 generally considered byte by byte, and (as in Ethernet)
- LSB forward shift LSFR
- right in the direction of the least significant bit,
so use a polynomial The reversed 0xEDB88320.
Data register in the CRC block STM32 - 32-bit
and shifts to MSB with a polynomial CRC32 0x04C11DB7
To understand why so little illustration:
Look at the picture:
all the bits arrive in the order flowers I marked the bits that correspond to each other for direct
and mirror polynomials numbering byte coincides with a shift in the memory.
Ie, CRC32 on STM32 can count as well as customary in ethernet.
For this purpose it is necessary to reverse the input speech
and eventually reverse the checksum.
It works only for the length of a multiple of 4.
First Software implementation.
Initialize table residues for rapid calculation of CRC:
static uint32_t crc32_table[ 256 ]; static uint32_t crc32r_table[ 256 ]; #define CRC32_POLY 0x04C11DB7 #define CRC32_POLY_R 0xEDB88320 static void crc32_init( void ) { int i, j; uint32_t c, cr; for ( i = 0; i < 256; ++i ) { cr = i; c = i << 24; for ( j = 8; j > 0; --j ) { c = c & 0x80000000 ? ( c << 1 ) ^ CRC32_POLY : ( c << 1 ); cr = cr & 0x00000001 ? ( cr >> 1 ) ^ CRC32_POLY_R : ( cr >> 1 ); } crc32_table[ i ] = c; crc32r_table[ i ] = cr; //printf("f[%02X]=%08X\t", i, crc32_table[i]); //printf("r[%02X]=%08X\t", i, crc32r_table[i]); } //printf("\n"); }
const uint32_t crc32_table[ 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 }; const uint32_t crc32r_table[ 256 ] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, };
Byte calculation of the normal CRC
uint32_t crc32_byte( uint32_t init_crc, uint8_t *buf, int len ) { uint32_t v; uint32_t crc; crc = ~init_crc; while ( len > 0 ) { v = *buf++; crc = ( crc >> 8 ) ^ crc32r_table[ ( crc ^ ( v ) ) & 0xff ]; len--; } return ~crc; }
Calculating the CRC on CRC block STM32
uint32_t crc32_stm32( uint32_t init_crc, uint32_t *buf, int len ) { uint32_t v; uint32_t crc; crc = ~init_crc; while ( len >= 4 ) { v = htonl( *buf++ );
crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v ) ) ]; crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v >> 8 ) ) ]; crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v >> 16 ) ) ]; crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v >> 24 ) ) ]; len -= 4; } if ( len ) { switch ( len ) { case 1: v = 0xFF000000 & htonl( *buf++ ); break; case 2: v = 0xFFFF0000 & htonl( *buf++ ); break; case 3: v = 0xFFFFFF00 & htonl( *buf++ ); break; } crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v ) ) ]; crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v >> 8 ) ) ]; crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v >> 16 ) ) ]; crc = ( crc << 8 ) ^ crc32_table[ 0xFF & ( ( crc >> 24 ) ^ ( v >> 24 ) ) ]; } return ~crc; }
Then I applied to htonl bytes in the word are in a certain order, regardless of LE / BE:
first in LSFR dressed byte that is in memory at offset 3 (as shown).
Still, the rest of the message does not fit into a 4-byte word is padded with zeros on the right and CRC doschitvaetsya further.
You can write this type of structure (to calculate the CRC pieces):
printf("crc32_byte = %08X\n", crc32_byte(crc32_byte(0, "12345", 5), "6789", 4)); printf("crc32_stm32 = %08X\n", crc32_stm32(crc32_stm32(0, "1234", 4), "56789", 5));
Here‘s what happens:
crc32_byte («123456789») = CBF43926
crc32_stm32 («123456789») = 500E6FA8
crc32_byte («12345678») = 9AE0DAAF
crc32_stm32 («12345678») = 0103AB06
Now the code for STM32:
First, purely hardware configurations CRC (it corresponds Softovaya crc32_stm32):
uint32_t crc32_native( char *bfr, int len, int clear ) { int l; uint32_t *p, x, crc; l = len / 4; p = (uint32_t*) bfr; x = p[ l ]; if ( clear ) CRC_ResetDR( ); while ( l-- ) { crc = CRC_CalcCRC( *p++ ); } switch ( len & 3 ) { case 1: crc = CRC_CalcCRC( x & 0x000000FF ); break; case 2: crc = CRC_CalcCRC( x & 0x0000FFFF ); break; case 3: crc = CRC_CalcCRC( x & 0x00FFFFFF ); break; } return 0xFFFFFFFF ^ crc; }
Then do a "soft on" or "in ethernet».
Fortunately, there are on the ARM instruction for reversing bits.
But that‘s not all.
After all, if poraskinut brains, you can add a delicious bun - still count Byte CRC hardware unit.
You just need to calculate the polynomial, the remainder of the broken pieces
and add it to the already counted by word CRC.
Balance - is essentially the same CRC, but with the initial state LSFR = 0 (see table initialization residues).
But here‘s the rub - CRC_ResetDR can set CRC register only 0xFFFFFFFF.
Thank balls that we should just 0 rather than something else.
One of the properties of the CRC is that if a message attributed to its CRC, the CRC of the new posts will be equal to 0.
In other words, if we will submit to the CRC register what we thought of it, the result will be 0.
CRC_ResetDR( ); CRC_CalcCRC( 0xFFFFFFFF );
Now we have to fill register a piece of one, two or three remaining bytes -
et voila, we take away our polynomial-residue and add it to the CRC.
The following code:
uint32_t reverse_32( uint32_t data ) { asm("rbit r0,r0"); return data; } ; uint32_t crc32_ether( char *buf, int len, int clear ) { uint32_t *p = (uint32_t*) buf; uint32_t crc, crc_reg; if ( clear ) CRC_ResetDR( );
while ( len >= 4 ) { crc_reg = CRC_CalcCRC( reverse_32( *p++ ) ); len -= 4; }
crc = reverse_32( crc_reg ); if ( len ) { CRC_CalcCRC( crc_reg ); switch ( len ) { case 1: crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFF ) ^ crc ) >> 24 ); crc = ( crc >> 8 ) ^ reverse_32( crc_reg ); break; case 2: crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFF ) ^ crc ) >> 16 ); crc = ( crc >> 16 ) ^ reverse_32( crc_reg ); break; case 3: crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFFFF ) ^ crc ) >> 8 ); crc = ( crc >> 24 ) ^ reverse_32( crc_reg ); break; } } return ~crc; }
That is, something like that, I think many will come in handy.
uint8_t pkt_alt[ ] = { 0x00, 0x10, 0xA4, 0x7B, 0xEA, 0x80, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x08, 0x00, 0x45, 0x00, 0x00, 0x2E, 0xB3, 0xFE, 0x00, 0x00, 0x80, 0x11, 0x05, 0x40, 0xC0, 0xA8, 0x00, 0x2C, 0xC0, 0xA8, 0x00, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, 0x1A, 0x2D, 0xE8, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0xB3, 0x31, 0x88, 0x1B }; uint8_t pkt_alt_d[ ] = { 0x00, 0xC0, 0x02, 0x37, 0x57, 0x28, 0x00, 0x10, 0xA4, 0x7B, 0xEA, 0x80, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3C, 0x02, 0x24, 0x00, 0x00, 0x80, 0x01, 0xB7, 0x47, 0xC0, 0xA8, 0x00, 0x04, 0xC0, 0xA8, 0x00, 0x01, 0x08, 0x00, 0x42, 0x5C, 0x02, 0x00, 0x09, 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x62, 0x31, 0xC5, 0x4E }; uint8_t pkt_xil[ ] = { 0x00, 0x0A, 0xE6, 0xF0, 0x05, 0xA3, 0x00, 0x12, 0x34, 0x56, 0x78, 0x90, 0x08, 0x00, 0x45, 0x00, 0x00, 0x30, 0xB3, 0xFE, 0x00, 0x00, 0x80, 0x11, 0x72, 0xBA, 0x0A, 0x00, 0x00, 0x03, 0x0A, 0x00, 0x00, 0x02, 0x04, 0x00, 0x04, 0x00, 0x00, 0x1C, 0x89, 0x4D, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x7A, 0xD5, 0x6B, 0xB3 };
so if anyone should, real ethernet-frames with CRC32 FCS
public class CRC32 { static UInt32[] Crc32Table = new UInt32[] { 0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9, 0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005, 0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61, 0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD }; static UInt32 DR;
public static void Reset() { DR = 0xFFFFFFFF; } public static void Write(UInt32 data) { DR = DR ^ data; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; DR = (DR << 4) ^ Crc32Table[DR >> 28]; }
public static UInt32 Read() { return DR; } }
The CRC processes 32-bits at a time, applying them in a small-endian fashion.
It is not performed byte wise in the manner most online testers use.
It can be computed on the STM32 or x86 PC with the following code.
The nibble table method is a trade off between speed and space
DWORD Crc32( DWORD Crc, DWORD Data ) { int i; Crc = Crc ^ Data; for ( i = 0; i < 32; i++ ) { if ( Crc & 0x80000000 ) Crc = ( Crc << 1 ) ^ 0x04C11DB7; // Polynomial used in STM32 else Crc = ( Crc << 1 ); } return ( Crc ); } DWORD Crc32Fast( DWORD Crc, DWORD Data ) { // Nibble lookup table for 0x04C11DB7 polynomial static const DWORD CrcTable[ 16 ] = { 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD }; Crc = Crc ^ Data; // Apply all 32-bits // Process 32-bits, 4 at a time, or 8 rounds // Assumes 32-bit reg, masking index to 4-bits // 0x04C11DB7 Polynomial used in STM32 Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; return ( Crc ); } void Crc32Demo( void ) { printf( "%08X\n\n", Crc32( 0xFFFFFFFF, 0x12345678 ) ); // 0xDF8A8A2B printf( "%08X\n\n", Crc32Fast( 0xFFFFFFFF, 0x12345678 ) ); // 0xDF8A8A2B }
CRC‘s by their nature are sensitive to bit and sequence errors, if you screw up the math you‘re going to get the wrong numbers.
The polynomial, endian-ness, and 32-bit data width of the STM32 are difficult for some people to get their heads around,
especially if they rely on web sources for their testing and knowledge
// STM32 CRC32 Test App - sourcer32@gmail.com #include <windows.h> #include <stdio.h> DWORD Crc32( DWORD Crc, DWORD Data ) { int i; Crc = Crc ^ Data; for ( i = 0; i < 32; i++ ) if ( Crc & 0x80000000 ) Crc = ( Crc << 1 ) ^ 0x04C11DB7; // Polynomial used in STM32 else Crc = ( Crc << 1 ); return ( Crc ); } DWORD Crc32Fast( DWORD Crc, DWORD Data ) { static const DWORD CrcTable[ 16 ] = { // Nibble lookup table for 0x04C11DB7 polynomial 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD }; Crc = Crc ^ Data; // Apply all 32-bits // Process 32-bits, 4 at a time, or 8 rounds Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; // Assumes 32-bit reg, masking index to 4-bits Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; // 0x04C11DB7 Polynomial used in STM32 Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; return ( Crc ); } void test( void ) { BYTE vector[ 12 ] = { 0x02, 0x07, 0x02, 0x00, 0x18, 0x8A, 0xD0, 0x23, 0x25, 0x2B, 0x09, 0x00 }; DWORD Crc; int i; for ( i = 0; i < 12; i++ ) printf( "%02X ", vector[ i ] ); putchar( ‘\n‘ ); Crc = 0xFFFFFFFF; // Initial state for ( i = 0; i < 12; i += 4 ) { Crc = Crc32Fast( Crc, *( (DWORD *) &vector[ i ] ) ); // 4-bytes at a time } printf( "%08X test\n", Crc ); } int main( int argc, char **argv ) { printf( "%08X\n\n", Crc32( 0xFFFFFFFF, 0x12345678 ) ); // 0xDF8A8A2B printf( "%08X\n\n", Crc32Fast( 0xFFFFFFFF, 0x12345678 ) ); // 0xDF8A8A2B test( ); return ( 1 ); }
// STM32 CRC32 Test App - sourcer32@gmail.com #include <windows.h> #include <stdio.h> #include <stdlib.h> //**************************************************************************** DWORD Crc32( DWORD Crc, DWORD Data ) { int i; Crc = Crc ^ Data; for ( i = 0; i < 32; i++ ) if ( Crc & 0x80000000 ) Crc = ( Crc << 1 ) ^ 0x04C11DB7; // Polynomial used in STM32 else Crc = ( Crc << 1 ); return ( Crc ); } //**************************************************************************** DWORD Crc32Block( DWORD Crc, DWORD Size, DWORD *Buffer ) // 32-bit units { while ( Size-- ) Crc = Crc32( Crc, *Buffer++ ); return ( Crc ); } //**************************************************************************** DWORD Crc32Fast( DWORD Crc, DWORD Data ) { static const DWORD CrcTable[ 16 ] = { // Nibble lookup table for 0x04C11DB7 polynomial 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD }; Crc = Crc ^ Data; // Apply all 32-bits // Process 32-bits, 4 at a time, or 8 rounds Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; // Assumes 32-bit reg, masking index to 4-bits Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; // 0x04C11DB7 Polynomial used in STM32 Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; Crc = ( Crc << 4 ) ^ CrcTable[ Crc >> 28 ]; return ( Crc ); } //**************************************************************************** DWORD Crc32FastBlock( DWORD Crc, DWORD Size, DWORD *Buffer ) // 32-bit units { while ( Size-- ) Crc = Crc32Fast( Crc, *Buffer++ ); return ( Crc ); } //**************************************************************************** void test( void ) { BYTE vector[ 12 ] = { 0x02, 0x07, 0x02, 0x00, 0x18, 0x8A, 0xD0, 0x23, 0x25, 0x2B, 0x09, 0x00 }; // ACD7E298 DWORD Crc; int i; for ( i = 0; i < sizeof( vector ); i++ ) printf( "%02X ", vector[ i ] ); putchar( ‘\n‘ ); Crc = 0xFFFFFFFF; // Initial state for ( i = 0; i < sizeof( vector ); i += 4 ) { Crc = Crc32Fast( Crc, *( (DWORD *) &vector[ i ] ) ); // 4-bytes at a time } printf( "%08X %08X test\n", Crc, Crc32FastBlock( 0xFFFFFFFF, sizeof( vector ) / 4, (void *) vector ) ); } //**************************************************************************** void TestFile( char *Filename ) { FILE *f; DWORD Size; BYTE *Buffer; f = fopen( Filename, "rb" ); if ( f ) { fseek( f, 0, SEEK_END ); Size = ftell( f ); fseek( f, 0, SEEK_SET ); if ( Size & 3 ) printf( "WARNING: File must be multiple of 4 bytes (32-bit) for valid results\n" ); Buffer = malloc( Size ); fread( Buffer, Size, 1, f ); fclose( f ); printf( "crc=%08X Slow\n", Crc32Block( 0xFFFFFFFF, Size >> 2, (void *) Buffer ) ); printf( "crc=%08X Fast\n", Crc32FastBlock( 0xFFFFFFFF, Size >> 2, (void *) Buffer ) ); free( Buffer ); } else printf( "ERROR: Unable to open file ‘%s‘\n", Filename ); } //**************************************************************************** int main( int argc, char **argv ) { printf( "STM32CRC Test\n\nUsage: STM32CRC [<file>]\n\n" ); if ( ( Crc32( 0xFFFFFFFF, 0x12345678 ) != 0xDF8A8A2B ) || ( Crc32Fast( 0xFFFFFFFF, 0x12345678 ) != 0xDF8A8A2B ) ) { printf( "ERROR: Internal Sanity Check Failed\n" ); } if ( argc > 1 ) TestFile( argv[ 1 ] ); else test( ); return ( 1 ); }
Now I could probably reimplement with a table driven varient but this should prove the concept
u32 revbit( u32 data ) { asm("rbit r0,r0"); return data; } ; u32 CalcCRC32( u8 *buffer, u32 size ) { u32 i, j; u32 ui32; RCC_AHBPeriphClockCmd( RCC_AHBPeriph_CRC, ENABLE ); CRC->CR = 1; asm("NOP"); asm("NOP"); asm("NOP"); //delay for hardware ready i = size >> 2; while ( i-- ) { ui32 = *( (u32 *) buffer ); buffer += 4; ui32 = revbit( ui32 ); //reverse the bit order of input data CRC->DR = ui32; } ui32 = CRC->DR; ui32 = revbit( ui32 ); //reverse the bit order of output data i = size & 3; while ( i-- ) { ui32 ^= (u32) *buffer++; for ( j = 0; j < 8; j++ ) if ( ui32 & 1 ) ui32 = ( ui32 >> 1 ) ^ 0xEDB88320; else ui32 >>= 1; } ui32 ^= 0xffffffff; //xor with 0xffffffff return ui32; //now the output is compatible with windows/winzip/winrar }
Fully hardware method:
uint32_t reverse_32( uint32_t data ) { asm("rbit r0,r0"); return data; } ; uint32_t crc32_ether( char *buf, int len, int clear ) { uint32_t *p = (uint32_t*) buf; uint32_t crc, crc_reg; if ( clear ) CRC_ResetDR( ); while ( len >= 4 ) { crc_reg = CRC_CalcCRC( reverse_32( *p++ ) ); len -= 4; } crc = reverse_32( crc_reg ); if ( len ) { CRC_CalcCRC( crc_reg ); switch ( len ) { case 1: crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFF ) ^ crc ) >> 24 ); crc = ( crc >> 8 ) ^ reverse_32( crc_reg ); break; case 2: crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFF ) ^ crc ) >> 16 ); crc = ( crc >> 16 ) ^ reverse_32( crc_reg ); break; case 3: crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFFFF ) ^ crc ) >> 8 ); crc = ( crc >> 24 ) ^ reverse_32( crc_reg ); break; } } return ~crc; }
标签:
原文地址:http://www.cnblogs.com/shangdawei/p/4604853.html