cancel
Showing results for 
Search instead for 
Did you mean: 

Jump from Openbootloader to the Application

j_filipe
Senior

Greetings! 
So, I used the OpenBootloader project, and then flashed a GPIO_IOToggle firmware in other area of the flash, close to the example in the video Introduction to Open Bootloader, Part 3: Loading an Application.  In that example the CubeProgrammer flashes through the DFU and check "run after programming". When I unplug the board and turn it back on, the OpenBootloader starts (as expected). 
What I want to do is, as soon as I flash the application, when I turn off the board and turn it on again, the application starts to run and not the bootloader, OR, it starts the bootloader, it checks if there's any application installed, and if yes, it jumps to the application immediately. 
Any clue on how to do that?
Thank you! 

19 REPLIES 19

Hello @j_filipe 


@j_filipe wrote:

@Saket_Om 
So tried to do the function you showed me previously, I did it more or less like this, but it doesn't give the jump, it stays in while(1)...


Which while(1)?

While debugging, did the execution enter the if statement: if ((appStack >= RAM_START) && (appStack < RAM_END))?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

@Saket_Om 
The while(1) inside main function...
No, the execution did not enter the if statement... 

j_filipe
Senior

@Saket_Om 
So, what is the alternative? 

T_Hamdi
ST Employee

Hello @j_filipe 

Thank you for sharing your experience with the OpenBootloader project.

To do this, you need to modify the openbootloader code so that at startup it checks if a valid user application is present in the designated flash memory area. If an application is found, the bootloader jumps directly to it; otherwise, it stays in bootloader mode.

Here is how you can implement this:

1/add the following declarations:

typedef void (*pFunction)(void);
pFunction JumpToApplication;
uint32_t JumpAddress;

2/Define the application start address (for example, 0x0800C000), which corresponds to where your user firmware is flashed.

3/In the bootloader’s main() function, before entering the bootloader loop, add the following check:

/* Test if user code is programmed starting from address 0x0800C000 */
    if (((*(__IO uint32_t *) 0x0800C000) & 0x2FFC0000) ==
        0x20000000)
    {
      /* Jump to user application */
      JumpAddress = *(__IO uint32_t *) (0x0800C000 + 4);
      JumpToApplication = (pFunction) JumpAddress;

      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t *) 0x0800C000);
      JumpToApplication();
    }

 

T_Hamdi_1-1761653378679.png

This address (0x0800C000 ) corresponds to the start address of your application, which is defined in your application and must match the address used when generating the application.

After this modification of your OpenBootloader code, the OpenBootloader checks if there is a valid application present; if yes, it jumps to the application, otherwise it enters bootloader mode.

thank you 

Hamdi 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb
j_filipe
Senior

@Saket_Om  @T_Hamdi 
Thank you for your patience so far. 
So I dropped the Openbootloader solution and I implemented an own bootloader. I am using the classic USB device middleware as communication protocol and I followed this tutorial, and so, I increased the minimum heap size for 0x300 and minimum stack size for 0x500. I am using some sort of xmodem communication to receive the .bin file, that passes 128 bytes per packet and after receives the 128bytes, the bootloader flashes the 128bytes. I tried to implement both of your solutions and I am not able to jump to the main application after flashing the firmware. There is something that the protocol does, if the last packet only has for example 1byte of firmware, it sends that 1byte followed by 127byte of a padding pattern (only 0x1A), I don't know if that is messing with the flash and not allowing the firmware to start. I compared the flash memory, (after flashing with my protocol and flashing the same .bin with STM32CubeProgrammer) using the 'cmp' command in bash, and only differences that I found were the following:
9847 32 ^Z 377 M-^?
9848 32 ^Z 377 M-^?
9849 32 ^Z 377 M-^?
9850 32 ^Z 377 M-^?
9851 32 ^Z 377 M-^?
9852 32 ^Z 377 M-^?
9853 32 ^Z 377 M-^?
9854 32 ^Z 377 M-^?
9855 32 ^Z 377 M-^?
9856 32 ^Z 377 M-^?

I guess that happens because of the 0x1A pattern that my protocol writes...
So, what I want to do in my bootloader is:
1 - Start, and checks if there's a valid firmware to run on a specific flash address
2 - If yes, jumps into the application, if no, starts the protocol to receive the firmware
3 - After flash finishes, jumps into the main application. 

I guess that's all... 
Thank you! 



hello @j_filipe 

Thank you for your effort and work on the bootloader implementation.

I would like to suggest considering the use of the   USB DFU (Device Firmware Upgrade) class   instead of the CDC class for your firmware update process. Here are some reasons why DFU might be a better fit:

  • Purpose-built for firmware updates: The USB DFU class is specifically designed for device firmware upgrade operations, providing a standardized and reliable protocol.

  • Simplifies implementation: Using DFU can reduce the complexity of your bootloader communication protocol compared to implementing a custom XMODEM over CDC.

  • Better integration: DFU is widely supported by tools such as STM32CubeProgrammer, making flashing and recovery easier.

Additionally, for practical implementation, you can refer to the official STM32U5 DFU example application available on GitHub: STM32U5 USB Device DFU Standalone Example.

I would like to try the first solution using the Open Bootloader and kindly ask for your feedback on its effectiveness in this context.

Thank you!

 

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb

@T_Hamdi 
Thank you for your response, but I did not ask for the DFU solution... I already was able to flash the application correctly. I changed the FLASH.ld file: 
FLASH (rx) : ORIGIN = 0x0800C000, LENGTH = 10K
and also the system_stm32u5xx.c file: 
#define VECT_TAB_OFFSET 0xC000UL
and generated the bin file. 

Instead of the padding pattern, I placed 0xFF and now the application is flashed correctly, I just need all the steps to make the application jump from the bootloader to the application. 
Thank you! 



hello @j_filipe 

To implement the jump from the bootloader to the application, you need to modify your bootloader code to include the jump logic—typically executed at startup—and optionally control this jump based on a user action, such as pressing a reset or user button.

This follows the same logic to jump as described in the first reply regarding the Open Bootloader, and the same approach can also be applied when using a USB DFU application. 

thank you 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb
j_filipe
Senior

@T_Hamdi @Saket_Om 
I figured it out. 
I managed to flash the firmware and then run it:

typedef void (application_t)(void);
static void jumpToApp(uint32_t address);
typedef struct
{
	uint32_t  		stack_addr;
	application_t* 	func_p;
} JumpStruct;

int main(void)
{
  // Initializes flash, etc.
  HAL_Init();

   // Make all the flashing firmware process

   // finally:
   jumpToApp(APP_START_ADDRESS);
   
   while(1){}
}


static void jumpToApp(const uint32_t address)
{
	const JumpStruct* vector_p = (JumpStruct*)address;

	DeInitEverything();

	asm("msr msp, %0; bx %1;" : : "r"(vector_p->stack_addr), "r"(vector_p->func_p));
}


static void DeInitEverything(void)
{
	USBD_DeInit(&hUsbDeviceFS);
	HAL_PCD_DeInit(&hpcd_USB_OTG_FS);

	HAL_ICACHE_Disable();
	HAL_GPIO_DeInit(MIC_SDIN0_GPIO_Port, MIC_SDIN0_Pin);
	HAL_GPIO_DeInit(USB_UCPD_CC2_GPIO_Port, USB_UCPD_CC2_Pin);
	HAL_GPIO_DeInit(WRLS_SPI2_NSS_GPIO_Port, WRLS_SPI2_NSS_Pin);
	HAL_GPIO_DeInit(USB_VBUS_SENSE_GPIO_Port, USB_VBUS_SENSE_Pin);
	HAL_GPIO_DeInit(OCTOSPI_R_IO6_GPIO_Port, OCTOSPI_R_IO6_Pin);
	HAL_GPIO_DeInit(WRLS_WKUP_B_GPIO_Port, WRLS_WKUP_B_Pin);
	HAL_GPIO_DeInit(MIC_CCK1_GPIO_Port, MIC_CCK1_Pin);
	HAL_GPIO_DeInit(OCTOSPI_R_IO4_GPIO_Port, OCTOSPI_R_IO4_Pin);
	HAL_GPIO_DeInit(USER_Button_GPIO_Port, USER_Button_Pin);
	HAL_GPIO_DeInit(OCTOSPI_R_IO7_GPIO_Port, OCTOSPI_R_IO7_Pin);
	HAL_GPIO_DeInit(OCTOSPI_R_DQS_GPIO_Port, OCTOSPI_R_DQS_Pin);
	HAL_GPIO_DeInit(UCPD_PWR_GPIO_Port, UCPD_PWR_Pin);
	HAL_GPIO_DeInit(PH3_BOOT0_GPIO_Port, PH3_BOOT0_Pin);
	HAL_GPIO_DeInit(OCTOSPI_R_IO5_GPIO_Port, OCTOSPI_R_IO5_Pin);
	HAL_GPIO_DeInit(OCTOSPI_F_NCS_GPIO_Port, OCTOSPI_F_NCS_Pin);
	HAL_GPIO_DeInit(USB_UCPD_CC1_GPIO_Port, USB_UCPD_CC1_Pin);

	__HAL_RCC_GPIOG_CLK_DISABLE();
	__HAL_RCC_GPIOC_CLK_DISABLE();
	__HAL_RCC_GPIOA_CLK_DISABLE();
	__HAL_RCC_GPIOI_CLK_DISABLE();
	__HAL_RCC_GPIOH_CLK_DISABLE();
	__HAL_RCC_GPIOB_CLK_DISABLE();
	__HAL_RCC_GPIOD_CLK_DISABLE();
	__HAL_RCC_GPIOE_CLK_DISABLE();
	__HAL_RCC_GPIOF_CLK_DISABLE();

	HAL_RCC_DeInit();
	HAL_DeInit();
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
}

 
This way worked for me! 
What is missing: 
At the beginnig of the program, check if there's an available application to run, and if yes, jump right next to it, skipping all the flashing process. 


Hello @j_filipe 

you can add a simple check before entering the bootloader. If the application address is valid, the system jumps to it. Otherwise, the system enters bootloader mode and later jumps to the application.

int main(void)
{
  // Initializes flash, etc.
  HAL_Init();
  // Simple MSP validity check
  if (((*(__IO uint32_t *) APP_START_ADDRESS) & 0x2FFC0000) == 0x20000000)
    {
           jumpToApp(APP_START_ADDRESS);
    }
  else
    {
   // Make all the flashing firmware process
  
   // finally:
   jumpToApp(APP_START_ADDRESS);
    }
   
   while(1){}
}

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Hamdi Teyeb