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 @ 2015-06-27 23:07  IAmAProgrammer  阅读(2862)  评论(0编辑  收藏  举报