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:

  1. As hardvarnogo count on STM32 Byte CRC
  2. 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的更多相关文章

  1. STM32的CRC32 实现代码 -- Ether

    uint32_t reverse_32( uint32_t data ) { asm("rbit r0,r0"); return data; } ; uint32_t crc32_ ...

  2. STM32的CRC32 测试代码

    // STM32 CRC32 Test App - sourcer32@gmail.com #include <windows.h> #include <stdio.h> DW ...

  3. 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 ...

  4. STM32的CRC32 软件实现代码

    对于STM32的32位CRC,如果假定它的一个主要目的是为了校验往内部FLASH存储数据的可靠性,那么(余数)初值是全1当然是比较合理的.由于STM32的32位CRC是纯32位,即每次必须输入32位的 ...

  5. STM32 CRC32与对应的软件CRC32(转)

    源:STM32 CRC32与对应的软件CRC32 简单实现STM32 CRC32使用 使用前记得使能STM32 CRC时钟 //STM32硬件CRC32 byte数据计算,将数据移到最高位,低位补上F ...

  6. [技术栈]CRC校验原理及C#代码实现CRC16、CRC32计算FCS校验码

    1.CRC.FCS是什么 CRC,全称Cyclic Redundancy Check,中文名称为循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检 ...

  7. STM32 CRC-32 Calculator Unit

    AN4187 - Using the CRC peripheral in the STM32 family At start up, the algorithm sets CRC to the Ini ...

  8. 数据帧CRC32校验算法实现

    本文设计思想采用明德扬至简设计法.由于本人项目需要进行光纤数据传输,为了保证通信质量要对数据进行校验.在校验算法中,最简单最成熟的非CRC校验莫属了. 得出一个数的CRC校验码还是比较简单的: 选定一 ...

  9. CRC32是什么?

    CRC32:CRC本身是“冗余校验码”的意思,CRC32则表示会产生一个32bit(8位十六进制数)的校验值.由于CRC32产生校验值时源数据块的每一个bit(位)都参与了计算,所以数据块中即使只有一 ...

随机推荐

  1. TC-572-D1L2 (双向搜索+记忆化)

    solution: 这一题是比较难实现的双向搜索题:(字符串+双向搜索+hash记忆化) 我们可以先把K的前半部分枚举出来,并将得出的所有结果和题目给的n个数的每一个数的前半部分都比对一遍,得到它和每 ...

  2. 苹果ANCS协议学习【转】

    苹果ANCS协议学习 转自:http://www.cnblogs.com/alexcai/p/4321514.html 综述 苹果通知中心(Apple Notification Center Serv ...

  3. python中open函数的用法

    用法如下: name = open('errname.txt','w')name.readline()name.close() 1.看下第一行的代码 用来访问磁盘中存放的文件,可以进行读写等操作,例如 ...

  4. Shiro:授权控制

    对容易忽略的地方记录如下: 1.需要引入下面2个依赖,具体版本根据自身环境修改: <dependency> <groupId>org.apache.geronimo.bundl ...

  5. 用Java检测远程主机是否能被连接

    有人推荐使用java的Runtime.exec()方法来直接调用系统的Ping命令.也有人完成了纯Java实现Ping的程序,使用的是Java的NIO包(native io, 高效IO包).我个人认为 ...

  6. Go语言规格说明书 之 词汇元素(Lexical elements)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,完整的介绍Go语 ...

  7. Android SO文件的兼容和适配

    开发Android应用时,有时候Java层的编码不能满足实现需求,就需要到C/C++实现后生成SO文件,再用System.loadLibrary()加载进行调用,这里成为JNI层的实现.常见的场景如: ...

  8. input onchange事件

    //输入帐号,默认赋值给员工电话和后台登录帐号$('#mobile_phone_').bind('input propertychange', function() { var phone = $(' ...

  9. EFCore CodeFirst 适配数据库

    EF6中可以直接根据代码模型生成数据库Database.SetInitializer即可 在EFCore中如何实现呢? 这项功能放在了DatabaseFacade对象中,传入数据库上下文对象实例化到一 ...

  10. Angular快速学习笔记(3) -- 组件与模板

    1. 显示数据 在 Angular 中最典型的数据显示方式,就是把 HTML 模板中的控件绑定到 Angular 组件的属性. 使用插值表达式显示组件属性 要显示组件的属性,最简单的方式就是通过插值表 ...