Forum: Mikrocontroller und Digitale Elektronik STM32F7: Eigener Bootloader startet die Applikation nicht


von Laspalmas (Gast)


Lesenswert?

Hallo zusammen,

ich habe einen bootlaoder geschrieben, der eine Applikation zuerst 
checkt und dann an der Adresse: 0x8060100 starten soll.
An der Adresse 0x8060000 sollen 256 Bytes Daten eines Headers reserviert 
sein und danach soll das Applikationscode folgen.
Ich habe folgende bekannte codezeilen  probiert. Leider ging es nicht
Es hängt und tut sich nichts mehr.
=================================================================

      addr = (GetApplicationStartAddress() + sizeof(APP_HEADER)+4);
      JumpAddress = *(__IO uint32_t*) addr;
      Jump_To_Application =  (pFunction) JumpAddress;
      __set_MSP(*(__IO uint32_t*)(GetApplicationStartAddress() +
                                                  sizeof(APP_HEADER)) );

      Jump_To_Application();

      while(1)
      {
        LED_Blink();
      }


wenn ich debugge finde ich:
                     addr: 0x8060104
                     JumpAddress: 0x80602F5
                     Jump_To_Application: 0x80602F5


Laut der Map-Datei der Applikation sollte eigentlich alles in Ordnung 
sein:
======================================================================== 
==
__ARM_use_no_argv                        0x00000000   Number         0 
main.o ABSOLUTE
    _cpp_initialize__aeabi                  - Undefined Weak Reference
    __cxa_finalize                            - Undefined Weak Reference
    __decompress                              - Undefined Weak Reference
    _clock_init                               - Undefined Weak Reference
    _microlib_exit                            - Undefined Weak Reference
    __Vectors_Size                           0x000001e0   Number 
0  startup_stm32f722xx.o ABSOLUTE
    __Vectors                                0x08060100   Data 
4  startup_stm32f722xx.o(RESET)
    __Vectors_End                            0x080602e0   Data 
0  startup_stm32f722xx.o(RESET)
    __main                                   0x080602e1   Thumb Code 
0  entry.o(.ARM.Collect$$$$00000000)
    _main_stk                                0x080602e1   Thumb Code 
0  entry2.o(.ARM.Collect$$$$00000001)
    _main_scatterload                        0x080602e5   Thumb Code 
0  entry5.o(.ARM.Collect$$$$00000004)
    __main_after_scatterload                 0x080602e9   Thumb Code 
0  entry5.o(.ARM.Collect$$$$00000004)
    _main_clock                              0x080602e9   Thumb Code 
0  entry7b.o(.ARM.Collect$$$$00000008)
    _main_cpp_init                           0x080602e9   Thumb Code 
0  entry8b.o(.ARM.Collect$$$$0000000A)
    _main_init                               0x080602e9   Thumb Code 
0  entry9a.o(.ARM.Collect$$$$0000000B)
    __rt_final_cpp                           0x080602f1   Thumb Code 
0  entry10a.o(.ARM.Collect$$$$0000000D)
    __rt_final_exit                          0x080602f1   Thumb Code 
0  entry11a.o(.ARM.Collect$$$$0000000F)
    Reset_Handler                            0x080602f5   Thumb Code 
8  startup_stm32f722xx.o(.text)
    ADC_IRQHandler                           0x0806030f   Thumb Code 
0  startup_stm32f722xx.o(.text)
    CAN1_RX0_IRQHandler                      0x0806030f   Thumb Code 
0  startup_stm32f722xx.o(.text)
    CAN1_RX1_IRQHandler                      0x0806030f   Thumb Code 
0  startup_stm32f722xx.o(.text)
    CAN1_SCE_IRQHandler                      0x0806030f   Thumb Code 
0  startup_stm32f722xx.o(.text)
    CAN1_TX_IRQHandler                       0x0806030f   Thumb Code 
0  startup_stm32f722xx.o(.text)

und Hier ist der Linker Skript für die Applikation:
===================================================

