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
voidtest(tpstBPBparam)
2
{
3
tpstBPB->dwRsvdSecCnt=10;
4
return;
5
}
6
7
voidmain(void)
8
{
9
tstBPBx;
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.....
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?
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.
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?
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.