Guten Morgen,
in der Hauptapplikation soll auf die Adresse 0x08010800 im Flash
gesprungen werden. Hier liegt eine Abbildung von der
Flashupdatefunktion.
Dieser Bereich habe ich allerdings im Linkerskript nicht angegeben.
Die Hauptapplikation liegt im Flash zwischen 0x08000000 und 0x0800FFFF.
Ab Adresse 0x08010000 bis 0x080FFFF liegt die neue Firmware. In diesem
Bereich ab der der Adresse 0x08010800 bis 0x08011000 liegt die
Flashupdatefunktion.
Variante 1:
stm32user schrieb:> flashloader_entry = * ((JUMP_TO_FLASH_UPDATE_FUNCTION *)0x08010800);
Du dereferenzierst ja die Adresse, d.h. lädst den Funktionspointer, der
ab der Stelle 0x08010800 gespeichert ist. Nur dass sich da kein
Funktionspointer befindet, sondern die Funktion selber. Du brauchst
einfach nur
Und dann im C-Code eine gewöhnliche Funktionsdeklaration.
Und warum willst du den Compiler per "register" am Optimieren hindern?
Das wird vermutlich ohnehin ignoriert.
Hall Dr. Sommer,
vielen Dank für deine schnelle Antwort.
Wenn ich dies so teste, dann wird in den HardFaultHandler gesprungen.
Das Programm hängt.
1
JumpAddress=(unsignedlong)(0x08010800);
2
Jump_To_Application=(pFunction)JumpAddress;
3
Jump_To_Application();
Im Debugger (IAR) habe ich die Flashbereiche überprüft.
FlashUpdateFunktion --> 0x08000800 bis 0x08001000
FlashUpdateFunktion --> 0x08010800 bis 0x08011000
Beide sind identisch. Warum funktioniert das Springen zu der Adresse
0x08010800 nicht?
Ich hab das auch mal aufm STM32F4 gemacht. hier mein Code.
1
#define APPLICATION_ADDR ((uint32_t)0x08008000)
2
JumpAddress=*(__IOuint32_t*)(APPLICATION_ADDR+4);
3
Jump_To_Application=(pFunction)JumpAddress;
4
__set_MSP(*(__IOuint32_t*)APPLICATION_ADDR);
5
Jump_To_Application();
Das war damals aus einem einfachen Bootloader. Der hat vorher den neuen
Code in den Flash kopiert und dann dort ausgeführt.
Der Code läuft wohl auch aufm STM32F2xxxx:
Beitrag "STM32F2 - Flashloader"
Das funktioniert auch nicht. HardFaultHandler wird ausgeführt.
0x08000000 und 0x0800FFFF --> In diesem Bereich liegt die
Hauptapplikation.
0x08000800 und 0x08001000 --> In der Hauptapplikation liegt die
FlashUpdate Funktion.
Die neue Firmware wird im oberen Flashbereich abgelegt:
0x08010000 und 0x0801FFFF --> Neue Firmware.
0x08010800 und 0x08011000 --> In der neuen Firmware ist die gleiche
FlashUpdate Funktion enthalten.
Sobald die neue Firmware im Flasgbereich abgelegt wurde, soll via
Funktionspointer auf die Flashadresse 0x08010800 gesprungen werden.
Leider funktioniert dies nicht.
Versetzt du auch den Stackpointer mit __set_MSP()?
Liegt die Adresse und der Funktionsdummy auf dem Stack oder sind die
global?
Hat die neue Firmware auch eine Vektortabelle dabei?
Wenn ja, musst du die auch laden
stm32user schrieb:> Wenn ich dies so teste, dann wird in den HardFaultHandler gesprungen.> Das Programm hängt.JumpAddress = (unsigned long)(0x08010800);> Jump_To_Application = (pFunction) JumpAddress;> Jump_To_Application();
Diese Variante sollte deiner Beschreibung nach funktionieren (mit der +1
für Thumb). Sicher, dass der Hardfault aufgrund des Sprunges und nicht
erst in der angesprungenen Funktion ausgelöst wird? Am besten im
Assembler den Sprung debuggen.
Arbeitet die Updatefunktion schon in deinem Test? D.h. wird das aktuelle
Programm gelöscht?
Fängt auf 0x8010800 überhaupt die Funktion an oder hast Du hier die
Interruptvektortabelle für die Hardfaults usw. während die Applikation
gelöscht ist? Dann wäre eher das Beispiel vom Bootloader relevant.
Die neue Firmware (+ Vektortabelle usw.) liegt im Flashadressraum:
0x08010000 - 0x0801FFFF
Was musste ich tun?
Vektortabelle/Interrupttabelle neu setzen?
Wie springe ich dan auf die Flashadresse: 0x08010800?
Das setzt die Vector Tabelle und den StackPointer.
Wahrscheinlich hat die zweite Firmware die Tabelle an der Adresse.
Danach dann auf die Firmware springen.
Hast du auch die Firmware richtig verlinkt? Also so, dass die davon
ausgeht auf deinen gewünschten Adressbereich zu sein?
Sonst kann es sein, dass deine Funktion eine nicht vorhandene Funktion
im alten Adressbereich aufrufen will und das zum HardFault führt.
Ich dachte, die neue Firmware soll umkopiert werden. D.h. sie würde auf
der oberen Adresse garnicht laufen. Damit kann die Vectortabelle von
dort auch nicht genutzt werden.
> Wie springe ich dan auf die Flashadresse: 0x08010800?
Die Frage ist noch immer, was dort steht. Und ob der Hardfault direkt
bei dem Assembler Jumpbefehl auftritt. Ich gehe davon aus, dass er erst
später innerhalb deiner Funktion auftritt.
Hi,
um eine neue Firmware an anderer Stelle zu starten, musst du das VTOR
(Vect Table Offset Reg) sowie den Stack Pointer neu setzen, dann ins
Programm springen.
Die Infos dazu findest du an Offset 0x00 (Stack Pointer) und 0x04
(ResetVect) deines Firmware-Images.
Für armcc (für gcc entsprechend):
Ich habe das so aufgezogen, dass mein Bootloader in den ersten 64k Flash
liegt, und keines Updates bedarf. Darüber liegt die Firmware. Diese wird
immer vom Bootloader gestartet.
Schlägt das FW Update aus irgendeinem Grund fehl, muss in meinem Falle
nur die SD Karte aus dem Gerät genommen, und auf diese das
Firmware-Image kopiert werden.
Dein Jump in den Hard Fault schaut danach aus, als wenn der SP nicht
geändert wurde, und der Library Init damit daneben geht.
Generell habe ich auf Cortex-M immer dabei:
1
voidHandleFault(void)
2
{
3
#ifdef _DEBUG
4
inti;
5
#endif
6
7
LED_PWR_OFF;
8
LED_OUTSTATE_ON;
9
10
#ifdef _DEBUG
11
while(1){
12
LED_PWR_ON;
13
LED_OUTSTATE_ON;
14
for(i=0;i<0xffff;i++)__NOP();
15
LED_PWR_OFF;
16
LED_OUTSTATE_OFF;
17
for(i=0;i<0xffff*10;i++)__NOP();
18
}
19
#else
20
NVIC_SystemReset();
21
#endif
22
}
23
24
voidHardFault_Handler(void)
25
{
26
TextOut("\n\n !!! HARD FAULT !!!");
27
HandleFault();
28
}
29
30
voidMemManage_Handler(void)
31
{
32
TextOut("\n\n !!! MEM MANAGE FAULT !!!");
33
HandleFault();
34
}
35
36
voidBusFault_Handler(void)
37
{
38
TextOut("\n\n !!! BUS FAULT !!!");
39
HandleFault();
40
}
41
42
voidUsageFault_Handler(void)
43
{
44
TextOut("\n\n !!! USAGE FAULT !!!");
45
HandleFault();
46
}
TextOut() geht wahlweise in den ITM Ch.0 (wenn ein Debugger
angeschlossen ist), oder in den 4kB BackLog Buffer der Karte, den man
dann mit Telnet auslesen kann.
Guten Morgen,
bisher bin funktioniert das ganze noch nicht so wie es soll.
Um eine Funktion in einen bestimmten Flashbereich zu legen, welche
Linkeranweisung müsste verwendet werden?
Variante 1:
Ist die Datei das Linker-File der neuen Firmware? Wenn ja, dann ist doch
ganz klar wo der Fehler liegt:
Du sagst der neuen Firmware dort, dass sie auf 0x08000000 läge. Das tut
sie aber nicht. Dann springst du dennoch in eine Funktion der neuen
Firmware und die ruft wahrscheinlich eine vorhandene Funktion auf, die
sie aber nicht finden kann, weil sie im Bereich der alten Firmware
sucht.
Du musst die neue Firmware so linken, dass sie ihre Vektortabelle auch
dort ablegen will wo du sie hin tust.
Dann läuft der Sprung und alles is hübsch.
Die "+4" brauchst du vermutlich dabei nicht, weil die im Bootloader nur
notwendig war, weil man damit direkt in die Reset ISR springt. Da du
deine Funktion callen willst, reicht ein "+0" oder "+1" wegen ThumbCode.
stm32user schrieb:> Um eine Funktion in einen bestimmten Flashbereich zu legen, welche> Linkeranweisung müsste verwendet werden?
Die meisten hier gegebenen Tipps gehen davon aus, dass deine neue
Software auf dem höheren Flashbereich gestartet werden soll. Kannst Du
bitte mal darauf eingehen?
Oder soll die alte Firmware gelöscht werden und die neue umkopiert
werden? So, wie ich dein Problem vertehe?
Könntest Du dies kurz klarstellen?
Wenn Du umkopieren willst, würde deine Lösung so nicht funktionieren und
auch die meisten der Tipps fehlschlagen.
(clib wird gelöscht, keine zweite Vektortabelle an aeiner sinnvollen
Stelle)
Das Linker-File ist von der Hauptapplikation. In dieser Hauptapplikation
gibt es eine FlashUdpdate-Funktion (0x08000800-0x08001000).
Die neue Firmware wird ab der Flashadresse 0x08010000 abgelegt. Die neue
Firmware ist quasi die abgeänderte Hauptapplikation mit der
FlashUpdate-Funktion. Da liegt ebenfalls die FlashUpdate-Funktion,
allerdings ab der Flashadresse 0x08010800 bis 0x08011000. Nun soll
nachdem die neue Firmware ab der Flashadresse 0x08010000 abgelegt wurde,
die FlashUdpade-Funktion von der Flashadresse 0x08010800 ausgeführt
werden.
OK. Das war ein guter Einwand von Steffen ;)
Jetzt habe ich dich definitiv verstanden. Dennoch bleibt das Problem
leider das gleiche.
Du springst in die FLASH_UPDATE Funktion der neuen Firmware und willst
kopieren. Diese Funktionen zum kopieren findet er dort aber nicht, weil
die eigentlich auf den ursprünglichen Bereich verlinkt sind.
Welcher Controller war das denn in deinem vorherigen Projekt?
Wie sieht denn deine "neue" FlasH_Update() aus?
Ich persönlich hätte eine Update-Routine geschrieben, die in einem ganz
anderen Bereich liegt und sich nach "Rollout" nicht mehr ändert. Diese
Funktionen kopieren die neue Firmware, die sich dann bei Bedarf noch
weitere Module laden kann. Somit umgehst du das Problem und kommst der
Architektur eines Bootloaders näher. Ich hab aber nicht weiter über mein
Vorgehen nachgedacht o.Ä.. Das war nur eine spontane Meinung.
Ich möchte allerdings keine zwei Applikationen. Eine für die
Hauptapplikation und die andere für den Flashloader. Es soll alles aus
einer Datei möglich sein.
Wenn ich die Flashloader Kopierfunktion in einen anderen Flashbereich
lege, dann wird beim Koiervorgang auch die Vektrotabelle sowie der
Stackpointer überschrieben. Wie soll das dann gehen?
Die Updatefunktion ist der kritische Punkt!
Sie muß an der Stelle stehen, wo sie auch aufgrund des Linkerfiles
stehen soll. Ansonsten ist sie nicht ausführbar.
Die Updatefunktion darf keine Referenzen auf die alte Firmware haben.
Diese wird ja gelöscht. Daher am besten direkte Registerzugriffe machen
und nicht Funktionen aus der STLib aufrufen. Der werden wohl auch auf
den Bereich der alten Firmware liegen. Oder auch die benötigten
Funktionen mit in die Update-Sektion legen. Doch dann wird es haarig.
Dann mußt Du alle Referenzen prüfen.
Außerdem nehme ich stark an, dass Du beim umkopieren auch die neue
Updatefunktion auf die alte schreibst. Daher müßte deine Updatefunktion
eigentlich in den RAM.
Ob deine Updatefunktion an der richtigen Stelle abgelegt wurde kannst Du
im Mappingfile prüfen. Die Syntax ist für jeden Compiler anders. Daher
weiß ich grad nicht, welche für den IAR korrekt ist.
Oder Du schaust Dir diese im Flash an.
Eine Interruptvektortabelle hat deine Funktion nicht. Daher am besten
alle Antworten hierzu erstmal ignorieren. Dein Design ist aber unschön,
da du im Fehlerfall keinen Handler hast und auch deine Kopieraktion
nicht erneut angestoßen wird.
Du must die Updatefunktion ab 0x08000800 nehmen. Da nur diese für diesen
Bereich übersetzt wurde.
==================================
Überdenke bitte dein Konzept. Es macht viele Probleme. Daher nutzen
eigentlich alle einen (selbstgeschriebenen) Bootloader.
Im einfachsten Fall prüft er nur, ob eine neue Software auf dem oberen
Bereich liegt und kopiert diese um. Wenn alles gut ist löscht er die
neue..
Danach oder wenn nichts zu tun ist, springt dieser in die Applikation.
Da dieses der einfachere Weg ist und üblich, kamen hierzu auch die
meisten Hinweise.
ACK
Sehe ich alles genauso.
Du kannst deinen "Bootloader" in deiner Applikation integrieren. So wird
dann beim Start deiner Firmware geprüft ob eine neue Version vorhanden
ist. Dann kopiert der die neue Firmware an die richtige Stelle und gut
ist.
Was macht denn die "neue" flash_update() mehr als die alte?
Wahrscheinlich nichts... Deswegen füge in der main() die Updateprüfung
ein und dann hast du auch kein zusätzliches Programm im Flash liegen
Ich hatte eher an einen unabhängigen Bootloader gedacht
- mit einer eigenen Vectortabelle
- mit einer eigenen clib
- mit einer eigenen STLib (u.a. Flashroutinen)
Also das übliche, was man unter einem Bootloader versteht.
Damit hat der Bootloader noch alles, wenn die eigentliche Applikation
gelöscht wird.
Meine erste Variante habe ich so gelöst, das ich eine zusätzliche
Applikation entwickelt habe, die nichts anderes macht als die Daten im
RAM (neue Firmware) in den unteren Flashspeicher 0x08000000 kopiert.
Wie könnte ich diese Applikation mit der Hauptapplikation verlinken?
Ich möchte nur einmal den Debugger anwerfen und nicht zweimal.
Muss er! Ansonsten ziehts ihn die Füße weg beim Löschen.
Außer, er kopiert alles in den RAM, was er braucht.
Aber das Projekt, bei dem das schonmal geklappt hat, würde mich
interessieren. Speziell die Lösung mit der Updatefunktion. Kann ja fast
nur der NXP mit seinen Flashfunktionen im ROM gewesen sein.
stm32user schrieb:> Wie könnte ich diese Applikation mit der Hauptapplikation verlinken?
Kompliziert. Die Updatefunktion und alles, worauf sie referenziert, muss
an eine Stelle, die nicht überschrieben wird.
Deine damalige Lösung war schon die richtige.
> Ich möchte nur einmal den Debugger anwerfen und nicht zweimal.
Man kann meist die Symbole des zweiten Programms nachladen. Meist muss
dieses aber schon im Flash stehen.