Forum: Mikrocontroller und Digitale Elektronik STM32F103 "Blue Pill" USB Bootloader Linux


von Martin B. (martin_b97)


Lesenswert?

Hallo zusammen,

ich habe gerade ein Problem, ein "Blue Pill" Board mit dem USB 
Bootloader von 
https://github.com/rogerclarkmelbourne/STM32duino-bootloader/tree/master/binaries 
(generic_boot20_pc13.bin) ans laufen zu kriegen.

Ich kann problemlos den Bootloader auf den Chip über mein parallel zum 
USB angeschlossenes USB-Serial Interface an PB9 und PB10 flashen, mit 
dem stm32loader.py script. Der Bootloader scheint auch aktiv zu sein 
anhand der LED blink codes, die er beim Betätigen der Reset Taste 
ausgibt.

Weiterhin bin ich in der Lage über den USB Bootloader ein vorher 
kompiliertes Programm per dfu-util (version 0.9) raufzuladen, nur dass 
dieses Programm dann keinerlei Funktion zeigt.

Lade ich das gleiche Programm ohne Bootloader über den stm32loader.py 
auf den Chip, funktioniert alles wie es soll. Ich habe ein einfaches 
Blinky ausprobiert.

Mein Verdacht ist, dass das Programm bei Verwendung des Bootloaders 
evtl. an eine andere Adresse im Flash geladen werden muss, aber da bin 
ich mir eben nicht sicher.

Leider finde ich nur Anleitungen, wie diese Arduino-GUIs zu verwenden 
sind, aber ich will das nur mit GCC und Makefile und den unter Linux 
vorhandenen Tools machen.

Grüße,
Martin

: Bearbeitet durch User
von Martin B. (ratazong)


Lesenswert?

Ja, der bootloader benutzt den ersten Bereich des Programmspeichers. Da 
wo dein programm normalerweise läuft.

Du musst wissen, wo der bootloader das Programm hinpackt. Dann musst Du 
den Linkerscript entsprechend anpassen.
Aber das ist noch nicht alles. Die Vektortable für die Interruptroutinen 
muss an der richtigen stelle stehen. Mit Glück passt das der Bootloader 
entsprechend an.
Wenn Du CubeMX benutzt, gibt noch eine weitere Falle.

Martin

von Martin B. (martin_b97)


Lesenswert?

Hallo,

