www.mikrocontroller.net

Forum: Compiler & IDEs Problem beim SRAM testen


Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche gerade einen kleinen Test zu schreiben, der alle 
Speicherzellen im Ram durchnudelt und schaut ob die auch noch 
funktionieren.
Soll ein einfacher Test ohne Kurzschlusserkennung sein. Außerdem soll er 
in C formuliert werden!

Habe das ganze so aufgezogen:
// Routine für den einfacheren RAM-Test
void RamTest(){
  if((iTempRamAdress + iRamCheckAnzahl) > RamE){  // Prüfen ob Prüfrahmen über Ramende hinaus
    iRamCheckAnzahl = (iTempRamAdress + iRamCheckAnzahl) - RamE;
    RamCheck(iTempRamAdress, RamE);        // Wenn ja, bis zum Ende prüfen und 
    iTempRamAdress = RamA;            // Pointer auf Anfang setzten
  }
  
  // Ramtest durchführen.
  RamCheck(iTempRamAdress, (iTempRamAdress + iRamCheckAnzahl));
    
  // Ramzelle auf nächste Zelle setzen (falls Ramende, dann auf Ramanfang)
  iTempRamAdress = iTempRamAdress + 1;
  if(iTempRamAdress > RamE)
    iTempRamAdress = RamA;
  
}

// eigentlicher Ramtest
void RamCheck(int iAadress, int iEadress){
  char iAdress = iAadress;            // Adresse übernehmen
  int iTemp;                     // Variable für Speicherzelleninhalt
  
  // solange nicht alle Zellen getestet wurden
  while(iAdress < iEadress){
    iTemp = *iAdress;              // Inhalt speichern
    *iAdress = 0x55;              // Testwerte schreiben und vergleichen
    if(!*iAdress == 0x55)
      testError();
    *iAdress = 0xAA;
    if(!*iAdress == 0xAA)
      testError();
    *iAdress = iTemp;              // Inhalt zurück schreiben
    iAdress++;                  // Nächste Zelle
  }
}

alle nicht deklarierten Variablen SIND im QC deklariert, darum bitte 
keine Sorgen machen.

Wenn ich jetzt den wunderschönen Programmcode kompilieren möchte, 
bekomme ich folgende Fehlermeldungen:
avr-gcc -c -mmcu=atmega169 -I. -g -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=TestLib.lst  -std=gnu99 -Wp,-M,-MP,-MT,TestLib.o,-MF,.dep/TestLib.o.d TestLib.c -o TestLib.o 
TestLib.c: In function 'RamCheck':
TestLib.c:282: error: invalid type argument of 'unary *' (have 'int')
TestLib.c:283: error: invalid type argument of 'unary *' (have 'int')
TestLib.c:284: error: invalid type argument of 'unary *' (have 'int')
TestLib.c:286: error: invalid type argument of 'unary *' (have 'int')
TestLib.c:287: error: invalid type argument of 'unary *' (have 'int')
TestLib.c:289: error: invalid type argument of 'unary *' (have 'int')

die Zeilen sind die unter der while-Schleife im RamCheck-Block.

Warum bekomme ich diese Fehlermeldung und wie bekomme ich sie weg. Ich 
möchte auf die einzelnen Ramzellen (bei meinem ATMega169P von 0x0100 bis 
0x04FF) zugreifen, sie auslesen, 2x schreiben und vergleichen, zurück 
schreiben und dann die nächste zelle in angriff nehmen.

Leider habe ich im Tutorial keine Codebeispiele gefunden und auch im 
Datasheet wird kein Beispiel genannt. Bin mir also leider nicht sicher 
wie ich das in C realisieren kann (in ASM wäre es kein Problem, doch 
bitte auf C-Ebene bleiben!)

Wer kann mir helfen?

Vielen Dank!
Max

