Hi,
ich entwickle gerade ein Programm für einen STM32F407VG unter Verwendung
von C++.
Hierfür nutze ich eine selbst kompilierte GCC Toolchain mit der newlib.
So weit funktioniert alles. Das Problem was ich habe kam, als ich
festgestellt habe, dass die Konstruktoren von globalen Variablen nicht
aufgerufen werden, also z.B.:
1
ColorcolorBlack(0x00,0x00,0x00);
Also habe ich ein bisschen gesucht und irgendwann gemerkt, dass in
meiner startup Assembler Datei kein Aufruf von __libc_init_array
erfolgte.
Also kurzerhand hinzugefügt:
1
[....]
2
/*enable fpu begin*/
3
ldr r0, =0xe000ed88 /*; enable cp10,cp11 */
4
ldr r1,[r0]
5
ldr r2, =0xf00000
6
orr r1,r1,r2
7
str r1,[r0]
8
/*enable fpu end*/
9
10
/* Call the clock system intitialization function.*/
11
bl SystemInit
12
13
/* Call static constructors */
14
bl __libc_init_array
15
/* Call the application's entry point.*/
16
bl main
17
bx lr
In der Linker-Datei sind die Definitionen für __preinit_array_start/end,
__init_array_start/end und __fini_array_start/end enthalten.
Das Problem was ich nun habe, ist, dass der Code zwar ohne Probleme
kompiliert, der STM32 aber (beim Durchsteppen mit dem Debugger) beim
Jump nach __libc_init_array in den HardFault_Handler springt (kurzzeitig
sah es auch mal danach aus, dass es der BusFault_Handler wäre, hier bin
ich mir nicht sicher).
Hat schonmal jemand eine solche Sache gehabt?
Liegt das eher an meiner Toolchain oder eher an meinem Code? Ich habe es
zwischenzeitlich mal mit der Sourcery CodeBench Toolchain kompiliert,
hier war das gleiche, insofern hatte ich die Toolchain erstmal
ausgeschlossen...
Ich wäre um Tipps sehr dankbar.
Vielen Dank und
MfG
Nils
Die waren eigentlich nur zum Verdeutlichen meiner Aussagen gedacht :)
Ich weiß nicht so recht, wie ich das Problem eingrenzen soll, daher habe
ich nicht mehr Code angehängt.
Das hole ich hiermit nach.
Vielen Dank und
MfG
Unter der folgenden URL findest Du ein Assembler-Startup, welcher es
"direkt" erledigt. Der relevante Teil ist bei mir mit stm32f407 im
Einsatz:
http://tech.munts.com/MCU/Frameworks/ARM/stm32f4/stm32f407vg.S
Für stm32f100 verwende ich einen C-Startup mit einer "abgespeckten"
__libc_init_array - Variante: Den Aufruf von _init() habe ich daraus
entfernt.
Beides funktioniert.
Warum der Aufruf von __libc_init_array bei Dir aus Assembler heraus
nicht funktioniert, kann ich nicht sagen.
Schau dir mal die Adresstabellen an, die bei __[pre]init_array_start
anfangen. Ob das korrekte adressierte und als Thumb-Code getaggte
Pointer sind.
Was man gerne falsch macht: Die Reihenfolge von Konstruktoraufrufen ist
undefiniert, auch fehlen da noch diverse andere Initialisierungen. Man
sollte also gut aufpassen, was man in Konstruktoren reinschreibt. Viel
mehr als Initialisierungen von Instanzvariablen sollte das nicht sein.
Statt den Startup-Code zu hacken kannst du diese Funktion ebenso gut am
Anfang von main() aufrufen.
Hallo,
vielen Dank für die Antworten.
@Roland H.
- Mit dem RTOS wollte ich grade ein wenig rumspielen, das ist
rausgeflogen zur Sicherheit, daran lags aber nicht.
- Vielen Dank für den Link, leider funktioniert es damit auch nicht.
Welchen Assembler verwendest du denn? Mein gcc-as meckert da schon über
die Kommentare ^^
@A.K.
Nachdem ich so weit alle globalen Sachen rausgenommen hatte (alle für
die ein selbstgeschrieber Konstruktor von nöten wäre), sind in dem Array
2 Einträge.
Wie finde ich denn heraus, ob es korrekt getaggte Thumb-Pointer sind?
Der eine Eintrag zeigt auf die Funktion frame_dummy.
Der andere ist ein wenig komisch:
Er zeigt auf die Adresse 0x08001551. Da gibt es aber nichts. Das fällt
rein prinzipiell in eine Funktion "_GLOBAL__sub_I_andale_mono" die an
Adresse 0x08001550 liegt (andale_mono ist ein globales uint8_t Array in
dem eine meiner Fonts liegt):
Wie man sieht wird hier die Adresse 0x08001551 "übersprungen". Dass das
für mich falsch aussieht, kann aber auch daran liegen, dass ich keine
Erfahrung mit der Art von Fehlersuche und Disassemblierungen habe.
Ich habe mittlerweile das ganze mal weiter geführt, indem ich am Anfang
meiner main Funktion folgendes mache:
Auf gut Deutsch, ich gehe manuell durch das Array von Konstruktoren und
rufe jeden einzelnen auf.
Folgendes passiert: Die zwei Einträge werden richtig gezählt, er läuft
in die Schleife und sichert sich die Adresse der ersten Funktion
(frame_dummy). Dann springt er per bx dort hin. So weit funktioniert
alles. Sobald aber die erste Instruktion dieser Funktion ausgeführt wird
(push {r3, lr}) springt er in den HardFault_Handler.
Nebenbei: Ich hatte zwischenzeitlich testweise ein paar globale
Klasseninstanzen mit Konstruktor erzeugt. Hier hatte ich komischerweise
keine Änderung an dem init_array (auch nicht mit explizitem extern vor
den Variablen).
Hat jemand noch eine Idee?
Vielen Dank
PS: Die newlib hat laut
http://newlib.sourcearchive.com/documentation/1.14.0/init_8c-source.html
einen Aufruf an _init() vor dem Konstruktoren Aufruf. Wenn ich den mit
rein nehme, springt er hier schon in den HardFault_Handler. Hier führt
er nicht mal den Sprung aus.
> Wie finde ich denn heraus, ob es korrekt getaggte Thumb-Pointer sind?
Das letzte Bit muss gesetzt sein, d.h. die Addresse ist immer ungrade.
Sonst ist es kein Thumb Pointer, sondern einer für den ARM Modus, den
der Cortex M3 nicht kennt und dann einen (Usage?) Fault erzeugt.
> Wie man sieht wird hier die Adresse 0x08001551 "übersprungen".
NACK. Das niederwertigste Bit wird ausmaskiert, da es den Prozessormodus
vorgibt, s.o. Man sollte sich schon die Doku zum Prozessor Core
anschauen, wenn man Disassembler Listings verstehen will. Die Addresse
des tatsächlich ausgeführten Codes ist also korrekt "0x08001550". Nur
darf man die wie oben erwähnt nicht ohne das unterste Bit in das PC
Register laden.
Jim Meba schrieb:>> Wie finde ich denn heraus, ob es korrekt getaggte Thumb-Pointer sind?>> Das letzte Bit muss gesetzt sein, d.h. die Addresse ist immer ungrade.> Sonst ist es kein Thumb Pointer, sondern einer für den ARM Modus, den> der Cortex M3 nicht kennt und dann einen (Usage?) Fault erzeugt.>>> Wie man sieht wird hier die Adresse 0x08001551 "übersprungen".>> NACK. Das niederwertigste Bit wird ausmaskiert, da es den Prozessormodus> vorgibt, s.o. Man sollte sich schon die Doku zum Prozessor Core> anschauen, wenn man Disassembler Listings verstehen will. Die Addresse> des tatsächlich ausgeführten Codes ist also korrekt "0x08001550". Nur> darf man die wie oben erwähnt nicht ohne das unterste Bit in das PC> Register laden.
Und wieder was dazu gelernt, vielen Dank :)
Nur damit ich das richtig verstehe: Die Adresse der ersten Funktion
(frame_dummy) im init_array ist "0x080001c8", d.h. es ist Code für den
ARM Modus und nicht Thumb-Modus Code? Was dann mein Problem erklären
dürfte?
Vielen Dank
Nils Hesse schrieb:> Nur damit ich das richtig verstehe: Die Adresse der ersten Funktion> (frame_dummy) im init_array ist "0x080001c8", d.h. es ist Code für den> ARM Modus und nicht Thumb-Modus Code? Was dann mein Problem erklären> dürfte?
Ja, das dürfte es. Wenn Bit 0 des Pointers nicht gesetzt ist, dann kann
der Prozessor das nicht ausführen und landet auf einem Fault. Wurde
dieser Code versehentlich für ARM-Modus übersetzt?