LR_IROM1 0x08060100 0x0001FF00  {    ; load region size_region
  ER_IROM1 0x08060100 0x0001FF00   {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00040000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

LR_ROM2  0x08060000 0x00000100
{
  ER_ROM2 0x08060000 0x00000100
  {
    Header.o(.constdata)
  }
}

liegt es jetzt an der Applikation oder an das Starten der Applikation 
vom Bootloader.
Ich bedanke mich für jede Hilfe.
Gruß
Laspalmas

von Laspalmas (Gast)


Lesenswert?

Hilfe! Ich komm nicht mehr weiter.
hat jemand eine Idee?
Gruß

von A. B. (Gast)


Lesenswert?

Wenn die Startadresse tatsächlich 0x8060100 sein soll, ist das '+4' doch 
zuviel?

Es lohnt sich, den Assembler-Code mal zu kontrollieren. Denn die 
Startadresse kann sicher nicht 0x8060100 lauten, sondern müsste wohl
0x8060101 lauten, wenn ein Sprung dahin ausgeführt wird. Das LSB muss 
gleich '1' sein, da bei ARM das den Thumb-Mode anzeigt.

Vielleicht wird das vom Compiler hier nicht automatisch gemacht, da 
vorher mit der Adresse herumgerechnet wird?

Und wie üblich: "Es hängt und tut sich nichts mehr." ist wenig 
hilfreich. Schließlich kann man mit dem Debug-Interface doch gerade dann 
in den Controller hineinsehen, Registerinhalte, PC etc. ...

von STM32User (Gast)


Lesenswert?

Hast du Interrupts im Bootloader verwendet ?

von Laspalmas (Gast)


Lesenswert?

Danke euch erstmal für die Antworten.

@STM32User:
nein. Interrupts habe ich nicht verwendet.
Sonst müssen sie abgeschaltet?


@A.B.
die +4 muss sein. Da +0 ist die Initialisierung des Stackpointers und 
danach kommt der erste Befehl was ausgeführt werden soll.oder?
was mich verwirrt ist: JumpAddress: 0x80602F5
wie kommt der Compiler draut. Ist es überhaupt richtig?

Danke.
Laspalmas

von Laspalmas (Gast)


Lesenswert?

Ich hab es gerade probiert ohne +4. Hat nichts geholfen.

      addr = (GetApplicationStartAddress() + sizeof(APP_HEADER));
      JumpAddress = *(__IO uint32_t*) addr;
      Jump_To_Application =  (pFunction) JumpAddress;
      __set_MSP(*(__IO uint32_t*)(GetApplicationStartAddress() +
                                                  sizeof(APP_HEADER)) );

      Jump_To_Application();

von A. B. (Gast)


Lesenswert?

Laspalmas schrieb:

> die +4 muss sein. Da +0 ist die Initialisierung des Stackpointers und
> danach kommt der erste Befehl was ausgeführt werden soll.oder?
> was mich verwirrt ist: JumpAddress: 0x80602F5
> wie kommt der Compiler draut. Ist es überhaupt richtig?

Moment mal, der Bootloader bringt doch seine eigene Vektor-Tabelle mit 
(inkl. Stackpointer-Init.) und soll nur einen Sprung zur Applikation 
machen?
Das würde heißen, nach JEDEM Reset startet zuerst der Booloader und 
der wiederum ggf. die Applikation? Dann ist das '+4' aber in der Tat 
zuviel, bzw. vielmehr die ganze Vektortabelle zuviel. Die 
Stackpointer-Initialisierung wird duch nur bei einem Reset automatisch 
durchgeführt.

Oder soll der Bootloader die Applikation "fest installieren"? Dann 
müsste die Startadresse in den Option-Bytes entsprechend umgebogen 
werden, die Vektortabelle der Applikation aktiv gemacht werden. Das ist 
mit einem einfachen Sprung nicht getan.

Wie der Compiler auf die 0x080602f5 kommt ist aber klar, das ist nix 
anderes als 'Reset_Handler'.

von Laspalmas (Gast)


Lesenswert?

Ja so ist es gedacht. Nach jedem Reset checkt der Bootloader die 
Integrität der Applikatoin und danach startet diese. Nach meinem 
Verständnis, soll der Bootloader ganz zurückziehen und überlässt die 
Hardware der Applikation.
D.h. Alle einstellungen was der Bootlaoder gemacht hat, sollen 
überschrieben sein, so als hätte die Applikation von Anfang an selbst 
gestartet ist.
Laut map-file denke ich dass der Linker die Verktor-Tabelle in der 
richtigen Stelle abgelegt hat. oder?

Gruß

von tom (Gast)


Lesenswert?

Hi,

Der Start Deines gebauten Codes sollte auf einem 512-bytes boundary 
liegen, also lokiere den nach 0x08060200. Stichwort ISR vector table 
Deiner Applikation, RTFM ;o).


__set_PRIMASK(1); // disable all isr's
JumpAddress = *(__IO uint32_t*) (0x08060200+4);
Jump_To_Application =  (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*)0x08060200;
Jump_To_Application();

Wenn Dein Linkerscript damit korrespondiert, sollte das mit arm-gcc tun.

Schau Dir im debugger an, ob die Werte für die Adressen richtig 
übernommen werden. Ich habe da mit EmBitz 1.1 und dem built-in gcc schon 
merkwürdiges gesehen...
Wie es mit Keil ist, keine Ahnung. Bei mir tut das mit CooCox 1.78 und 
arm gcc 4.7 2012q4 problemlos.

Gutt Lack, Tom.

von A. B. (Gast)


Lesenswert?

tom schrieb:
> Hi,
>
> Der Start Deines gebauten Codes sollte auf einem 512-bytes boundary
> liegen, also lokiere den nach 0x08060200. Stichwort ISR vector table
> Deiner Applikation, RTFM ;o).

