2021-10-15 08:00 AM
Hi,
I'm trying to write my own bootloader. It's located in 0x8000000 address of internal flash. I simply want to jump into 0x8080000 internal flash address when I press the external pushbutton connected to the EXTI. The code located into 0x8080000 just toggles a user led. I wrote my own bootloader code:
Bootloader
#define APPLICATION_BASE_ADDR 0x8080000
typedef void (*pFunction)(void); /* Function pointer definition */
/* ------------------------- Functions -------------------------------------- */
void Bootloader_JumpToApplication(void){
uint32_t JumpAddress = *(__IO uint32_t*)(APPLICATION_BASE_ADDR+4);
pFunction Jump = (pFunction)JumpAddress;
HAL_UART_DeInit(&huart3);
HAL_GPIO_DeInit(USER_Btn_GPIO_Port, USER_Btn_Pin);
HAL_GPIO_DeInit(GPIOC, RMII_MDC_Pin|RMII_RXD0_Pin|RMII_RXD1_Pin);
HAL_GPIO_DeInit(GPIOA, RMII_REF_CLK_Pin|RMII_MDIO_Pin|RMII_CRS_DV_Pin);
HAL_GPIO_DeInit(GPIOB, LD1_Pin|LD3_Pin|LD2_Pin);
HAL_GPIO_DeInit(RMII_TXD1_GPIO_Port, RMII_TXD1_Pin);
HAL_GPIO_DeInit(USB_PowerSwitchOn_GPIO_Port, USB_PowerSwitchOn_Pin);
HAL_GPIO_DeInit(USB_OverCurrent_GPIO_Port, USB_OverCurrent_Pin);
HAL_GPIO_DeInit(GPIOA, USB_SOF_Pin|USB_ID_Pin|USB_DM_Pin|USB_DP_Pin);
HAL_GPIO_DeInit(USB_VBUS_GPIO_Port, USB_VBUS_Pin);
HAL_GPIO_DeInit(GPIOG, RMII_TX_EN_Pin|RMII_TXD0_Pin);
__HAL_RCC_GPIOC_CLK_DISABLE();
__HAL_RCC_GPIOH_CLK_DISABLE();
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOD_CLK_DISABLE();
__HAL_RCC_GPIOG_CLK_DISABLE();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
HAL_RCC_DeInit();
HAL_DeInit();
__disable_irq();
SCB->VTOR = APPLICATION_BASE_ADDR;
/* let's do The Jump! */
__set_MSP(*(__IO uint32_t*)APPLICATION_BASE_ADDR);
Jump();
}
Both of codes are generated with STM32CubeMX. Both main.c code are:
Bootloader
int main(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
while (1) { }
}
Application
int main(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
while (1){
HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
HAL_Delay(500);
}
}
I also modified linker files as shown:
Bootloader
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0807FFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x2002FFFF;
define symbol __ICFEDIT_region_CCMRAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_CCMRAM_end__ = 0x1000FFFF;
Application
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08080000;
define symbol __ICFEDIT_region_ROM_end__ = 0x081FFFFF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x2002FFFF;
define symbol __ICFEDIT_region_CCMRAM_start__ = 0x10000000;
define symbol __ICFEDIT_region_CCMRAM_end__ = 0x1000FFFF;
When I try to debug bootloader code, so I push the button, the led should toggle in my application only lights up. If I try to stop debug, it seems the jump is correctly done. So where is the problem? Could you help me please? Thank you.
Best regards,
Antonio
2021-10-15 08:36 AM
> __disable_irq();
There's no need to globally disable interrupts before you jump. They should all be disabled individually since, if they're not, they're going to jump to incorrect code in the new application.
So either remove that line, or enable interrupt again in your main program.
2021-10-16 01:18 AM
Unfortunately I tried both to remove "__disable_irq()" line and to individually disable bootloader IRQs but nothing changes. Do you have any other suggestions? Thank you.
2021-10-16 03:40 AM
2021-10-16 04:33 AM
You're right, I should not jump inside an interrupt service routine. In general, despite being inside an interrupt, it works only if I disable the same interrupt I also use in my application. Is it correct? Should I not use the same interrupts both in the bootloader and in the application? Maybe the problems are:
1) the jump is into an interrupt service routine
2) I use the same interrupt in my application for another scope
Could it be possible?
2021-10-16 08:03 AM
Ok the only problem is the first. I can't jump into an interrupt service routine. I verified that and It's working fine now! I jump from bootloader to application and back again to the bootloader. Thank you @TDK for the support.
Best regards,
Antonio
2021-10-16 08:06 AM
If you jump from within an ISR, your are now running your main loop from that ISR. The jump to bootloader code functions similarly to a "goto" statement. Thus, the same ISR can never fire (since you're already in it) and only interrupts with a higher preemption than it will fire.
2021-10-17 11:27 AM
int main(void){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
while (1) { }
}
In EXTI or other ISR you need only set semaphore, and in main while if and jump to ...