cancel
Showing results for 
Search instead for 
Did you mean: 

How to boot to random address without VECT_TAB_OFFSET ? stm32f072

Javier1
Principal

I developed my first canbus bootloader for a stm32f105.

Now im in need to use that same bootloader in a stm32f072.

The bootloader works but im unable to build a program that starts from a flash address other than 0x8000000.....

0693W00000Bbh6AQAR.png 

How are multi programm apps being programmes in stm32f0xx families?

we dont need to firmware by ourselves, lets talk
1 ACCEPTED SOLUTION

Accepted Solutions

Okay i built the courage to give this another go and made it work.

 What i did ( following your steps @Community member​ :(

  • added all your defines and variables
/* USER CODE BEGIN PD */
     #define VECTOR_TABLE_SIZE (31 + 1 + 7 +9)//31 positive vectors, 0 vector, and 7 negative vectors (and extra 9 i dont know why)
    #define SYSCFG_CFGR1_MEM_MODE__MAIN_FLASH      0  // x0: Main Flash memory mapped at 0x0000 0000
    #define SYSCFG_CFGR1_MEM_MODE__SYSTEM_FLASH    1  // 01: System Flash memory mapped at 0x0000 0000
    #define SYSCFG_CFGR1_MEM_MODE__SRAM            3  // 11: Embedded SRAM mapped at 0x0000 0000
/* USER CODE END PD */
 
 
..........
 
 
/* USER CODE BEGIN PV */
volatile uint32_t __attribute__((section(".ram_vector,\"aw\",%nobits @"))) ram_vector[VECTOR_TABLE_SIZE];
extern volatile uint32_t g_pfnVectors[VECTOR_TABLE_SIZE];
/* USER CODE END PV */

placed the function before system init

int main(void)
{
  /* USER CODE BEGIN 1 */
 
	    	    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;  // early enable to ensure clock is up and running when it comes to usage
	    	    for (uint32_t i = 0; i < VECTOR_TABLE_SIZE; i++) {//copy vector table
	    	      ram_vector[i] = g_pfnVectors[i];
	    	    }
	    	    SYSCFG->CFGR1 = (SYSCFG->CFGR1 & ~SYSCFG_CFGR1_MEM_MODE) | (SYSCFG_CFGR1_MEM_MODE__SRAM * SYSCFG_CFGR1_MEM_MODE_0);  // remap 0x0000000 to RAM
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  • Added this to the linker script
...............................
 .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
/*javi*/
/*https://community.st.com/s/question/0D53W00000trgpiSAA/how-to-boot-to-random-address-without-vecttaboffset-stm32f072*/
  /* redirected vector must go to top of the RAM  */
  .ram_vector :
  {
    *(.ram_vector)
  } >RAM
/*javi*/
 
 
 
.................

we dont need to firmware by ourselves, lets talk

View solution in original post

13 REPLIES 13
Javier1
Principal

okay, i found someone with my same issue in stack overflow

https://stackoverflow.com/questions/64152604/no-vtor-offset-given-in-stm32f072

we dont need to firmware by ourselves, lets talk

There's no VTOR register in Cortex-M0.

You have to remap RAM to the 0x0000'0000 area (see SYSCFG_CFGR1.MEM_MODE), and copy the custom vector table (from the application's beginning) there.

JW

Reference manual page 168 explains the SYSCFG mem_mode bits.

MEM_MODE[1:0]: Memory mapping selection bits
These bits are set and cleared by software. They control the memory internal mapping at
address 0x0000 0000. After reset these bits take on the value selected by the actual boot
mode configuration. Refer to Chapter 2.5: Boot configuration for more details.
x0: Main Flash memory mapped at 0x0000 0000
01: System Flash memory mapped at 0x0000 0000
11: Embedded SRAM mapped at 0x0000 0000

So in a normal programm

  • MEM_MODE=Main Flash
  • Linker script places the vector table at the beggining of flash

But now we want

  • MEM_MODE=Embedded SRAM
  • Linker script stores Vector table in SRAM

MEMORY
{
  RAM    (xrw)                                   : ORIGIN = 0x20000000,   LENGTH = 16K
  BOOTLOADER    		(rx)    : ORIGIN = 0x08000000,   LENGTH = 18K
  APP		    		(rx)            : ORIGIN = 0x08004800,   LENGTH = 34K
  Configuration         (rx)                : ORIGIN = 0x0800D000,   LENGTH = 2K
  Patterns    			(rx)           : ORIGIN = 0x0800D800,   LENGTH = 10K
}
 
/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >RAM//<-- changed isr table to be in ram memory

  

@Community member​ Once i do this, Does the linker table know that the first part of the sram should not be overwriten?

we dont need to firmware by ourselves, lets talk

> Also the ref manual says MEM_MODE value doesnt reset to 0x00 but it does, if i set it to 0x03 after reset appears as 0x00 again

It resets to the value set by the boot procedure, e.g. if BOOT0 pin is high, it is set during boot to 0b01 to boot from the System Memory (i.e. bootloader). Thus, "normally", after reset it is set to 0b00 to boot from the "normal" FLASH.

> Once i do this, Does the linker table know that the first part of the sram should not be overwriten?

No, you should do it yourself.

There are several ways to achieve this.

As an example, in 'F031, I declare this:

#define SYSCFG_CFGR1_MEM_MODE__MAIN_FLASH      0  // x0: Main Flash memory mapped at 0x0000 0000
#define SYSCFG_CFGR1_MEM_MODE__SYSTEM_FLASH    1  // 01: System Flash memory mapped at 0x0000 0000
#define SYSCFG_CFGR1_MEM_MODE__SRAM            3  // 11: Embedded SRAM mapped at 0x0000 0000
 
 
 #define VECTOR_TABLE_SIZE (USART1_IRQn /* highest supported ISR in F031 */ + 1 + 16 /* because there are "negative counted" system-exceptions and interrupts, too */)
  volatile uint32_t __attribute__((section(".ram_vector,\"aw\",%nobits @"))) ram_vector[VECTOR_TABLE_SIZE];
  extern volatile uint32_t g_pfnVectors[VECTOR_TABLE_SIZE];

then, as first thing in main() (*) I do this:

int main(void) {
    
  {
    uint32_t i;
 
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;  // early enable to ensure clock is up and running when it comes to usage
    for (i = 0; i < VECTOR_TABLE_SIZE; i++) {
      ram_vector[i] = g_pfnVectors[i];
    }
    SYSCFG->CFGR1 = (SYSCFG->CFGR1 AND ~SYSCFG_CFGR1_MEM_MODE) OR (SYSCFG_CFGR1_MEM_MODE__SRAM * SYSCFG_CFGR1_MEM_MODE_0);  // remap 0x0000000 to RAM
 
  }
[continue with main()]

Note, that I don't use Cube's envirnoment, thus I don't have any SystemInit() or similar call in the startup code.

Symbol g_pfnVectors comes from the startup code, it's the label of the vector table, as it is located in FLASH at the beginning of the application:

startupXXXX.S:
 
[...]
/******************************************************************************
*
* The minimal vector table for a Cortex M0.  Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
   .section .isr_vector,"a",%progbits
  .type g_pfnVectors, %object
  .size g_pfnVectors, .-g_pfnVectors
 
 
g_pfnVectors:
  .word  _estack
  .word  Reset_Handler
  .word  NMI_Handler
  .word  HardFault_Handler
[etc]

And I make sure the vector table copy in RAM goes as first to the top of RAM by placing an explicit section as the first input section going into RAM, in linker script:

[here ends the code (FLASH) section]
 
  /* redirected vector must go to top of the RAM  */
  .ram_vector :
  {
    *(.ram_vector)
  } >RAM
 
  /* 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 */
[etc]

JW

@Community member​ 

>It resets to the value set by the boot procedure, e.g. if BOOT0 pin is high, it is set during boot to 0b01 to boot from the System Memory (i.e. bootloader). Thus, "normally", after reset it is set to 0b00 to boot from the "normal" FLASH.

Thats bad news because i have no acess to the BOOT0 pin.

So what youre doing is : (it took me some time to digest)

  • reserving RAM space for the vector table in the linker
  • copy the vector table from Flash to RAM
  • modify SYSCFG->CFGR1 to offset 0x0000 0000 to isr vector in RAM
  • code runs....

So somehow my bootloader needs to have its isrvector table at the beginning of my flash memory (0x8000 0000), as it normally would do.

Bootloader has a reserved space in RAM for the isr of my app?

Before jumping to my app i need to:

  • reserving RAM space for the vector table in the linker
  • copy the vector table from Flash to RAM
  • modify SYSCFG->CFGR1 to offset 0x0000 0000 to isr vector in RAM
  • jump to RAM vector table

Is this doable?:

>And I make sure the vector table copy in RAM goes as first to the top of RAM by placing an explicit section as the first input section going into RAM, in linker script:

I would also need to do this

we dont need to firmware by ourselves, lets talk

What I do is, I leave things as they are normally, for the bootloader.

I perform the copy of vector table and change to SYSCFG->CFGR1 as the first thing in main() of the application. I anticipate, that there's no interrupt enabled by that point, and that nothing will throw a fault (i.e. there's no need for the vector table).

As I've said, there are several ways to do this; yes, this all can be done also in the bootloader, but I decided to do it otherwise.

JW

I am trying it your way, i like it.

questions from your code

  • Frist the linker script
  .ram_vector :
  {
    *(.ram_vector)
  } >RAM

where is .ram_vector comming from?from the volatile uint32_t __attribute__((section(".ram_vector,\"aw\",%nobits @"))) ram_vector[VECTOR_TABLE_SIZE];?

  • Then copying the vector table from flash to ram
 #define VECTOR_TABLE_SIZE (USART1_IRQn /* highest supported ISR in F031 */ + 1 + 16 /* because there are "negative counted" system-exceptions and interrupts, too */)
////i didnt undestood that, the reference manual says STM32f0xx devices have a vector table the size of 31+1+7 vectors
  volatile uint32_t __attribute__((section(".ram_vector,\"aw\",%nobits @"))) ram_vector[VECTOR_TABLE_SIZE];
////i have no idea of what this does, is this telling the linker what .ram_vector is?
 
  extern volatile uint32_t g_pfnVectors[VECTOR_TABLE_SIZE];
////thisone looks for the somewhere else defined g_pfnVectors but i dont get the [VECTOR_TABLE_SIZE] part, shouldnt g_pfnVectors have a fixed already defined size?

we dont need to firmware by ourselves, lets talk

> linker script

> where is .ram_vector coming from?

The name, "ram_vector" is a name arbitrarily chosen by me.

I need to tell the linker, "put my vector array as the first thing into RAM". So, in linker script, I insert those lines above anything else which would go into RAM.

Then, in program, I define the array as

> volatile uint32_t __attribute__((section(".ram_vector,\"aw\",%nobits @"))) ram_vector[VECTOR_TABLE_SIZE];

which tells the linker, that this variable should go to the .ram_vector section (the "\"aw\" etc. part... I honestly don't remember the exact reason, this is probably intended to prevent linker to put initialization values into FLASH; a similar effect should be achievable by tagging the .ram_vector as NOLOAD - usually there are several alternative ways to do things).

>> #define VECTOR_TABLE_SIZE (USART1_IRQn /* highest supported ISR in F031 */ + 1 + 16 /* because there are "negative counted" system-exceptions and interrupts, too */)

> ////i didnt undestood that, the reference manual says STM32f0xx devices have a vector table the size of 31+1+7 vectors

Yes, it's safe to define simply 31 + 1 + 7.

I always attempt to reduce consumed memory - there's no need to go beyond USART1 specifically in 'F031, for which this was intended, as there are no peripherals which have interrupts with higher numbers in that model. On the other hand, in this particular application where I took this from, USART1 is indeed used with interrupt; would it not be used I'd put the highest used ISR's number there.

This is a minor optimization which you may be not needing.

> extern volatile uint32_t g_pfnVectors[VECTOR_TABLE_SIZE];

> ////thisone looks for the somewhere else defined g_pfnVectors

Yes, I have it as a label at the beginning of the vector table, in the startup file.

> shouldnt g_pfnVectors have a fixed already defined size?

Yes, even with optimizing the size of the array in RAM, this indeed might always have the full size.

JW

Okay i built the courage to give this another go and made it work.

 What i did ( following your steps @Community member​ :(

  • added all your defines and variables
/* USER CODE BEGIN PD */
     #define VECTOR_TABLE_SIZE (31 + 1 + 7 +9)//31 positive vectors, 0 vector, and 7 negative vectors (and extra 9 i dont know why)
    #define SYSCFG_CFGR1_MEM_MODE__MAIN_FLASH      0  // x0: Main Flash memory mapped at 0x0000 0000
    #define SYSCFG_CFGR1_MEM_MODE__SYSTEM_FLASH    1  // 01: System Flash memory mapped at 0x0000 0000
    #define SYSCFG_CFGR1_MEM_MODE__SRAM            3  // 11: Embedded SRAM mapped at 0x0000 0000
/* USER CODE END PD */
 
 
..........
 
 
/* USER CODE BEGIN PV */
volatile uint32_t __attribute__((section(".ram_vector,\"aw\",%nobits @"))) ram_vector[VECTOR_TABLE_SIZE];
extern volatile uint32_t g_pfnVectors[VECTOR_TABLE_SIZE];
/* USER CODE END PV */

placed the function before system init

int main(void)
{
  /* USER CODE BEGIN 1 */
 
	    	    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;  // early enable to ensure clock is up and running when it comes to usage
	    	    for (uint32_t i = 0; i < VECTOR_TABLE_SIZE; i++) {//copy vector table
	    	      ram_vector[i] = g_pfnVectors[i];
	    	    }
	    	    SYSCFG->CFGR1 = (SYSCFG->CFGR1 & ~SYSCFG_CFGR1_MEM_MODE) | (SYSCFG_CFGR1_MEM_MODE__SRAM * SYSCFG_CFGR1_MEM_MODE_0);  // remap 0x0000000 to RAM
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  • Added this to the linker script
...............................
 .fini_array :
  {
    . = ALIGN(4);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(4);
  } >FLASH
  
/*javi*/
/*https://community.st.com/s/question/0D53W00000trgpiSAA/how-to-boot-to-random-address-without-vecttaboffset-stm32f072*/
  /* redirected vector must go to top of the RAM  */
  .ram_vector :
  {
    *(.ram_vector)
  } >RAM
/*javi*/
 
 
 
.................

we dont need to firmware by ourselves, lets talk