Skip to main content
Graduate
January 13, 2025
Question

Stm32H750 bootloader - Failure when jumping to application

  • January 13, 2025
  • 5 replies
  • 2411 views

Hi everyone,

I’m working on a custom bootloader for an STM32H750 and need some help. My goal is to be able to update the unit from USB and for doing so I use an external eeprom to store the MCU FW and load it into RAM at startup. The main reason to use the RAM to execute the code is that the h750 flash is 128KB and it can only be erased by 128KB sector. 

I can succesfully write the code into the eeprom and load into ram at startup (address 0x20000000). However, when I try to jump to it, the debugger shows a 0x2xxxxxxx address but it get stuck. 

For the application code, I took the original flash based code, modified the scatter file for the linker as follows:

 

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM1 0x20000000 0x00020000 { ; load region size_region
 ER_IROM1 0x20000000 0x00020000 { ; load address = execution address
 *.o (RESET, +First)
 *(InRoot$$Sections)
 .ANY (+RO)
 .ANY (+XO)
 }
 RW_IRAM2 0x24020000 0x00080000 { ; RW data
 .ANY (+RW +ZI)
 }
}

 

I also tried setting the VTOR to 0x20000000 in the application, but it didn’t help. Looking at the .bin file, the stack pointer (SP) and program counter (PC) appear to point to valid addresses within the 0x20000000 range.

Here is the part of the code which is supposed to jump to the app.

 

#define APP_BASE_RAM (0x20000000)
uint32_t *p; 
void (*jmp)();
----------

.....
__disable_irq();				
p = (uint32_t *)(APP_BASE_RAM);
 
SCB->VTOR = (uint32_t)p; // Set Vector Table Offset Register (VTOR) to RAM base
__set_MSP(*p);	
__DSB(); // Data Synchronization Barrier 
__ISB(); // Instruction Synchronization Barrier
			
jmp = (void (*)())p[1];		
__enable_irq();			
while (true) ;

 

I’m not sure if there’s something I’m missing in the application code or bootloader setup. Has anyone encountered a similar issue or have suggestions on what I could check next?

