Forum: Mikrocontroller und Digitale Elektronik Schlanker UART Bootloader für STM32F031c6


von Hochsitz C. (hochsitzcola)


Lesenswert?

Ich habe hier einen E-Bike-Controller, den ich gern über UART flashen 
würde. Wäre prinzipiell kein Problem, leider hat der Hersteller den 
Boot0 Pin nicht auf einen Header gelegt und die Platine komplett 
vergossen. Also möchte ich einen eigenen Bootloader auf die Startadresse 
legen und mein eigentliches Programm an eine höhere Adresse. Dazu gibt 
es einige Beispielprojekte, ich habe dieses auf den STM32F031C6 
portiert:

https://github.com/ferenc-nemeth/stm32-bootloader#references

Das Blöde ist, der Bootloader frisst alleine schon knapp 8kB und der C6 
hat nur 32, so daß die Luft für das eigentliche Programm knapp wird.

Kennt jemand einen geeigneten Bootloader, der weniger Speicher frisst?

Gruß
hochsitzcola

von Bauform B. (bauformb)


Lesenswert?

Da ist doch schon ein UART Bootloader eingebaut, man muss ihn "nur" 
starten. Dein Bootloader müsste nur entscheiden, was gestartet werden 
soll, Hauptprogramm oder integrierter Bootloader. Das darf maximal 42 
Byte kosten.

Wenn der NRST Pin raus geführt ist, kann dein Bootloader das RCC_CSR 
abfragen. Wenn PIN_RSTF nicht gesetzt ist, wird das Hauptprogramm 
gestartet, sonst der UART Bootloader. Ohne Reset-Pin muss man irgendwas 
anderes abfragen, aber das Prinzip bleibt gleich.

Obwohl so ein Programm nur ein paar Zeilen hat, findet man vor allem 
viele misslungene Versuche. Die BootLoaderUniversalAnsprungFunktion() 
hat auch einige Anläufe gebraucht, aber sie hat am Ende funktioniert:

Beitrag "Re: STM32L031K6 Sprung in Bootloader aus Applikation funktioniert nicht"

von Andreas B. (abm)


Lesenswert?

Da der integrierte Bootloader nicht verwendbar war (UART-Pins 
anderweitig besetzt) musste ich einen eigenen schreiben, incl. 
CRC-Berechnung, Software-UART, der nach dem Reset max. 10ms auf ein 
bestimmtes Muster wartet und sonst in die Applikation springt. Das ging 
mit etwas Mühe beim G030 in 2kByte, man muss halt das ganze HAL-Zeugs 
weglassen ...

von Hochsitz C. (hochsitzcola)


Lesenswert?

Bauform B. schrieb:
> Die BootLoaderUniversalAnsprungFunktion()
> hat auch einige Anläufe gebraucht

Prima, auf die Idee, per Software den nativen Bootloader anzuspringen, 
bin ich gar nicht gekommen, das werde ich ausprobieren!

Gruß
hochsitzcola

von Hochsitz C. (hochsitzcola)


Lesenswert?

Hm, der STM32F031c6 ist ein ARM Cortex M0 Prozessor, der anscheinend das 
Remapping nicht beherrscht:

[q]Physical remap
Once the boot mode is selected, the application software can modify the 
memory accessible
in the code area. This modification is performed by programming the 
MEM_MODE bits in
the SYSCFG configuration register 1 (SYSCFG_CFGR1). Unlike Cortex® M3 
and M4, the
M0 CPU does not support the vector table relocation. For application 
code which is located
in a different address than 0x0800 0000, some additional code must be 
added in order to be
able to serve the application interrupts. A solution is to relocate by 
software the vector table
to the internal SRAM:
• Copy the vector table from the flash (mapped at the base of the 
application load
address) to the base address of the SRAM at 0x2000 0000.
• Remap SRAM at address 0x0000 0000, using SYSCFG configuration register 
1.
• Then once an interrupt occurs, the Cortex®-M0 processor fetches the 
interrupt handler
start address from the relocated vector table in SRAM, then it jumps to 
execute the
interrupt handler located in the flash. [/q]

