CRC für Eeprom-Datenprüfung

Ich wollte die Redundanz im Eeprom überprüfen und die Daten auf aufgetretene oder nicht aufgetretene Fehler überprüfen, und am Ende las ich den CRC-Code. Ich fand es nützlich, habe aber einige Zweifel, die geklärt werden müssen.

Mein Ziel ist es, die Speicheradressen 0-15k des EEPROM zu überprüfen und die Prüfsumme im Speicher zu speichern und dasselbe für die nächsten 15k-30k Adresspositionen zu tun. Die beiden Adressorte speichern die gleichen Daten und es wird so gemacht, dass der EEPROM-Speicher verwendet wird.

Nun, als ich anfing, die Dokumente zu lesen. Am Ende habe ich einen nützlichen 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);
}

Hier wartet die ' Nachricht ' nach meinem Verständnis auf Bytes und setzt die CRC-Berechnung fort, bis das Zeichen nicht empfangen wird. Wenn ich die beiden Blöcke des EEPROM-Speichers wie gesagt überprüfen wollte. Wie kann ich den Eeprom-Speicher an die Nachrichtenvariable anhängen?

Nun, mein weiterer * Zweifel ist, ob Eeprom-Lesen eine Grenze beim Lesen von Leseadressen von 0-15k am Stück hat, eher wie Eeprom-Schreiben * Ich brauche Ihre Eingaben, um diesen Versuch nützlich und lohnend zu machen. Grüße

Der Code, den Sie oben eingefügt haben, geht davon aus, dass Sie den CRC einer nullterminierten Datenzeichenfolge in der Variablen haben möchten message. Aber Sie möchten den CRC von (fast) Ihrem gesamten EEPROM, also ersetzen Sie einfach die whileKlausel durch eine Schleife über (den größten Teil) Ihres EEPROM-Adressraums und message[i]durch ein Lesen des i-ten 32-Bit-Wortes Ihres EEPROM. Im Gegensatz zum Schreiben wird es beim Lesen nicht beeinträchtigt. Denken Sie daran, den Teil des EEPROM auszuschließen, in dem Sie die CRC-Prüfsumme zum Vergleich speichern.

Antworten (2)

Während der von PeterJ vorgeschlagene Ansatz in Ordnung ist, ist es sauberer, die "Datenschicht" -Logik (EEPROM-Zugriff) von der CRC-Routine zu entkoppeln.

Dieser CRC-32 ist universell einsetzbar, er ist nicht an programmspezifisches Verhalten gebunden:

// 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; 
}

Dann füttern Sie einfach Datenblöcke in die CRC-Funktion, wie Sie es für richtig halten und wie es Ihre Anwendung erfordert.

Dieses Anwendungsbeispiel ist nur niedergeschrieben. Es verwendet die fiktive Funktion eeprom_read(), die einen Datenblock aus dem EEPROM liest. Wir beginnen bei der EEPROM-Adresse 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

Beachten Sie, dass NUMBEROFBLOCKS nur ein Platzhalter ist. Ich hoffe, du verstehst die Idee.

Da Ihr Code die Variable nicht verwendet i, warum nicht einfach while(length--)anstelle der ersten for-Schleife?
@David: Sie haben in der Tat Recht, Sie können die Funktion CalcCRC32() bearbeiten. Ich habe den Code aus einem alten Projekt eingefügt, wo ich das offensichtlich übersehen habe.
@Rev1-0 Ich beschloss zu testen, ob dies einen praktischen Unterschied machen würde. Ergebnisse sind in dieser Frage .
@David: Diese Funktion war in der Tat ein gutes Beispiel dafür, dass es oft Raum für Optimierungen gibt.
Nun, in welchem ​​​​Compiler wurde dieser Code kompiliert. Nun, ich versuchte es in C18 für dasselbe und endete mit einem Fehler, der auf die for-Schleife hinwies. Der Fehler lautete: "8: Fehler: Syntaxfehler". Derselbe Code mit uint16 und anderen ersetzt durch lang.
@Rookie91: Dir ist klar, dass nur der erste Codeblock kompiliert werden soll (getestet mit GCC 4.3.3)? Der zweite Block war nur ein Anwendungsbeispiel, wie in der Antwort angegeben.
Wenn also die Länge größer ist, wird der Speicher voll geladen, richtig?
@Rookie91: Nein. Darum geht es in meinem Beispiel. CRC wird blockweise berechnet. Der Speicherbedarf hängt von der Blockgröße (Ihrer Wahl) ab. Sie könnten 20k in 200-Byte-Blöcken berechnen und 100 Mal wiederholen. Dies würde nur (vorübergehend) die zusätzlichen 200 Byte Speicher erfordern.

Wenn Sie einen Mikrocontroller mit begrenztem RAM verwenden, möchten Sie wahrscheinlich nicht versuchen, einen 16k-Datenblock in den Speicher zu laden. Wenn Sie den obigen Code neu anordnen, können Sie die folgende (ungetestete) Funktion ausprobieren, die das EEPROM Byte für Byte innerhalb der Schleife liest. Die Funktion read_eepromhabe ich mir ausgedacht, also müssen Sie die passende Funktion für Ihren Compiler finden.

#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);
}

Ich habe auch Ihre Variablendeklarationen ersetzt, um stdint.h zu verwenden - es ist wahrscheinlich gut, darüber zu lesen und es zu verwenden. Bei einigen eingebetteten Compilern ist ein unsigned intbeispielsweise nicht 32 Bit, sodass der Code dadurch portabler wird.

Ich vertraue darauf, dass die Umkehrung nur eine Nicht(~)-Operation ist
@Rookie91, ja das stimmt. Ich habe den ursprünglichen Code, den Sie gefunden haben, nicht sehr genau untersucht, konnte aber keine offensichtlichen Probleme damit erkennen.