anbei mal mein Linker-Script (hoffe es ist auch das relevante 
Linker-Script, habe da nicht so die Ahnung, da bisher nur mit AVRs 
unterwegs gewesen). Da war das nicht so relevant.
1
/*
2
Default linker script for STM32F10x_128K_20K with GNU-ld
3
Martin Thomas, 9/2009
4
A heavily modified "Default linker script for STM32F10x_512K_64K" 
5
Copyright RAISONANCE S.A.S. 2008 found in the STM fw-library.
6
(there is not much left from Raisonance's code and nearly everything
7
has been modified or reordered)
8
*/
9
10
/* Program Entry, set to mark it as "used" and avoid gc */
11
ENTRY(Reset_Handler)
12
13
/* Memory Spaces Definitions */
14
MEMORY
15
{
16
  RAM      (RWX) : ORIGIN = 0x20000000+0, LENGTH = 20K-0
17
  EXTSRAM  (RWX) : ORIGIN = 0x68000000, LENGTH = 0
18
  FLASH    (RX)  : ORIGIN = 0x08000000+0, LENGTH = 128K-2K-0
19
  EEMUL    (RWX) : ORIGIN = 0x08000000+128k-2k, LENGTH = 2k
20
  FLASHB1  (RX)  : ORIGIN = 0x00000000, LENGTH = 0
21
  EXTMEMB0 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
22
  EXTMEMB1 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
23
  EXTMEMB2 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
24
  EXTMEMB3 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
25
}
26
27
/* higher address of the user mode stack */
28
_estack = ORIGIN(RAM)+LENGTH(RAM);
29
30
/* start of the two 1kByte pages used by EEprom emulation at end of flash */
31
_seemul = ORIGIN(EEMUL);
32
33
/* There will be a link error if there is not this amount of RAM free at the end. */
34
_Minimum_Stack_Size = 0x100 ;
35
36
/* Check valid alignment for VTOR */
37
ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table");
38
39
/* Sections Definitions */
40
41
SECTIONS
42
{
43
44
  /* the program code is stored in the .text section, which goes to Flash */
45
  .text :
46
  {
47
    . = ALIGN(0x80); /* PM0056, Rev.1 (4/2009), 4.3.3 */
48
    _isr_vectorsflash_offs = . - 0x08000000;
49
    KEEP(*(.isr_vectorsflash))
50
    . = ALIGN(4);
51
    CREATE_OBJECT_SYMBOLS
52
    *(.text .text.* .gnu.linkonce.t.*)
53
    *(.plt)
54
    *(.gnu.warning)
55
    *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
56
    *(.ARM.extab* .gnu.linkonce.armextab.*)
57
    *(.gcc_except_table)
58
  } >FLASH
59
60
  .eh_frame_hdr : ALIGN (4)
61
  {
62
    KEEP (*(.eh_frame_hdr))
63
  } >FLASH
64
  .eh_frame : ALIGN (4)
65
  {
66
    KEEP (*(.eh_frame))
67
  } >FLASH
68
  
69
  /* .ARM.exidx is sorted, so has to go in its own output section.  */
70
  __exidx_start = .;
71
  .ARM.exidx :
72
  {
73
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
74
  } >FLASH
75
  __exidx_end = .;
76
77
  .rodata : ALIGN (4)
78
  {
79
    *(.rodata .rodata.* .gnu.linkonce.r.*)
80
    
81
    . = ALIGN(4);
82
    KEEP(*(.init))
83
    
84
    . = ALIGN(4);
85
    __preinit_array_start = .;
86
    KEEP (*(.preinit_array))
87
    __preinit_array_end = .;
88
    
89
    . = ALIGN(4);
90
    __init_array_start = .;
91
    KEEP (*(SORT(.init_array.*)))
92
    KEEP (*(.init_array))
93
    __init_array_end = .;
94
    
95
    . = ALIGN(4);
96
    KEEP(*(.fini))
97
    
98
    . = ALIGN(4);
99
    __fini_array_start = .;
100
    KEEP (*(.fini_array))
101
    KEEP (*(SORT(.fini_array.*)))
102
    __fini_array_end = .;
103
    
104
    . = ALIGN(0x4);
105
    KEEP (*crtbegin.o(.ctors))
106
    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
107
    KEEP (*(SORT(.ctors.*)))
108
    KEEP (*crtend.o(.ctors))
109
    
110
    . = ALIGN(0x4);
111
    KEEP (*crtbegin.o(.dtors))
112
    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
113
    KEEP (*(SORT(.dtors.*)))
114
    KEEP (*crtend.o(.dtors))
115
    
116
    *(.init .init.*)
117
    *(.fini .fini.*)
118
    
119
    PROVIDE_HIDDEN (__preinit_array_start = .);
120
    KEEP (*(.preinit_array))
121
    PROVIDE_HIDDEN (__preinit_array_end = .);
122
    PROVIDE_HIDDEN (__init_array_start = .);
123
    KEEP (*(SORT(.init_array.*)))
124
    KEEP (*(.init_array))
125
    PROVIDE_HIDDEN (__init_array_end = .);
126
    PROVIDE_HIDDEN (__fini_array_start = .);
127
    KEEP (*(.fini_array))
128
    KEEP (*(SORT(.fini_array.*)))
129
    PROVIDE_HIDDEN (__fini_array_end = .);
130
    
131
    . = ALIGN (8);
132
    *(.rom)
133
    *(.rom.b)
134
    _etext = .;
135
    /* This is used by the startup in order to initialize the .data secion */
136
    _sidata = _etext;
137
  } >FLASH
138
139
  /* This is the initialized data section
140
  The program executes knowing that the data is in the RAM
141
  but the loader puts the initial values in the FLASH (inidata).
142
  It is one task of the startup to copy the initial values from FLASH to RAM. */
143
  .data : ALIGN (8)
144
  {
145
    /* This is used by the startup in order to initialize the .data section */
146
    _sdata = . ;
147
    
148
    . = ALIGN(0x80);
149
    _isr_vectorsram_offs = . - 0x20000000;
150
    KEEP(*(.isr_vectorsram))
151
    
152
    . = ALIGN(4);
153
    KEEP(*(.jcr))
154
    *(.got.plt) *(.got)
155
    *(.shdata)
156
    *(.data .data.* .gnu.linkonce.d.*)
157
    . = ALIGN (8);
158
    *(.ram)
159
    *(.ramfunc*)
160
     . = ALIGN(4);
161
    /* This is used by the startup in order to initialize the .data section */
162
    _edata = .;
163
  } >RAM AT>FLASH
164
165
  /* This is the uninitialized data section */
166
  .bss (NOLOAD):
167
  {
168
    . = ALIGN(4);
169
    /* This is used by the startup in order to initialize the .bss section */
170
    _sbss = .;
171
    *(.shbss)
172
    *(.bss .bss.* .gnu.linkonce.b.*)
173
    *(COMMON)
174
    . = ALIGN (8);
175
    *(.ram.b)
176
    . = ALIGN(4);
177
     /* This is used by the startup in order to initialize the .bss section */
178
     _ebss = . ;
179
    _end = .;
180
    __end = .;
181
  } >RAM AT>FLASH
182
183
184
    /* This is the user stack section 
185
    This is just to check that there is enough RAM left for the User mode stack
186
    It should generate an error if it's full.
187
     */
188
    ._usrstack (NOLOAD):
189
    {
190
        . = ALIGN(4);
191
        _susrstack = . ;
192
        . = . + _Minimum_Stack_Size ;
193
        . = ALIGN(4);
194
        _eusrstack = . ;
195
    } >RAM
196
197
198
    /* this is the FLASH Bank1 */
199
    /* the C or assembly source must explicitly place the code or data there
200
    using the "section" attribute */
201
    .b1text :
202
    {
203
        *(.b1text)                   /* remaining code */
204
        *(.b1rodata)                 /* read-only data (constants) */
205
        *(.b1rodata*)
206
    } >FLASHB1
207
    
208
    /* this is the EXTMEM */
209
    /* the C or assembly source must explicitly place the code or data there
210
    using the "section" attribute */
211
    
212
    /* EXTMEM Bank0 */
213
    .eb0text :
214
    {
215
        *(.eb0text)                   /* remaining code */
216
        *(.eb0rodata)                 /* read-only data (constants) */
217
        *(.eb0rodata*)
218
    } >EXTMEMB0
219
    
220
    /* EXTMEM Bank1 */
221
    .eb1text :
222
    {
223
        *(.eb1text)                   /* remaining code */
224
        *(.eb1rodata)                 /* read-only data (constants) */
225
        *(.eb1rodata*)
226
    } >EXTMEMB1
227
    
228
    /* EXTMEM Bank2 */
229
    .eb2text :
230
    {
231
        *(.eb2text)                   /* remaining code */
232
        *(.eb2rodata)                 /* read-only data (constants) */
233
        *(.eb2rodata*)
234
    } >EXTMEMB2
235
    
236
    /* EXTMEM Bank0 */
237
    .eb3text :
238
    {
239
        *(.eb3text)                   /* remaining code */
240
        *(.eb3rodata)                 /* read-only data (constants) */
241
        *(.eb3rodata*)
242
    } >EXTMEMB3
243
    
244
    
245
    
246
    /* after that it's only debugging information. */
247
    
248
    /* remove the debugging information from the standard libraries */
249
/*    DISCARD :
250
    {
251
     libc.a ( * )
252
     libm.a ( * )
253
     libgcc.a ( * )
254
     }
255
*/
256
257
  /* Stabs debugging sections.  */
258
  .stab          0 : { *(.stab) }
259
  .stabstr       0 : { *(.stabstr) }
260
  .stab.excl     0 : { *(.stab.excl) }
261
  .stab.exclstr  0 : { *(.stab.exclstr) }
262
  .stab.index    0 : { *(.stab.index) }
263
  .stab.indexstr 0 : { *(.stab.indexstr) }
264
  .comment       0 : { *(.comment) }
265
  /* DWARF debug sections.
266
     Symbols in the DWARF debugging sections are relative to the beginning
267
     of the section so we begin them at 0.  */
268
  /* DWARF 1 */
269
  .debug          0 : { *(.debug) }
270
  .line           0 : { *(.line) }
271
  /* GNU DWARF 1 extensions */
272
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
273
  .debug_sfnames  0 : { *(.debug_sfnames) }
274
  /* DWARF 1.1 and DWARF 2 */
275
  .debug_aranges  0 : { *(.debug_aranges) }
276
  .debug_pubnames 0 : { *(.debug_pubnames) }
277
  /* DWARF 2 */
278
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
279
  .debug_abbrev   0 : { *(.debug_abbrev) }
280
  .debug_line     0 : { *(.debug_line) }
281
  .debug_frame    0 : { *(.debug_frame) }
282
  .debug_str      0 : { *(.debug_str) }
283
  .debug_loc      0 : { *(.debug_loc) }
284
  .debug_macinfo  0 : { *(.debug_macinfo) }
285
  /* SGI/MIPS DWARF 2 extensions */
286
  .debug_weaknames 0 : { *(.debug_weaknames) }
287
  .debug_funcnames 0 : { *(.debug_funcnames) }
288
  .debug_typenames 0 : { *(.debug_typenames) }
289
  .debug_varnames  0 : { *(.debug_varnames) }
290
  /* DWARF 3 */
291
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
292
  .debug_ranges   0 : { *(.debug_ranges) }
293
294
  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
295
  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
296
  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }
