www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mysteriöses Problem


Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht 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:
void test(tpstBPB param)
{
  tpstBPB->dwRsvdSecCnt = 10;
  return;
}

void main(void)
{
  tstBPB x;
  test(&x); /* soweit funktioniert alles; wenn test beendet wird ist 
               dwRsvdSecCnt = 10 */
  if(x.dwRsvdSecCnt) /* und hier ist es plötzlich 35 */
  {
    /* ... */
  }
}

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:
ldr r0,=(Adresse wo das dwRsvdSecCnt-Feld liegt)
cmp r0,#0
...

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

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

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void test(tpstBPB param)
{
  tpstBPB->dwRsvdSecCnt = 10;
  return;
}
tpstBPB ist doch ein Variablentyp und keine Variable.

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

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

Autor: Walter (Gast)
Datum:

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

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
noch ne Anmerkung
es sollte
void test(tpstBPB *param)
heißen

Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Tobias Plüss (hubertus)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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?

Autor: Tobias Plüss (hubertus)
Datum:

Bewertung
0 lesenswert
nicht 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.

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.