CRC32 of Ether FCS with STM32
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:
- As hardvarnogo count on STM32 Byte CRC
- How to calculate the soft-CRC so that it coincided with hardovoy for STM32
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
unsigned long CrcSTM32( unsigned long Crc, unsigned long Data )
{
int i; Crc = Crc ^ Data; for ( i = ; i < ; i++ )
if ( Crc & 0x80000000 )
Crc = ( Crc << ) ^ 0x04C11DB7; // Polynomial used in STM32
else
Crc = ( Crc << ); return ( Crc );
}
To understand why so little illustration:
- Firstly, CRC - bitwise function. Parallel counting CRC - buns consequence of binary mathematics polynomials.
- boot order bit in LSFR should not be broken, depending on the bit depth and acuity of architecture
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[ ];
static uint32_t crc32r_table[ ]; #define CRC32_POLY 0x04C11DB7
#define CRC32_POLY_R 0xEDB88320 static void crc32_init( void )
{
int i, j;
uint32_t c, cr;
for ( i = ; i < ; ++i )
{
cr = i;
c = i << ;
for ( j = ; j > ; --j )
{
c = c & 0x80000000 ? ( c << ) ^ CRC32_POLY : ( c << );
cr = cr & 0x00000001 ? ( cr >> ) ^ CRC32_POLY_R : ( cr >> );
}
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[ ] =
{ 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[ ] =
{ 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 > )
{
v = *buf++;
crc = ( crc >> ) ^ 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 >= )
{
v = htonl( *buf++ );
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v ) ) ];
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v >> ) ) ];
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v >> ) ) ];
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v >> ) ) ];
len -= ;
}
if ( len )
{
switch ( len )
{
case :
v = 0xFF000000 & htonl( *buf++ );
break;
case :
v = 0xFFFF0000 & htonl( *buf++ );
break;
case :
v = 0xFFFFFF00 & htonl( *buf++ );
break;
}
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v ) ) ];
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v >> ) ) ];
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v >> ) ) ];
crc = ( crc << ) ^ crc32_table[ 0xFF & ( ( crc >> ) ^ ( v >> ) ) ];
}
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(, "", ), "", ));
printf("crc32_stm32 = %08X\n", crc32_stm32(crc32_stm32(, "", ), "", ));
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 / ;
p = (uint32_t*) bfr;
x = p[ l ];
if ( clear )
CRC_ResetDR( );
while ( l-- )
{
crc = CRC_CalcCRC( *p++ );
}
switch ( len & )
{
case :
crc = CRC_CalcCRC( x & 0x000000FF );
break;
case :
crc = CRC_CalcCRC( x & 0x0000FFFF );
break;
case :
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 >= )
{
crc_reg = CRC_CalcCRC( reverse_32( *p++ ) );
len -= ;
}
crc = reverse_32( crc_reg );
if ( len )
{
CRC_CalcCRC( crc_reg );
switch ( len )
{
case :
crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFF ) ^ crc ) >> );
crc = ( crc >> ) ^ reverse_32( crc_reg );
break;
case :
crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFF ) ^ crc ) >> );
crc = ( crc >> ) ^ reverse_32( crc_reg );
break;
case :
crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFFFF ) ^ crc ) >> );
crc = ( crc >> ) ^ 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 << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
DR = (DR << ) ^ Crc32Table[DR >> ];
}
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 = ; i < ; i++ )
{
if ( Crc & 0x80000000 )
Crc = ( Crc << ) ^ 0x04C11DB7; // Polynomial used in STM32
else
Crc = ( Crc << );
} return ( Crc );
} DWORD Crc32Fast( DWORD Crc, DWORD Data )
{
// Nibble lookup table for 0x04C11DB7 polynomial
static const DWORD CrcTable[ ] =
{ 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 << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ]; 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 = ; i < ; i++ )
if ( Crc & 0x80000000 )
Crc = ( Crc << ) ^ 0x04C11DB7; // Polynomial used in STM32
else
Crc = ( Crc << ); return ( Crc );
} DWORD Crc32Fast( DWORD Crc, DWORD Data )
{
static const DWORD CrcTable[ ] =
{ // 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 << ) ^ CrcTable[ Crc >> ]; // Assumes 32-bit reg, masking index to 4-bits
Crc = ( Crc << ) ^ CrcTable[ Crc >> ]; // 0x04C11DB7 Polynomial used in STM32
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ]; return ( Crc );
} void test( void )
{
BYTE vector[ ] =
{ 0x02, 0x07, 0x02, 0x00, 0x18, 0x8A, 0xD0, 0x23, 0x25, 0x2B, 0x09, 0x00 };
DWORD Crc;
int i; for ( i = ; i < ; i++ )
printf( "%02X ", vector[ i ] ); putchar( '\n' ); Crc = 0xFFFFFFFF; // Initial state
for ( i = ; i < ; i += )
{
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 ( );
}
// 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 = ; i < ; i++ )
if ( Crc & 0x80000000 )
Crc = ( Crc << ) ^ 0x04C11DB7; // Polynomial used in STM32
else
Crc = ( Crc << ); 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[ ] =
{ // 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 << ) ^ CrcTable[ Crc >> ]; // Assumes 32-bit reg, masking index to 4-bits
Crc = ( Crc << ) ^ CrcTable[ Crc >> ]; // 0x04C11DB7 Polynomial used in STM32
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ];
Crc = ( Crc << ) ^ CrcTable[ Crc >> ]; 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[ ] =
{ 0x02, 0x07, 0x02, 0x00, 0x18, 0x8A, 0xD0, 0x23, 0x25, 0x2B, 0x09, 0x00 }; // ACD7E298
DWORD Crc;
int i; for ( i = ; i < sizeof( vector ); i++ )
printf( "%02X ", vector[ i ] ); putchar( '\n' ); Crc = 0xFFFFFFFF; // Initial state for ( i = ; i < sizeof( vector ); i += )
{
Crc = Crc32Fast( Crc, *( (DWORD *) &vector[ i ] ) ); // 4-bytes at a time
} printf( "%08X %08X test\n", Crc,
Crc32FastBlock( 0xFFFFFFFF, sizeof( vector ) / , (void *) vector ) );
} //**************************************************************************** void TestFile( char *Filename )
{
FILE *f;
DWORD Size;
BYTE *Buffer; f = fopen( Filename, "rb" ); if ( f )
{
fseek( f, , SEEK_END ); Size = ftell( f ); fseek( f, , SEEK_SET ); if ( Size & )
printf(
"WARNING: File must be multiple of 4 bytes (32-bit) for valid results\n" ); Buffer = malloc( Size ); fread( Buffer, Size, , f ); fclose( f ); printf( "crc=%08X Slow\n",
Crc32Block( 0xFFFFFFFF, Size >> , (void *) Buffer ) ); printf( "crc=%08X Fast\n",
Crc32FastBlock( 0xFFFFFFFF, Size >> , (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 > )
TestFile( argv[ ] );
else
test( ); return ( );
}
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 = ; asm("NOP");
asm("NOP");
asm("NOP");
//delay for hardware ready i = size >> ; while ( i-- )
{
ui32 = *( (u32 *) buffer ); buffer += ; 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 & ; while ( i-- )
{
ui32 ^= (u32) *buffer++; for ( j = ; j < ; j++ )
if ( ui32 & )
ui32 = ( ui32 >> ) ^ 0xEDB88320;
else
ui32 >>= ;
} 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 >= )
{
crc_reg = CRC_CalcCRC( reverse_32( *p++ ) );
len -= ;
}
crc = reverse_32( crc_reg );
if ( len )
{
CRC_CalcCRC( crc_reg );
switch ( len )
{
case :
crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFF ) ^ crc ) >> );
crc = ( crc >> ) ^ reverse_32( crc_reg );
break;
case :
crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFF ) ^ crc ) >> );
crc = ( crc >> ) ^ reverse_32( crc_reg );
break;
case :
crc_reg = CRC_CalcCRC( reverse_32( ( *p & 0xFFFFFF ) ^ crc ) >> );
crc = ( crc >> ) ^ reverse_32( crc_reg );
break;
}
}
return ~crc;
}
CRC32 of Ether FCS with STM32的更多相关文章
- STM32的CRC32 实现代码 -- Ether
uint32_t reverse_32( uint32_t data ) { asm("rbit r0,r0"); return data; } ; uint32_t crc32_ ...
- STM32的CRC32 测试代码
// STM32 CRC32 Test App - sourcer32@gmail.com #include <windows.h> #include <stdio.h> DW ...
- Calculate CRC32 as in STM32 hardware (EWARM v.5.50 and later)
http://supp.iar.com/Support/?note=64424&from=note+11927 BackgroundThe STM32 devices from ST Micr ...
- STM32的CRC32 软件实现代码
对于STM32的32位CRC,如果假定它的一个主要目的是为了校验往内部FLASH存储数据的可靠性,那么(余数)初值是全1当然是比较合理的.由于STM32的32位CRC是纯32位,即每次必须输入32位的 ...
- STM32 CRC32与对应的软件CRC32(转)
源:STM32 CRC32与对应的软件CRC32 简单实现STM32 CRC32使用 使用前记得使能STM32 CRC时钟 //STM32硬件CRC32 byte数据计算,将数据移到最高位,低位补上F ...
- [技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码
1.CRC.FCS是什么 CRC,全称Cyclic Redundancy Check,中文名称为循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检 ...
- STM32 CRC-32 Calculator Unit
AN4187 - Using the CRC peripheral in the STM32 family At start up, the algorithm sets CRC to the Ini ...
- 数据帧CRC32校验算法实现
本文设计思想采用明德扬至简设计法.由于本人项目需要进行光纤数据传输,为了保证通信质量要对数据进行校验.在校验算法中,最简单最成熟的非CRC校验莫属了. 得出一个数的CRC校验码还是比较简单的: 选定一 ...
- CRC32是什么?
CRC32:CRC本身是“冗余校验码”的意思,CRC32则表示会产生一个32bit(8位十六进制数)的校验值.由于CRC32产生校验值时源数据块的每一个bit(位)都参与了计算,所以数据块中即使只有一 ...
随机推荐
- py-faster-rcnn代码阅读2-config.py
简介 该文件指定了用于fast rcnn训练的默认config选项,不能随意更改,如需更改,应当用yaml再写一个config_file,然后使用cfg_from_file(filename)导入以 ...
- py-faster-rcnn代码阅读3-roidb.py
roidb是比较复杂的数据结构,存放了数据集的roi信息.原始的roidb来自数据集,在trian.py的get_training_roidb(imdb)函数进行了水平翻转扩充数量,然后prepare ...
- 苹果ANCS协议学习【转】
苹果ANCS协议学习 转自:http://www.cnblogs.com/alexcai/p/4321514.html 综述 苹果通知中心(Apple Notification Center Serv ...
- springcloud中的API网关服务Zuul
到目前为止,我们Spring Cloud中的内容已经介绍了很多了,Ribbon.Hystrix.Feign这些知识点大家都耳熟能详了,我们在前文也提到过微服务就是把一个大的项目拆分成很多小的独立模块, ...
- shell脚本 ------ 输出带颜色的字体
shell脚本中echo显示内容带颜色显示,echo显示带颜色,需要使用参数-e 格式如下: echo -e “\033[字背景颜色:文字颜色m字符串\033[0m” 例如: echo -e “\03 ...
- 【前端vue开发】vue开发输入姓名,电话,公司表单提交组件
<template> <div id="parti-info"> <div> <span>您的姓名:</span> &l ...
- Android 常用动画之RotateAnimation
前两天接到任务做一个UI,有用到动画,于是抽空看了下Android动画相关知识. Android Animation共有四大类型,分别是 Alpha 透明度动画 Scale 大小伸 ...
- 虚拟机Failed to start LSB: Bring up/down networking
1.执行 service network restart 出现以下错误 Restarting network (via systemctl): Job for network.service f ...
- SOA 解惑
SOA 解惑 SOA 不是一种技术,它是一种设计方法.最近一段时间我碰到了很多关于 SOA 的具有误导性的文章.尤其是,有些人混淆了 SOA 和诸如 BPM.ESB 以及复合事件处理 (CEP) 之类 ...
- Android应用--QR的生成(二维码)
二维码的定义: 二维码(2-dimensional bar code),是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的. 在许多种类的二维条码中,常用的码制 ...