Genau, und wenn der Bootloader sozusagen dann 'tot' sein soll, muss man 
manuell
0. Alle Interrupts abschalten (ggf. auch DMA)
1. Stackpointer neu laden (aus 0x08060200)
2. Vektortabelle verschieben (Vector Table Offset register auf 
0x08060200)
3. Indirekten Sprung über Vektor-Tabelle+4

Das geht freilich nur in Assembler ...

von Guest (Gast)


Lesenswert?

Laspalmas schrieb:
> danach kommt der erste Befehl was ausgeführt werden soll.oder?
Nö, da steht die Adresse des Reset Handlers.
Wenn du in der Applikation Interrupts haben willst musst du auch noch 
das VTOR Register setzen. Ansonsten wird in der Applikation die Vektor 
Tabelle des Bootloaders benutzt.

Du kannst auch mal hier rein schauen:
https://www.segger.com/downloads/application-notes/AN01005

von Stumpf (Gast)


Lesenswert?

Hatte das Problem schon vor einer ganzen Weile.
Das Problem war der Vector Table der nicht umgestellt war.

Vor dem Umschalten die Adresse ändern
1
SCB->VTOR = ApplicationAddress; // Vector Table Relocation in Internal FLASH 
2
3
   // Jump to user application 
4
   JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
5
   Jump_To_Application = (pFunction) JumpAddress;
6
   // Initialize user application's Stack Pointer 
7
   __set_MSP(*(__IO uint32_t*) ApplicationAddress);
8
   Jump_To_Application();

So funktioniert es bei mir.

von Guest (Gast)


Lesenswert?

A. B. schrieb:
> Das geht freilich nur in Assembler ...

Nope. Geht auch problemlos in C.
Beispiel steht in der App Note bzw. bei Segger gibt es auch ein 
Demoprojekt.

von Guest (Gast)


Lesenswert?

Und das Thumb Bit nicht vergessen:

#define THUMB_BIT 1
#define APP_START_ADDR 0x00100000
#define APP_STACK_PTR (*(volatile OS_U32*)(APP_START_ADDR + 0x00))
#define APP_RESET_PTR (*(volatile OS_U32*)(APP_START_ADDR + 0x04))

AppPtr = (void (*)(void))(APP_RESET_PTR | THUMB_BIT);

von Steffen R. (steffen_rose)


Lesenswert?

Laspalmas schrieb:
> wenn ich debugge finde ich:
>                      addr: 0x8060104
>                      JumpAddress: 0x80602F5
>                      Jump_To_Application: 0x80602F5

Wenn deine Interrupttabelle bei 0x8060100 liegt, wirst du möglicherweise 
Probleme bekommen, wenn du die Flashtabelle nutzt (Alignment 0x200 oder 
so, je nach Derivate).

Laspalmas schrieb:
> was mich verwirrt ist: JumpAddress: 0x80602F5
> wie kommt der Compiler draut. Ist es überhaupt richtig?

Passt. An der Stelle steht die Adresse, wo du hinspringen sollst. Auch 
das Thumb bit ist bereits ordentlich gesetzt.

A. B. schrieb:
> Das würde heißen, nach JEDEM Reset startet zuerst der Booloader und
> der wiederum ggf. die Applikation? Dann ist das '+4' aber in der Tat
> zuviel, bzw. vielmehr die ganze Vektortabelle zuviel.

Das ist die Vektortabelle der Applikation.

