Forum: Compiler & IDEs Problem beim SRAM testen


von Max (Gast)


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:
1
// Routine für den einfacheren RAM-Test
2
void RamTest(){
3
  if((iTempRamAdress + iRamCheckAnzahl) > RamE){  // Prüfen ob Prüfrahmen über Ramende hinaus
4
    iRamCheckAnzahl = (iTempRamAdress + iRamCheckAnzahl) - RamE;
5
    RamCheck(iTempRamAdress, RamE);        // Wenn ja, bis zum Ende prüfen und 
6
    iTempRamAdress = RamA;            // Pointer auf Anfang setzten
7
  }
8
  
9
  // Ramtest durchführen.
10
  RamCheck(iTempRamAdress, (iTempRamAdress + iRamCheckAnzahl));
11
    
12
  // Ramzelle auf nächste Zelle setzen (falls Ramende, dann auf Ramanfang)
13
  iTempRamAdress = iTempRamAdress + 1;
14
  if(iTempRamAdress > RamE)
15
    iTempRamAdress = RamA;
16
  
17
}
18
19
// eigentlicher Ramtest
20
void RamCheck(int iAadress, int iEadress){
21
  char iAdress = iAadress;            // Adresse übernehmen
22
  int iTemp;                     // Variable für Speicherzelleninhalt
23
  
24
  // solange nicht alle Zellen getestet wurden
25
  while(iAdress < iEadress){
26
    iTemp = *iAdress;              // Inhalt speichern
27
    *iAdress = 0x55;              // Testwerte schreiben und vergleichen
28
    if(!*iAdress == 0x55)
29
      testError();
30
    *iAdress = 0xAA;
31
    if(!*iAdress == 0xAA)
32
      testError();
33
    *iAdress = iTemp;              // Inhalt zurück schreiben
34
    iAdress++;                  // Nächste Zelle
35
  }
36
}

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:
1
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 
2
TestLib.c: In function 'RamCheck':
3
TestLib.c:282: error: invalid type argument of 'unary *' (have 'int')
4
TestLib.c:283: error: invalid type argument of 'unary *' (have 'int')
5
TestLib.c:284: error: invalid type argument of 'unary *' (have 'int')
6
TestLib.c:286: error: invalid type argument of 'unary *' (have 'int')
7
TestLib.c:287: error: invalid type argument of 'unary *' (have 'int')
8
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

von Mr.X (Gast)


Lesenswert?

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

von Max (Gast)


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!

von Oliver (Gast)


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

von Max (Gast)


Lesenswert?

Danke, das werde ich morgen einmal ausprobieren und dann Feedback geben!

von Max (Gast)


Lesenswert?

Ok, ich stehe grad vor den nächsten Problem.
Habe das ganze nun umgesetzt:
1
// Routine für den einfacheren RAM-Test
2
void Ram_Test(){
3
  if((iTempRamAdress + iRam_CheckAnzahl) > RamE){  // Prüfen ob Prüfrahmen über Ramende hinaus
4
    iRam_CheckAnzahl = (iTempRamAdress + iRam_CheckAnzahl) - RamE;
5
    Ram_Check(iTempRamAdress, RamE);        // Wenn ja, bis zum Ende prüfen und 
6
    iTempRamAdress = RamA;              // Pointer auf Anfang setzten
7
  }
8
  
9
  // Ram_Test durchführen.
10
  Ram_Check(iTempRamAdress, (iTempRamAdress + iRam_CheckAnzahl));
11
    
12
  // Ramzelle auf nächste Zelle setzen (falls Ramende, dann auf Ramanfang)
13
  iTempRamAdress = iTempRamAdress + 1;
14
  if(iTempRamAdress > RamE)
15
    iTempRamAdress = RamA;
16
  
17
}
18
19
// eigentlicher Ram_Test
20
void Ram_Check(int iAadress, int iEadress){
21
  unsigned char *iAdress;
22
  iAdress = (unsigned char*)iAadress;      // Adresse übernehmen
23
  int iTemp;                     // Variable für Speicherzelleninhalt
24
  
25
  // solange nicht alle Zellen getestet wurden
26
  while(iAdress < iEadress){
27
    iTemp = *iAdress;              // Inhalt speichern
28
    *iAdress = 0x55;              // Testwerte schreiben und vergleichen
29
    if(!*iAdress == 0x55)
30
      testError();
31
    *iAdress = 0xAA;
32
    if(!*iAdress == 0xAA)
33
      testError();
34
    *iAdress = iTemp;              // Inhalt zurück schreiben
35
    iAdress++;                  // Nächste Zelle
36
  }
37
}