297
}
298
299
/* mthomas:  from the STM example - moved here for now to keep it as reference, not 
300
   used in the project (useful anyway?)*/
301
302
/* default stack size(s). These are used by the startup in order to allocate stacks for 
303
the different modes. */
304
__Stack_Size = 1024 ;
305
306
PROVIDE ( _Stack_Size = __Stack_Size ) ;
307
__Stack_Init = _estack - __Stack_Size ;
308
309
/*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/
310
PROVIDE ( _Stack_Init = __Stack_Init ) ;

Was müsste ich jetzt da ändern um mit dem USB-Bootloader klarzukommen?

Grüße,
Martin

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Wau! So ein Hammer script für das BluePill?

Benutzt du die HAL-Lib?

von Martin B. (ratazong)


Lesenswert?

MEMORY
{
  RAM      (RWX) : ORIGIN = 0x20000000+0, LENGTH = 20K-0
  EXTSRAM  (RWX) : ORIGIN = 0x68000000, LENGTH = 0
  FLASH    (RX)  : ORIGIN = 0x08000000+0, LENGTH = 128K-2K-0
  EEMUL    (RWX) : ORIGIN = 0x08000000+128k-2k, LENGTH = 2k
  FLASHB1  (RX)  : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB0 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB1 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB2 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB3 (RX)  : ORIGIN = 0x00000000, LENGTH = 0
}

in der Memeory Beschreibung musst Du die Zeile FLASH anpassen. Da steht 
ORIGIN  und LENGTH
0x8000000 ist start of flash des stm, da steht jetzt Dein bootloader. Du 
musst die Adresse entsprechend erhöhen und die Länge kürzen.

von Karl (Gast)


Lesenswert?

pegel schrieb:
> Wau! So ein Hammer script für das BluePill?

Manche Leute haben das berühmte "Warum soll ichs mir einfach machen 
wenns auch kompliziert geht?" eben wirklich verinnerlicht.

von Martin B. (martin_b97)


Lesenswert?

Hallo,

freut mich, dass ich euch mit meinem anscheinend 'overkill' 
Linker-Script zum Lachen bringen konnte. Ich hab das aus irgend einem 
Projekt übernommen und es hat funktioniert. So what? Falls jemand was 
geeigneteres rumliegen hat nehme ich gerne das.

Aber es funktioniert leider noch nicht, daher noch einige Fragen:

dfu-util -l liefert folgendes:
1
dfu-util -l
2
dfu-util 0.9
3
4
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
5
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
6
This program is Free Software and has ABSOLUTELY NO WARRANTY
7
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
8
9
Found DFU: [1eaf:0003] ver=0201, devnum=98, cfg=1, intf=0, path="1-1.1", alt=2, name="STM32duino bootloader v1.0  Upload to Flash 0x8002000", serial="LLM 003"
10
Found DFU: [1eaf:0003] ver=0201, devnum=98, cfg=1, intf=0, path="1-1.1", alt=1, name="STM32duino bootloader v1.0  Upload to Flash 0x8005000", serial="LLM 003"
11
Found DFU: [1eaf:0003] ver=0201, devnum=98, cfg=1, intf=0, path="1-1.1", alt=0, name="STM32duino bootloader v1.0  ERROR. Upload to RAM not supported.", serial="LLM 003"

Es scheint also mehrere mit alt=? auswählbare Versionen zu geben, die an 
verschiedene Flash-Adressen laden. Macht das nun der Bootloader von 
selbst oder muss es trotzdem im Linker-Script angepasst werden?

Mein Aufruf von dfu-util zum Flashen sieht dann so aus:
1
dfu-util -a 2 -D ./FLASH_RUN/project.bin

Ausgabe ist folgende:
1
dfu-util 0.9
2
3
Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
4
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
5
This program is Free Software and has ABSOLUTELY NO WARRANTY
6
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/
7
8
dfu-util: Invalid DFU suffix signature
9
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
10
Opening DFU capable USB device...
11
ID 1eaf:0003
12
Run-time device DFU version 0110
13
Claiming USB DFU Interface...
14
Setting Alternate Setting #2 ...
15
Determining device status: state = dfuIDLE, status = 0
16
dfuIDLE, continuing
17
DFU mode device DFU version 0110
18
Device returned transfer size 1024
19
Copying data from PC to DFU device
20
Download  [=========================] 100%         4928 bytes
21
Download done.
22
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
23
Done!

Ich habe das mit den FLASH Adressen 0x08000000, 0x08002000 und 
0x08005000 im Linker-Script versucht, jedoch ohne Erfolg.

Hat noch jemand eine Idee?

Grüße,
Martin

von pegel (Gast)


Lesenswert?

Hättest du meine Frage nach HAL beantwortet ....

Aber auch so mein Tip.
In der HAL Lib gibt es ein IAP_Binary_Template Projekt,
das steht wie es gemacht wird.

Wenn du an der Funktion des Boot-Ladens interessiert bist, empfehle ich 
dazu das IAP_Main Projekt, welches über die serielle Schnittstelle 
funktioniert.

von Martin B. (martin_b97)


Lesenswert?

Hallo pegel,

ich benutze kein HAL. Den Bootloader über seriell habe ich ja schon 
benutzt um den USB Bootloader draufzuspielen. Der funktioniert also.

Grüße,
Martin

von pegel (Gast)


Lesenswert?

Ich meinte nicht nur das Benutzen, sondern das Erstellen und Verstehen 
des Bootloaders und der passenden Anwendung.

von Martin B. (martin_b97)


Lesenswert?

Hallo,

wie du vielleicht merkst, verstehe ich das Ganze nicht wirklich.

Was ich bisher dachte zu wissen:

der Bootloader setzt sich an die Startadresse, an der normal das 
Programm startet (in diesem Fall wohl 0x08000000). Nach einem Reset 
wartet der Bootloader auf ein zu übertagendes Programm. Wenn er das 
bekommt, lädt er es in einen höheren Adressbereich (in diesem Fall z.B. 
0x08002000) und führt es dann aus.

Wenn ein Programm schon vorhanden ist wartet der Bootloader kurz ob er 
ein neues Programm empfangen soll und führt ansonsten schon das 
vorhandene aus.

Soweit mein Verständnis. Was ich nicht weiß, ist wie ein solches 
Programm beschaffen sein muss, damit es über den Bootloader gestartet 
werden kann. Ich war der Meinung dass das halbwegs transparent abläuft, 
aber so scheint es nicht zu sein.

Grüße,
Martin

von pegel (Gast)


Lesenswert?

Das stimmt im Prinzip auch so.
Zuerst musst du wissen an welche Adresse der Bootloader dein Programm 
lädt.

Ein gutes Programm zur Verwaltung des Speichers ist der 
STM32CubeProgrammer.
Der kann SWD, dfu und USB.

Damit kannst du sehen wohin dein Prog geladen wird und es entsprechend 
anpassen.

Dann aus der IAP_Binary_Template/readme.txt:

To build such application, some special configuration has to be 
performed:
1. Set the program load address at 0x08004000, using your toolchain 
linker file
2. Relocate the vector table at address 0x08004000, using the 
"NVIC_SetVectorTable"
   function.

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.