Forum: Mikrocontroller und Digitale Elektronik Mysteriöses Problem


von Tobias P. (hubertus)


Lesenswert?

Hallo,
ich bin grade am Debuggen.
Und irgendwie bekomme ich langsam graue Haare, weil ich mich so ärgere.
Folgende Situation:
ich bin daran, ein Dateisystem zu programmieren. Als Zielsystem sehe ich 
einen LPC2468 vor, welcher über 64M externes SDRAM und SD-Karte verfügt.
Des Weiteren:

  - Interrupts sind deaktiviert (I- und F-Bits im CPSR sind gesetzt)
  - Das System läuft im User Mode
  - Clock 72 MHz
  - SDRAM funktioniert einwandfrei (RAM-Test läuft mehrfach ohne Fehler
    durch)
  - SD-Karte funktioniert
  - Alle Stacks sind 8 MByte gross
  - Optimierungen des Compilers sind ausgeschaltet
  - Ich verwende die IAR EWARM Testversion, welche sonst sehr gut
    funktioniert
  - structs sind korrekt als "__packed" definiert

Das Problem ist das folgende:
Der Code, welcher meines Erachtens einwandfrei ist, und welcher auch mal 
lief, stürzt an unterschiedlichen Stellen immer wieder ab. Ich habe z.B. 
eine Struktur stBPB. Die hat ein Feld dwRsvdSectCnt. An irgend einer 
Stelle im Programm erhält dieses Feld den Wert 10. Ich steppe nun durch 
den C-Code hindurch, und während des nächsten C-Statements hat das Feld 
plötzlich den Wert 35:
1
void test(tpstBPB param)
2
{
3
  tpstBPB->dwRsvdSecCnt = 10;
4
  return;
5
}
6
7
void main(void)
8
{
9
  tstBPB x;
10
  test(&x); /* soweit funktioniert alles; wenn test beendet wird ist 
11
               dwRsvdSecCnt = 10 */
12
  if(x.dwRsvdSecCnt) /* und hier ist es plötzlich 35 */
13
  {
14
    /* ... */
15
  }
16
}

So, ich weiss, mit obigem Code kann man nicht viel anfangen, er dient 
nur zur Veranschaulichung meines Problems.

Was ich nun festgestellt habe, nachdem ich das Disassembly angeschaut 
habe:
Der Compiler generiert einen total seltsamen Code. Da werden völlig 
abstruse Werte zum Stackpointer hinzuaddiert, irgendwelche Register 
einfach überschrieben etc. Der Witz ist nämlich der folgende: wenn die 
Funktion test() beendet wird, dann ist an der Adresse, wo das 
dwRsvdSecCnt-Feld liegt, wirklich 10 gespeichert. Also alles in Butter.
Im Register r0 ist irgend ein beliebiger zufälliger Wert.
Jetzt steppe ich zum if-Statement. Und was steht da für ein 
Assemblercode?
Eigentlich würde man ja sowas erwarten:
1
ldr r0,=(Adresse wo das dwRsvdSecCnt-Feld liegt)
2
cmp r0,#0
3
...

Interessanterweise wird aber im ganzen Programm nachher NIE MEHR auf 
diese Adresse von dwRsvdSecCnt zugegriffen. Stattdessen steht im 
Assemblercode:
1
add r0, r6, r8 ; warum auch immer, in r8 steht kein wert, der benötigt wird
2
add sp, sp, #0x280 ; den stackpointer zu manipulieren ist wohl keine gute 
3
                   ; idee....
4
...

und im Statement nach "add sp, sp, #0x280" stürzt die CPU ab und geht 
zum Reset-Vektor.

WAS ZUM GEIER ist denn das?! Sämtliche anderen Programme laufen 
einwandfrei. Keine Abstürze, keine solchen komischen Codestrukturen. Es 
funktioniert einfach. Nur in diesem Projekt scheint der Wurm drin zu 
sein, und ich finde es nicht. Wenn ich die Optimierungen des Compilers 
einschalte, ist das Ergebnis ähnlich, nur liegen die Variablen an ein 
bisschen anderen Adressen und die fehlerhaft berechneten Werte sind ein 
bisschen anders.