tom schrieb:
> __set_PRIMASK(1); // disable all isr's
> JumpAddress = *(__IO uint32_t*) (0x08060200+4);
> Jump_To_Application =  (pFunction) JumpAddress;
> __set_MSP(*(__IO uint32_t*)0x08060200;
> Jump_To_Application();

Nur der Vollständigkeit halber:
Da der Stack umgebogen wurde, muss Jump_To_Application im Register 
liegen. Ist aber eigentlich immer der Fall. Aber wenn du am Verzweifeln 
bist check einfach mal diese Stelle im Assembler.

A. B. schrieb:
> 2. Vektortabelle verschieben (Vector Table Offset register auf
> 0x08060200)

Das ist diskutabel. Ich bin auch dafür, dass im Bootloader zu machen. 
Aber auf jedenfall gibt es regelmäßig derartige Einstellungen in der 
Applikation, die das Register zurücksetzen. An diese Stelle muss man 
genauso denken.

von Laspalmas (Gast)


Angehängte Dateien:

Lesenswert?

Danke Tom:

ich hab mittlerweile auf den Header verzichtet und die Applikation
an der Adresse: 0x8060000 kompiliert. Der Bootlaoder auch angepasst:

      __set_PRIMASK(1);
      addr = 0x8060000+4;
      JumpAddress = *(__IO uint32_t*) addr;
      Jump_To_Application =  (pFunction) JumpAddress;
      __set_MSP(*(__IO uint32_t*)(0x8060000) );

      Jump_To_Application();

aber immer noch das gleiche Problem.
Die Jump-Adresse die berechnet ist gleich: 0x80601F5 ???
(Siehe Anhang: Debug-Ausgabe)


Map-File der Applikation (Ausschnitt):
    0x08060000   0x000001e0   Data   RO         1849    RESET 
startup_stm32f722xx.o
    0x080601e0   0x00000000   Code   RO         1854  * 
.ARM.Collect$$$$00000000  mc_w.l(entry.o)
    0x080601e0   0x00000004   Code   RO         1857 
.ARM.Collect$$$$00000001  mc_w.l(entry2.o)
    0x080601e4   0x00000004   Code   RO         1860 
.ARM.Collect$$$$00000004  mc_w.l(entry5.o)
    0x080601e8   0x00000000   Code   RO         1862 
.ARM.Collect$$$$00000008  mc_w.l(entry7b.o)
    0x080601e8   0x00000000   Code   RO         1864 
.ARM.Collect$$$$0000000A  mc_w.l(entry8b.o)
    0x080601e8   0x00000008   Code   RO         1865 
.ARM.Collect$$$$0000000B  mc_w.l(entry9a.o)
    0x080601f0   0x00000000   Code   RO         1867 
.ARM.Collect$$$$0000000D  mc_w.l(entry10a.o)
    0x080601f0   0x00000000   Code   RO         1869 
.ARM.Collect$$$$0000000F  mc_w.l(entry11a.o)
    0x080601f0   0x00000004   Code   RO         1858 
.ARM.Collect$$$$00002712  mc_w.l(entry2.o)
    0x080601f4   0x00000024   Code   RO         1850    .tex

von Steffen R. (steffen_rose)


Lesenswert?

Laspalmas schrieb:
> aber immer noch das gleiche Problem.

Ich vermute das Problem in der Applikation, nicht im Bootloader.
Die üblichen Verdächtigen wie Umstellen der Vektortabelle wurden 
genannt.
Oft geht die Applikation auf davon aus, dass nach dem Reset die 
Interrupte enabled sind und gern disabled man diese im Bootloader.

Einfach mal die Applikation per Bootloader flashen und dann ohne Flashen 
die Applikation debuggen.

von Laspalmas (Gast)


Lesenswert?

Ja ich denke auch dass die Applikation nicht In Ordnung ist.
Mal ein Veständnisfrage: kann ich die Applikation mit Keil debuggen 
obwohl sie liegt an der Adresse 0x8060000 samt Verktortabelle & co und 
nicht an Adresse 0x8000000?.
Der Bootloader befindet sich an 0x8000000.
D.h nach einem Reset ist erstmal Reset-Händer an 0x8000004 des 
Bootloader gefragt?
wie kann ich das umgehen?
Danke

von Steffen R. (steffen_rose)


Lesenswert?

Laspalmas schrieb:
> wie kann ich das umgehen?

Nicht umgehen...
Ziel ist es, dass alles so ist wie am Ende, d.h. Bootloader im Flash, 
Applikation im Flash, ggf. Prüfdaten im Flash.
Aufpassen, dass man beim Debuggen nicht erased und flashed.

In diesem Zustand einfach die Applikation debuggen. Natürlich wird so 
erst der Bootloader durchlaufen und erst dann die Applikation.
Ich setze meinen erstne Breakpoint in den Resetvektor der Applikation, 
um zu sehen, dass alles wie erwartet anläuft.

Ab jetzt ganz normal debuggen.

von Laspalmas (Gast)


Lesenswert?

Vieeeeeelen Danke an Alle.
Granz Großer Lob!

Es lag an der Applikation genauer gesagt an HAL_Delay() die nicht mehr 
funktionniert (bis jetzt nicht. Ursache muss ich noch finden.
Vielleicht liegt es an __set_PRIMASK(1): alle Interrupts abschalten).
D.h. mit folgenden Code hat der Boot-Loader die Applikation gestartet:

      __set_PRIMASK(1);
      addr = GetApplicationStartAddress() + sizeof(APP_HEADER)+4;
      JumpAddress = *(__IO uint32_t*) addr;
      Jump_To_Application =  (pFunction) JumpAddress;
      __set_MSP(*(__IO uint32_t*)(GetApplicationStartAddress() + 
sizeof(APP_HEADER)) );

      Jump_To_Application();


Vielen Dank noch mal.
Laspalmas.

von Guest (Gast)


Lesenswert?

Laspalmas schrieb:
> Vielleicht liegt es an __set_PRIMASK(1):

Ja klar, das ist das Problem. Einerseits möchtest du Interrupts im 
Bootloader sperren aber andererseits muss die Applikation die CPU in dem 
Zustand wie nach dem Reset vorfinden. Und das heißt Interrupts sind nach 
dem Reset enabled (PRIMASK=0, BASEPRI=0). Der Ausweg aus dem Dilemma ist 
die Interrupts in dem Applikation Startup Code einzuschalten.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Laspalmas schrieb:
> Vieeeeeelen Danke an Alle.
> Granz Großer Lob!
>
> Es lag an der Applikation genauer gesagt an HAL_Delay() die nicht mehr
> funktionniert (bis jetzt nicht. Ursache muss ich noch finden.
> Vielleicht liegt es an __set_PRIMASK(1): alle Interrupts abschalten).
> D.h. mit folgenden Code hat der Boot-Loader die Applikation gestartet:
>
>       __set_PRIMASK(1);
>       addr = GetApplicationStartAddress() + sizeof(APP_HEADER)+4;
>       JumpAddress = *(__IO uint32_t*) addr;
>       Jump_To_Application =  (pFunction) JumpAddress;
>       __set_MSP(*(__IO uint32_t*)(GetApplicationStartAddress() +
> sizeof(APP_HEADER)) );
>
>       Jump_To_Application();
>
>
> Vielen Dank noch mal.
> Laspalmas.

An der Stelle möchte ich noch auf eine sehr sehr gerne gemachte 
Denklücke hinweisen:

Da dein BL HAL_Delay() benutzt, aber über das Flash Layout jenseits 
seines Bereiches keinen Einfluss hat, muss der Code für HAL_Delay() im 
BL Bereich des Flashes sitzen.

So weit so gut. Interessant wird's nun aber, wenn deine App auch 
HAL_Delay() benutzt. Hier gibt es mehrere Implementationsvarianten:

1. Der Bootloader ist nicht ersetzbar. Dann darf die App statisch 
Informationen aus dem Linker Map file des BL nutzen, um absolut dort 
hinzuspringen. Geht natürlich nicht in die Andere Richtung...
2. Die App dupliziert den Code für HAL_Delay(). Das geht prinzipiell, 
ist aber mit grosser Vorsicht zu geniessen (manche HAL Funktionen 
benutzen geteilte globale Variablen, die dann logischerweise für BL und 
App an verschiedenen Stellen sitzen, was ein Anlass für sehr lange 
Debugsessions und ein Grund zur Freude für die Kaffeeindustrie sein 
kann). Ausserdem ist es nicht Sinn und Zweck der Sache, Code doppelt zu 
halten.
3. Dynamische Sprungtabellen, also ein indirektes 
Funktionsaufrufinterface zwischen BL und App. Im frei herunterladbaren 
Beispielcode zum Buch Kapitel 9 hast Du ein Beispiel wie man so etwas 
machen kann (nur falls Du das noch nicht in Betracht gezogen hast; es 
hat mich ca. 5 BL gebraucht, bis ich das so mit Allen Fallstricken und 
Randpoblemchen gerade gezogen habe). Funktioniert auch in beide 
Richtungen (also Aufrufe vom BL in Applikationsocde, was auf der ersten 
Blick schräg erscheint, aber zuweilen in Form von Callbacks sinnvoll 
sein kann).

: Bearbeitet durch User
von eagle user (Gast)


Lesenswert?

Guest schrieb:
> Laspalmas schrieb:
>> Vielleicht liegt es an __set_PRIMASK(1):
>
> Ja klar, das ist das Problem. Einerseits möchtest du Interrupts im
> Bootloader sperren

Warum möchte ich das? Es gibt doch nach einem Reset keine aktive 
Interrupt-Quelle? Und wenn der Bootloader ein oder zwei Interrupts 
braucht, kann er die auch wieder abschalten bzw. das Modul resetten. 
Dafür gibt es doch extra die RCC_ Reset Register? Oder nicht?

von Guest (Gast)


Lesenswert?

eagle user schrieb:
> Warum möchte ich das?

Weil du irgendwann vor dem Sprung in die Applikation die Interrupt 
Vektor Tabelle umstellst (VTOR). D.h. es kann passieren, das im 
Bootloader Interrupts auf der Interrupt Vektor Tabelle der Applikation 
laufen. Und das kann ganz gewaltig schief gehen.

von Steffen R. (steffen_rose)


Lesenswert?

Ruediger A. schrieb:
> 2. Die App dupliziert den Code für HAL_Delay(). Das geht prinzipiell,
> ist aber mit grosser Vorsicht zu geniessen

Bei mir sind Bootloader und Applikation völlig getrennte Projekte. Da 
sie nichts voneinander wissen, gibts auch keine Verwechslungen.

eagle user schrieb:
> Und wenn der Bootloader ein oder zwei Interrupts
> braucht, kann er die auch wieder abschalten bzw. das Modul resetten.

Prinzipiell hast du recht und wird wohl auch ST so sehen. Klassisch habe 
ich aber gelernt all den Wenn und Abers aus dem Weg zu gehen und die 
globalen Interrupte abzuschalten.
Und in diesem Fall auch erst wieder einzuschalten, wenn das Register für 
die Vectortable richtig gesetzt ist.

von Steffen R. (steffen_rose)


Lesenswert?

Guest schrieb:
> eagle user schrieb:
>> Warum möchte ich das?
>
> Weil du irgendwann vor dem Sprung in die Applikation die Interrupt
> Vektor Tabelle umstellst (VTOR). D.h. es kann passieren, das im
> Bootloader Interrupts auf der Interrupt Vektor Tabelle der Applikation
> laufen. Und das kann ganz gewaltig schief gehen.

Berücksichtige bitte die Aussage:

eagle user schrieb:
> kann er die auch wieder abschalten bzw. das Modul resetten.

Beim Sprung in die Applikation initialisierte Peripherie zu hinterlassen 
(die Interrupte auslöäsen könnte, wenn nicht abgeschaltet) ist 
vielleicht nicht ganz so gut.

Anm:
Ich bin auch ein Verfechter des Abschaltens der globalen Interrupte. 
Aber die Argumentation greift nicht.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Steffen R. schrieb:
> Ruediger A. schrieb:
>> 2. Die App dupliziert den Code für HAL_Delay(). Das geht prinzipiell,
>> ist aber mit grosser Vorsicht zu geniessen
>
> Bei mir sind Bootloader und Applikation völlig getrennte Projekte. Da
> sie nichts voneinander wissen, gibts auch keine Verwechslungen.
>

Doch doch, die gibt es, und genau das ist mein Punkt:

Wenn Du zwei komplett voneinander getrennte Instanzen von der HAL hast, 
können die nicht miteinander funktionieren, jedenfalls nicht solange Du 
die Standardimplementation benutzt.

Die Defaultimplementation der HAL unter ST registriert einen 
Timerinterruphandler, der eine globale Variable uwTick incrementiert, 
und HAL_Delay() berechnet lediglich solange die Differenz zwischen 
uwTick und dessen Stand bei Eintritt in HAL_Delay(), bis das gewünschte 
Delta überschritten wird.

Hast Du zwei verschiedene Instanzen der HAL, dann hast Du auch zwei 
voneinander unbhängige Instanzen von uwTick - aber vermutlich nur einen 
ISR (HAL_InitTick() benutzt zumindestens in der Standardimplementation 
nur einen Timer). Abhängig davon, "wessen" ISR mit dem Timer assoziiert 
ist, wird der eine oder der Andere Timer funktionieren, die Andere 
uwTick aber vermutlich niemals inkrementiert (was u.A. zu einem nie 
wiederkehrenden HAL_Delay() führt).

Und das ist nur die Spitze des Eishügels (für einen Berg ist es nun doch 
nicht komplex genug), denn die Prozessorfrequenz ist ebenfalls in einer 
globalen Variable abgelegt, nämlich SystemCoreClock - von der es besser 
keine zwei Instanzen geben sollte (weil nämlich die Clock in der Regel 
nur einmal initialisiert wird, nämlich vom BL, und damit ist die Instanz 
von SystemCoreClock von der Applikation undefiniert. Die Variable wird 
aber zuweilen benutzt, u.A. um Ableitungsfaktoren für Baudraten u.ä. zu 
berechnen).

Das sind zwei der Gründe, warum ich mit der HAL von ST nicht so 
begeistert bin; erstensmal benutzt sie von mir ungefragt einen 
Timerinterrupt für ein busy wait (dessen Priorität ich sowieso erst in 
mein Schema unterbringen muss, also ganz transparent ist es sowieso 
nicht, und vermutlich könnte ich applikationswaits besser durch 
suspended waits realisieren), und zweitens sind diese 
Bootloaderunverträglichkeiten sehr sehr gemeine Angelegenheiten zum 
Debuggen.

: Bearbeitet durch User
von Stefan K. (stefan64)


Lesenswert?

Ruediger A. schrieb:
> Wenn Du zwei komplett voneinander getrennte Instanzen von der HAL hast,
> können die nicht miteinander funktionieren, jedenfalls nicht solange Du
> die Standardimplementation benutzt.

Die funktionieren auch nicht miteinander, sondern nacheinander.

Ich mache das genauso wie Steffen, sowohl der Bootloader als auch die 
Applikation benutzen die HAL-Lib. Aber beide wissen nichts voneinander 
(außer die Startadresse der Application Vector Table und die CRC der 
Appl.). Deshalb kann man auch nicht von 2 verschiedenen Instanzen 
sprechen.

Gruß, Stefan

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Stefan K. schrieb:
> Ruediger A. schrieb:
>> Wenn Du zwei komplett voneinander getrennte Instanzen von der HAL hast,
>> können die nicht miteinander funktionieren, jedenfalls nicht solange Du
>> die Standardimplementation benutzt.
>
> Die funktionieren auch nicht miteinander, sondern nacheinander.
>
> Ich mache das genauso wie Steffen, sowohl der Bootloader als auch die
> Applikation benutzen die HAL-Lib. Aber beide wissen nichts voneinander
> (außer die Startadresse der Application Vector Table und die CRC der
> Appl.). Deshalb kann man auch nicht von 2 verschiedenen Instanzen
> sprechen.
>

Also sind die BL nach Starten der App komplett inaktiv? Dann kann das 
funktionieren. In den BLs, die ich geschrieben habe, ist das aber nicht 
der Fall. Da hängt z.B. der BL mit im Hostkommunikationsprotokoll drin, 
filtert alle Softwaredownloadtelegramme heraus, baut das 
Applikationsimage aus den Telegrammen und flasht es dann. Da es vor 
Allem bei kleineren Controllern schwer möglich ist, so etwas potentiell 
footprintreiches wie Hostkommunikationscode zu verdoppeln, wird bei 
diesen Systemen kontrolliert zwischen BL und App hin- und her 
aufgerufen, und da werden solche Themen relevant.

Man kann auf die Art und Weise sogar mit 32k RAM und 128k Flash einen 
selbst und die Applikation upgradenden Bootloader mit minimalem eigenen 
footprint schreiben.

> Gruß, Stefan

Zurück ;-)

