cancel
Showing results for 
Search instead for 
Did you mean: 

Can not jump to APP from bootloader on STM32G0B0CET6

sg0993
Associate II

Hi I have a question that blocked me for several days, Hopefully someone can help, thanks a lot.

1:MCU:STM32G0B0CET6,Develop tool:STM32CubeIDE

2:I wanna have a test for OTA ,so i create a bootloader project and app project

3:Flash segmentation:

1)Bootloader(32KB),0x08000000~0x08007FFF

    APP(240K):0x08008000~0x08047FFF

    APP BAK(236K):0x08048000~0x08079FFF

   INFO(8K):0x0807A000~x0807FFFF

4:In Bootloader ,try to jump to APP(0x08008000):

5:Attached the source code (bootloader and app) and hex file(in debug directory)

6:Modifed "ld" file in bootloader project and app project, and I confirm  the stack address in 0x08008000 and reset_handler in 0x08008004 is correct.

And have set vector in main entry(first line in main()):SCB->VTOR = FLASH_BASE | 0x8000;

7:If i use stm32CubeProgrammmer and STM32CubeIDE to start ,app will be run ,But app can not run via bootloader software jump.

 

bootloader jump slide:

void RunUserCode( void )
{
    uint32_t* ucaddr;

   // if( ( ( *( uint32_t* )ROM_APP_VECT_START_ADDR ) & 0x2FFC0000 ) == 0x20000000 )
    if( ( *( uint32_t* )APP1ADDR ) == 0x20023FF8)
    {
       	HAL_DeInit();//DeInit The Peripherals Used By The Bootloader
        //Rocky report fault shield first __set_FAULTMASK( 1 );
        __disable_irq();
        __set_MSP( *( __IO uint32_t* )APP1ADDR ); // Get top of stack address and initialize SP
        __set_PSP( *( __IO uint32_t* )APP1ADDR );
        __set_CONTROL( 0 );
        ucaddr = ( uint32_t* )( ROM_APP_VECT_RESET_ADDR ); // Get APP Reset Handler address
        ( *( ( void( * )( void ) )( *ucaddr ) ) )();    // Let's Jump!
    }
}

 app vector set:

int main(void)
{

  /* USER CODE BEGIN 1 */
	/* 第一步:强制设置向量表偏移,优先级最高 */
  //SCB->VTOR = 0x08008000;  // 必须放在最前面!
  SCB->VTOR = FLASH_BASE | 0x8000; 
   setMainState(BOOT,3);
  /* 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 */
  MX_GPIO_Init();

bootloader ld slice: :

/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 144K
  FLASH  (rx)     : ORIGIN = 0x08000000,   LENGTH = 32K
}

/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

APP ld Slice:

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */

_estack = 0x20023FF8;/*8 bytes alignment*/

_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Memories definition */
MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 144K  
 
  FLASH  (rx)     : ORIGIN = 0x08008000,   LENGTH = 240K  
}

/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

flash readback screen shot for boot and app:

sg0993_0-1767521397710.png

sg0993_1-1767521424042.png

 

1 ACCEPTED SOLUTION

Accepted Solutions
gbm
Principal

1. The interrupts are disabled while jumping to the app. They must be enabled.

2. No need to set PSP.

3. The code may not work if compiled with the default -O0. Use -O1 or above.

4.The routine jumping to the app should be invoked in the bootloader right after reset, before initializing peripherals. It should NOT be called from ISR. See some other threads on bootloaders and app starting.

5. See the content of the file, esp. the comments:

https://github.com/gbm-ii/STM32_Inc/blob/main/cm_boot.h

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

View solution in original post

10 REPLIES 10
gbm
Principal

1. The interrupts are disabled while jumping to the app. They must be enabled.

2. No need to set PSP.

3. The code may not work if compiled with the default -O0. Use -O1 or above.

4.The routine jumping to the app should be invoked in the bootloader right after reset, before initializing peripherals. It should NOT be called from ISR. See some other threads on bootloaders and app starting.

5. See the content of the file, esp. the comments:

https://github.com/gbm-ii/STM32_Inc/blob/main/cm_boot.h

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
sg0993
Associate II

Hi gpm,

Thanks for your timely response and the issues has been solved.

I try to modify one by one of suggestions you posted.