Mein Compiler macht daraus das:
1
@0000048C: Ram_Test
2
189:          wdt_reset();              // Watchdog zurück setzen
3
+0000048C:   91200116    LDS       R18,0x0116     Load direct from data space
4
+0000048E:   91300117    LDS       R19,0x0117     Load direct from data space
5
+00000490:   91800118    LDS       R24,0x0118     Load direct from data space
6
+00000492:   91900119    LDS       R25,0x0119     Load direct from data space
7
+00000494:   0F82        ADD       R24,R18        Add without carry
8
+00000495:   1F93        ADC       R25,R19        Add with carry
9
+00000496:   E045        LDI       R20,0x05       Load immediate
10
+00000497:   3080        CPI       R24,0x00       Compare with immediate
11
+00000498:   0794        CPC       R25,R20        Compare with carry
12
+00000499:   F09C        BRLT      PC+0x14        Branch if less than, signed
13
---- TestLib.c ------------------------------------------------------------------------------------
14
265:          iRam_CheckAnzahl = (iTempRamAdress + iRam_CheckAnzahl) - RamE;
15
+0000049A:   5F8F        SUBI      R24,0xFF       Subtract immediate
16
+0000049B:   4094        SBCI      R25,0x04       Subtract immediate with carry
17
+0000049C:   93900119    STS       0x0119,R25     Store direct to data space
18
+0000049E:   93800118    STS       0x0118,R24     Store direct to data space
19
283:        iAdress = (unsigned char*)iAadress;      // Adresse übernehmen
20
+000004A0:   01C9        MOVW      R24,R18        Copy register pair
21
+000004A1:   C001        RJMP      PC+0x0002      Relative jump
22
296:          iAdress++;                  // Nächste Zelle
23
+000004A2:   9601        ADIW      R24,0x01       Add immediate to word
24
287:        while(iAdress < iEadress){
25
+000004A3:   E024        LDI       R18,0x04       Load immediate
26
+000004A4:   3F8F        CPI       R24,0xFF       Compare with immediate
27
+000004A5:   0792        CPC       R25,R18        Compare with carry
28
+000004A6:   F3D8        BRCS      PC-0x04        Branch if carry set
29
267:          iTempRamAdress = RamA;              // Pointer auf Anfang setzten
30
+000004A7:   E080        LDI       R24,0x00       Load immediate
31
+000004A8:   E091        LDI       R25,0x01       Load immediate
32
+000004A9:   93900117    STS       0x0117,R25     Store direct to data space
33
+000004AB:   93800116    STS       0x0116,R24     Store direct to data space
34
271:        Ram_Check(iTempRamAdress, (iTempRamAdress + iRam_CheckAnzahl));
35
+000004AD:   91800116    LDS       R24,0x0116     Load direct from data space
36
+000004AF:   91900117    LDS       R25,0x0117     Load direct from data space
37
+000004B1:   91200118    LDS       R18,0x0118     Load direct from data space
38
+000004B3:   91300119    LDS       R19,0x0119     Load direct from data space
39
+000004B5:   0F28        ADD       R18,R24        Add without carry
40
+000004B6:   1F39        ADC       R19,R25        Add with carry
41
+000004B7:   C001        RJMP      PC+0x0002      Relative jump
42
296:          iAdress++;                  // Nächste Zelle
43
+000004B8:   9601        ADIW      R24,0x01       Add immediate to word
44
287:        while(iAdress < iEadress){
45
+000004B9:   1782        CP        R24,R18        Compare
46
+000004BA:   0793        CPC       R25,R19        Compare with carry
47
+000004BB:   F3E0        BRCS      PC-0x03        Branch if carry set
48
274:        iTempRamAdress = iTempRamAdress + 1;
49
+000004BC:   91800116    LDS       R24,0x0116     Load direct from data space
50
+000004BE:   91900117    LDS       R25,0x0117     Load direct from data space
51
+000004C0:   9601        ADIW      R24,0x01       Add immediate to word
52
+000004C1:   93900117    STS       0x0117,R25     Store direct to data space
53
+000004C3:   93800116    STS       0x0116,R24     Store direct to data space
54
275:        if(iTempRamAdress > RamE)
55
+000004C5:   5080        SUBI      R24,0x00       Subtract immediate
56
+000004C6:   4095        SBCI      R25,0x05       Subtract immediate with carry
57
+000004C7:   F034        BRLT      PC+0x07        Branch if less than, signed
58
276:          iTempRamAdress = RamA;
59
+000004C8:   E080        LDI       R24,0x00       Load immediate
60
+000004C9:   E091        LDI       R25,0x01       Load immediate
61
+000004CA:   93900000    STS       0x0000,R25     Store direct to data space
62
+000004CC:   93800116    STS       0x0116,R24     Store direct to data space
63
+000004CE:   9508        RET                      Subroutine return
64
281:      void Ram_Check(int iAadress, int iEadress){
65
+000004CF:   01FC        MOVW      R30,R24        Copy register pair
66
+000004D0:   C002        RJMP      PC+0x0003      Relative jump
67
288:          iTemp = *iAdress;              // Inhalt speichern
68
+000004D1:   8180        LDD       R24,Z+0        Load indirect with displacement
69
295:          *iAdress = iTemp;              // Inhalt zurück schreiben
70
+000004D2:   9381        ST        Z+,R24         Store indirect and postincrement
71
287:        while(iAdress < iEadress){
72
+000004D3:   17E6        CP        R30,R22        Compare
73
+000004D4:   07F7        CPC       R31,R23        Compare with carry
74
+000004D5:   F3D8        BRCS      PC-0x04        Branch if carry set
75
298:      }
76
+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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Max (Gast)


Angehängte Dateien:

Lesenswert?

Ok, habe mal angehängt, was ich so zusammen geschrieben habe!

von Max (Gast)


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!)

von Karl H. (kbuchegg)


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)
1
void Ram_Check( unsigned char* StartAddr, unsigned char* EndAddr )
2
{
3
  unsigned char  OriginalByte;
4
  volatile unsigned char* TestAddr;
5
6
  for( TestAddr = StartAddr; TestAddr < EndAddr; ++TestAddr ) {
7
    OriginalByte = *TestAddr;
8
9
    *TestAddr = 0x55;
10
    if( *TestAddr != 0x55 ) {
11
      *TestAddr = OriginalByte;
12
      testError();
13
    }
14
15
    *TestAddr = 0xAA;
16
    if( *TestAddr != 0xAA ) {
17
      *TestAddr = OriginalByte;
18
      testError();
19
    }
20
21
    *TestAddr = OriginalByte;
22
  }
23
}

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.)

