Forum: Compiler & IDEs STM32 Speicherproblem?


von Florian M. (micro-flo)


Angehängte Dateien:

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:
1
void u_putchar(char c) {
2
  // Loop until USART1 DR register is empty
3
  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET) {
4
    ;
5
  }
6
  USART_SendData(USART1, c);
7
}
8
9
void uputs(const char *c) {
10
  while(*c) u_putchar(*c++);  // send string char by char
11
}
12
13
#ifdef T_DEBUG
14
  uputs("START\r\n");
15
#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 :)

von Arne (Gast)


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.

von Wayne (Gast)


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

von (prx) A. K. (prx)


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.

von Wayne (Gast)


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?

von (prx) A. K. (prx)


Lesenswert?

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

von Julian (Gast)


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)

von Wayne (Gast)


Lesenswert?

Ok, wieder was dazu gelernt.

Bleibt die Frage was im String drine steht.

von (prx) A. K. (prx)


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.

von Florian M. (micro-flo)


Lesenswert?

Die Debug Texte mache ich teilweise statisch so:
1
uputs("START\r\n");

oder dynamisch so:
1
char data[40];
2
sprintf(data, "address: %i, value: %i\r\n", address, value);
3
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...

von (prx) A. K. (prx)


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.

von Florian M. (micro-flo)


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:
1
char Text[30] = " ";
2
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.
1
sprintf(Name, "Temp: %i   ", Temp);

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

von (prx) A. K. (prx)


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.

von Florian M. (micro-flo)


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:
1
target halted due to breakpoint, current mode: Thread 
2
xPSR: 0x01000000 pc: 0x080069bc msp: 0x20008000
3
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
4
Error: SWJ-DP STICKY ERROR
5
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
6
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
7
Error: SWJ-DP STICKY ERROR
8
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
9
Warn : Block read error address 0xfffffff8, count 0x1
10
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
11
Error: SWJ-DP STICKY ERROR
12
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
13
Error: AHBAP Cached values: dp_select 0x0, ap_csw 0xa2000012, ap_tar 0xffffffff
14
Error: SWJ-DP STICKY ERROR
15
Error: Read MEM_AP_CSW 0x23000052, MEM_AP_TAR 0xfffffffc
16
Warn : Block read error address 0xfffffff8, count 0x1

Das ist der Registerinhalt:
1
Main  
2
  r0  536903366  
3
  r1  4294967295  
4
  r2  1  
5
  r3  0  
6
  r4  1  
7
  r5  536903366  
8
  r6  1  
9
  r7  536902972  
10
  r8  1  
11
  r9  4294967295  
12
  r10  536903052  
13
  r11  536903148  
14
  r12  4294967295  
15
  sp  0x20007c4c  
16
  lr  4294967289  
17
  pc  0x08000081  
18
  f0  0  
19
  f1  0  
20
  f2  0  
21
  f3  0  
22
  f4  0  
23
  f5  0  
24
  f6  0  
25
  f7  0  
26
  fps  0  
27
  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?

von Florian M. (micro-flo)


Lesenswert?

Register im Breakpoint vor Absturz
1
Main  
2
  r0  80  
3
  r1  117  
4
  r2  2  
5
  r3  117  
6
  r4  536903360  
7
  r5  2  
8
  r6  536873120  
9
  r7  536871640  
10
  r8  255  
11
  r9  5  
12
  r10  7  
13
  r11  1  
14
  r12  16843009  
15
  sp  0x20007e78  
16
  lr  134229227  
17
  pc  0x08004151  
18
  f0  0  
19
  f1  0  
20
  f2  0  
21
  f3  0  
22
  f4  0  
23
  f5  0  
24
  f6  0  
25
  f7  0  
26
  fps  0  
27
  cpsr  1627389984

Register wenn im BusFault_Handler
1
Main  
2
  r0  536903366  
3
  r1  4294967295  
4
  r2  1  
5
  r3  0  
6
  r4  1  
7
  r5  536903366  
8
  r6  1  
9
  r7  536902972  
10
  r8  1  
11
  r9  4294967295  
12
  r10  536903052  
13
  r11  536903148  
14
  r12  4294967295  
15
  sp  0x20007c4c  
16
  lr  4294967289  
17
  pc  0x08000081  
18
  f0  0  
19
  f1  0  
20
  f2  0  
21
  f3  0  
22
  f4  0  
23
  f5  0  
24
  f6  0  
25
  f7  0  
26
  fps  0  
27
  cpsr  1627389989

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

von (prx) A. K. (prx)


Lesenswert?

Geh diesen Teil mal auf Maschinenebene Schritt für Schritt durch.

von Florian M. (micro-flo)


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

von (prx) A. K. (prx)


Lesenswert?

Und?

von Florian M. (micro-flo)


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.

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.