4
\$\begingroup\$

I wanted to check redundancy in eeprom and crosscheck the data for any errors occurred or not and I ended up reading CRC code. I found it useful but have some doubts that need clarity.

My objective is to check the memory address locations 0-15k of eeprom and store the checksum in memory and do the same for next 15k-30k address locations. The Both address locations store the same data and it is done so that eeprom memory is utilized.

Well When I began reading the docs. I ended up with a useful code:

unsigned int crc32(unsigned char *message) {
  int i, j;
  unsigned int byte, crc;
  i = 0;
  crc = 0xFFFFFFFF;
  while (message[i] != 0) {
    byte = message[i]; // Get next byte.
    byte = reverse(byte); // 32-bit reversal.
    for (j = 0; j <= 7; j++) { // Do eight times.
      if ((int)(crc ^ byte) < 0)
        crc = (crc << 1) ^ 0x04C11DB7;
      else crc = crc << 1;
      byte = byte << 1; // Ready next msg bit.
    }
    i = i + 1;
  }
  return reverse(~crc);
}

Here as far as my understanding the 'message' awaits bytes and continues CRC calculation until the character is not received. If I wanted to check the two blocks of eeprom memory as said before. How can I append the eeprom memory to the message variable.

Well my another *doubt is whether eeprom read have any limit regarding reading reading address from 0-15k at a stretch rather like eeprom write * I need your inputs to make this attempt useful and rewarding Regards

\$\endgroup\$
  • 1
    \$\begingroup\$ The code you have pasted above assumes that you want the CRC of a zero-terminated string of data in the variable message. But you want the CRC of (almost) your entire EEPROM, so just replace the while clause with a loop over (most of) your EEPROM address space, and message[i] with a read of the i-th 32-bit word of your EEPROM. Unlike writing, reading it will not degrade it. Remember to exclude the part of the EEPROM where you store the CRC checksum for comparison. \$\endgroup\$ – pyramids Nov 20 '13 at 6:28
5
\$\begingroup\$

While the suggested approach from PeterJ is fine, its cleaner to decouple the "data layer" logic (EEPROM access) from the CRC routine.

This CRC-32 can be universally used, its not bound to program specific behavior:

// CCITT CRC-32 (Autodin II) polynomial
uint32_t CalcCRC32(uint32_t crc, uint8_t *buffer, uint16_t length) {
    while(length--) {
        crc = crc ^ *buffer++; 

        for (uint8_t j=0; j < 8; j++) { 
           if (crc & 1) 
              crc = (crc >> 1) ^ 0xEDB88320; 
           else 
              crc = crc >> 1; 
        } 
    } 

   return crc; 
}

Then you just feed blocks of data to the CRC function like you see fit and as required by your application.

This usage example is just written down. It uses the fictional function eeprom_read() which reads a block of data from EEPROM. We start at EEPROM address 0.

const uint8_t BLOCKLENGTH = 128;
uint32_t crc32;
uint8_t buffer[BLOCKLENGTH];    // temporary data buffer

crc32 = 0xFFFFFFFF;  // initial CRC value 

for (uint16_t i=0; i < NUMBEROFBLOCKS; i++) {
    eeprom_read(BLOCKLENGTH * i, buffer, BLOCKLENGTH);    // read block number i from EEPROM into buffer
    crc32 = CalcCRC32(crc32, buffer, BLOCKLENGTH);        // update CRC
}

// crc32 is your final CRC here

Note that NUMBEROFBLOCKS is just a placeholder. I hope you get the idea.

\$\endgroup\$
  • 1
    \$\begingroup\$ As your code doesn't use the i variable, why not just while(length--) instead of the first for loop? \$\endgroup\$ – David Nov 20 '13 at 8:44
  • \$\begingroup\$ @David: You are indeed right, feel free to edit the CalcCRC32() function. I pasted the code from an old project, where I obviously missed that. \$\endgroup\$ – Rev1.0 Nov 20 '13 at 9:20
  • \$\begingroup\$ @Rev1-0 I decided to test to see if this would make a practical difference. Results are in this question. \$\endgroup\$ – David Nov 22 '13 at 21:40
  • \$\begingroup\$ @David: This function indeed served as a good example that there often is room for optimization. \$\endgroup\$ – Rev1.0 Nov 22 '13 at 22:06
  • \$\begingroup\$ Well in which compiler was this code compiled.Well i tried in C18 for the same and ended up with an error pointing to the for loop The error being:"8:Error: syntax error".The same code with uint16 and others replaced with long. \$\endgroup\$ – Rookie91 Nov 27 '13 at 6:55
2
\$\begingroup\$

If you're using a microcontroller with limited RAM you probably won't want to try loading a 16k chunk of data into memory. Re-arranging the code above you could try the below (untested) function that reads the EEPROM byte by byte within the loop. The function read_eeprom is something I've made up so you'll need to find the appropriate function for your compiler.

#include <stdint.h>

uint32_t crc32(uint16_t start_address, uint16_t number_of_bytes) {
  uint8_t j;
  uint32_t crc, byte;
  crc = 0xFFFFFFFF;
  while (number_of_bytes--) {
    byte = read_eeprom(start_address++);
    byte = reverse(byte); // 32-bit reversal.
    for (j = 0; j <= 7; j++) { // Do eight times.
      if ((int32_t)(crc ^ byte) < 0)
        crc = (crc << 1) ^ 0x04C11DB7;
      else 
        crc = crc << 1;
      byte = byte << 1; // Ready next msg bit.
    }
  }
  return reverse(~crc);
}

I've also replaced your variable declarations to use stdint.h - it's probably good to read about that and use it. On some embedded compilers an unsigned int won't be 32 bits for example so this makes the code more portable.

\$\endgroup\$
  • \$\begingroup\$ I trust the reverse is just a Not(~)operation \$\endgroup\$ – Rookie91 Nov 27 '13 at 5:36
  • \$\begingroup\$ @Rookie91, yes that's right. I didn't check much into the original code that you'd found but couldn't see any obvious problems with it. \$\endgroup\$ – PeterJ Nov 27 '13 at 5:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.