mikrocontroller.net

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


Autor: Martin B. (martin_b97)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Martin B. (ratazong)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Martin B. (martin_b97)
Datum:

Bewertung
0 lesenswert
nicht 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.
/*
Default linker script for STM32F10x_128K_20K with GNU-ld
Martin Thomas, 9/2009
A heavily modified "Default linker script for STM32F10x_512K_64K" 
Copyright RAISONANCE S.A.S. 2008 found in the STM fw-library.
(there is not much left from Raisonance's code and nearly everything
has been modified or reordered)
*/

/* Program Entry, set to mark it as "used" and avoid gc */
ENTRY(Reset_Handler)

/* Memory Spaces Definitions */
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
}

/* higher address of the user mode stack */
_estack = ORIGIN(RAM)+LENGTH(RAM);

/* start of the two 1kByte pages used by EEprom emulation at end of flash */
_seemul = ORIGIN(EEMUL);

/* There will be a link error if there is not this amount of RAM free at the end. */
_Minimum_Stack_Size = 0x100 ;

/* Check valid alignment for VTOR */
ASSERT(ORIGIN(FLASH) == ALIGN(ORIGIN(FLASH), 0x80), "Start of memory region flash not aligned for startup vector table");

/* Sections Definitions */

SECTIONS
{

  /* the program code is stored in the .text section, which goes to Flash */
  .text :
  {
    . = ALIGN(0x80); /* PM0056, Rev.1 (4/2009), 4.3.3 */
    _isr_vectorsflash_offs = . - 0x08000000;
    KEEP(*(.isr_vectorsflash))
    . = ALIGN(4);
    CREATE_OBJECT_SYMBOLS
    *(.text .text.* .gnu.linkonce.t.*)
    *(.plt)
    *(.gnu.warning)
    *(.glue_7t) *(.glue_7) *(.vfp11_veneer)
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    *(.gcc_except_table)
  } >FLASH

  .eh_frame_hdr : ALIGN (4)
  {
    KEEP (*(.eh_frame_hdr))
  } >FLASH
  .eh_frame : ALIGN (4)
  {
    KEEP (*(.eh_frame))
  } >FLASH
  
  /* .ARM.exidx is sorted, so has to go in its own output section.  */
  __exidx_start = .;
  .ARM.exidx :
  {
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
  } >FLASH
  __exidx_end = .;

  .rodata : ALIGN (4)
  {
    *(.rodata .rodata.* .gnu.linkonce.r.*)
    
    . = ALIGN(4);
    KEEP(*(.init))
    
    . = ALIGN(4);
    __preinit_array_start = .;
    KEEP (*(.preinit_array))
    __preinit_array_end = .;
    
    . = ALIGN(4);
    __init_array_start = .;
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array))
    __init_array_end = .;
    
    . = ALIGN(4);
    KEEP(*(.fini))
    
    . = ALIGN(4);
    __fini_array_start = .;
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    __fini_array_end = .;
    
    . = ALIGN(0x4);
    KEEP (*crtbegin.o(.ctors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*crtend.o(.ctors))
    
    . = ALIGN(0x4);
    KEEP (*crtbegin.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*crtend.o(.dtors))
    
    *(.init .init.*)
    *(.fini .fini.*)
    
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array))
    PROVIDE_HIDDEN (__init_array_end = .);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(.fini_array))
    KEEP (*(SORT(.fini_array.*)))
    PROVIDE_HIDDEN (__fini_array_end = .);
    
    . = ALIGN (8);
    *(.rom)
    *(.rom.b)
    _etext = .;
    /* This is used by the startup in order to initialize the .data secion */
    _sidata = _etext;
  } >FLASH

  /* This is the initialized data section
  The program executes knowing that the data is in the RAM
  but the loader puts the initial values in the FLASH (inidata).
  It is one task of the startup to copy the initial values from FLASH to RAM. */
  .data : ALIGN (8)
  {
    /* This is used by the startup in order to initialize the .data section */
    _sdata = . ;
    
    . = ALIGN(0x80);
    _isr_vectorsram_offs = . - 0x20000000;
    KEEP(*(.isr_vectorsram))
    
    . = ALIGN(4);
    KEEP(*(.jcr))
    *(.got.plt) *(.got)
    *(.shdata)
    *(.data .data.* .gnu.linkonce.d.*)
    . = ALIGN (8);
    *(.ram)
    *(.ramfunc*)
     . = ALIGN(4);
    /* This is used by the startup in order to initialize the .data section */
    _edata = .;
  } >RAM AT>FLASH

  /* This is the uninitialized data section */
  .bss (NOLOAD):
  {
    . = ALIGN(4);
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;
    *(.shbss)
    *(.bss .bss.* .gnu.linkonce.b.*)
    *(COMMON)
    . = ALIGN (8);
    *(.ram.b)
    . = ALIGN(4);
     /* This is used by the startup in order to initialize the .bss section */
     _ebss = . ;
    _end = .;
    __end = .;
  } >RAM AT>FLASH


    /* This is the user stack section 
    This is just to check that there is enough RAM left for the User mode stack
    It should generate an error if it's full.
     */
    ._usrstack (NOLOAD):
    {
        . = ALIGN(4);
        _susrstack = . ;
        . = . + _Minimum_Stack_Size ;
        . = ALIGN(4);
        _eusrstack = . ;
    } >RAM


    /* this is the FLASH Bank1 */
    /* the C or assembly source must explicitly place the code or data there
    using the "section" attribute */
    .b1text :
    {
        *(.b1text)                   /* remaining code */
        *(.b1rodata)                 /* read-only data (constants) */
        *(.b1rodata*)
    } >FLASHB1
    
    /* this is the EXTMEM */
    /* the C or assembly source must explicitly place the code or data there
    using the "section" attribute */
    
    /* EXTMEM Bank0 */
    .eb0text :
    {
        *(.eb0text)                   /* remaining code */
        *(.eb0rodata)                 /* read-only data (constants) */
        *(.eb0rodata*)
    } >EXTMEMB0
    
    /* EXTMEM Bank1 */
    .eb1text :
    {
        *(.eb1text)                   /* remaining code */
        *(.eb1rodata)                 /* read-only data (constants) */
        *(.eb1rodata*)
    } >EXTMEMB1
    
    /* EXTMEM Bank2 */
    .eb2text :
    {
        *(.eb2text)                   /* remaining code */
        *(.eb2rodata)                 /* read-only data (constants) */
        *(.eb2rodata*)
    } >EXTMEMB2
    
    /* EXTMEM Bank0 */
    .eb3text :
    {
        *(.eb3text)                   /* remaining code */
        *(.eb3rodata)                 /* read-only data (constants) */
        *(.eb3rodata*)
    } >EXTMEMB3
    
    
    
    /* after that it's only debugging information. */
    
    /* remove the debugging information from the standard libraries */