So, nun meine Frage:
könnt ihr mir einen Tipp geben, wo ich suchen soll?
Einfach ein neues Projekt erstellen, die Files hinzufügen und neu 
Compilieren? Ein "Project -> Clean" und "Project -> Build All" hat 
nichts gebracht. Das Verhalten des Codes ist sowohl als Debug-Version im 
RAM als auch als Releas im ROM gleich bzw. ähnlich.
Und wie gesagt: andere Projekte auf demselben System mit ähnlichen 
Konstrukten im C-Code funktionieren.
Ich weiss echt nicht weiter, ich versuche schon seit zwei Tagen das zu 
debuggen.....

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

1
void test(tpstBPB param)
2
{
3
  tpstBPB->dwRsvdSecCnt = 10;
4
  return;
5
}
tpstBPB ist doch ein Variablentyp und keine Variable.

Es sollte doch
1
void test(tpstBPB param)
2
{
3
  param->dwRsvdSecCnt = 10;
4
}
heißen (return hat hier keine Funktion, da die Prozedur sowieso beendet 
ist).

Ok, das ist nicht das Problem - fiel mir aber unangenehm auf.

von Walter (Gast)


Lesenswert?

vielleicht zerschießt dein Programm den Stack und deshalb das seltsame 
disassembly?
Wie schaut der <Code denn aus bevor das programm losläuft

von Walter (Gast)


Lesenswert?

noch ne Anmerkung
es sollte
void test(tpstBPB *param)
heißen

von Tobias P. (hubertus)


Lesenswert?