von Karl H. (kbuchegg)


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.

von Max (Gast)


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 ;)):
1
// Routine für den einfacheren RAM-Test
2
void Ram_Test(){
3
  if((cErsteRamZelle + cTestLaenge) > RamE){    // Prüfen ob Prüfrahmen über Ramende hinaus
4
    unsigned char cTestLaengeTemp = (cErsteRamZelle + cTestLaenge) - RamE;
5
    Ram_Check(cErsteRamZelle, RamE);      // Wenn ja, bis zum Ende prüfen und 
6
    cErsteRamZelle = RamA;            // Pointer auf Anfang setzten
7
    Ram_Check(cErsteRamZelle, (cErsteRamZelle + cTestLaengeTemp));
8
  }
9
  else
10
    // Ram_Test durchführen.
11
    Ram_Check(cErsteRamZelle, (cErsteRamZelle + cTestLaenge));
12
    
13
  // Ramzelle auf nächste Zelle setzen (falls Ramende, dann auf Ramanfang)
14
  cErsteRamZelle = cErsteRamZelle + 1;
15
  if(cErsteRamZelle > RamE)
16
    cErsteRamZelle = RamA;
17
  
18
}
19
20
// eigentlicher Ram_Test
21
void Ram_Check( unsigned char* cStartAddr, unsigned char* cEndAddr )
22
{
23
  unsigned char cOriginalByte;
24
  volatile unsigned char* cTestAddr;
25
26
  for(cTestAddr = cStartAddr; cTestAddr < cEndAddr; ++cTestAddr ) {
27
    cOriginalByte = *cTestAddr;
28
29
    *cTestAddr = 0x55;
30
    if( *cTestAddr != 0x55 )
31
      testError();
32
33
    *cTestAddr = 0xAA;
34
    if( *cTestAddr != 0xAA )
35
      testError();
36
37
    *cTestAddr = cOriginalByte;
38
  }
39
}

