carmstm32interruptlinker-scripts

Stm32 relocating vector table placement in flash


I was trying to achieve this memory structure in my mcu flash

My Linker Script declares in the following order

But after the bootloader jumps to the Main Firmware Reset Handler an exception occours sometime when initalizing the .bss section (it correctly jumps to the reset handler and updates the VTOR)

Everything works if the Main firmware vector table is located before the Main Firmware Image Info, but when I try to swap the twos my firmware crashes during the .bss initialization of the main firmware after bootloader launches it.

Am i missing something? Is there any reason why I cannot seem to interpose a reserved section before the isr vector's?

In the system_stm32wlxx.c in the SystemInit function for the main firmware I have

  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;

Where VECT_TAB_OFFSET = Size of Bootloader section, if the vector table is placed before the image infos. or VECT_TAB_OFFSET = Size of Bootloadersection +Size of Image info section, if the vector table is placed after the image infos.

To perform the jump in the bootloader I have

main_app_code = (uint32_t*) ((uint32_t)&__program1_start+(uint32_t)&__vect_start_offset); // main application base address
uint32_t main_app_stack_pointer = main_app_code[0]; // first word contains the address of the stack pointer
uint32_t main_app_reset_handler = main_app_code[1]; // second word contains the address of the reset handler

where __program1_start is defined in the linker script the address of base flash+bootloader size and __vect_start_offset is also defined in the linker script as the size of the image info section ( or 0 if the isr table is placed before the image info section)

The code is then followed by

/** set the main stack pointer and then perform a jump to the main app reset handler*/
 __set_MSP(main_app_stack_pointer);
/// Jump to application
((void(*)())main_app_reset_handler)();

Linker script of main firmware memory partitioning

/* Memories definition */
MEMORY
{
  RAM    (xrw)  : ORIGIN = 0x20000000, LENGTH = 64K
  RAM2   (xrw)  : ORIGIN = 0x10000000, LENGTH = 32K
  BOOT (rx)     : ORIGIN = 0x08000000, LENGTH = __boot_size
  FLASH   (rx)  : ORIGIN = 0x08000000+LENGTH(BOOT), LENGTH = __program_size
  FLASH2  (rx)  : ORIGIN = ORIGIN(FLASH)+LENGTH(FLASH), LENGTH = __program_size
  DATA (rx)     : ORIGIN = ORIGIN(FLASH2)+LENGTH(FLASH2), LENGTH = __data_size
}

/* Sections */
SECTIONS
{
  

  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
  
/* burn specific firmware data into a section*/
  .fw_infos :
  {
    . = ALIGN(4);
    __fw_crc = ABSOLUTE(.); /* memory address*/
    KEEP(*(.fw_infos)) /* Startup code */
    . = ALIGN(4);
  } >FLASH
etc etc...

Solution

  • I found the cause of the problem, when the image info section was placed before the isr_vector section the expression below should have been equal to 0x8000000|5820 = 0x8005820:

    SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;
    

    But SCB->VTOR is only writable from bits 7 to 31.

    So SCB->VTOR was set to 0x8005800 instead of 0x8005820, this caused the main firmware to crash.

    When instead isr_vector section was placed first, the expression was equal to 0x8000000|5800 and said value is correctly assigned to the SCB->VTOR address and everything worked fine.

    My solution was to change the main firmware linker script, altering the alignment of the Image Info section with the ALIGN(256) command (instead of the previous ALIGN(4)), in this way the following section (the isr_vector section) is placed onto an address whose bits 0-7 are zero and therefore there is no risk of corrupting the SCB->VTOR value.

    SECTIONS
    {
      /* burn specific firmware data into a section*/
      
      .fw_infos :
      {
        . = ALIGN(256);
        __fw_crc = ABSOLUTE(.); /* memory address*/
        KEEP(*(.fw_infos)) /* Startup code */
        . = ALIGN(256);
      } >FLASH
      
      /* The startup code into "FLASH" Rom type memory */
      .isr_vector :
      {
        . = ALIGN(256);
        __vector_start = ABSOLUTE(.); /* memory address*/
        KEEP(*(.isr_vector)) /* Startup code */
        . = ALIGN(4);
      } >FLASH
    

    In some cases ALIGN(128) would work, but in my case ALIGN(256) is necessary because I have 62 interrupt sources and according to Armv7 Architecture:

    The Vector table must be naturally aligned to a power of two whose alignment value is greater than or equal to (Number of Exceptions supported x 4), with a minimum alignment of 128 bytes. On power-on or reset, the processor uses the entry at offset 0 as the initial value for SP_main, see The SP registers. All other entries must have bit [0] set to 1, because this bit defines the EPSR.T bit on exception entry. See Reset behavior and Exception entry behavior for more information.

    So 62*4 = 148 requires 256 alignment.