Hallo Leute,
ja sorry, ich war ein bisschen durch den Wind, als ich den Beispielcode 
geschrieben habe. Ihr wisst ja, was ich meinte, in meinem Code hier 
steht es schon richtig ;-)
Und ihr habt natürlich absolut recht.
Walter, dein Tipp ist nicht schlecht. Aber leider liegt es daran auch 
nicht :-( Ich habe grade das Memory vor- und nach dem Sart des Programms 
utnersucht. Ist in beiden Fällen gleich, und wenn ich den Code, den der 
Compiler generiert, disassembliere bzw. mir das Listing anschaue, sieht 
der auch gleich aus.
Dass mein Programm den Stack zerschiesst denke ich schon deswegen nicht, 
da der Stack so riesengross ist, dass er gar nicht erst überlaufen kann. 
Sofern der Stackpointer also richtig initialisiert wurde, was er 
definitiv ist, kann der Stack ja gar nicht zerschossen werden.
Was ich allerdings noch anmerken musss ist, dass in meinem Programm der 
MCI-Treiber von Keil verwendet wird (also der grässliche Code, den man 
im Sample Code Bundle auf der NXP-Website runterladen kann).
Zudem wird auch noch DMA benutzt, um Sektoren von der SD-Karte ins 
Memory zu schaufeln.
Kennt jemand evtl. diesen MCI-Treiber und weiss, ob der vielleicht 
Ursache des mysteriösen Problems sein könnte?
Ich könnte mir durchaus vorstellen, dass diese addiererei mit dem 
Stackpointer vielleicht schon irgend einen Sinn ergibt, aber vielleicht 
wird durch diesen schrecklichen NXP-Code irgendwas am Stack manipuliert. 
Wer weiss?

von Jürgen (Gast)


Lesenswert?

Die seltsamen Befehle

add r0, r6, r8
add sp, sp, #0x280

sehen für mich nach Daten und nicht nach echten Assemblerbefehlen aus, 
irgendwie ist da dein Programm etwas durch den Wind.

Und bitte! Wenn du willst daß man dir hilft, kopiere demnächst deinen 
Code und kürze ihn, anstatt beim Abtippen noch fünf Fehler einzubauen.

von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

Hallo,
also ich konnte das Problem ein bisschen eingrenzen. Es scheint wirklich 
dieser seltsame MCI-Treiber zu sein. Mein restliches Programm verstehe 
ich vollständig (da ich es ja auch selber geschrieben habe...), und ich 
gehe jede Wette ein, dass der Teil des Codes mehr oder weniger 
Fehlerfrei ist.
Nun, wie auch immer. Da das MCI im Handbuch des LPC2468 absolut lausig 
dokumentiert ist (sprich: so gut wie gar nicht), habe ich diesen 
MCI-Treiber von Keil.
Der scheint aber nur so halbwegs zu funktionieren; er ist ja auch 
schrecklich programmiert....
Im Anhang habe ich meine beiden Files, die für das MCI zuständig sind. 
Ich habe den Code etwas umgeschrieben (vielleicht ist dabei ein Fehler 
passiert?), da ich gezwungen bin, ganz bestimmte Datentypen und eine 
bestimmte Darstellung einzuhalten.
Also, wie auch immer - der Ablauf meines Programms ist wie folgt:

- ich habe mein struct und rufe (void)MCI_fReadSect(0, (tpByte)&stBPB, 
1); auf. Dadurch wird (angeblich) Sektor 0 der Karte gelesen, und per 
DMA in den Speicher übertragen, wo sich stBPB drin befindet. Soweit 
funktioniert das auch.
- in der nächsten Zeile will ich noch ein anderes struct mit Daten 
füllen, die ich von der Karte lese. Aufruf ist der selbe wie oben, nur 
dass diesmal Sektor 1 gelesen wird und eine andere Adresse übergeben 
wird.
VOR dem Aufruf von MCI_fReadSect enthält die Variable stBPB korrekte 
Daten. Nachdem das Programm aber von MCI_fReadSect zurückkommt, enthält 
mein stBPB alles nur NULL. Das legt den Verdacht nahe, dass der 
MCI-Treiber irgendwas überschreibt. Oder?
Das kann nur von dem kommen, denn wie bereits erwähnt sind die 
Interrupts alle ausgeschaltet (Bits I und F sind gesetzt).
Liegt der Bock vielleicht beim DMA?
Dann noch zu diesem MCI-Treiber. Gibts keinen besseren? Ausserdem stören 
mich die vielen for-Schleifen, die da drin sind zum Verzögern. Aber ohne 
scheint der Code auch nicht zu laufen.
Gibts dazu irgendwelche Infos?

von Tobias P. (hubertus)


Lesenswert?

Wieso ist eigentlich die Diskussion immer automatisch zuende, wenn das 
Stichwort MCI auftaucht? ;-)
Der Code läuft noch immer nicht.
Zumindest weiss ich jetzt so annähernd, was das Problem sein könnte.
Sobald der Treiber den Befehl READ_SECTOR (CMD17) abgesetzt hat, wird im 
MCIStatus-Register das Bit STARTBITERR gesetzt.
Ich schliesse daraus, dass mein Bus-Speed entweder zu langsam oder zu 
schnell ist.
Des Weiteren: will man nur einen einzelnen Sektor lesen, dann 
funktioniert das so halbwegs. Beim ersten Sektor den man liest, 
funktioniert alles. Liest man einen weiteren Sektor, dann kann man, ja 
nach eingestellter Clock Rate, unterschiedliches Verhalten beobachten:
a) es werden zufällige Daten (meist jedoch 0) ins Memory geschrieben.
b) wie a, jedoch werden mehr Daten ins Memory geschrieben, als man 
angefordert hat. Sprich: es wird u.U. der Stack mit 0 überschrieben, 
oder der Speicherbereich, in dem gewisse Variablen liegen.
In beiden Fällen ist im MCIStatus das Bit STARTBITERR gesetzt.
Weiss jemand weiter? Meine Karte ist eine 512 MB Sandisk; die ist noch 
kein Jahr alt. Eine 128 MB Panasonic von 2003 verhält sich identisch. 
Eine 16 MB Canon-Karte antwortet immer mit 0x00.

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.