Prinzipiell steht da ja, was man machen muß, für mich sind das 
allerdings bisher böhmische Dörfer, da werde ich mich wohl tiefer 
reinknien müssen.

https://community.st.com/t5/stm32-mcus-embedded-software/interrupt-vector-table-relocation-on-cortex-m0/td-p/483434

Gruß
hochsitzcola

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Hochsitz C. schrieb:
> Dazu gibt es einige Beispielprojekte, ich habe dieses auf
> den STM32F031C6 portiert:
> https://github.com/ferenc-nemeth/stm32-bootloader#references

Wie weit bist du denn mit der Portierung? Im Original wird doch auch das 
VTOR benutzt? Die Kopie im RAM ist für die Hardware oder auf 
Assembler-Ebene kein Problem, aber wie sieht das Linker Script dafür 
aus???

Welchen Compiler bzw. welche IDE benutzt du für das Hauptprogramm?

Ich glaube, es wird einfacher, wenn es nur ein Programm gibt. Dann liegt 
die Vectortable ganz normal im Flash auf 0. Das normale Hauptprogramm 
entscheidet dann, ob es selbst starten soll oder ob es zum eingebauten 
UART-Bootloader springt.

Diese Entscheidung könnte theoretisch ein Menüpunkt in der normalen 
Benutzeroberfläche sein. Aber ich würde auf jeden Fall den NRST-Pin o.ä. 
abfragen. Wenn der Code dafür erstmal funktioniert, sollte der 
Mechanismus doch genauso unkaputtbar sein wie ein getrennter Bootloader. 
Es sind ja nur wenige Zeilen im crt0 aka reset_handler aka 
startup_xxx.s.

von Hochsitz C. (hochsitzcola)


Lesenswert?

