Hallo Forum,
ich habe auf einem STM32F103 das Problem, dass nach einer Vector Table
Relocation keine Interrupte mehr auslösen.
Um diesem Fehler zu ergründen, habe ich mit der aktuellen STM32CubeMX
eine Testapplikation erstellt, die nur Systick und Timer2 bedient und
einen IR auslösen kann.
Die ISR von Timer2 inkrementiert eine Variable je um eins.
Diese Applikation läuft ohne Probleme wenn...
...sie ohne VT Offset läuft,
...sie mit VT Offset läuft, die vorgannte Variante aber zuvor nicht aus
dem Flash gelöscht wurde.
Wenn jedoch der Flash zuerst gelöscht und dann aufgespielt wird, lösen
die IR nicht mehr aus.
Ich habe die betreffenden Register zwischen funktionierender und nicht
funktionierender Applikation verglichen...SETENA, CLRENA sind gesetzt
für Timer2.
PRIMASK, BASEPRI, FAULTMASK sind 0, das ist auch OK.
VTOR berücksichtigt den Offset 0x5000, also auch OK.
Allerdings habe ich bei Programmstop SCB->ICSR einen Unterschied
feststellen. VECTACTIVE ist dort 0x3. Nach Doku wäre das IR 3-16=-13,
der gerade aktiv ist. Was für ein Interrupt ist das? Wäre das Hardfault?
Mir fehlt da an der Stelle ein bisschen der Ansatz. Kann mir jemand vllt
einen Hinweis geben...?
Gruß
Es reicht nicht den Code an anderer Stelle im Flash abzulegen und den
Zeiger auf die Vektortabelle anzupassen. Am Anfang des Flash muss
zusätzlich eigener Code (ein Jump oder eine geeignete VT) stehen, der
die Code-Ausführung an das Programm weiter gibt.
(Habe lange keine STMs mehr programmiert. Hoffentlich verwechsel ich da
nichts.)
Ich meine schon. Der STM32 startet doch immer bei 0x08000000. Oder
nicht?
Wenn das Programm bei 0x08005000 liegt, dann fehlt noch ein zweites
Programm bei 0x08000000, welches den Sprung macht. In EMBlocks habe ich
jedenfalls (aus welchen Gründen auch immer) so gemacht. Truestudio habe
ich nie verwendet.
BrilleAuf schrieb:> # Reconfig vector table offset reg to match pp location> set *0xe000ed08 = 0x5000>> # Get app stackpointer> set $sp = *(unsigned int*)0x5000>> # Get app entry point> set $pc = *(unsigned int*)0x5004
Ich kenne TreuStudio nicht, aber muesste es da nicht 0x08005000 und
0x08005004 heissen?
Jump schrieb:> Ich meine schon. Der STM32 startet doch immer bei 0x08000000. Oder> nicht?
Glaube ich auch
Wo befindet sich der Code deines Startup scripts? du könntest im Linker
Script noch eine section von 0x08000000 bis 0x08005000 definieren in die
du den startup code legst, der dann entweder gleich alles dort macht
oder einfach zum echten startup code auf 0x08005000 springt
Darth Moan schrieb:> Ich kenne TreuStudio nicht, aber muesste es da nicht 0x08005000 und> 0x08005004 heissen?
Soweit ich weiß bootet der stm32 immer von 0x0, aber remapped
unterschiedlichen speicher dorthin, je nach gesetzten boot pins, also
ist bei normalem boot mode 0x8000000 und 0x0 der gleiche Speicher.
Er verwendet aber ein start script im TrueStudio, das VTOR, SP und PC
explizit setzt. siehe oben.
Die SystemInit will doch auch die 'ganze' Adresse ins VTOR schreiben:
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in
Internal FLASH */
Er setzt da aber nur 0x5000 rein.
Ich mutmasse jetzt natürlich, dass er später ab 0x08000000 eine
Bootloader
einfügen möchte. Aber jetzt mit TrueStudion nur die Applikation testen
will.
Ist natürlich etwas viel gemutmasst.
Da CubeMX im Spiel ist, wird vermutlich HAL benutzt.
In der HAL Lib gibt es ein Beispiel IAP_Binary_Template das von
IAP_Main(Bootloader) aufgerufen wird.
Brauchst davon nur den else Zweig:
1
/* Jump to user application */
Irgendwie muss er aber schon wissen wohin der Sprung gehen soll.
Darth Moan schrieb:> Ich mutmasse jetzt natürlich, dass er später ab 0x08000000 eine> Bootloader> einfügen möchte. Aber jetzt mit TrueStudion nur die Applikation testen> will.
Dann wäre es am einfachsten schon jetzt eine bootloader section
einzubauen und dort nur einen jump zur application machen. Sollte dann
evtl funktionieren.
Ich entwickle meine Programme immer bei 0x08010000. Erst das Release
wird für 0x08000000 kompiliert. Grund: Es kommt vor, dass ich zigtausend
Flashvorgänge bis zum Release brauche. Auf diese Weise lässt selbst ein
STMF030 (erlaubt wären dort nur 1000 Zyklen) mit gutem Gewissen
debuggen.
Möglicherweise wusste ich nicht wie man eine "bootloader section"
erstellt und habe mir deshalb mit einem zweiten Programm geholfen. Das
zweite Programm müsste nur einmalig als Starterprogramm nach 0x08000000
geflasht werden. Für "BrilleAuf" könnte es so aussehen:
Alex D. schrieb:> Dann wäre es am einfachsten schon jetzt eine bootloader section> einzubauen und dort nur einen jump zur application machen. Sollte dann> evtl funktionieren.
Auch wenn er explizit 0x5000 ins VTOR schreibt?
BrilleAuf schrieb:> Target Software Startup Script anpassen (Truestudio):> ...> # Reconfig vector table offset reg to match pp location> set *0xe000ed08 = 0x5000
Wie gesagt, TrueStudio hab ich nicht.
Also eigentlich bin ich ja auch der Meinung, es ist besser, sofort ein
Bootloader-Placebo zu benutzen.
Dann kann man auch gleich testen ob es ohne Debugger startet.
Man weiss ja nicht so genau, was die da sonst noch so alles
initialisieren.
Darth Moan schrieb:> Auch wenn er explizit 0x5000 ins VTOR schreibt?
Denke schon, habe auch mal schnell mit einem Debugger getestet: bei
normalem boot (boot0 == 0 && boot1 == 0) wird 0x8000000 auf 0x0
remapped, das heißt auf 0x5000 ist der gleiche speicher wie auf
0x8005000. Ist vielleicht nicht der beste Stil und ziemlich verwirrend,
aber sollte (denke ich) funktionieren.
Es kann doch VTOR nur per -Programm- beschrieben werden. Der Start ist
dann aber schon geschehen. Die Startadresse in der Vektortabelle wird
also nicht mehr berücksichtigt. Das heisst, es muss -vorher- für
passende Daten bei 0x08000000 (eine VT evtl. mit Code) für den Sprung
zum Programm gesorgt werden. Entweder per zweites Programm oder Einträge
im Linkerskript evtl. automatisch generiert infolge eines
Häkchens/Befehls in Truestudio.
"BrilleAuf" hat das Problem vermutlich schon gelöst.
Du musst zunächst einen Dummy-Bootloader (oder auch schon den echten
Bootloader) flashen der
* Sicherstellt dass jetzt kein Interrupt mehr kommt
* VTOR umbiegt
* Den Stackpointer mit dem Inhalt von 0x8005000 lädt
* Den Programcounter mit dem Inhalt von 0x8005004 lädt
Beispiel aus meinem CAN-Bootloader:
(APP_START ist bei mir ein makro das die Adresse der verschobenen
Vektortabelle enthält und beispielhaft deinitialisiere ich hier eine im
Bootloader benutzte Hardware die ansonsten weiter lustig Interrupts
generiert hätte)
1
/**
2
* Prepare everything for running the application and jump
3
* to its entry point.
4
*/
5
voidjump_app(void){
6
/*
7
* de-initialize all interrupt using hardware
8
* because we are going to relocate the vector
9
* table now and MUST NOT cause any IRQ anymore
10
*/
11
flexcan_deinit();
12
13
// relocate the vector table and simulate reset
14
SCB->VTOR=APP_START;
15
asm(" ldr r1, [%0,#0] \n\t"
16
" ldr r2, [%0,#4] \n\t"
17
" mov sp, r1 \n\t"
18
" mov pc, r2 \n\t"
19
::"r"(APP_START)
20
);
21
}
Du machst also entweder nen Dummy-Bootloader oder nen echten Bootloader
der nach einem Reset oder nach dem Einschalten zügig das obige macht und
flasht den nach 0x8000000
Von dem Moment an kannst Du Deine für 0x8005000 gelinkte Anwendung ganz
normal in der IDE laden und debuggen so oft Du willst, nur kein chip
erase machen sonst ist der Bootloader wieder weg.
Deaktiviere falls vorhanden auch jegliche flash security in Deinem
Bootloader (setze im Bootloader nicht die Lockbits wie sonst üblich bei
kommerziellen Projekten) sonst schlägt der Bootloader beim ersten Start
die Tür hinter sich zu und schließt zweimal ab und es wird nichts mit
debuggen.
Man braucht kein komplettes Programm, man muss lediglich dafür sorgen,
dass der Reset-Vektor an 0x0800004 die richtige Adresse (hier:
0x08005000) beinhaltet. Stackpointer-Initialwert auch an 0x08000000
eintragen. Dann klappts auch mit dem Starten eine Applikation an
beliebiger Stelle im Speicher.
Marvin M schrieb:> Man braucht kein komplettes Programm, man muss lediglich dafür sorgen,
Bist du sicher?
Ich habe das gerade mit einem BluePill Board probiert und es klappt
nicht.
Mein vorgehen:
1
1. in CubeMX normales Projekt angelegt, PC13 ist LD1
2
2. SW4STM32 Projekt erzeugt
3
3. in der main.c LD1 Blinky eingebaut
4
3.1. in der system_stm32f1xx.c -> #define VECT_TAB_OFFSET 0x00005000U
Darth Moan schrieb:> Er verwendet aber ein start script im TrueStudio, das VTOR, SP und PC> explizit setzt. siehe oben.>> Die SystemInit will doch auch die 'ganze' Adresse ins VTOR schreiben:> SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in> Internal FLASH */>> Er setzt da aber nur 0x5000 rein.
Ja, aber im VTOR steht dann 0x8005000. Es geht ja hier nur um vereiste
ISR. Die App würde sonst nicht laufen.
Darth Moan schrieb:> Ich mutmasse jetzt natürlich, dass er später ab 0x08000000 eine> Bootloader> einfügen möchte. Aber jetzt mit TrueStudion nur die Applikation testen> will.> Ist natürlich etwas viel gemutmasst.
Liegst aber schon ganz richtig. Deshalb eine
Grüne-Wiese-Testapplikation.
Ein ähnliches Problem habe ich auch, wenn ich Applikationen testweise
ins RAM lade und dort starte. Auch wenn ich VTOR setze, werden
(scheinbar) keine INTs ausgelöst. Woran es wirklich liegt, habe ich aber
nicht herausgefunden.
Jörg
pegel schrieb:> Hänge mal deine fertige hex an, dann versuche ich zu vergleichen.
Ich habe das Gefühl, dass Pegel hier schon auf dem richtigen Weg ist.
Das sind jetzt zwei Varianten. eine ohne VT Offset und ein mit VT Offset
0x5000.
Auf den ersten Blick sieht das gut aus.
Alle Int. Vectoren sind um 0x00005000 versetzt, so wie es sein muss.
Der Tim2 Interrupt an 0x080050B0 ist vermutlich auch richtig belegt.
Es ist nicht ein fehlendes volatile oder so etwas in der Art, oder?
Man kann in der Hauptschleife mit dem Debugger stoppen. Dann sehe
ich,dass Systick und Timerwerte erhöht wurden. Die funktionieren, denke
ich.
Was ich wirklich nicht sicher klären kann ist, warum der aktuelle IR 0x3
sein soll und was das bedeutet. Man kann das z.B. aus xPSR lesen...Man
muss dort noch 16 abziehen, also 3-16=-13 :-\
Scheint vllt so zu sein, dass dieser IR alles blockiert...
BrilleAuf schrieb:> Liegst aber schon ganz richtig. Deshalb eine> Grüne-Wiese-Testapplikation.
Es soll also einen Bootloader geben. Gibt es den?
In "TestISR.VTOR_5k.hex" ist nichts für den Startbereich (ersten 8 Bytes
von 0x0800000) definiert. Solange Du diesen nicht definierst (Bootloader
oder Linkerskript), wird das Laufverhalten definitiv undefiniert sein!
Es ist daher fraglich was du da debuggst.
OK.
für diesen Test gibt es aktuell keinen BL. Ich probiere hier alles ohne.
Im Linkerfile gibt es genau eine Anpassung:
…
MEMORY
{
FLASH (rx) : ORIGIN = 0x08005000, LENGTH = 108K // <-HIER
angepasst
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
}
…
Kann es sein, dass der MSP hier noch her muss? :-|
Moin,
BrilleAuf schrieb:> Was ich wirklich nicht sicher klären kann ist, warum der aktuelle IR 0x3> sein soll und was das bedeutet. Man kann das z.B. aus xPSR lesen...Man> muss dort noch 16 abziehen, also 3-16=-13 :-\
Na wenn ich mich nicht verzähle müsste das ja dann der Hard Fault sein.
Wenn also aus irgendeinem Grund der Debugger an Adresse 0x5000 nicht das
selbe liest, wie an 0x08005000 dann könnte er ziemlich bald in den Hard
Fault wollen.
Wenn der Vector, den er zu lesen glaubt aber illegal ist, was dann?
Hattest du mal versucht die set Anweisungen mit 0x08005000 und
0x08005004
auszuführen?
Kannst du dann den Startup code single steppen?
So ein Verhalten hatte ich nur mal als der Hard Fault versehentlich
mitten
ins Programm gezeigt hatte. Der wurde angesprungen, und alles unterhalb
war damit blockiert. Ich lief dann irgendwann auf meinen BP, aber eben
nur zufällig.
Darth Moan schrieb:> Na wenn ich mich nicht verzähle müsste das ja dann der Hard Fault sein.
Ohne Bootloader wäre das eigentlich nicht unerwartet.
BrilleAuf schrieb:> Kann es sein, dass der MSP hier noch her muss? :-|
Zur Zeit wird zwar der neue Code geflasht, der aktive ist aber
irgendwas. Dein Linkerskript hat zur Zeit keine oder keine passenden
Einträge, da im Hex-File nichts für 0x08000000 definiert ist.
Das Anpassen des Linkerskripts (etwas Code ist auch nötig) wäre zwar
weniger Arbeit, ist aber deutlich schwerer (viele Fehlerquellen ->
dauert länger). Da du sowieso einen Bootloader verwenden willst, würde
ich an deiner Stelle eher das tun. Du bräuchtes dann ein zweites
Projekt. Beispiel für main.c vom Bootloader:
pMainApp();// ist eigentlich ein Call statt Jump, aber egal
14
return0;
15
}
Da evtl. nach dem Bootloader noch irgendwo falsche Werte für VTOR
gesetzt werden, füge bitte zu Testzwecken in deiner main.c vom
Hauptprogramm eine erneute Zuweisung der Vektortabelle durch:
Ich hatte mich auch schon gefragt, ob ich mich verzählt habe. Scheint
theoretisch wirklich der Hardfault zu sein. Schön, das es einer
verifiziert hat.
Die Zusammenhänge erscheinen mir aber komisch. Das fehlt irgendwas :-(
Muss ich mal am WE drüber nachdenken...
Danke an alle für die bisherigen Infos!
BrilleAuf schrieb:> Die Zusammenhänge erscheinen mir aber komisch. Das fehlt irgendwas :-(
Warum "komisch"???
Da wird irgendwas ausgeführt, da der Bootloader fehlt. Erstelle erst
einen Bootloader!
Äh, mal ne doofe Frage, muss das Start Script SP setzen oder MSP?
Macht TrueStudio da einen Unterschied?
> set $pc = *(unsigned int*)0x5004Jump schrieb:> __set_MSP
Jump schrieb:> Warum "komisch"???>> Da wird irgendwas ausgeführt, da der Bootloader fehlt. Erstelle erst> einen Bootloader!
Er setzt im Debugger explizit den PC auf seinen Applikations-Einstieg
und
lässt dann den Core loslaufen. Wenn der Debugger richtig funktioniert,
wovon ich ausgehe, sollte er nicht erst den Core durch den Reset
schicken.
Aber wer weiss.
Daher die Frage nach dem Steppen.
Jump schrieb:>> Er setzt im Debugger explizit den PC auf seinen Applikations-Einstieg>> und> Wirklich? Hat er das geschrieben?BrilleAuf schrieb:> Target Software Startup Script anpassen (Truestudio):> ...> # Get app entry point> set $pc = *(unsigned int*)0x5004
Also ich interpretiere das TrueStudio Start Script genau so.
Aber ich habe TrueStudio nicht, also erstmal nur Vermutung.
Vielleicht sollte ich TrueStudio mal ausprobieren.
Ok, er hat es wirklich geschrieben. Das "Startup Script" betrifft also
den Debugger und nicht wie ich glaubte den Compiler/Linker. Es sollte
dann eigentlich ohne Bootloader laufen.
Im "Startup Script" setzt er VTOR, Stackpointer und Entry point. Das
sieht alles richtig aus. Aber - möglicherweise wird VTOR beim Startup
seines Programms (EntryPoint bis main.c) unbewusst verändert (bei
"EmBlocks" würde das nämlich in SystemInit() passieren). Man könnte
einen Breakpoint in der main.c setzen und prüfen, ob VTOR (*0xe000ed08)
tatsächlich noch 0x08005000 ist.
Jump schrieb:> (bei> "EmBlocks" würde das nämlich in SystemInit() passieren)
EmBlocks ist eine IDE, was hat die damit zu tun was der OP in seiner
SystemInit macht?
Ich verstehe nicht was der Zirkus soll. Flash doch einfach schonmal den
Bootloader drauf, danach wird sich die verschoben gelinkte Firmware ganz
normal debuggen lassen. Der Bootloader wird dafür sorgen daß alles
richtig ist bevor er sie anspringt.
Bernd K. schrieb:> EmBlocks ist eine IDE, was hat die damit zu tun was der OP in seiner> SystemInit macht?
Bei EmBlocks wird beim Anlegen eines Standardprojekts Code
zusammengestellt. Die SystemInit() steht in der Datei
"system_stm32f10x.c". Als Autor wird "MCD Application Team" genannt. Der
Code kann bei allen IDE's laufen, muss aber nicht (z.B. geht auch reines
ASM).
Bernd K. schrieb:> Ich verstehe nicht was der Zirkus soll. Flash doch einfach schonmal den> Bootloader drauf, danach...
Nein. Wenn über Debugger (richtig) gestartet, dann braucht man den
Bootloader nicht. Dort liegt nicht das Problem. (Ich selber würde es
aber auch über den Bootloader machen.)
Jump schrieb:> Nein. Wenn über Debugger (richtig) gestartet, dann braucht man den> Bootloader nicht.
Der Debugger müsste dann aber auch VTOR umstellen bevor er es startet.
Oder das Programm muss irgendwo beim Start selbst das VTOR für sich
umbiegen was aber ebenfalls unelegant ist.
Und warum ist es mit Bootloader eleganter? Ganz einfach: Wenn man das
alles den Bootloader machen lässt und selber die VTOR unangetastet lässt
dann ist der einzige Unterschied zwischen Standalone-Anwendung und
verschobener Anwendung die Angabe eines anderen Linkerscripts im
Makefile. Man muß weder in der IDE noch in den Debuggereinstellungen
irgendwelche Einstellungen ändern um es mal in der einen und mal in der
anderen Form zu debuggen, das halte ich für eleganter und in der Praxis
auch einfacher zu handhaben wenn weder irgendwelcher Code in der
Anwendung noch die Debuggereinstellungen irgendwas davon wissen müssen
mit welchem Linkerscript zufällig gerade gelinkt wurde und an welcher
Stelle im Flash die Anwendung zu liegen kommt.
Einzige Voraussetzung: Wenn die bootloaderfähgige Konfiguration debuggt
werden soll muss auch ein Bootloader drauf sein, was auch einen
ziemlichen Sinn ergibt denn man will ja auch mal das Gesamtgebilde
debuggen wie es später mal laufen soll.
Alles durchlesen ist mir jetzt zu aufwendig - auf die Gefahr hin, dass
die ANtwort überflüssig ist: guck mal im Manual nach dem Alignement für
die Vector Interrupt Tabelle. Kann sonst sein, dass hier was
abgschnitten wird. Typisch für STMs.
No Risk No FUN;-)
Joe J. schrieb:> ...Alignement...
Gefordert sind 0x200 Alignment und "BrilleAuf" verwendet 0x5000. ->
passt
Bernd K. schrieb:> Der Debugger müsste dann aber auch VTOR umstellen bevor er es startet.> Oder das Programm muss irgendwo beim Start selbst das ...
Unterstreiche ich alles.
Ich habe da noch einen Speziallfall...
Ich verwende den STMF030 sehr häufig. Da der Flash nur 1000 Zyklen
verträgt, verschiebe ich das Programm beim Debuggen in den oberen
Flash-Bereich. Ein separater Bootloader ist für diesen speziellen Fall
ziemlich umständlich. Deshalb pfusche ich den Bootloader direkt mit in
das Projekt hinein. (Das Ganze macht natürlich nur dann Sinn, wenn der
Flasher nicht grundsätzlich den gesamten Flash neu beschreibt, sondern
unveränderte Flash-Seiten erkennt und überspringt.)
Ergänzung bzw. Änderung im Linkerskript: