2

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

My Linker Script declares in the following order

  • Bootloader firmware
  • Main Firmware
    • Main Firmware Image Info (ie. crc, version number)
    • Main Firmware vector table . .everything else

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...
  • 1
    you have not provided enough information, please provide a minimal example, including how you insure the alignment of the vtor, what core you are using as vtor can vary by core/architecture, etc...should only take you a few dozen lines of code to demonstrate the problem that you are describing – old_timer Nov 09 '22 at 20:41
  • if you already have to have the reset vector at 0x00000004 why are you putting your vtor elsewhere? is it in ram? you would init that after .data and .bss ideally not before. your description just does not make sense so we need an example. – old_timer Nov 09 '22 at 20:43
  • you initialize vtor in C? – old_timer Nov 09 '22 at 20:43
  • 2
    It sounds like you are linking the bootloader and the main firmware using one invocation of the linker? I consider that very dangerous; you don't want your bootloader depending on any library functions or stuff in the main firmware, and vice versa, unless it is done very carefully through a well-defined and stable API. They should be linked separately, and combined into a single HEX file later if necessary. – David Grayson Nov 09 '22 at 20:43
  • depends on the overall application as to whether the bootloader should be separate, but from what is there so far it implies that they are developed to be separate but for some reason linked together... – old_timer Nov 09 '22 at 20:45
  • 1
    Sorry for the unintended confusion: the code line SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; Resides in the main firmware, boot loader starts at 0x08000000 so no need for any offset there. bootloader and main firmware have each their own linker script. bootloader and main firmware have their own separate vector tables. (Updated main thread adding memory partitioning in main firmware linker script) – Matteo Vittorio Ricciutelli Nov 09 '22 at 21:22
  • Also I would like to remark that the application works fine if there firmware image info section comes after the isr section in flash, this would exclude problems about the bootloader itself. I am just frustrated because the application crashes if I have the firmware Info section placed before the main firmware isr vector section – Matteo Vittorio Ricciutelli Nov 09 '22 at 21:29
  • I’m voting to close this question because reading the manual indicates VTOR must be aligned. In fact, I have just did the same thing two months ago. I read the manual. – artless noise Nov 11 '22 at 19:49

1 Answers1

1

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.

user16217248
  • 3,119
  • 19
  • 19
  • 37
  • See: [Align in linker scripts](https://stackoverflow.com/questions/8458084/align-in-linker-scripts/72942905#72942905). Some of your stanza do nothing. For instance the first 'ALIGN(256)' in isr_vector. It is happen-stance that you have the alignment. START(.fw_infos) + 256 is aliged to 256, because .fwinfo is aligned to 256. – artless noise Nov 11 '22 at 19:55
  • Also, the STM32 will always require a boot vector at either 0x8000000 or 0x20000000. This is the default VTOR after boot. You can relocate it afterwards, but your initial image must place a valid vector table here. The best might be to copy the flash to RAM. I did this for PIC images where the copy routine also did address fix-ups; so there is only one Flash copy and it is used as a template for the RAM version (like initdata). – artless noise Nov 11 '22 at 20:00