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


von Roland K. (rolandk)


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

von Stefan B. (stefan) Benutzerseite


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?

von (prx) A. K. (prx)


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.

von Juergen (Gast)


Lesenswert?

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

von Juergen (Gast)


Lesenswert?

Wenn du das über 235 Bytes berechnen willst, warum schreibst du dann 
236?

von (prx) A. K. (prx)


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.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

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

von rolandk (Gast)


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

von rolandk (Gast)


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

von Hans (Gast)


Lesenswert?

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

Hmmm, muesste da nicht rec_buf stehen?

VG,
Hans

von Juergen (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.