Thanks in advance!

    This topic has been closed for replies.

    5 replies

    Technical Moderator
    January 13, 2025

    Hello @dc_matt ,

    Make sure that you are using the correct start address to jump to the bootloader for STM32H7 devices (0x1FF09800).

    For more details, please check the AN2606.

    In addition, please have a look on this FAQ "Jump to Bootloader from application on STM32H7 devices":

    Jump to bootloader from application on STM32H7 dev... - STMicroelectronics Community

     

    dc_mattAuthor
    Graduate
    January 13, 2025

    Hello,

    I accidentally clicked on "SOLUTION" by mistake. This isn't the first time it's happened, so there might be an issue with the forum's user interface.Should I create a new thread? Last time my post was left uncommented afer accepting the answer by mistake ... 

    Regarding your comment, I'm not sure I fully understand it. My goal is to run the code from RAM, and the address I'm using is 0x20000000. And my bootloader is fully custom. Is there a fundamental mistake in my understanding?


    Technical Moderator
    January 13, 2025

    Hi @dc_matt 

    I removed the Accept Solution, and I will report your feedback internally to the Community team. No need to create a new post. We can continue the discussion here.

     

    Maybe you should check the security Settings and ensure that there are no security settings or option bytes that might prevent the code from executing in RAM.

    dc_mattAuthor
    Graduate
    January 13, 2025

    Can it be related to the VTOR setting in the application code? I set it to 0x20000000. Is it correct?

    Can the scatter file I shared above be wrong?

    After the jmp() instruction the step by step debugger gets stuck and when I press STOP, the Disassembly shows the CPU stuck at the line

    0x2000D3C6                               B                      0x2000D3C6                               

    Technical Moderator
    January 14, 2025

    I think the issue is with the application code or the jump process. 

    The VTOR should be set to the start address of the application in RAM. In your case, setting it to 0x20000000 is correct if your application starts at this address.

    Make sure also that the jump to the application is correct by setting the stack pointer and program counter to the values at the start of the application.

     

    dc_mattAuthor
    Graduate
    January 14, 2025

    Hi @Imen.D  thanks fo your reply. I do set the SP and PC to the first two words of the memory. To make sure the jump code works I tried to set the address to the bootloader address (0x08000000) and it correctly jumps and re-execute it. However, when I set the RAM address from where I want to execute the application code, 0x20000000 in this case, it doesnt. I also tried to change the address to 0x24000000 (AXI) but the result is the same. VTOR is correctly set.

    #define APP_BASE_RAM (0x20000000)
    uint32_t *p; 
    void (*jmp)();
    ----------
    
    .....
    __disable_irq();				
    p = (uint32_t *)(APP_BASE_RAM);
     
    SCB->VTOR = (uint32_t)p; // Set Vector Table Offset Register (VTOR) to RAM base
    __set_MSP(*p);	
    __DSB(); // Data Synchronization Barrier 
    __ISB(); // Instruction Synchronization Barrier
    			
    jmp = (void (*)())p[1];		
    __enable_irq();			
    while (true) ;

     I think the problem might be in the ram compilated code of the application but no idea how I could verify that. The flash version works correctly. Does the application VTOR need to be handled in a specific way?

    dc_mattAuthor
    Graduate
    January 14, 2025

    Any suggestion about how to properly debug the issue? Can it be related to the use of DTCM RAM as executable ram region?

    dc_mattAuthor
    Graduate
    January 15, 2025

    Hello, I tried to change the memory allocation for both bootloader and application to make sure there is no ram memory overlap but no improvements. Any advise?

    Bootloader:

    LR_IROM1 0x08000000 0x00020000  {    ; load region size_region
      ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
       .ANY (+RO)
       .ANY (+XO)
      }
      RW_IRAM2 0x24040000 0x00040000  {  ; RW data
       .ANY (+RW +ZI)
      }
    }

     

    Application:

    LR_IROM1 0x20000000 0x00020000  {    ; load region size_region
      ER_IROM1 0x20000000 0x00020000  {  ; load address = execution address
       *.o (RESET, +First)
       *(InRoot$$Sections)
       .ANY (+RO)
       .ANY (+XO)
      }
      RW_IRAM2 0x24020000 0x00040000  {  ; RW data
       .ANY (+RW +ZI)
      }
    }

    Super User
    January 16, 2025

    In your code after __enable_irq() the "jmp" variable remains unused. You do not actually jump.

    jmp = (void (*)())p[1];		
    __enable_irq();			
    while (true) ;

     

    dc_mattAuthor
    Graduate
    January 16, 2025

    Hi @Pavel A. , sorry, that is a copy paste mistake. In the code, right after the 

    jmp = (void (*)())p[1];		

    there is jmp(); 
    I can see the Reset Handler address being correctly loaded into PC.

    Hi @Tesla DeLorean Thanks for your comment, I must admit that the community seems divided when it comes to hadling bootloaders and applications.

    I have found some interesting comments from you in this post, where you recommend not to set the SP in the botloader but in the Reset Handler of the application. Additionally you recommend not to set VTOR as well as disabling the interrupts. The user here had a clear PC corruption after using __set_MSP and this is not my case. But now I wonder if the issue is related to the MSP.

    https://community.st.com/t5/stm32-mcus-products/after-calling-set-msp-the-local-variables-get-corrupted/td-p/90447

    I´ve found this ARM article where instead they say to use __set_MSP, set VTOR, disable peripherals, disable interrupts etc ... I think I am really getting lost here :D

    https://developer.arm.com/documentation/ka001423/latest/

    dc_mattAuthor
    Graduate
    January 23, 2025

    Dear all, the issue was solved by replacing

    __set_MSP(*p);	

    with:
    __set_MSP(*(volatile uint32_t*)p);

    Please note that p was defined as:

    volatile uint32_t *p.