von Steffen R. (steffen_rose)


Lesenswert?

Ruediger A. schrieb:
> Hast Du zwei verschiedene Instanzen der HAL, dann hast Du auch zwei
> voneinander unbhängige Instanzen von uwTick - aber vermutlich nur einen
> ISR (HAL_InitTick() benutzt zumindestens in der Standardimplementation
> nur einen Timer).

2 Programme
2 Vektortabellen, daher ist das Umstellen so wichtig
2 unabhängige Interrupthandler

=> Da die Applikation nichts von Interrupthandler des Bootloaders weiß, 
kann sie diesen auch nicht nutzen. Der Preis der Unabhängigkeit.

Ruediger A. schrieb:
> denn die Prozessorfrequenz ist ebenfalls in einer
> globalen Variable abgelegt, nämlich SystemCoreClock

Den Prozessor interessiert diese Variable garnicht.
Aber davon abgesehen, wird diese von der clib des Bootloaders auf den 
Initialwert des Bootloaders gesetzt und von der clib der Applikation auf 
den Initialwert der Applikation.
Und natürlich kann diese Variable in jedem Fall an einer anderen Stelle 
liegen.

Ich glaube du hast eher deinen Punkt 1 im Blick, bei der die HAL nur 
einmal im Flash liegt. In dem Fall müssen alle Beteiligten die gleichen 
Adressen nutzen. Und dann wird es aus meiner Sicht kompliziert.

