Forum: Mikrocontroller und Digitale Elektronik STM32F4 eigener Bootloader inkl. Flashen per .hex Datei


von Alex K. (alexk99123)


Lesenswert?

Hi,
ich baue derzeit für ein Projekt eine Bootloader Firmware in C für den 
o.g. Mikrocontroller. Die Bootloader Firmware soll bei jedem Start 
ausgeführt werden. Ziel der Bootloader Firmware ist es:
1) Checken, ob eine valide Firmwareversion in mindestens einer von zwei 
Flash-Regionen vorliegt. Sind valide Firmwareversionen vorhanden? Dann 
lade die neueste Version. Ich möchte hierfür Flash Sektor 8-9(ab 
0x08080000) und 10-11(ab 0x080C0000) verwenden. Diese Regionen habe ich 
bereits im Linkerscript des Bootloaders vermerkt. Hier habe ich noch 
nicht dran gearbeitet. Meine Idee ist, an festen Positionen im Flash 
eine Prüfsumme zu hinterlegen, die dann durch Auslesen des Flashs 
verifiziert werden kann.

2) Firmwareupdate per RS485 Schnittstelle als .Hex File. Ist keine 
valide FW-Version vorhanden ODER ist ein FW-Update explizit gewünscht, 
lass dir von einem PC eine neue FW-Version als .Hex File übertragen.
Was hierbei bereits funktioniert: Per PC liest das.Hex-File aus, dieses 
wird Zeile für Zeile übertragen. Die Datenverarbeitung des .Hex-Files 
funktioniert auch. D.h. ich erhalte entsprechend 
https://de.wikipedia.org/wiki/Intel_HEX#End_of_File_Record_(Typ_01)
Bytecount, Adresse, Typ, Datenfeld und Prüfsumme. Die Verarbeitung des 
Addressoffsets passt auch. Jede Zeile wird auch bereits per Prüfsumme 
verifiziert. Im Prinzip schaffe ich es auch, den Flash jetzt ab der 
angegebenen Adresse Byte pro Byte zu beschreiben.

Ich habe mir ein Probeprogramm geschrieben, zu dem der Bootloader nach 
dem Flashprozess springen soll. Bei dem Compilieren dieses 
Probeprogrammes habe ich im Linker den ROM - Bereich auf die absolute 
Adresse 0x08080000 geändert und habe das Vector Table Offset auf 
0x00080000 gestellt. ABER:

Wie springe ich nach erfolgreichem Flashen zu dem Programm? Muss ich 
wirklich einfach nur an die gegebene Adresse springen mit irgendeiner 
Art Jump Befehl?

von Random .. (thorstendb) Benutzerseite


Lesenswert?

1
#define NVIC_VectTab_FLASH       0x90000
2
#define SP_OFFS                     0
3
#define RESET_OFFS                  4
4
5
  void (*user_code_entry)(void);
6
  register uint32_t MSP __ASM("msp");
7
8
  //__DSB();
9
  //__ISB();
10
  SCB->VTOR       = NVIC_VectTab_FLASH;
11
  user_code_entry = (void (*)(void))(( *((unsigned int *)(NVIC_VectTab_FLASH + RESET_OFFS))) );
12
  MSP             = *((unsigned int *)(NVIC_VectTab_FLASH + SP_OFFS));
13
  //__DSB();
14
  //__ISB();
15
  user_code_entry();
16
17
  while(1);     // should never reach this ...

von Werner P. (werner4096)


Lesenswert?

Hi,

ich mach das so:
1
void Bootloader_JumpToApplication(void)
2
{
3
    uint32_t  JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4); // one byte past vector table
4
    pFunction Jump        = (pFunction)JumpAddress;
5
6
    HAL_RCC_DeInit();
7
    HAL_DeInit();
8
9
    SysTick->CTRL = 0;
10
    SysTick->LOAD = 0;
11
    SysTick->VAL  = 0;
12
13
#if(SET_VECTOR_TABLE)
14
    SCB->VTOR = APP_ADDRESS;
15
#endif
16
17
    __set_MSP(*(__IO uint32_t*)APP_ADDRESS);
18
    Jump();
19
}

und die APP_ADDRESS
1
#define APP_ADDRESS (uint32_t)0x08008000

Hab ich halt von einem Beispiel abgeschaut ;-)

von Alex K. (alexk99123)


Lesenswert?

Random .. schrieb:
>
1
> #define NVIC_VectTab_FLASH       0x90000
2
> #define SP_OFFS                     0
3
> #define RESET_OFFS                  4
4
> 
5
>

Danke für die Antwort! D.h. NVIC_VectTab_FLASH wäre bei mir 0x08008000 
und dann muss man 1Byte weiterspringen? Was bedeutet SP_OFFS?

von Alex K. (alexk99123)


Lesenswert?

Werner P. schrieb:
> Hab ich halt von einem Beispiel abgeschaut ;-)
Danke, ein solches Beispiel hat mir eben gefehlt! Ich werde es morgen 
mal ausprobieren.
Wo steht eigentlich, dass man 1Byte weiter springen muss, als zur Vector 
Table?

: Bearbeitet durch User
von Werner P. (werner4096)


Lesenswert?

Alex K. schrieb:
> Werner P. schrieb:
> Wo steht eigentlich, dass man 1Byte weiter springen muss, als zur Vector
> Table?

Kann ich Dir spontan nicht sagen. Ich musste auf die Schnelle einen 
Bootloader schreiben. Da hab ich das mal so übernommen.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

SP = Stack Pointer
RESET = Reset Vector

Die ersten beiden Einträge in deinem "fertig gelinkten" Image sind der 
Stack Pointer und der Reset Vector (Einsprungpunkt). Diese werden nach 
RESET von der CPU automatisch geladen.
Willst du jetzt Bootloader und Programm jeweils in sich abgeschlossen 
linken, kannst du auf dieses zurückgreifen, und den Reset der CPU vom 
Bootloader aus nachstellen, um deine Firmware zu starten.

Der StackPointer wird in das MSP (Main Stack Pointer) geladen.
Der ResetVector wird in den Function Pointer geladen, welcher dann 
später als Funktion ausgeführt wird. Man könnte noch ein __NO_RETURN 
einfügen.
Der Vector Table Offset ist der Start des Images, und wird in das VTOR 
Register geladen.

von Alex K. (alexk99123)


Lesenswert?

Random .. schrieb:
> SP = Stack Pointer
> RESET = Reset Vector
> ....

Danke für die Erklärung!

Werner P. schrieb:
> Hi,
>
> ich mach das so:

Funktioniert tadellos, vielen Dank!

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.