Ich habe jetzt viel gelesen, leider funktioniert es nicht :-(
Es stolpern wohl regelmäßig Verwender der STM32F0-Prozessoren über 
dieses Problem:
Zum Beispiel hier:
https://community.st.com/t5/stm32-mcus-products/stm32f072-boot-to-random-address-without-vtor/td-p/579357

Ich habe versucht die vector Tabelle an die Adresse 0x20000000 zu 
schreiben:
1
__IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable")));
2
...
3
4
void __attribute__ ((noreturn))BootLoaderUniversalAnsprungFunktion(void) // ™pegel
5
{
6
7
8
9
  for(i = 0; i < 48; i++)
10
  {
11
     VectorTable[i] = *(__IO uint32_t*)(0x08000000 + (i<<2));
12
  }
13
  RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; //Takt aktivieren
14
  SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_MEM_MODE_1; //Bit löschen
15
  SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_0; //System Memory auf Adresse 0 remappen
16
//    //SysTick zurücksetzen, wird im Bootloader benötigt
17
    SysTick->CTRL = 0;
18
    SysTick->LOAD = 0;
19
    SysTick->VAL = 0;
20
21
22
   __asm__ volatile (
23
      " movs  r0, #0\n"         // Auf 0x0 befindet sich jetzt system memory
24
      " ldr   r1, [r0, #4]\n"   // Startadresse des Bootloaders
25
      " ldr   r0, [r0, #0]\n"   // sein initial Stackpointer
26
      " msr   msp, r0\n"        //
27
      " mov   pc, r1\n"         // dies ist ein jump aka branch
28
   );
29
30
   while(1);
31
}

Geht leider nicht :-(
Ich arbeite mit der Cube IDE. Ich konnte nicht mal herausfinden wo 
.RAMVectorTable definiert ist, aber er kennt es anscheinend..

Irgendwelche Ideen?

Gruß
hochsitzcola

von Bauform B. (bauformb)


Lesenswert?

Hochsitz C. schrieb:
1
SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_MEM_MODE_1; //Bit löschen
2
SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_0; //System Memory auf Adresse 0 remappen
Das ist die Einstellung für System Memory, also für den internen 
Bootloader, Wenn du den starten willst, musst du nichts kopieren. Es 
geht auch garnicht, weil ab 0 Flash ist (eben System Memory). Für den 
Bootloader braucht man auch kein VTOR.

Für RAM ab 0 müssten beide CFGR Bits gesetzt sein. Aber dazu passt die 
Flash-Adresse der Kopie nicht. 0x08000000 wäre ja dein Bootloader.

Was hast du jetzt genau vor?


> Ich arbeite mit der Cube IDE. Ich konnte nicht mal herausfinden wo
> .RAMVectorTable definiert ist, aber er kennt es anscheinend..

Nachdem der Name nur für die section gebraucht wird, muss er den nicht 
kennen. Der Linker legt einfach eine section mit dem Namen an.

von Hochsitz C. (hochsitzcola)


Lesenswert?

Bauform B. schrieb:
> Das normale Hauptprogramm
> entscheidet dann, ob es selbst starten soll oder ob es zum eingebauten
> UART-Bootloader springt.

Bauform B. schrieb:
> Was hast du jetzt genau vor?

Ich möchte einfach nur auf Befehl in den nativen Bootloader springen, 
damit ich mit dem STM32CubeProgrammer über UART die Firmware updaten 
kann.

Der Befehl kann zum Beispiel ein gezogener Bremhebel (GPIO Pin wird auf 
0 gezogen) beim Einschalten sein.

Kann ich dann nicht einfach an die Bootloaderadresse 0x1FFFEC00 
springen?!
https://www.st.com/resource/en/application_note/an2606-stm32-microcontroller-system-memory-boot-mode-stmicroelectronics.pdf

Gruß
hochsitzcola

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Hochsitz C. schrieb:
> Ich möchte einfach nur auf Befehl in den nativen Bootloader springen,

Aus dem normalen Hauptprogramm heraus? Das auf 0x08000000 beginnt?
Dann befindet sich die Vectortable ja automatisch auf der richtigen 
Adresse und es funktioniert ohne VTOR und du musst nichts kopieren.

> Kann ich dann nicht einfach an die Bootloaderadresse 0x1FFFEC00
> springen?!

Du musst nicht einmal die genaue Adresse kennen, die steht ja im Flash 
(System Memory) und das wird mit dem SYSCFG.CFGR nach 0 umgeschaltet. 
Danach steht die Adresse für den Sprung auf 0x00000004. Das kleine 
Assemblerprogramm liest die und springt zum Bootloader.

von Hochsitz C. (hochsitzcola)


Lesenswert?

Bauform B. schrieb:
> Das kleine
> Assemblerprogramm liest die und springt zum Bootloader.

Hm, funktioniert aber nicht. Wenn ich das
1
    SysTick->CTRL = 0;
2
    SysTick->LOAD = 0;
3
    SysTick->VAL = 0;

weglasse, bootet der Prozessor sofort neu in das normale Programm.

Mit den drei Zeilen stoppt zwar die "normale" UART Kommunikation, aber 
CubeProgrammer kann sich trotzdem nicht mit dem Prozessor verbinden:
>  06:44:29 : Serial Port COM6 is successfully opened.

>  06:44:29 : Port configuration: parity = even, baudrate = 115200, data-bit= 8, 
stop-bit = 1.0, flow-control = off

>  06:44:31 : Timeout error occured while waiting for acknowledgement.

>  06:44:31 : Error: Activating device: KO. Please, verify the boot mode 
configuration and check the serial port configuration. Reset your device then try 
again...

Gruß
hochsitzcola

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Schön langsam brauchen wir jemand, der sich mit Cube auskennt...

Hochsitz C. schrieb:
> bootet der Prozessor sofort neu in das normale Programm.

Immerhin, es könnte schlimmer sein, vielleicht fehlt nur eine kleine 
Kleinigkeit. Aber auch dafür wäre es seht hilfreich, wenn wir hier dein 
aktuelles Programm anschauen könnten.

Besonders interessant ist natürlich deine Datei mit dem Assemblertext, 
und main, und die startup Datei. In dem github-Projekt heißt die 
startup/startup_stm32f100xb.s; weiß jemand, wo Cube den entsprechenden 
Quelltext versteckt?

Wenn du die nicht findest: die ELF-Datei, die du zum Flashen benutzt 
hast, wäre ein guter Ersatz.

von Chris R. (emigraen)


Lesenswert?

Hi,

ich habe das ganze für einen STM32F072 umgesetzt, dazu hier ein paar 
Code-Schnipsel, ich hoffe sie helfen weiter.

Für die Vektortabelle muss man im Linkerskript (z.B. STM32F072C8TX.ld im 
CUBE-Projektverzeichnis) eine zusätzliche Section am Anfang des RAM 
anlegen.
Die muss die erste RAM-Section sein, also vor der .data-Section:
Das muss sowohl im (Boot)Loader als auch in der eigentlichen Applikation 
gemacht werden, damit die Vektortabelle dort jeweils an der richtigen 
Stelle liegt.

1
  /* zus?tzliche Section f?r Vektortabelle im RAM: */
2
  
3
  .isr_vector_ram (NOLOAD):
4
  {
5
    . = ALIGN(4);
6
    KEEP(*(.isr_vector_ram)) /* Startup code */
7
    . = ALIGN(4);
8
  } >RAM


Die Vektortabelle dann folgendermaßen im RAM definieren (main.c):
1
#define VECTOR_TABLE_SRAM
2
#define VECTOR_TABLE_LENGTH      48      // Länge der Interrupt-Vektortabelle, siehe Startup-Code.
3
#define ST_BOOTLOADER_STARTADRESSE  0x1FFFC800  // siehe Datenblatt
4
#define BOOTLOADER_FLASH_SIZE_KB  12      // für Bootloader reservierter Speicher. Muss ein Vielfaches der Pagegröße sein!
5
6
#define VECTOR_TABLE_ARRAY_SIZE  (VECTOR_TABLE_LENGTH+1)    // hinter Vektortabelle noch 1 Platz mehr für Variable für Bootloader-Request
7
8
// Muss mit Angaben im Linkerskript der Applikation übereinstimmen. Linkerskript des Bootloaders idealerweise auch anpassen, damit es keine Überlappung geben kann.
9
#define APPLIKATION_STARTADRESSE        (0x08000000 + BOOTLOADER_FLASH_SIZE_KB * 1024)  // Platz für Bootloader freihalten
10
11
#ifdef VECTOR_TABLE_SRAM
12
// Die Interrupt-Vektortabelle im RAM. Dort müssen nachher die Vektoren der Applikation hinkopiert werden
13
volatile uint32_t VectorTable[VECTOR_TABLE_ARRAY_SIZE] __attribute__((section(".isr_vector_ram"))) = {0};  //
14
#endif

Ich habe hinter der Vektortabelle noch einen zusätzlichen Eintrag 
freigelassen, damit kann das Hauptprogramm dort eine Magic Number 
reinschreiben und anschließend einen RESET auslösen. Der Bootloader kann 
dann auf diese Nummer prüfen und ggf. den ST-Bootloader starten. So kann 
der Bootloader indirekt aus dem Hauptprogramm gestartet werden
1
static uint32_t check_backup_reg_bootloader()
2
{
3
  uint32_t ret = 0;
4
  uint32_t bkup_reg;
5
6
  // reservierte RAM-Variable laden
7
  bkup_reg = VectorTable[VECTOR_TABLE_ARRAY_SIZE-1];
8
9
  if (bkup_reg == MAGIC_NUMBER_START_ST_BOOTLOADER)  // ST-Bootloader starten, vorher aber Nummber löschen, sonst Endlosschleife.
10
  {
11
    ret = 1;
12
  }
13
  else if (bkup_reg == MAGIC_NUMBER_START_CUSTOM_BOOTLOADER) // custom Bootloader bleibt aktiv, Timeout deaktivieren
14
  {
15
    ret = 2;
16
  }
17
  else if (bkup_reg == MAGIC_NUMBER_START_APP)
18
  {
19
    ret = 3;
20
  }
21
22
  VectorTable[VECTOR_TABLE_ARRAY_SIZE-1] = 0;  // Nummer löschen
23
  __DSB();            // memory barrier, damit Schreibzugriff garantiert zu Ende ist
24
25
  return ret;
26
}


Das Anspringen von ST-Bootloader oder Hauptprogramm geht folgendermaßen:
1
int main(void)
2
{
3
  uint32_t check;
4
  check = check_backup_reg_bootloader();  // Backupregister prüfen, ggf. Bootloader starten
5
  if (check == 1)
6
  {
7
     // ST-Bootloader
8
     start_app_or_bootloader(0);
9
  }
10
  else if (check == 2)
11
  {
12
     // Applikation
13
     start_app_or_bootloader(1);
14
  }
15
16
  while(1)
17
  {
18
  }
19
}
20
21
// 0 = Bootloader, 1 = Applikation
22
static void start_app_or_bootloader(uint32_t mode)
23
{
24
  void (*JumpAddress)(void);
25
26
  // Startadresse der Applikation bzw des Bootloaders: dort beginnt die Vektortabelle
27
  volatile uint32_t addr;
28
  if (mode == 0)
29
  {
30
    addr = ST_BOOTLOADER_STARTADRESSE;    // Adresse des SystemFLASH Bootloaders
31
  }
32
  else
33
  {
34
    addr = APPLIKATION_STARTADRESSE;
35
  }
36
37
  if (mode == 0)   // Bootloader --> System Memory auf 0 remappen
38
  {
39
    __DSB();  // memory access barrier
40
    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();   // remap system memory to address 0:
41
    __DSB();
42
  }
43
  else // Applikation: Vektortabelle der Applikation dorthin kopieren und dann SRAM auf 0 remappen
44
  {
45
#ifdef VECTOR_TABLE_SRAM
46
  // Vektortabelle ins RAM kopieren
47
  uint32_t* app_ptr = (uint32_t*)((uint32_t)APPLIKATION_STARTADRESSE);
48
  for (uint32_t i=0; i<VECTOR_TABLE_LENGTH; i++)
49
  {
50
    VectorTable[i] = app_ptr[i];
51
  }
52
  __DSB();  // memory access barrier
53
  __HAL_SYSCFG_REMAPMEMORY_SRAM();   // remap SRAM to address 0:
54
  __DSB();
55
#else
56
  // TODO: VTOR setzen für Prozessoren die es haben
57
  #error "VTOR noch nicht implementiert!"
58
#endif
59
  }
60
61
  // Sprungadresse ist zweiter Eintrag der Vektortabelle (erster Eintrag ist Stackpointer)
62
  // Use address with 4 bytes offset which specifies jump location where program starts
63
  JumpAddress = (void (*)(void)) (*((uint32_t *)(addr + 4)));
64
65
  /**
66
   * Set main stack pointer.
67
   * This step must be done last otherwise local variables in this function
68
   * don't have proper value since stack pointer is located on different position
69
   *
70
   * Set direct address location which specifies stack pointer in SRAM location
71
   */
72
  __set_MSP(*(uint32_t *)addr);
73
  __DSB();
74
75
  /**
76
   * Call our function to jump to set location
77
   * This will start system memory execution
78
   */
79
  JumpAddress();
80
81
  // sollte hier nie ankommen
82
  while(1) HAL_NVIC_SystemReset();
83
}

von Hochsitz C. (hochsitzcola)


Lesenswert?

Bauform B. schrieb:
> Aber auch dafür wäre es seht hilfreich, wenn wir hier dein aktuelles
> Programm anschauen könnten.

Das Projekt findest du hier:
https://github.com/stancecoke/Lishui9FET

Allerdings habe ich die nicht funktionierende Funktion noch nicht 
commited. Kann ich heute Abend mal machen und auch die elf Datei mit 
hochladen.

@emigraen: das muss ich erst mal sacken lassen 😁 Ich bin gestern über 
ähnliche Tipps gestolpert, aber mir fehlt da offensichtlich eine Menge 
Hintergrundwissen. Ich will ja gar keinen custom Bootloader verwenden, 
wenn es auch mit dem nativen geht...

Gruß
hochsitzcola

: Bearbeitet durch User
von Chris R. (emigraen)


Lesenswert?

Hochsitz C. schrieb:
> Ich will ja gar keinen custom Bootloader verwenden,
> wenn es auch mit dem nativen geht...

Musst du auch nicht, dann vereinfacht es die Sache deutlich.
Dann brauchst du die Vektortabelle im RAM garnicht, sondern musst 
einfach direkt aus deinem Hauptprogramm meine Beispielfunktion aufrufen:
1
start_app_or_bootloader(0);

Die entsprechenden Code-Teile zum Umkopieren der Tabelle kannst du dort 
dann rauslöschen und das Linkerskript muss dann auch nicht angepasst 
werden.

Der Vorteil an einem kleinen Custom-Bootloader wäre, dass er prüfen 
könnte ob überhaupt eine Applikation geflasht ist und dann im Notfall 
immer den ST-Bootloader anspringt. (Er braucht gar keine eigene 
Flash-Funktion haben, sondern springt nur weiter entweder zur 
Applikation oder zum ST-Bootloader.)

von Hochsitz C. (hochsitzcola)


Lesenswert?

Chris R. schrieb:
> Die entsprechenden Code-Teile zum Umkopieren der Tabelle kannst du dort
> dann rauslöschen und das Linkerskript muss dann auch nicht angepasst
> werden

Das habe ich jetzt auch gemacht, natürlich die Bootloaderadresse 
angepasst, aber das geht auch nicht :-(
Wenn ich im Debugmode die Routine anspringe kommt diese Meldung:
>Break at address "0x2050604" with no debug information available, or outside of 
program code.

Ich habe mit den verschiedensten Kombinationen der vorgeschlagenen 
Lösungen rum gespielt, darum nicht über die vielen auskommentierten 
Zeilen wundern.

https://github.com/stancecoke/Lishui9FET/commit/541ecbb84eb2d1370c0b425124a7ff16c917790c

Die elf-Datei liegt auch im Repo:
https://github.com/stancecoke/Lishui9FET/blob/main/Documentation/Lishui9FET.elf

Gruß
hochsitzcola

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

Bauform B. schrieb:

> Ich glaube, es wird einfacher, wenn es nur ein Programm gibt. Dann liegt
> die Vectortable ganz normal im Flash auf 0. Das normale Hauptprogramm
> entscheidet dann, ob es selbst starten soll oder ob es zum eingebauten
> UART-Bootloader springt.

Das ist genau das Gegenteil von einem guten Bootloader. Von so einem 
sollte das zu ladende "Hauptprogramm" überhaupt nichts wissen müssen 
(allerhöchstens, dass es etwas weniger Flash zur Verfügung hat als es 
"normal" für das Target ist, damit beim Linken eine entsprechende 
Fehlermeldung geworfen werden kann).

Und wenn es nötig ist, das aus dem "Hauptprogramm" den Bootloader zu 
starten, dann sollte es reichen, den µC einfach von dort aus zu zu 
resetten. Wenn die Architektur keine Softwarelösung dafür hergibt (eher 
die Ausnahme), dann halt notfalls über einen GPIO an RESET (mit 
entsprechender Hilfsschaltung dazwischen, sprich: Monoflop).

von Chris R. (emigraen)


Lesenswert?

Hochsitz C. schrieb:
> Das habe ich jetzt auch gemacht, natürlich die Bootloaderadresse
> angepasst, aber das geht auch nicht :-(

Es fehlt (in deinem auskommentierten Code) mindestens das Remapping des 
System Memory auf Adresse 0 wie in meinem Code oben geschrieben:
1
    __DSB();  // memory access barrier
2
    __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();   // remap system memory to address 0:
3
    __DSB();

Ohne das funktioniert es nicht.

Es kann auch potenziell problematisch sein (sollte mit dem Fehler wsl. 
nichts zu tun haben), wenn Teile der HW initialisiert sind wenn man zum 
ST-Bootloader springt. Man weiß nicht, wie genau er initialisiert, also 
sollte vorher alles zurückgesetzt sein. Am einfachsten lässt sich das 
sicherstellen, wenn man vor dem Init von Hardware zum Bootloader 
springt.
Ich mache das so, dass ich eben die Magic Number nach der Vektortabelle 
ganz am Anfang der main() prüfe und ggf. springe, noch bevor Takt usw. 
initialisiert wird. Dann kann man nichts vergessen zu de-initialisieren.

Versuch mal testweise, ganz am Anfang der main() zu springen, um solche 
Probleme auszuschließen.



Hochsitz C. schrieb:
> Break at address "0x2050604" with no debug information available, or
> outside of
> program code.

0x2050604 ist wohl tatsächlich ungültiger Speicherbereich, siehe Memory 
Map im Datenblatt. Also springst du irgendwo falsch hin.
Mit Assembler kann ich leider nicht weiterhelfen, aber im C-Code kannst 
du ja die Sprungadresse (Variable JumpAddress) im Debugger anschauen, 
bevor der Sprung ausgeführt wird. Dass nach dem Sprung das Debuggen 
nicht mehr geht, sollte normal sein, da dann ja der ST-Bootloader 
ausgeführt wird.
https://www.st.com/resource/en/reference_manual/rm0091-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf

Nachtrag: Denkbar wäre auch, dass noch Interrupts aktiviert sind, wenn 
du nicht alles sauber deinitialisierst. Wenn in der Vektortabelle des 
ST-Bootloaders dann kein gültiger Handler eingetragen ist, springt er 
evtl. in ungültigen Bereich. Also noch ein Argument, möglichst früh im 
Programm dorthin zu springen. (Oder einmal den Umweg über RESET zu 
gehen.)

: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Chris R. schrieb:
> du ja die Sprungadresse (Variable JumpAddress) im Debugger anschauen

Die Adresse passt und das remap system memory to address 0 hatte ich 
auch gemacht. Interrupts deaktivieren auch. Direkt am Anfang der main() 
auch nicht. Ich glaub ich brauch erst mal ne Pause :-)
Vielleicht probiere ich dann erst mal den BOOT0 PIN auf GND zu legen, ob 
der STCube Programmer dann die Verbindung hinbekommt...

Gruß
hochsitzcola

: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

An den Boot0 Pin ist nicht ranzukommen :-(
Gibt es eigentlich einen Timeout, wie lange der Bootloader auf den 
Programmer wartet? Und was hat es mit dem Magic Number auf sich, von dem 
immer die Rede ist?!

Gruß
hochsitzcola

von Hochsitz C. (hochsitzcola)


Lesenswert?

Vielleicht bringt mich das auf die richtige Spur?!
https://community.st.com/t5/stm32-mcus/how-to-jump-to-system-bootloader-from-application-code-on-stm32/ta-p/49424

Lässt mich dieser empty-check ggf. stolpern:
>except for the STM32F0 and some STM32L0 that have an empty check mechanism in 
place.

Im reference manual steht:
>Empty check
On STM32F04x and STM32F09x devices only, internal empty check flag is 
implemented to
allow easy programming of virgin devices by the boot loader

Damit sollte der STM32F031C6 diesen empty check nicht haben?!

Edit:
ich habe das o.g. How-To so eingebaut, siehe letztes commit, wenn ich 
jetzt im Debug-Mode den Prozessor anhalte, tummelt er sich irgendwo im 
Adressbereich 0x1fffed72, 0x1fffed68, 0x1fffed7c, sollte also eigentlich 
passen. Aber warum reagiert er nicht auf den Verbindungsversuch vom Cube 
Programmer?!

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Hochsitz C. schrieb:
> Vielleicht bringt mich das auf die richtige Spur?!

Da geht's doch darum, wie man den Bootloader aus dem laufenden 
Hauptprogramm heraus aufruft. Das meiste davon ist überflüssig, wenn das 
Hauptprogramm garnicht läuft. Also wenn du diese Abfrage noch vor main() 
einbaust:

Hochsitz C. schrieb:
> Der Befehl kann zum Beispiel ein gezogener Bremhebel (GPIO Pin wird auf
> 0 gezogen) beim Einschalten sein.


Hochsitz C. schrieb:
> Gibt es eigentlich einen Timeout, wie lange der Bootloader auf den
> Programmer wartet?

Der eingebaute wartet beliebig lange, bis zum nächsten Reset.

> Und was hat es mit dem Magic Number auf sich, von dem
> immer die Rede ist?!

Der entscheidende Punkt: beim Start des Bootloaders müssen die 
Hardware-Register so aussehen, wie nach einem Reset. Dafür gibt es drei 
Möglichkeiten:
a) man startet den Bootloader so früh wie möglich, bevor irgendwelche 
Hardware initialisiert wird
b) man setzt alle einzeln zurück
c) das Hauptprogramm erzeugt selbst einen Hardware-Reset per AIRCR. 
Nachdem das Programm wieder startet, muss es erkennen, ob das ein 
normaler Reset war oder der selbst erzeugte. Dafür kann man eine Magic 
Number ins RAM oder in ein Backup-Register schreiben. Wenn da die 
magische Bitkombination steht, wird zum Bootloader gesprungen, sonst zum 
Hauptprogramm. Man kann stattdessen auch das RCC.CSR Register auswerten. 
Das ist genau dafür da, um verschiedene Reset-Auslöser zu unterscheiden.

von Hochsitz C. (hochsitzcola)


Lesenswert?

Bauform B. schrieb:
> Also wenn du diese Abfrage noch vor main()
> einbaust:

habe ich ja auch probiert, vor jeder Hardwareinitialisierung zu 
springen:
https://github.com/stancecoke/Lishui9FET/blob/92edff1ca3bb2cc05348b4964c219251c542f4e0/Core/Src/main.c#L163

der Prozessor tummelt sich ja anscheinend auch im richtigen 
Adressbereich. Nur er mag sich nicht mit dem Cube Programmer verbinden 
:-(

Gruß
hochsitzcola

: Bearbeitet durch User
von Hochsitz C. (hochsitzcola)


Lesenswert?

Hm, habe noch mal viel gelesen und probiert, hat immer noch nicht 
geklappt. Ich werde das Ganze als nächste an einem Bluepill-Board 
ausprobieren um zu schauen, ob es ggf. an einer Eigenart des STM32F031 
liegt...

Gruß
hochsitzcola

von Hochsitz C. (hochsitzcola)


Lesenswert?

Aaaahhh, ich bin so ein Depp! Die Hardware, die ich nutze, hat UART1 auf 
PB6/PB7 remapped. Dann kann das natürlich nicht gehen mit dem nativen 
Bootloader. :-)

Gruß
hochsitzcola

: Bearbeitet durch User
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.