The root cause is "The interrupts are disabled while jumping to the app. They must be enabled".

So why the interrupts disabling make jump fail? Hopefully get your response again.

Your app must execute with interrupts enabled. If you disable interrupts in the bootoader, then some piece of code must enable them - either the bootloader or the app. In ARM-M architecture interrupts are enabled out of reset, so normally when you write software you assume they are enabled and don't enable them explicitly in the app.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
STOne-32
ST Employee

Dear @gbm ,

Thank you, a lot, for the key contribution. much appreciated and well done for the great catch!

Dear @sg0993 ,

We have these sources codes from our IAP example:

STM32G0xx_IAP/STM32G0xx_IAP at main · stm32-hotspot/STM32G0xx_IAP · GitHub  

Bootloader project is here: STM32G0xx_IAP/STM32G0xx_IAP/IAP_Main at main · stm32-hotspot/STM32G0xx_IAP · GitHub

and main Application as well.

In case it is helpful for other members and to make aware of it inside our  STMicroelectronics - STM32 Hotspot · GitHub

Have a great day,

STOne-32

Hi Gpm,

I also have another question:

1)some peripheral device like USART2,if i start Bootloader project or app project using stm32cubeide in debug mode ,the USART2 can work in app ,but if then power off and restart, app is running ,usart1 is working,but usart2 is not working,why?I try to make usart1 and usart2 configuration same in bootloader and app.,but situation is different.

int main(void)
{

  /* USER CODE BEGIN 1 */
 

  /* 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 */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		//RunUserCode();
		 RunUserCode();
	HAL_Delay(5000);
  }
  /* USER CODE END 3 */
}

I always recommend to go through reset to invoke the app from the bootloader (or the bootloader from the app). Set some flag not affected by reset, issue reset via NVIC_SystemReset(), then at the very start of the bootloader, before configuring any clocks or peripherals, check the flag and start the app or the bootloader.

This way you may avoid all the possible surprises connected to peripheral setup, and, believe me, there are many of them, like SYSCFG stuff or peripheral clock source selection.

Below is a fragment of my portable STM32 bootloader code I use with 5 different STM32 families:

int main(void)
{
	enable_bootflag_access();
	uint32_t boot_addr = get_boot_flag();
	set_boot_flag(0);

	if (boot_addr == BOOT_ADDR)
	{
		app_start(BOOT_ADDR);	// start ST built-in bootloader
	}

	if (boot_addr != (uint32_t)&g_pfnVectors && !force_boot())	// skip searching for app if SWDIO pulled down
	{
		if (boot_addr < FLASH_BASE || (boot_addr & 0x1ff))
			boot_addr = APP_BASE;

		if (boot_addr > FLASH_BASE)
		{
			// check/search for app
			for (boot_addr &= PAGE_BASE_MASK; boot_addr < APP_END; boot_addr += FLASH_PAGE_SIZE)
			{
				if (app_is_valid(boot_addr))
				{
					// app present, delay for double-reset detection
					set_boot_flag((uint32_t)&g_pfnVectors);	// start bootloader after 2nd reset
					// wait for 0.5 s
					SysTick_Delay(INIT_HCLK_FREQ / 2u);	// if MCU is reset during this delay, bootloader will start

					set_boot_flag(0);	// 2nd reset did not happen - normal start after next reset
					app_invoke(boot_addr);	// start the app
				}
			}
			app_not_found = 1;
		}
	}

    // start the bootloader...

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
sg0993
Associate II

Hi  gpm,

It seems that  USART2 also do not work properly  if i move RunUserCode() to the entry of main() according to your suggestion(determine to restart or start app according to the flag). It's so wield that USART1 is ok while USART2  is not in APP. That really  bothers me.....do you have any suggestion? Many thanks.

// 1. 应用程序地址配置(根据ld文件的32KB FLASH/144KB RAM修改)
#define APP1_ADDR          0x08008000U       // 应用程序起始地址(Flash):Bootloader占前32KB Flash的前半部分,App从0x08008000开始
#define FLASH_BASE         0x08000000U       // STM32 Flash基地址(与ld文件一致)
#define RAM_BASE           0x20000000U       // STM32 RAM基地址(与ld文件一致)
#define RAM_SIZE           0x00024000U       // RAM大小:144KB(0x24000 = 144*1024)
#define RAM_END            (RAM_BASE + RAM_SIZE) // RAM结束地址:0x20024000

// 2. 引导标志位定义(核心修改:用.noinit修饰全局变量)
#define FLAG_BOOT_APP      0x55AA55AAU       // 跳应用标志
#define FLAG_BOOTLOADER    0xA55AA55AU       // 留bootloader标志
#define FLAG_NONE          0x00000000U       // 无标志

// 关键:.noinit全局变量,复位后值不丢失(RAM未掉电时)
__attribute__((section(".noinit"))) volatile uint32_t g_boot_flag;


/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
void RunUserCode(void);

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
RTC_HandleTypeDef hrtc;

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */
void RunUserCode(void);
static uint32_t GetBootFlag(void);
static void SetBootFlag(uint32_t flag);
static uint8_t CheckAppValid(uint32_t app_addr);

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* ########################### 核心函数实现 ########################### */
/**
 * @brief  读取引导标志位(.noinit全局变量)
 * @retval 标志位值
 */
static uint32_t GetBootFlag(void)
{
  // 直接读取.noinit全局变量,无需初始化,复位后值保留
  return g_boot_flag;
}

/**
 * @brief  设置引导标志位(.noinit全局变量)
 *   flag: 要设置的标志值
 */
static void SetBootFlag(uint32_t flag)
{
  g_boot_flag = flag;
}

/**
 * @brief  检查应用程序是否有效(适配32KB Flash)
 *   app_addr: 应用程序起始地址
 * @retval 1-有效,0-无效
 */
static uint8_t CheckAppValid(uint32_t app_addr)
{
  uint32_t stack_top = *(volatile uint32_t *)app_addr;      // 应用栈顶地址
  uint32_t reset_handler = *(volatile uint32_t *)(app_addr + 4); // 应用复位函数地址

  // 通用有效性检查:
  // 1. 栈顶地址在144KB RAM范围内(0x20000000 ~ 0x20024000)
  // 2. 复位函数地址在32KB Flash范围内(0x08000000 ~ 0x08008000)
  if ((stack_top >= RAM_BASE) && (stack_top < RAM_END) && (reset_handler >= (FLASH_BASE + 0x8000)) ) // 32KB = 0x8000
  {
    return 1;
  }
  return 0;
}
void RunUserCode( void )
{
    uint32_t* ucaddr;
	uint32_t boot_flag = GetBootFlag();
   // if( ( ( *( uint32_t* )ROM_APP_VECT_START_ADDR ) & 0x2FFC0000 ) == 0x20000000 )
    if((boot_flag == FLAG_BOOT_APP) && CheckAppValid(APP1_ADDR))
    {
    	SetBootFlag(FLAG_NONE);
       	//HAL_DeInit();//DeInit The Peripherals Used By The Bootloader
        //Rocky report fault shield first __set_FAULTMASK( 1 );
        //__disable_irq();
        __set_MSP( *( __IO uint32_t* )APP1ADDR ); // Get top of stack address and initialize SP
        //__set_PSP( *( __IO uint32_t* )APP1ADDR );
        __set_CONTROL( 0 );
        ucaddr = ( uint32_t* )( ROM_APP_VECT_RESET_ADDR ); // Get APP Reset Handler address
        ( *( ( void( * )( void ) )( *ucaddr ) ) )();    // Let's Jump!
    }
	SetBootFlag(FLAG_BOOT_APP);
	NVIC_SystemReset();
}
int main(void)
{

  /* USER CODE BEGIN 1 */
 	RunUserCode();


  /* 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 */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		//RunUserCode();
		//RunUserCode();
	HAL_Delay(5000);
  }
  /* USER CODE END 3 */
}

 

gbm
Principal

In the code above, there is no reason for any USART to start incorrectly.

BUT for the above code to work, .noinit section must be handled correctly in the linker script, which is not always the case with CubeMX-generated linker scripts.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
sg0993
Associate II

Hi gpm,

I also think there is no reason for any USART to start incorrectly.

I know the link scripts modification and add the below in the ld file:

 .noinit (NOLOAD) :
  {
    . = ALIGN(4);
    *(.noinit)      
    *(.noinit.*)    
    . = ALIGN(4);
  } >RAM

I will try again in another board and get back to you.