Ich finde meinen Weg einfacher, weil man an fast nichts denken muss und 
eine Applikation auch leicht ohne Bootloader testen kann. Aber natürlich 
verbraucht dies zusätzlichen Flash.

von Stefan K. (stefan64)


Lesenswert?

Ruediger A. schrieb:
> Da es vor
> Allem bei kleineren Controllern schwer möglich ist, so etwas potentiell
> footprintreiches wie Hostkommunikationscode zu verdoppeln, wird bei
> diesen Systemen kontrolliert zwischen BL und App hin- und her
> aufgerufen, und da werden solche Themen relevant.

Das verstehe ich, das ist natürlich ein ganz anderer Fall.
Bei uns ist glücklicherweise immer mehr als genug Flash übrig, so dass 
solche Klimmzüge nicht nötig werden.

Viele Grüße, Stefan

von Steffen R. (steffen_rose)


Lesenswert?

Ruediger A. schrieb:
> Man kann auf die Art und Weise sogar mit 32k RAM und 128k Flash

Wieviel Funktiionalität packt ihr in den Bootloader und wie komplex ist 
Eure Hostkommunikation, dass du einen 128k Flash Prozessor als klein 
bezeichnest?

Neugier ist ernst gemeint.

von fsffsfsfdsfsdfsfsdffsdffweewrw5etrdfghjztrfvbnhjzt (Gast)


