cancel
Showing results for 
Search instead for 
Did you mean: 

Jumping and executing application code from SDRAM.

Zainulabedeen
Associate III

Hello all, 

MCU: STM32H733ZG

I am facing issue as i am trying to jump from bootloader to the Application code which is located in the SDRAM. In the bootloader stage when the MCU receives the binary from OTA it is stored inside the External Flash. After receiving the binary image and storing it inside the External Flash, the image is copied from External Flash inside the SDRAM and then jumps to the application code. When it jumps to the application code, i open disassembly view and it starts running instructions stored inside the SDRAM until it reaches a specific address `0xC000150E` which is inside the `SystemInit` function. After calling the instruction at this address the disassembly closes up and a text of can not read register at `0xDEADBEE` appears.

image_2025-09-01_182022793.png

When checking the line located at this address and commenting that line which is this Screenshot 2025-09-01 171447.png

the problem persists at the same address of `0xC000150E` even though the previous line was commented out. It always crashes at this address. Kindly someone suggest what could be the issue? Why it always crash at this exact address.

Here is the disassembly before and after commenting that line

Zainulabedeen_0-1756732330890.png

Zainulabedeen_0-1756742697584.png

 

Here is my MPU configurations:

void MPU_Config(void)
{
    MPU_Region_InitTypeDef MPU_InitStruct = {0};

    /* Disables the MPU */
    HAL_MPU_Disable();

    /** Initializes and configures the Region and the memory to be protected
     */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    MPU_InitStruct.BaseAddress      = 0x0;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_4GB;
    MPU_InitStruct.SubRegionDisable = 0x87;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_DISABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_SHAREABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /** Initializes and configures the Region and the memory to be protected
     */
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.BaseAddress      = 0x24000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_128KB;
    MPU_InitStruct.SubRegionDisable = 0x0;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /** Initializes and configures the Region and the memory to be protected
     */
    MPU_InitStruct.Number       = MPU_REGION_NUMBER2;
    MPU_InitStruct.Size         = MPU_REGION_SIZE_256B;
    MPU_InitStruct.IsCacheable  = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Region 4: External Flash (OCTOSPI, 0x90080000  - 0x907FFFFF) now with Full Access (readable & writable)
     * This area is removed from Region 0 to apply the desired access rights here.
     */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0x90000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_8MB;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; // Read/Write access
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER4;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE; // If XIP (code execution) is desired; otherwise MPU_INSTRUCTION_ACCESS_DISABLE
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Configure the MPU attributes for SDRAM */
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.BaseAddress      = 0xC0000000;          // Start address of SDRAM Bank 1
    MPU_InitStruct.Size             = MPU_REGION_SIZE_8MB; // SDRAM size
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE; // Currently MPU_ACCESS_CACHEABLE causes incorrect data
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.Number           = MPU_REGION_NUMBER3; // MPU region number
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /* Enables the MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

 

1 ACCEPTED SOLUTION

Accepted Solutions

I resolved it.

I just needed to call 

__enable_irq(); 

after system SystemClock_Config(); in the application and it start working.

 

One question, it seems if i configure something from the bootloader i can use inside my application even though i skip the HAL_Init(), SystemClock_Config()and all other peripheral initialization given that i configured it inside the bootloader. I can even toggle GPIO if i initialize it inside the Bootloader but then HAL_Delay() or anything related to timer does not work then. Can someone explain me why?

Thanks a lot.

View solution in original post

7 REPLIES 7
Zainulabedeen
Associate III

Update i was able to execute from the SDRAM after commenting the Application SystemInit().

But now the HAL_Delay() don't work however the configured peripherals works.

Can someone explain why and how to fix it or systemInit is failing.

 

I will be grateful Thanks.

 i was able to execute from the SDRAM after commenting the Application SystemInit().

Very good.

But now the HAL_Delay() don't work

Maybe because the SystemInit() sets the interrupt vectors base address but it is no longer called.

Set the address directly in your app main():

    extern int g_pfnVectors;  /* defined in GCC startup_xxx.s */
    SCB->VTOR = (uint32_t)(uintptr_t)&g_pfnVectors;

Or even better: copy the vectors from the app image in SDRAM to the internal SRAM (ITCRAM) for best performance.

Hello @Zainulabedeen 

Did you relocate the vector table offset address in systemInit().

Saket_Om_0-1756826063511.png

 

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

 

I bypassed the SystemInit() function in the application, since the system was already initialized by the bootloader. Before jumping from the bootloader, I also relocated the vector table to SDRAM.

The reason for skipping SystemInit() in the application was that running it again caused crashes, as mentioned earlier. Because both the bootloader and application use the same clock configuration, there was no need to re-run SystemInit() in the application.

Here is my jump code:

static void jump_to_application(uint32_t address)
{
    // Disable D/I Caches
    SCB_DisableICache();
    SCB_DisableDCache();
    delay_us(50000);

    __disable_irq();

    for (uint8_t i = 0; i < 8; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
    }

    for (uint8_t i = 0; i < 8; i++)
    {
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }

    RCC->APB2RSTR |= RCC_APB2RSTR_SYSCFGRST;
    RCC->APB2RSTR &= ~(RCC_APB2RSTR_SYSCFGRST);
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;

    SCB->VTOR     = address;
    SysTick->CTRL = 0x00;
    SysTick->LOAD = 0x00;
    SysTick->VAL  = 0x00;

    JumpToApp(address);
}

I’d appreciate a review of my setup to check if there are any mistakes.

I tried adding __enable_irq() at the very start of main() (before HAL_Init()), as suggested by @Pavel A. However, in this case the code never reached HAL_Delay(). Instead, it started making unexpected jumps around HAL_InitTick() and HAL_RCC_GetClockConfig(), and never progressed past HAL_Init(). It did, however, enter TIM6_DAC_IRQHandler(), which shows that interrupts were running correctly.

I’m using Timer 6 as the system timebase since I’m running an RTOS.

Can someone help me understand why this behavior occurs? Should I only enable interrupts after HAL_Init()? When I disable global interrupts before jumping from the bootloader, the code goes past HAL_Init() and into the HAL_Delay() I added. The issue with HAL_Delay() not working was simply because I had disabled global interrupts earlier.

 

FYI: @Pavel A. 

Pavel A.
Super User

Be careful not to disturb the FMC, which is used for the SDRAM.

Before JumpToApp (line 29) stop in the debugger and look at your app code in SDRAM (disassembly or dump): does it look sane?

I tried adding __enable_irq() ... as suggested by @pavel A

Sorry, I haven't suggested that. I've suggested to copy the vectors to the internal RAM (and point the VTOR there, of course)

 Should I only enable interrupts after HAL_Init()?

No, because HAL_Init can call HAL_Delay, which won't work with disabled interrupts (unless you implement it without the tick interrupt).

 

I resolved it.

I just needed to call 

__enable_irq(); 

after system SystemClock_Config(); in the application and it start working.

 

One question, it seems if i configure something from the bootloader i can use inside my application even though i skip the HAL_Init(), SystemClock_Config()and all other peripheral initialization given that i configured it inside the bootloader. I can even toggle GPIO if i initialize it inside the Bootloader but then HAL_Delay() or anything related to timer does not work then. Can someone explain me why?

Thanks a lot.

Pavel A.
Super User

Set a breakpoint in TIM6_DAC_IRQHandler. Does it break there?