mikrocontroller.net

Forum: Compiler & IDEs STM32 Speicherproblem?


Autor: Florian Micro (micro-flo)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
Nachdem ich ein Problem damit hatte, den STM32 zu starten und es im 
Endeffekt ein Speicherproblem war 
(Beitrag "STM32 ohne JTAG starten") möchte ich dem nun auf den 
Grund gehen, weil ich sehr viele merkwürdige Phänomen habe.

Meine Debug-Ausgaben mache ich so:
void u_putchar(char c) {
  // Loop until USART1 DR register is empty
  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) {
    ;
  }
  USART_SendData(USART1, c);
}

void uputs(const char *c) {
  while(*c) u_putchar(*c++);  // send string char by char
}

#ifdef T_DEBUG
  uputs("START\r\n");
#endif

Sobald ich alle (oder einige) Debug-Ausgaben ausschalte, funktioniert 
das Programm fehlerfrei.
Sind alle Debug-Ausgaben aktiv, habe ich sehr merkwürdige Fehler.
Z.B. startet der STM32 nicht 2x, er stürzt ab, Variablen aus dem Eeprom 
haben falsche Werte etc.

Beim AVR lag es daran, weil die Debug-Texte im RAM lagen und mir den 
Stack zerstört haben. Mit PSTR und pgmspace konnte ich die Texte in den 
Flash legen und das Problem lösen.
Aber der ARM hat eine andere Speicherarchitektur und legt Strings 
automatisch in den Flash?

Ich benutze einen STM32F105RB. 128k Flash, 32k RAM.
Das Linkerskript ist von M.Thomas, nur angepasst auf 32k RAM.

Wie macht ihr Debug-Ausgaben bzw. arbeitet mit Strings?
Sieht das Linkerskript ok aus?
Wo kann ich noch schauen?

Vielen Dank :)

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Florian Micro schrieb:
> Aber der ARM hat eine andere Speicherarchitektur und legt Strings
> automatisch in den Flash?

Das ist wohl weniger Aufgabe des ARM, als der Kombination 
Compiler/Linker!
Schau Dir doch einfach das Map-File an, da steht doch die Adresse jeder 
Konstante/Variable drin.

Autor: Wayne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein uputs läuft den gesamten Speicher ab, da die while-Schleife immer 
gültig ist. Versuchs entweder mit einer fixen Größe oder einer 
vernünftigen Endbedingung für den String, z.B. mit (*c == '\r').

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wayne schrieb:

> Dein uputs läuft den gesamten Speicher ab, da die while-Schleife immer
> gültig ist.

Wieso? Ein Test auf '\0' ist bei Strings in C nicht eben selten.

Autor: Wayne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meinet wegen auch '\0'. Daran habe ich so auf die Schnelle nicht 
gedacht. Aber zeig mir, wo das im Code-Schnipsel des Threaderstellers 
passiert?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In
  while(*c)
was das Gleiche ist wie
  while(*c != 0)
was bei char* effektiv das Gleiche ist wie
  while(*c != '\0')