Autor: Mr.X (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du übergibst eine Variable und sprichst sie dann als Pointer an? Das 
geht doch gar nicht.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich ruf über die Ram-Test(void) quasi den Test-Vorlauf auf. Dort 
bastel ich mir die Adresse zusammen. Meine Idee ist, dass diese dann als 
0xirgendwas vorliegen, so dass ich nachher mit *0xirgendwas auf den 
Speicher komme. Liege ich da Falsch? Wie könnte man es anders machen?

Im Prinzip will ich jede Speicherzelle zwischen 0x0100 und 0x4FF einmal 
ansprechen.

Ich steh wahrscheinlich auf dem Schlauch und seh vor lauter Bäumen den 
Wald nicht, vielleicht kann mir jemand einen Stubs in die richtige 
Richtung geben!

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Meine Idee ist, dass diese dann als
>0xirgendwas vorliegen, so dass ich nachher mit *0xirgendwas auf den
>Speicher komme.

Das mag ja sein, der Compiler sieht aber nichts von deiner Idee. Was der 
sieht, ist ein "int iAadress", auf das du dann den Operator "*" 
anwendest, und das geht nicht.

Was du vermutlich möchtest, ist ein Pointer auf eine Speicherstelle, 
also einen pointer auf einen unsigned char, "unsigned char *iAadress". 
Dem Pointer kannst du deine zusammengebastelte Adresse zuweisen, und 
dann damit per *-Operator im Speicher rumfuhrwerken.

Oliver

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, das werde ich morgen einmal ausprobieren und dann Feedback geben!

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, ich stehe grad vor den nächsten Problem.
Habe das ganze nun umgesetzt:
// Routine für den einfacheren RAM-Test
void Ram_Test(){
  if((iTempRamAdress + iRam_CheckAnzahl) > RamE){  // Prüfen ob Prüfrahmen über Ramende hinaus
    iRam_CheckAnzahl = (iTempRamAdress + iRam_CheckAnzahl) - RamE;
    Ram_Check(iTempRamAdress, RamE);        // Wenn ja, bis zum Ende prüfen und 
    iTempRamAdress = RamA;              // Pointer auf Anfang setzten
  }
  
  // Ram_Test durchführen.
  Ram_Check(iTempRamAdress, (iTempRamAdress + iRam_CheckAnzahl));
    
  // Ramzelle auf nächste Zelle setzen (falls Ramende, dann auf Ramanfang)
  iTempRamAdress = iTempRamAdress + 1;
  if(iTempRamAdress > RamE)
    iTempRamAdress = RamA;
  
}

// eigentlicher Ram_Test
void Ram_Check(int iAadress, int iEadress){
  unsigned char *iAdress;
  iAdress = (unsigned char*)iAadress;      // Adresse übernehmen
  int iTemp;                     // Variable für Speicherzelleninhalt
  
  // solange nicht alle Zellen getestet wurden
  while(iAdress < iEadress){
    iTemp = *iAdress;              // Inhalt speichern
    *iAdress = 0x55;              // Testwerte schreiben und vergleichen
    if(!*iAdress == 0x55)
      testError();
    *iAdress = 0xAA;
    if(!*iAdress == 0xAA)
      testError();
    *iAdress = iTemp;              // Inhalt zurück schreiben
    iAdress++;                  // Nächste Zelle
  }
}

Mein Compiler macht daraus das:
@0000048C: Ram_Test
189:          wdt_reset();              // Watchdog zurück setzen
+0000048C:   91200116    LDS       R18,0x0116     Load direct from data space
+0000048E:   91300117    LDS       R19,0x0117     Load direct from data space
+00000490:   91800118    LDS       R24,0x0118     Load direct from data space
+00000492:   91900119    LDS       R25,0x0119     Load direct from data space
+00000494:   0F82        ADD       R24,R18        Add without carry
+00000495:   1F93        ADC       R25,R19        Add with carry
+00000496:   E045        LDI       R20,0x05       Load immediate
+00000497:   3080        CPI       R24,0x00       Compare with immediate
+00000498:   0794        CPC       R25,R20        Compare with carry
+00000499:   F09C        BRLT      PC+0x14        Branch if less than, signed
---- TestLib.c ------------------------------------------------------------------------------------
265:          iRam_CheckAnzahl = (iTempRamAdress + iRam_CheckAnzahl) - RamE;
+0000049A:   5F8F        SUBI      R24,0xFF       Subtract immediate
+0000049B:   4094        SBCI      R25,0x04       Subtract immediate with carry
+0000049C:   93900119    STS       0x0119,R25     Store direct to data space
+0000049E:   93800118    STS       0x0118,R24     Store direct to data space
283:        iAdress = (unsigned char*)iAadress;      // Adresse übernehmen
+000004A0:   01C9        MOVW      R24,R18        Copy register pair
+000004A1:   C001        RJMP      PC+0x0002      Relative jump
296:          iAdress++;                  // Nächste Zelle
+000004A2:   9601        ADIW      R24,0x01       Add immediate to word
287:        while(iAdress < iEadress){
+000004A3:   E024        LDI       R18,0x04       Load immediate
+000004A4:   3F8F        CPI       R24,0xFF       Compare with immediate
+000004A5:   0792        CPC       R25,R18        Compare with carry
+000004A6:   F3D8        BRCS      PC-0x04        Branch if carry set
267:          iTempRamAdress = RamA;              // Pointer auf Anfang setzten
+000004A7:   E080        LDI       R24,0x00       Load immediate
+000004A8:   E091        LDI       R25,0x01       Load immediate
+000004A9:   93900117    STS       0x0117,R25     Store direct to data space
+000004AB:   93800116    STS       0x0116,R24     Store direct to data space
271:        Ram_Check(iTempRamAdress, (iTempRamAdress + iRam_CheckAnzahl));
+000004AD:   91800116    LDS       R24,0x0116     Load direct from data space
+000004AF:   91900117    LDS       R25,0x0117     Load direct from data space
+000004B1:   91200118    LDS       R18,0x0118     Load direct from data space
+000004B3:   91300119    LDS       R19,0x0119     Load direct from data space
+000004B5:   0F28        ADD       R18,R24        Add without carry
+000004B6:   1F39        ADC       R19,R25        Add with carry
+000004B7:   C001        RJMP      PC+0x0002      Relative jump
296:          iAdress++;                  // Nächste Zelle
+000004B8:   9601        ADIW      R24,0x01       Add immediate to word
287:        while(iAdress < iEadress){
+000004B9:   1782        CP        R24,R18        Compare
+000004BA:   0793        CPC       R25,R19        Compare with carry
+000004BB:   F3E0        BRCS      PC-0x03        Branch if carry set
274:        iTempRamAdress = iTempRamAdress + 1;
+000004BC:   91800116    LDS       R24,0x0116     Load direct from data space
+000004BE:   91900117    LDS       R25,0x0117     Load direct from data space
+000004C0:   9601        ADIW      R24,0x01       Add immediate to word
+000004C1:   93900117    STS       0x0117,R25     Store direct to data space
+000004C3:   93800116    STS       0x0116,R24     Store direct to data space
275:        if(iTempRamAdress > RamE)
+000004C5:   5080        SUBI      R24,0x00       Subtract immediate
+000004C6:   4095        SBCI      R25,0x05       Subtract immediate with carry
+000004C7:   F034        BRLT      PC+0x07        Branch if less than, signed
276:          iTempRamAdress = RamA;
+000004C8:   E080        LDI       R24,0x00       Load immediate
+000004C9:   E091        LDI       R25,0x01       Load immediate
+000004CA:   93900000    STS       0x0000,R25     Store direct to data space
+000004CC:   93800116    STS       0x0116,R24     Store direct to data space
+000004CE:   9508        RET                      Subroutine return
281:      void Ram_Check(int iAadress, int iEadress){
+000004CF:   01FC        MOVW      R30,R24        Copy register pair
+000004D0:   C002        RJMP      PC+0x0003      Relative jump
288:          iTemp = *iAdress;              // Inhalt speichern
+000004D1:   8180        LDD       R24,Z+0        Load indirect with displacement
295:          *iAdress = iTemp;              // Inhalt zurück schreiben
+000004D2:   9381        ST        Z+,R24         Store indirect and postincrement
287:        while(iAdress < iEadress){
+000004D3:   17E6        CP        R30,R22        Compare
+000004D4:   07F7        CPC       R31,R23        Compare with carry
+000004D5:   F3D8        BRCS      PC-0x04        Branch if carry set
298:      }
+000004D6:   9508        RET                      Subroutine return

Warum ist das so extrem seltsam umgsetzt? Es sieht für mich so aus, 
alsob die Befehle in zum Teil falscher Reihenfolge auftreten oder gleich 
ganz geschluckt werden.

Kann sich das jemand erklären?

btw. wo kommt das wdt_reset her? Das habe ich, wie man oben im Quellcode 
sieht, garnicht verwendet.. Sondern an ganz anderen Stellen in meinem 
Programm

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max wrote:

> Warum ist das so extrem seltsam umgsetzt?

[x] Send compilable code, please.

> Es sieht für mich so aus,
> alsob die Befehle in zum Teil falscher Reihenfolge auftreten oder gleich
> ganz geschluckt werden.

Das wird nicht der Fall sein.  Reich mal übersetzbaren Code
rüber, dann kann man sich den generierten Assemblercode mal
angucken.

> btw. wo kommt das wdt_reset her?

Ist keins drin.  Oder wo würdest du den entsprechenden Code dafür
sehen?

Ich finde nach wie vor diese Disassembler-Listings absolut scheußlich
und verwirrend.  Ich schau mir lieber direkt den Assemblercode an,
den der Compiler ausspuckt, ganz und gar ohne irgendwelchen C-Code
dazwischen.  Den halte ich mir dann daneben (heutige Bildschirme sind
zum Glück ja breit genug) und versuche nachzuvollziehen, was der
Compiler da warum wohl gemacht hat.

Autor: Max (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ok, habe mal angehängt, was ich so zusammen geschrieben habe!

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hm seltsam. habe in der oben angehängten make mal die optimierung 
ausgeschaltet (vorher s), nun geht der Timer-Test nichtmehr, dafür sieht 
aber der Ram_Test in ASM ziemlich identisch mit dem in C aus.. Also, 
wenn ihr sehen wollt wo das Problem ist, dann bitte mal die optimierung 
auf s schalten (langsam krieg ich graue haare mit c!)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Code ist furchtbar.
Du mischt da Datentypen wie du gerade lustig bist (Aber Hauptsache du 
benutzt ungarische Notation. Genau deshalb find ich die unsinnig: Sie 
bringt in der Praxis überhaupt nichts. Dein Code ist das beste Beispiel 
dafür. Mit ordentlichen Variablennamen, jedes zweite Wort in deinem Code 
ist entweder Tmp, Temp oder Adress wäre das Chaos schon um einiges 
kleiner)
void Ram_Check( unsigned char* StartAddr, unsigned char* EndAddr )
{
  unsigned char  OriginalByte;
  volatile unsigned char* TestAddr;

  for( TestAddr = StartAddr; TestAddr < EndAddr; ++TestAddr ) {
    OriginalByte = *TestAddr;

    *TestAddr = 0x55;
    if( *TestAddr != 0x55 ) {
      *TestAddr = OriginalByte;
      testError();
    }

    *TestAddr = 0xAA;
    if( *TestAddr != 0xAA ) {
      *TestAddr = OriginalByte;
      testError();
    }

    *TestAddr = OriginalByte;
  }
}

Ich denke mal, das fehlende volatile war dein Problem. Ohne dieses 
volatile findet der Compiler raus, dass die Funktion im Grunde nichts 
macht und optimiert sie komplett weg.

(Und lass die Datentypen in dieser Funktion so wie sie jetzt sind! Dein 
Komplettpaket wird jetzt einige Fehler aufweisen. Arbeite dich von 
dieser Funktion zurück und korrigiere deine Probleme beim Aufrufer.)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max wrote:
> langsam krieg ich graue haare mit c!

Dann solltest du die Sprache mal lernen. Solche Low-Level Dinge sind 
aber nicht wirklich gut geeignet das zu tun.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, ich bin eigentlich sehr vertraut mit C aber das hier ging grad 
irgendwie garnicht. ;/ Werd mich da aber noch reinfuchsen!

Also meine Lösung sieht bis jetzt so aus (Dank sei Karl Heinz ;)):
// Routine für den einfacheren RAM-Test
void Ram_Test(){
  if((cErsteRamZelle + cTestLaenge) > RamE){    // Prüfen ob Prüfrahmen über Ramende hinaus
    unsigned char cTestLaengeTemp = (cErsteRamZelle + cTestLaenge) - RamE;
    Ram_Check(cErsteRamZelle, RamE);      // Wenn ja, bis zum Ende prüfen und 
    cErsteRamZelle = RamA;            // Pointer auf Anfang setzten
    Ram_Check(cErsteRamZelle, (cErsteRamZelle + cTestLaengeTemp));
  }
  else
    // Ram_Test durchführen.
    Ram_Check(cErsteRamZelle, (cErsteRamZelle + cTestLaenge));
    
  // Ramzelle auf nächste Zelle setzen (falls Ramende, dann auf Ramanfang)
  cErsteRamZelle = cErsteRamZelle + 1;
  if(cErsteRamZelle > RamE)
    cErsteRamZelle = RamA;
  
}

// eigentlicher Ram_Test
void Ram_Check( unsigned char* cStartAddr, unsigned char* cEndAddr )
{
  unsigned char cOriginalByte;
  volatile unsigned char* cTestAddr;

  for(cTestAddr = cStartAddr; cTestAddr < cEndAddr; ++cTestAddr ) {
    cOriginalByte = *cTestAddr;

    *cTestAddr = 0x55;
    if( *cTestAddr != 0x55 )
      testError();

    *cTestAddr = 0xAA;
    if( *cTestAddr != 0xAA )
      testError();

    *cTestAddr = cOriginalByte;
  }
}

mit
// Variable beinhaltet die erste zu testende Ramzelle
unsigned char *cErsteRamZelle = (unsigned char*)0x0100;    

// Anzahl der zu testenden Ramzellen pro Zyklus
unsigned char cTestLaenge = 10;      

// Anfang und Ende vom Ram
unsigned char* RamA = (unsigned char*)0x0100;
unsigned char* RamE = (unsigned char*)0x04FF;

Es funktioniert auch soweit!

In wiefern ist mein Code noch furchbar, abgesehen von der genannten 
Routinen, in denen ich wirklich fies rumgefuhrwerkt habe und die 
keinesfalls "Endgültig" waren ;)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schmeiss diese bescheuerte hungarian Notation raus.

cStartAddr
beispielsweise ist kein char, wie dein Präfix suggeriert!

Zwichen cOriginalByte und cStartAddr besteht ein fundamentaler 
Unterschied in den Datentypen, trotzdem benutzt du denselben 
hungarian-Präfix dafür! Ein krasses Beispiel dafür wie blödsinnig das 
Alles ist. Diese Hungarian sieht auf den ersten Blick gut aus. Die ist 
es aber nicht. Sie ist eine Mogelpackung!

Einige dich mit dir selbst, ob du Variablen Namen mit englischen oder 
mit deutschen Begriffen bildest.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist schlecht, etwas aufs Ram zu schreiben, und gleich danach von 
derselben Speicherzelle zu lesen. Mit ein wenig Glück bekommst du 
sogar denselben Wert zurück, wenn du gar kein RAM angeschlossen hast, 
einfach indem Leiterplattenkapazitäten den Wert auf dem Datenbus 
speichern.

Mit deiner Routine würde nicht mal ein Kurzschluss über alle 
Adressleitungen erkannt :-o

Besser schreibst du ein (zufälliges) Bitmuster auf 10 oder 13 oder 15 
oder 17 (also keine 2er Potenz) aufeinanderfolgende Speicherzellen, und 
vergleichst dann die zurückgelesenen Werte mit lokal gespeicherten 
Werten.

Autor: Mr.X (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Es ist schlecht, etwas aufs Ram zu schreiben, und gleich danach von
>derselben Speicherzelle zu lesen. Mit ein wenig Glück bekommst du
>sogar denselben Wert zurück, wenn du gar kein RAM angeschlossen hast,
>einfach indem Leiterplattenkapazitäten den Wert auf dem Datenbus
>speichern.
Wenn ich aber einen RAM angeschlossen habe, dann bekomme ich den 
RAM-Wert zurück, welcher auch der selbe ist, ausser der RAM ist defekt.

>Mit deiner Routine würde nicht mal ein Kurzschluss über alle
>Adressleitungen erkannt :-o
Wieso nicht?

>Besser schreibst du ein (zufälliges) Bitmuster auf 10 oder 13 oder 15
>oder 17 (also keine 2er Potenz) aufeinanderfolgende Speicherzellen, und
>vergleichst dann die zurückgelesenen Werte mit lokal gespeicherten
>Werten.
Warum keine 2er Potenz? Welche Fehler werden durch den Test erkannt? 
Stuck-At-Faults? Transition-Faults? Coupling-Faults? Ich glaub keine 
davon, oder nur durch Zufall, da der Zufallswert gerade passt.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mr.X wrote:

> Wenn ich aber einen RAM angeschlossen habe, dann bekomme ich den
> RAM-Wert zurück, welcher auch der selbe ist, ausser der RAM ist defekt.

Auch wenn das RAM defekt ist bekommst du so u.U. den korrekten Wert 
zurück. Je nachdem was genau defekt ist. Beispielsweise wenn es nicht 
mehr auf CE/OE reagiert, oder eine Dx Leitung defekt ist und floatet.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Tests sind mir vorgegeben und sind nicht von mir entwickelt. Wie 
bereits einige Zeit vorher in einem Thema erwähnt dreht es sich dabei um 
eine Bachelor-Abschlussarbeit und die RAM und ROM-Tests sind nur der 
letzte Schliff ;)

Aber trotzdem danke für eure Anregungen, auch wenn ich, im Stress, grad 
ein wenig resistent dafür bin. Hoffe einfach nur das ich es schaffe 
pünktlich mit einer mir gefallenden Qualität abzugeben.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller wrote:

> Besser schreibst du ein (zufälliges) Bitmuster auf 10 oder 13 oder 15
> oder 17 (also keine 2er Potenz)

Diese Einschränkung versteh ich auch nicht.
Warum keine 2-er Potenz?

Ich hätts so gemacht:
maximal 256 Bytes in einem Rutsch testen.
Lokales Array für entsprechend viel Speicherplatz.
max 256 Bytes (i) mit den Werten 0 bis i füllen.
Wieder auslesen und vergleichen
dieselben Zellen mit ~i füllen
wieder auslesen und vergleichen.

Damit sollten Leitungskapazitäten ausreichend ausgetrickst sein und 
solange die Anzahl an Bytes nicht zu klein ist, sollten sich 
Kurzschlüsse auch zeigen.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nächstes problem, wo ich bestimmt einfach grad zu verwirrt bin für.

ich möchte den ROM (Flash-Speicher) testen, indem ich über ihn eine 
CRC-Summe bilde, welche ich dann im Flash-Mem ablegen möchte.
Diese soll dann zur Laufzeit ab und zu mal verglichen werden, ob im Rom 
auch noch alles grün ist.

Meine Idee:
CRC-Summe über den beschriebenen Teil im Flash, da der restliche ja eh 
uninteressant ist.

Diese Summe am Ende des Flashs ablegen (inklusive der Start- und 
Endzelle)

Zur Laufzeit ab und zu mal ein paar Zellen zu einer Prüfsumme 
zusammenfassen, solange bis die Prüfsumme über alle Zellen geht (nicht 
alle auf einmal, da zu Zeitaufwendig!)

Dann prüfen.

Nun meine Probleme:
1. Wie kriege ich eine CRC über das Flash-File hin, was NUR die 
bestimmten Zellen betrachtet? Geht das über das make-file? Wenn ja, 
jemand ein Tutorial zur hand? Google spuckt mir kaum brauchbares raus.

2. Macht es überhaupt sinn NUR die gebrauchten Zellen zu betrachten?

3. Wie verbastel ich den Code am besten? Ich bin da absolut ratlos..

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, ich habe jetzt mittels der avr/crc16.h eine funkion geschrieben, 
welche meiner meinung nach das CRC schrittweise berechnet. nun bleibt 
noch offen, wie ich das CRC einer datei berechne, wohin ich es in der 
datei schreibe und wie ich erkennen kann von wo bis wo die summe 
gebildet wurde.

am liebsten wäre es mir, dass ich die letzten x zellen des flashs für 
den CRC nutzen kann. also an die letzte zelle (wenns denn passt) die 
CRC-Summe hinschreibe, an Ende-1 das Ende des Bereichs über den ich die 
CRC gebildet habe und an Ende-2 den Anfang (wobei dieser ja eh 
sinnigerweise 0x0000 sein sollte).

Gibt es eine einfache möglichkeit das zu machen? srecord habe ich schon 
gelesen, allerdings komme ich nicht ganz dahinter ob er die CRC über die 
gesamte datei bildet, wohin er die summe schreibt und sowas.. wenn es 
über die gesamte datei bildet, dann bringt es mir ja nicht, da die sich 
ja ändert wenn er die CRC dann einfügt..

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht kann mir ja doch einer helfen.

Also ich habe jetzt mit srecord 1.42 (für Windows) eine CRC16-Summe 
(CCITT) über meine *.hex datei gebildet. Diese wurde in den letzten 
beiden Zellen (0x3FFE, 0x3FFF - Big Endian-Art) gespeichert.

Allerdings kann ich nirgendwo nachsehen, über welchen Bereich dieser 
Datei die Summe gebildet wurde, also kann ich auch mit meiner 
Kontrollroutine nicht die korrekte (oder eher die Prüfsumme über den 
korrekten Rahmen) bilden.

Meine Funktion sieht so aus:
// Zeiger auf aktuelle Position des Flashspeichers
unsigned char *cFlashZeiger = (unsigned char*)0x0000;
// Anzahl der zu testenden Flashzellen pro Zyklus
unsigned int iFlashTestLaenge = 10;
// aktueller CRC-Wert
uint16_t iCRC;
// Anfang und Ende der CRC-Berechnung des Flash-Speichers
unsigned char *FlashA = (unsigned char*)0x0000;
unsigned char *FlashE = (unsigned char*)0x3FFE;

.
.
.
.

// Test des Flash-Speichers
void Flash_Test(){
  if((cFlashZeiger + iFlashTestLaenge) >= FlashE){
    unsigned int iFlashTestLaengeTemp = (cFlashZeiger + iFlashTestLaenge) - FlashE;
    for(int i = 0; i < iFlashTestLaengeTemp; i++){
      iCRC  =  _crc_ccitt_update(iCRC, pgm_read_byte(cFlashZeiger++));
    }
    // Prüfen ob ermittelte CRC mit erwarteter Übereinstimmt
    uint16_t iCRCCheck = pgm_read_word(FlashE + 1);
    if(iCRCCheck != iCRC){
      // wenn nicht, Fehlerroutine aufrufen
      while(1){
        cli();
        wdt_disable();
        DDRB = 0xFF;
        DDRD = 0xFF;
        PORTD = iCRC>>8; 
        PORTB = iCRC;
      }
    }
    // Zeiger auf Flashanfang zurück setzten
    cFlashZeiger = FlashA;
  }
  else{
    for(int i = 0; i <= iFlashTestLaenge; i++){
      iCRC = _crc_ccitt_update(iCRC, pgm_read_byte(cFlashZeiger++));
    }
  }
    
}
 wobei die while(1)-Schleife im moment nur zu Testzwecken drin ist um zu 
sehen was denn die CRC-Routine berechnet hat.

Kann mir bitte jemand sagen, wie ich rausfinden kann über welchen 
Bereich der CRC von der hex gebildet wird?

Autor: Max (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
zefix, hier die Datei OHNE CRC-Wert, bildet ihr mal selber und sagt mir 
ob bei euch auch 0x5226 raus kommt

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max wrote:

> Kann mir bitte jemand sagen, wie ich rausfinden kann über welchen
> Bereich der CRC von der hex gebildet wird?

Denk logisch!
Weiss das srecord Utility, wie gross der nicht benutzte Flash Bereich 
ist?
Nein
Weiss das srecord Utility, wie gross der benutzte Flash Bereich ist?
Ja, im File steht ja drinnen, was dort abzulegen ist.

Und jetzt geb ich die Frage an dich zurück:
Was wird wohl das srecord Utility machen (können)?

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich komm nicht wirklich dahinter was du mir damit sagen willst.. Ich 
vermute du möchstest mir sagen, dass die CRC-Summe nur über den 
benutzten bereich gebildet wird, darum frage ich dich nun: woher weiß 
das programm wo dieser Endet? Endet er vor dem ersten 0xFFFF? Was wird 
als "Loch" definiert, da im Manual steht, dass Löcher nicht 
berücksichtigt werden!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Max wrote:
> woher weiß
> das programm wo dieser Endet? Endet er vor dem ersten 0xFFFF? Was wird
> als "Loch" definiert, da im Manual steht, dass Löcher nicht
> berücksichtigt werden!

Schon mal in ein HEX File hineingeschaut und eine Beschreibung des 
Formats studiert?

Hinweis: Am Anfang der jeder Zeile steht sowas wie ein Befehl und im 
Falle dass hier Datenbytes abgelegt wurden, auch, wohin diese Bytes im 
Speicher gehören.
Ergo -> Das srecord Utility ist in der Lage sich ein komplettes 
Speicherabbild des Flash zu basteln. Das einzige was es nicht weiß ist, 
wie gross das Flash ist. Aber vielleicht gibts ja auch einen Command 
Line Switch dafür.

(Edit: In der Zeit, die du hier verplemperst, hättest du schon 3 mal 
selbst ein CRC Tool schreiben können und von dem genau wüsstest, was es 
tut)


So, klink mich jetzt wieder aus. Du hast weiter oben das Zauberwort 
gesagt: Bachelor-Abschlussarbeit
Und das ist ja dann schliesslich nicht irgendwas. Immerhin verlangst du 
dann von deinem ersten Arbeitgeber einen Haufen Geld dafür, dass du was 
kannst.

Autor: Max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe schon in das Hex-File reingeschaut und gesehen, dass dort 
deutlich mehr Daten drin stehen als mir später vom AVR-Studio als 
Programmspeicher angezeigt werden.

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Max,

sowohl zu deiner CRC-Frage als auch deiner RAM-Test-Frage gibt es zwei 
schöne Artikel auf der netrino-Seite:

http://www.netrino.com/Embedded-Systems/How-To/CRC...
http://www.netrino.com/Embedded-Systems/How-To/Mem...

Viel Erfolg,
Markus

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.