Lesenswert?

habe auch 2 komplett getrennte projekte draus gemacht
hatte das anfangs mit fester lib im flash und gelinkten aufrufen
aber sobald man was ändert hatte ich das problem das alles nchmal 
durchkompiliert werden muss

daher BL ab adresse 0x8000000 und appl ab 0x8010000
 ja der BL is recht groß
aber da sind nch mehr daten dahinter.


aber wichtg ist für den BL die vectortabelle zu setzen und für die 
applikation

beides muss entsprechend vor dem JUMP in das VTOR register geladen 
werden

also von APPL zu BL  oder umgedreht
immer ISR aus ,
adresse laden ,
VTOR laden,
sprung zu adresse

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Steffen R. schrieb:
> Ruediger A. schrieb:
>> Man kann auf die Art und Weise sogar mit 32k RAM und 128k Flash
>
> Wieviel Funktiionalität packt ihr in den Bootloader und wie komplex ist
> Eure Hostkommunikation, dass du einen 128k Flash Prozessor als klein
> bezeichnest?
>
> Neugier ist ernst gemeint.

Hast ne PM

von fsffsfsfdsfsdfsfsdffsdffweewrw5etrdfghjztrfvbnhjz (Gast)


Lesenswert?

Steffen R. schrieb:
> dass du einen 128k Flash Prozessor als klein
> bezeichnest?