mit
1
// Variable beinhaltet die erste zu testende Ramzelle
2
unsigned char *cErsteRamZelle = (unsigned char*)0x0100;    
3
4
// Anzahl der zu testenden Ramzellen pro Zyklus
5
unsigned char cTestLaenge = 10;      
6
7
// Anfang und Ende vom Ram
8
unsigned char* RamA = (unsigned char*)0x0100;
9
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 ;)

von Karl H. (kbuchegg)


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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.

von Mr.X (Gast)


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.

von (prx) A. K. (prx)


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.

von Max (Gast)


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.

von Karl H. (kbuchegg)


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.

von Max (Gast)


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..

von Max (Gast)


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..

von Max (Gast)


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:
1
// Zeiger auf aktuelle Position des Flashspeichers
2
unsigned char *cFlashZeiger = (unsigned char*)0x0000;
3
// Anzahl der zu testenden Flashzellen pro Zyklus
4
unsigned int iFlashTestLaenge = 10;
5
// aktueller CRC-Wert
6
uint16_t iCRC;
7
// Anfang und Ende der CRC-Berechnung des Flash-Speichers
8
unsigned char *FlashA = (unsigned char*)0x0000;
9
unsigned char *FlashE = (unsigned char*)0x3FFE;
10
11
.
12
.
13
.
14
.
15
16
// Test des Flash-Speichers
17
void Flash_Test(){
18
  if((cFlashZeiger + iFlashTestLaenge) >= FlashE){
19
    unsigned int iFlashTestLaengeTemp = (cFlashZeiger + iFlashTestLaenge) - FlashE;
20
    for(int i = 0; i < iFlashTestLaengeTemp; i++){
21
      iCRC  =  _crc_ccitt_update(iCRC, pgm_read_byte(cFlashZeiger++));
22
    }
23
    // Prüfen ob ermittelte CRC mit erwarteter Übereinstimmt
24
    uint16_t iCRCCheck = pgm_read_word(FlashE + 1);
25
    if(iCRCCheck != iCRC){
26
      // wenn nicht, Fehlerroutine aufrufen
27
      while(1){
28
        cli();
29
        wdt_disable();
30
        DDRB = 0xFF;
31
        DDRD = 0xFF;
32
        PORTD = iCRC>>8; 
33
        PORTB = iCRC;
34
      }
35
    }
36
    // Zeiger auf Flashanfang zurück setzten
37
    cFlashZeiger = FlashA;
38
  }
39
  else{
40
    for(int i = 0; i <= iFlashTestLaenge; i++){
41
      iCRC = _crc_ccitt_update(iCRC, pgm_read_byte(cFlashZeiger++));
42
    }
43
  }
44
    
45
}
 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?

von Max (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


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)?

von Max (Gast)


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!

von Karl H. (kbuchegg)


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.

von Max (Gast)


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.

von Markus (Gast)


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-Calculation-C-Code
http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C

Viel Erfolg,
Markus

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.