www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik NXP 2368 ARM CRC-Berechnung; C-Problem?


Autor: Roland K. (rolandk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

benötige mal die Hilfe eines ARM7 bzw. C-Experten:
Ich arbeite mit dem Keil Evakuation-Board mit dem 2368 von NXP
und der Keil MDK Versiuon 4.03.
In meiner Software habe ich die Wahl, aus Kompatibilitätsgründen Daten 
über den
I2C-Bus in ein externes RAM oder in den FLASH des Controllers zu 
schreiben. Das Schreiben
und Lesen ins RAM funktioniert einwandfrei, der CRC wird richtig 
berechnet.

Das Speichern und Auslesen ins und aus dem FLASH funktioniert ebenfalls
einwandfrei, nur bei der Berechnung des CRC nach dem Auslesen erhalte 
ich ein falsches Ergebnis und weiß nicht, weshalb. Die Daten werden 
richtig geschrieben und auch wieder ausgelesen (jedenfalls lt. 
Debugger).

Wenn ich den CRC 5 mal berechnen lasse, erhalte ich 3 unterschiedliche 
Ergebnisse.
Ich benutze haargenau die gleiche Routine und die gleichen Buffer.

Im Flash werden keine Daten versehentlich überschrieben oder gelöscht.
Auch stehen sie im Memory-Bereich an der richtigen Adresse.
(Sie werden ja richtig ausgelesen.)

Wo ist der sch... Fehler?

Hat jemand eine Idee? Bin für jeden Hinweis oder Tip dankbar!


Freundlicher Gruß


Roland


Hier mein Code (Auszüge):


#define START_ADRESS_DATA   0x00010000    // Startadresse Flashdaten

#define numFlash      512   // Blockgröße, Anzahl Bytes zum Schreiben

int i;

unsigned char rec_buf[numFlash];
unsigned char send_buf[numFlash];
long crc, crc_read;



for (i=0;i<236;i++)        // den Sendebuffer vorbesetzen
  {
  send_buf[i]=(unsigned char) i;
  }

  send_buf[236]=0x00;

  crc=crc32i(&send_buf[1],236);    // CRC bis Byte 235 berechnen, 
Routine ist i.O.
  send_buf[237]=(char)((crc >> 24)& 0xFF);  // CRC anhängen
  send_buf[238]=(char)((crc >> 16)& 0xFF); // statt char > unsigned char 
einstellen bringt nichts
  send_buf[239]=(char)((crc >> 8)& 0xFF);
  send_buf[240]=(char)(crc & 0xFF);


  // hier die Daten über den I2C-Bus ins RAM schreiben, funktioniert 
einwandfrei
  send_to_ram(send_buf);        // Daten ins RAM schreiben
  read_from_ram (rec_buf);        // Daten aus RAM in rec_buf schreiben

  crc=crc32i(&rec_buf[1],236);  // CRC vom 1. Wert (nicht vom 0ten!) 
über 235 Bytes
                         // berechnen
  crc_read=   rec_buf[237];
  crc_read=(crc_read<<8) | rec_buf[238];
  crc_read=(crc_read<<8) | rec_buf[239];
  crc_read=(crc_read<<8) | rec_buf[240];

// Beim Vergleich stimmen die CRCs überein, alles i.o.
  if(crc!=crc_read)    // CRCs stimmen nicht überein
    {
    // Fehlerroutine
    }



// Jetzt die Routine zum Schreiben ins Flash

void write_flash(unsigned long FLASH_adr,unsigned char *buf)
   {
  prepare_sector(GetSecNum (FLASH_adr),GetSecNum (FLASH_adr+numFlash));
    if(result[0]!=CMD_SUCCESS)
      while(1);
  command[0] = 51;
    command[1] = FLASH_adr;
    command[2] = (unsigned long)buf;
    command[3] = numFlash;
    command[4] = cclock;
    dis_interrupt();           // Interrupts disablen
    iap_entry(command,result);
    en_interrupt();
  }

void write_parm_to_flash()        //
  {
  erase_sector(GetSecNum (START_ADRESS_DATA),GetSecNum 
(START_ADRESS_DATA+numFlash));
  write_flash(START_ADRESS_DATA, send_buf);
  }


// und die Daten wieder einlesen
  for(i=0; i<241; i++)                     // aus Flash auslesen
    {
    rec_buf[i]=*((unsigned char*)START_ADRESS_DATA+i); // ab Adresse
    }

// Die eingelesenen Werte im rec_buf stimmen mit denen im Sendepuffer 
überein

// Und jetzt kommts!
  crc=crc32i(&rec[1],236);    // Hier wird der CRC falsch 
berechnet!!!!!!!!!!
// Wenn ich den CRC 5 mal berechnen lasse, erhalte ich 3 
unterschiedliche Werte

  crc_read=   rec_buf[237];    // Werte im Buffer sind in Ordnung!!!
  crc_read=(crc_read<<8) | rec_buf[238];
  crc_read=(crc_read<<8) | rec_buf[239];
  crc_read=(crc_read<<8) | rec_buf[240];


  if(crc!=crc_read)      // hier stimmen dire CRCs nicht überein
    {
    // Fehlerroutine
    }

// Die Werte in crc_read sind die gleichen, wie die ins Flash 
geschriebenen
// wurden. Die sind mit den Werten in der Routine zum Schreiben ins RAM
// absolut identisch. Der CRC wird am Anfang also richtig berechnet.



// Hier die Routine zum Brechnen des CRC; ich habe bereits eine andere
//Routine verwendet, das Ergebnis ist das gleiche.

unsigned long crc32i(unsigned char *txt,int l)      // Berechnung der 
Checksumme
{
  int i,j;
  int hbit,bit;
  unsigned long crc32=0xffffffff;

  for (i=0;i<l;i++)
    {
    for (j=0x01;j<=0x80;j=j<<1)
      {
      bit =(txt[i] & j) ? 1 :0;
      hbit=(crc32  & 0x01) ? 1 : 0;
      if (hbit != bit) crc32=(crc32>>1) ^ CRC32POLY;
      else crc32=crc32>>1;
      }
    }
  return (crc32^0xffffffff);
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, schwierig.

Ich würde mir zwei Kanarienvögelchen beschaffen, die den Bereich 
abgrenzen, über den die CRC berechnet wird.

Vielleicht liest du über den eigentlichen 236 Byte großen Bereich hinaus 
und der Unterschied ist dadurch zu erklären, dass in der verbotenen Zone 
einmal Nullen stehen (unsigned char rec_buf[numFlash]; unsigned char 
send_buf[numFlash]; sind initialisiert?) oder eine eingetragene CRC.

hbit, bit und j würde ich unsigned char definieren und nicht int.

Wie ist das technisch mit dem Lesen aus dem externen Flash? Die Daten 
sind zum Zeitpunkt der CRC Berechnung garantiert alle gelesen, da hängen 
nicht noch Daten in der Leitung, die beim schnellen Ablauf den Anschluss 
verpassen aber beim langsamen Debuggen Zeit hatten einzutrudeln?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan B. schrieb:

> hbit, bit und j würde ich unsigned char definieren und nicht int.

Du hast zu viel mit 8-Bittern programmiert. Bei grösseren Maschinchen 
ist das ineffizient.

Autor: Juergen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Effizient wird das erst wenn der CRC byteweise berechnet wird, mit einer 
Tabelle.

Autor: Juergen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du das über 235 Bytes berechnen willst, warum schreibst du dann 
236?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Juergen schrieb:

> Effizient wird das erst wenn der CRC byteweise berechnet wird, mit einer
> Tabelle.

Erst einmal wird es so schneller. Ob effizienter hängt davon ab, worauf 
es dem Programmierer dabei ankommt. Platz oder Zeit.

Ausserdem gibt es neben der algorithmischen Effizienz auch eine des 
Compilers. Registervariablen sind als Maschinenworte effizienter 
umgesetzt, kleinere Datentypen können zu zusätzlichem Code führen, ohne 
Nutzen.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hatte mich an unsigned char *txt orientiert und die Effizienz 
erstmal aussen vor gelassen.

Autor: rolandk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Stefan,

danke für Deine Antwort. Ein Lesen über die Buffergrenzen hinaus findet 
nicht statt. Habe ich kontrolliert. Der I2C-Buffer als auch der 
Flashbuffer sind beide gleich als 'unsigned char flash_buf[512] oder 
'unsigned char i2c_buf[256] definiert. Und bei I2C funktionierts ja. 
Aber Dein Tip mit dem Timing-Problem klingt interessant. Werde da mal 
ein Delay einbauen:

Gruß


Roland

Autor: rolandk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Juergen

weil die CRC-Routine <236 berechnet.


>>>>>>>>>>>>>>>>>>>>>
unsigned long crc32i(unsigned char *txt,int l)      // Berechnung der 
Checksumme
{
  for (i=0;i<l;i++)
    {

>>>>>>>>>>>>>>>>>>
hier steht '<l' also <236, sind in C 235.

Gruß

Roland

Autor: Hans (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> // Und jetzt kommts!
>>   crc=crc32i(&rec[1],236);    // Hier wird der CRC falsch

Hmmm, muesste da nicht rec_buf stehen?

VG,
Hans

Autor: Juergen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> for (i=0;i<l;i++)
> hier steht '<l' also <236, sind in C 235.

Da du bei 0 anfängst, sind es 236.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.