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: 

  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 = 0; i < 32; i++ )
    if ( Crc & 0x80000000 )
      Crc = ( Crc << 1 ) ^ 0x04C11DB7; // Polynomial used in STM32
    else
      Crc = ( Crc << 1 );
  
  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[ 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;
}
复制代码

 

posted @   IAmAProgrammer  阅读(2930)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
历史上的今天:
2013-06-27 磁盘相关概念以及知识
点击右上角即可分享
微信分享提示