/*    DISCARD :
    {
     libc.a ( * )
     libm.a ( * )
     libgcc.a ( * )
     }
*/

  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /* DWARF 3 */
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
  .debug_ranges   0 : { *(.debug_ranges) }

  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }
}

/* mthomas:  from the STM example - moved here for now to keep it as reference, not 
   used in the project (useful anyway?)*/

/* default stack size(s). These are used by the startup in order to allocate stacks for 
the different modes. */
__Stack_Size = 1024 ;

PROVIDE ( _Stack_Size = __Stack_Size ) ;
__Stack_Init = _estack - __Stack_Size ;

/*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/
PROVIDE ( _Stack_Init = __Stack_Init ) ;

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

Grüße,
Martin

: Bearbeitet durch User
Autor: pegel (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Wau! So ein Hammer script für das BluePill?

Benutzt du die HAL-Lib?

Autor: Martin B. (ratazong)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl (Gast)
Datum:

Bewertung
-1 lesenswert
nicht 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.

Autor: Martin B. (martin_b97)
Datum:

Bewertung
0 lesenswert
nicht 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:
dfu-util -l
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

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"
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"
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:
dfu-util -a 2 -D ./FLASH_RUN/project.bin

Ausgabe ist folgende:
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release!!!
Opening DFU capable USB device...
ID 1eaf:0003
Run-time device DFU version 0110
Claiming USB DFU Interface...
Setting Alternate Setting #2 ...
Determining device status: state = dfuIDLE, status = 0
dfuIDLE, continuing
DFU mode device DFU version 0110
Device returned transfer size 1024
Copying data from PC to DFU device
Download  [=========================] 100%         4928 bytes
Download done.
state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present
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

Autor: pegel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Martin B. (martin_b97)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: pegel (Gast)
Datum:

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

Autor: Martin B. (martin_b97)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: pegel (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.