Search code examples
stm32bootloaderstm32f0

Place bootloader after the Application in Flash Memory


I wrote a Bootloader for my STM32F042k6 board that functions pretty well. On System Reset the Bootloader is launched and can later jump to the Application. That was great:). Now I wish to do the opposite in my Flash. I wish Launch my Bootloader at a start address other than 0x08000000 lets say at 0x08007000. When I do the modifications in the Linker Script the Programm cannot be debugged. In simple words I wish to place my bootloader at the end of my Flash. Without forget that the Bootloader is always the first Code to run after Reset. Thanks in advance for your help and comments Here is my Linker Script:

/* Entry Point */
ENTRY(Boot_Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20001800;    /* end of 6K RAM */

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0;      /* required amount of heap  */
_Min_Stack_Size = 0x80; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{   
  BOOTLOADER (rx) : ORIGIN = 0x08007000, LENGTH = 4K    
  FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 28K 
  RAM (xrw)       : ORIGIN = 0x200000C0, LENGTH = 6K - 192
  MEMORY_B1 (rx)  : ORIGIN = 0x60000000, LENGTH = 0K
}


/* Define output sections */
SECTIONS
{
  /* The startup code goes first into BOOTLOADER */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >BOOTLOADER



  /* The program code and other data goes into BOOTLOADER */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >BOOTLOADER

  /* Constant data goes into BOOTLOADER */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >BOOTLOADER

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >BOOTLOADER
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >BOOTLOADER

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >BOOTLOADER
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >BOOTLOADER
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >BOOTLOADER

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> BOOTLOADER

  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(4);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(4);
  } >RAM

  /* MEMORY_bank1 section, code must be located here explicitly            */
  /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
  .memory_b1_text :
  {
    *(.mb1text)        /* .mb1text sections (code) */
    *(.mb1text*)       /* .mb1text* sections (code)  */
    *(.mb1rodata)      /* read-only data (constants) */
    *(.mb1rodata*)
  } >MEMORY_B1

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

Solution

  • I'm afraid you're looking after a solution for the wrong problem. Programs loaded by a bootloader can be debugged. I'm doing it all the time.

    So something goes wrong before your application hits the first breakpoint set by the debugger.

    A probably incomplete list of things to check

    • The bootloader does something that makes debugging impossible
      • disables the SWD pins
      • does not jump to the application reset handler
      • starts a watchdog
      • does not disable all possible interrupts
      • does not return to thread mode
      • wrong value in the stack pointer
    • loading the application in the debugger damages the bootloader
      • e.g. erases the wrong flash sectors
    • the application startup code fails
      • problem with the application linker script
      • sets wrong value in the stack pointer
      • sets wrong value in NVIC->VTOR - check this one first if you're using HAL