Skip to main content
Jack3
Senior
August 19, 2019
Question

STM32H7 Bootloader jumps as clean as possible to application

  • August 19, 2019
  • 1 reply
  • 2643 views

Hi,

for this experiment, I use a NUCLEO-H743ZI (with 'Y' version MCU).

I have created two different versions of an application and two versions of a bootloader.

They are just very simple.

One (let's call it version A) is just a blinking a LED and printing on a UART.

The other (version B) is likewise, but also drives an OLED display.

The bootloader prints 'b' to the serial port every 500mS, the app prints 'a' to the serial port every 500mS.

When pressing the user button during reset, the bootloader enters a while loop (printing b's),

and only jumps to the application if the user button is released and pressed again.

If the user button is released during a reset the bootloader jumps to the application directly.

Bootloader A works fine with application A, and B with B.

Somehow I cannot let bootloader A have app B started, or let bootloader B have app A started.

I thought these could be independent programs.

I searched and read a lot about this topic, but I can't seem to find a solution.

What can I check?

My current JumpToApplication program in the bootloader:

void Bootloader_JumpToApplication(uint32_t AppAddress)
{
 typedef void (*pFunction)(void);
 
 /* Set the address of the entry point to application */
 volatile uint32_t BootAddr = AppAddress;
 
 printmsg("BL_DEBUG_MSG: Bootloader_JumpToApplication\n");
 
 uint32_t MSPValue = *(__IO uint32_t*)BootAddr;
 printmsg("BL_DEBUG_MSG: MSP value: 0x%08x\n", MSPValue);
 
 uint32_t JumpAddress = *(__IO uint32_t*)(BootAddr + 4);
 
 pFunction JumpToApplication = (pFunction)JumpAddress;
 printmsg("BL_DEBUG_MSG: JumpAddress: 0x%08x\n", JumpAddress);
 
 f_mount(NULL, SDPath, 1);
 HAL_SD_MspDeInit(&hsd1);
 FATFS_UnLinkDriver(SDPath);
 
 __HAL_RCC_USART1_FORCE_RESET();
 __HAL_RCC_USART3_FORCE_RESET();
 HAL_Delay(5);
 __HAL_RCC_USART1_RELEASE_RESET();
 __HAL_RCC_USART3_RELEASE_RESET();
 HAL_Delay(5);
 
 HAL_SPI_MspDeInit(&hspi1);
 HAL_SPI_MspDeInit(&hspi2);
 HAL_SPI_MspDeInit(&hspi4);
 HAL_ETH_MspDeInit(&heth);
 HAL_UART_MspDeInit(&huart3);
 
 
// HAL_SD_MspDeInit(&hsd1);
 
 SCB_DisableDCache();
 SCB_DisableICache();
 HAL_MPU_Disable();
 HAL_SuspendTick();
 /* Make sure you disable the RCC in your bootloader code *before* you call the application */
 /* Set the clock to the default state */
 HAL_RCC_DeInit();
 // Modify the HAL_DeInit function:
 // HAL_StatusTypeDef HAL_DeInit(void)
 // {
 // /* Reset of all peripherals */
 // // __HAL_RCC_AHB3_FORCE_RESET(); // This causes a CPU reset
 // RCC->AHB3RSTR &= 0x7fffffff; // have bit 31 set to 0
 // __HAL_RCC_AHB3_RELEASE_RESET();
 HAL_DeInit();
// HAL_SuspendTick();
 
 /* Disable all interrupts */
 __disable_irq();
 
 // Disable SysTick and clear its exception pending bit, if it is used in the bootloader, e. g. by the RTX.
 /* Disable Systick timer */
 SysTick->CTRL = 0;
 SysTick->LOAD = 0;
 SysTick->VAL = 0;
 
 /* Clear Interrupt Enable Register & Interrupt Pending Register */
 for (uint8_t i = 0; i < 8; i++)
 {
 // Disable all enabled interrupts in NVIC
 NVIC->ICER[i] = 0xFFFFFFFF;
 // Clear all pending interrupt requests in NVIC
 NVIC->ICPR[i] = 0xFFFFFFFF;
 }
 
 /* Re-enable all interrupts */
 __enable_irq();
 
 SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;
 
 // Disable individual fault handlers if the bootloader used them.
 SCB->SHCSR &= ~(SCB_SHCSR_USGFAULTENA_Msk | \
 SCB_SHCSR_BUSFAULTENA_Msk | \
 SCB_SHCSR_MEMFAULTENA_Msk);
 
 // Activate the MSP, if the core is found to currently run with the PSP.
 if( CONTROL_SPSEL_Msk & __get_CONTROL( ) )
 { /* MSP is not active */
 __set_CONTROL( __get_CONTROL( ) & ~CONTROL_SPSEL_Msk ) ;
 }
 
 __HAL_RCC_SYSCFG_CLK_ENABLE();
 
 SCB->VTOR = BootAddr;
 
 SystemClock_Config();
 __enable_irq();
 HAL_ResumeTick();
 
 // Configure the Main Stack Pointer. This function comes from CMSIS.
 __set_MSP(*(__IO uint32_t*) BootAddr);
 
 __set_CONTROL(0);
 
 Boot_Delay(200);
 
 JumpToApplication();
}

Thanks for helping!

This topic has been closed for replies.

1 reply

Tesla DeLorean
Guru
August 19, 2019

>>What can I check?

Review the code generated? Following the failing branch down the rabbit-hole, and see where it goes, and the mechanism by which it fails.

If JumpToApplication is a stacked variable, moving the stack could be an issue.

Interrupts (SysTick) will have entirely different ideas about RAM usage, and no memory on the far side initialized properly (pointers/instances).

Running code in BootAddr context, not your own.

HAL_ResumeTick()? SystemClock_Config()? Why?

Use a delay based on processor ticks, not SysTick.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Jack3
Jack3Author
Senior
August 19, 2019

Hi Clive,

thank you very much! The app seems to hang on HAL_Delay, which uses SysTick.

I can use a delay based on processor ticks, but don't I need Systick for HAL to be working anyway, like the SDMMC library?

Tomorrow I will try to get closer to what is causing the issue.

I will check the JumpToApplication variable too.

What exactly to you mean with "running code in BootAddr context, not your own"?

Did I do something wrong? I can post the source on github tomorrow, if that helps.

Btw, for the app, I only changed the FLASH location in the linker (ld) file so the app (its vector table) was located at 0x08080000, instead of 0x0800000. Were there more changes required?

It would be my ultimate goal to make a bootloader, which can load and flash some app of choice (from SD card) and jump to it. But it seems picky on my app.

If I use that app, add the JumpToApplication function and make it a bootloader, it seems it better starts the app it was based on. But then I have stuff for the app in it, which I don't need for the bootloader itself. I hope you understand the problem, I try to describe.

Rgds,

Jack.

Tesla DeLorean
Guru
August 19, 2019

>>What exactly to you mean with "running code in BootAddr context, not your own"?

SCB->VTOR = BootAddr; <<< This, you're on the wrong side of the looking glass, fine for A=A or B=B

>>I can use a delay based on processor ticks, but don't I need Systick for HAL to be working anyway, like the SDMMC library?

Not saying you can't do that, just saying you can't flip context and expect uwTick for A and B to reside in the same/interchangeable spot.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..