Autor: Julian (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wayne schrieb:
> Aber zeig mir, wo das im Code-Schnipsel des Threaderstellers
> passiert?

Florian Micro schrieb:
> while(*c) u_putchar(*c++)

sobald eine \0 auftaucht ist *c == 0. D.h. die While-Schleife wird 
verlassen. (In C sind alle werte ungleich 0 True, die 0 ist False)

Autor: Wayne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, wieder was dazu gelernt.

Bleibt die Frage was im String drine steht.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist ziemlich egal, denn zumindest bei string literals ("abcd") ist 
bekannt, was hinten dran hängt: '\0'. Bei Debug-Ausgaben sind meist 
literals.

Interessanter wäre, wo die Debugs alle stehen. Mancher müllt sich seine 
Interrupt-Handler mit Warteschleifen so voll, dass es eng wird. Oder hat 
dort nicht genug Stack vorgesehen. Tausend Möglichkeiten.

Autor: Florian Micro (micro-flo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Debug Texte mache ich teilweise statisch so:
uputs("START\r\n");

oder dynamisch so:
char data[40];
sprintf(data, "address: %i, value: %i\r\n", address, value);
uputs(data);

Beim ersten Beispiel macht der Compiler die \0 automatisch ans Ende und 
beim zweiten Beispiel macht das die sprintf Funktion.
Meine Variablen sind auch immer lang genug, dass die \0 reinpasst.
Das sollte nicht das Problem sein und deshalb stürzt er auch nicht ab.

Die Interrupts sind sauber und sehr kurz. Keinerlei Debug-Texte.

Den Stack habe ich von 1024 Byte auf 8192 Byte angehoben ohne jegliche 
Änderung.
Jetzt ist er auf 4096 Byte.

Wenn ich das Programm aktuell ohne meine Debugs kompiliere habe ich 
diese Ausgabe:

section             size        addr
.text              58660   134217728
.ARM.exidx             8   134276388
.rodata             5784   134276400
.data               1904   536870912
.bss                 576   536872816
._usrstack          4096   536873392
.comment            1470           0
.debug_aranges      5048           0
.debug_pubnames    15278           0
.debug_info        76211           0
.debug_abbrev      13582           0
.debug_line        28193           0
.debug_frame       18532           0
.debug_str         25133           0
.debug_loc         51625           0
.debug_ranges       5176           0
.ARM.attributes       49           0
Total             311325


Mit meinen Debugs:

section             size        addr
.text              59468   134217728
.ARM.exidx             8   134277196
.rodata             6768   134277208
.data               1904   536870912
.bss                 568   536872816
._usrstack          4096   536873384
.comment            1470           0
.debug_aranges      5064           0
.debug_pubnames    15322           0
.debug_info        76297           0
.debug_abbrev      13582           0
.debug_line        28322           0
.debug_frame       18564           0
.debug_str         25169           0
.debug_loc         51696           0
.debug_ranges       5192           0
.ARM.attributes       49           0
Total             313539


Wo läuft das was über? Bin ziemlich verzweifelt...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Florian Micro schrieb:

> Den Stack habe ich von 1024 Byte auf 8192 Byte angehoben ohne jegliche
> Änderung. Jetzt ist er auf 4096 Byte.

Bei ARMs vergessen manche die Interrupt-Stacks. Die meinte ich.

Autor: Florian Micro (micro-flo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss man die Interrupt-Stacks noch definieren oder initialisieren?

Ich habe die startup Datei nochmal kontrolliert und korrigiert.
Das Linkerskript scheint ok.

Der Fehler bleibt...
Ich kann zwar die Zeilen auskommentieren, wo der ARM abstürzt, aber dann 
stürzt er einfach ein bisschen später ab.
Er springt in den Default_Handler.

Eine konkrete Stelle wo er abstürzt:
char Text[30] = " ";
sprintf(Text, "Bat: %0.1f", Battery);

Kommentiere ich das aus, stürzt er beim nächsten sprintf mit %f ab.
Andere sprintf mit %i dazwischen funktionieren.
sprintf(Name, "Temp: %i   ", Temp);

Was ist da anders? Wird da ein bestimmtes Register oder besonders viel 
Speicher benutzt?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Florian Micro schrieb:

> Muss man die Interrupt-Stacks noch definieren oder initialisieren?

Sorry, ich war grad beim falschen Controller. Ist ein Standardfehler bei 
den ARM7 aber nicht beim STM32.

Bei dem wär's hilfreich, wenn du erfährst, welche Exception ausgelöst 
wurde (Default_Handler ist nicht hilfreich). Und anhand der 
Steuerregister vom Core rauskriegst, welcher Zugriff d.h. welche Adresse 
das war.

Autor: Florian Micro (micro-flo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe jetzt folgende Handler noch implementiert:
MemManage_Handler
BusFault_Handler
UsageFault_Handler

Dann einen Breakpoint auf die Stelle gesetzt, wo er abstürzt und mit 
Single Step rein.

OpenOCD zeigt dann das an:
target halted due to breakpoint, current mode: Thread 
xPSR: 0x01000000 pc: 0x080069bc msp: 0x20008000
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
Error: SWJ-DP STICKY ERROR
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
Error: SWJ-DP STICKY ERROR
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
Warn : Block read error address 0xfffffff8, count 0x1
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
Error: SWJ-DP STICKY ERROR
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
Error: SWJ-DP STICKY ERROR
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
Warn : Block read error address 0xfffffff8, count 0x1

Das ist der Registerinhalt:
Main  
  r0  536903366  
  r1  4294967295  
  r2  1  
  r3  0  
  r4  1  
  r5  536903366  
  r6  1  
  r7  536902972  
  r8  1  
  r9  4294967295  
  r10  536903052  
  r11  536903148  
  r12  4294967295  
  sp  0x20007c4c  
  lr  4294967289  
  pc  0x08000081  
  f0  0  
  f1  0  
  f2  0  
  f3  0  
  f4  0  
  f5  0  
  f6  0  
  f7  0  
  fps  0  
  cpsr  1627389989  

Hilft das weiter?
Lese gerade was von data_abort exception. Aber das R14 habe ich nicht 
und ich weiß auch nicht, ob data_abort bei mir auftritt?

Autor: Florian Micro (micro-flo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Register im Breakpoint vor Absturz
Main  
  r0  80  
  r1  117  
  r2  2  
  r3  117  
  r4  536903360  
  r5  2  
  r6  536873120  
  r7  536871640  
  r8  255  
  r9  5  
  r10  7  
  r11  1  
  r12  16843009  
  sp  0x20007e78  
  lr  134229227  
  pc  0x08004151  
  f0  0  
  f1  0  
  f2  0  
  f3  0  
  f4  0  
  f5  0  
  f6  0  
  f7  0  
  fps  0  
  cpsr  1627389984  

Register wenn im BusFault_Handler
Main  
  r0  536903366  
  r1  4294967295  
  r2  1  
  r3  0  
  r4  1  
  r5  536903366  
  r6  1  
  r7  536902972  
  r8  1  
  r9  4294967295  
  r10  536903052  
  r11  536903148  
  r12  4294967295  
  sp  0x20007c4c  
  lr  4294967289  
  pc  0x08000081  
  f0  0  
  f1  0  
  f2  0  
  f3  0  
  f4  0  
  f5  0  
  f6  0  
  f7  0  
  fps  0  
  cpsr  1627389989  

Disassemble der "Absturzstelle"
0x08004150 <BuildText+680>: ldr     r3, [pc, #156]  ; (0x80041f0 <BuildText+840>)
0x08004152 <BuildText+682>: ldr     r1, [pc, #160]  ; (0x80041f4 <BuildText+844>)
0x08004154 <BuildText+684>: ldrd    r2, r3, [r3]
0x08004158 <BuildText+688>: mov     r0, r4
0x0800415a <BuildText+690>: bl      0x8009560 <sprintf>
0x0800415e <BuildText+694>: mov     r0, r4
0x08004160 <BuildText+696>: movs    r1, #9
0x08004162 <BuildText+698>: ldr     r2, [pc, #92]  ; (0x80041c0 <BuildText+792>)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geh diesen Teil mal auf Maschinenebene Schritt für Schritt durch.

Autor: Florian Micro (micro-flo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Scheint so, dass ich den Fehler gefunden habe :)
Keine Abstürze mehr und das Teil startet auch nach Stromreset neu.

Vielen Dank fürs Helfen! Hab wieder viel gelernt :)

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und?

Autor: Florian Micro (micro-flo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab viel über die Exceptions und Fault Handler gelesen.
Der BusFault kommt wohl nur, wenn etwas mit dem Speicher nicht stimmt.
Also bin ich das Linkerskript nochmal durch. Das war ok.
Aber ich benutze emuliertes Eeprom, das hinten im Flash liegt. Wird zwar 
auch im Linkerskript definiert, aber nochmal in der eeprom.h!
Und da liegt das standardmäßig bei 64k.
Jetzt hat mein Programm wohl die 64k geknackt und sich damit mit dem 
Eeprom überschnitten.
Das Eeprom liegt jetzt bei 124k (mein STM32 hat 2kb Pages und 2 braucht 
man fürs Eeprom, also 4k).

Für mich ist das total nachvollziehbar.
Durch das auskommentieren der Debug-Meldungen wurde mein Programm 
kleiner und hat damit nicht mehr im Eeeprom Bereich gewildert (bzw. 
andersrum).


>Geh diesen Teil mal auf Maschinenebene Schritt für Schritt durch.
Wir kann ich das machen in Eclipse? Step into? Da ist er bei mir sofort 
in den FaultHandler.


Meine Definition für das Eeeprom sieht im Linkerskript jetzt so aus:
>EEMUL    (RWX) : ORIGIN = 0x08000000+128K-4K, LENGTH = 4K
Kann ich darauf aus meiner Header oder C-Datei irgendwie zugreifen?
Dann muss man nicht an zwei Stellen ändern.

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.