ich habe einen F745 mit 1MB flash und 320k ram ...

Flash ist ca 50-60% voll
Ram je nach betriebsmodus bis zu 90% voll

von tom (Gast)


Lesenswert?

@Laspalmas

Freue mich das Dir geholfen werden konnte.

Wenn Dein BL ein vollkommen eigenständiges Programm ist und die 
Applikation auch (kein shared code der im BL-Bereich liegt), dann sollte 
das alles so funktionieren. Und ja, bevor Du die ISR's in der 
Applikation wieder freigibst, MUSST Du die VECT_TAB_BASE natürlich auf 
die Basisadresse Deiner Applikation setzen, siehe Appnote(s). Da ich 
Deinen zusätzlichen startup-code (SystemInit() bei arm-gcc) nicht kenne, 
am besten erst nach diesem Aufruf in Deiner main() funktion. Und die 
"komische" Adresse die Du da siehst ist in der tat die Adresse des 
compiler startup-codes, wo der kontext des C-Programmes hergestellt 
wird. Da kannst Du Dich belesen wieso warum weshalb bei Interesse.

Um die mit Offset lokierte Applikation zu debuggen, kannst Du Dir ein 
Minimalprogramm bauen das unten im Flash sitzt und direkt in Deine 
Applikation springt - Du weisst ja jetzt wie ;o). Beim download deiner 
Applikation sollte natürlich der untere Flash Bereich nicht gelöscht 
werden - debugger einstellungen checken.

Viel Erfolg, Tom.

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.