Skip to main content
Graduate II
February 14, 2025
Solved

Unable to execute code in SDRAM on STM32H745

  • February 14, 2025
  • 8 replies
  • 3789 views

Hi all,

Board: STM32H745I-DISCO

IDE: 1.16.1

 

I am facing some issues with trying to execute code on the SDRAM. I have a 2nd stage bootloader that loads the user application onto QSPI located at 0x9000 0000. After that, I copy the user application code to the SDRAM 0xD0000000. This part works as verified in the debugger. 

However when I try to jump to the SDRAM address, my program is not executing. And it seems like the SDRAM has lost connection? Attached below is the image(sdram_becomes_unreadable.PNG) where my bootloader jumped to the SDRAM address but unable to read from the SDRAM. There is no hard fault.. 

Background: 
I have tried to load the user application onto QSPI and jump to the QSPI address, my program executes successfully. 
I have checked my MPU configuration to make sure that SDRAM is MPU_INSTRUCTION_ACCESS_ENABLE. 
Below is my MPU configuration

 

 

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_NUMBER1;
 MPU_InitStruct.BaseAddress = 0x90000000;
 MPU_InitStruct.Size = MPU_REGION_SIZE_128MB;
 MPU_InitStruct.SubRegionDisable = 0x00;
 MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
 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;
 MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

 HAL_MPU_ConfigRegion(&MPU_InitStruct);

 /** Initializes and configures the Region and the memory to be protected
 */
 MPU_InitStruct.Number = MPU_REGION_NUMBER2;
 MPU_InitStruct.BaseAddress = 0xD0000000;
 MPU_InitStruct.Size = MPU_REGION_SIZE_64MB;
 MPU_InitStruct.SubRegionDisable = 0x0;

 HAL_MPU_ConfigRegion(&MPU_InitStruct);
 /* Enables the MPU */
 HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

}

 

 

Lastly, I tried to bank swap the SDRAM to 0x70000000, and execute from there incase the SDRAM is still in Execute Never(XN) mode. But this doesn't work too as the SDRAM is unreadable after the jump. 

What am I missing? Do I need to initialize the SDRAM for my user application? How come this is not needed for QSPI in such a scenario? 

 

Regards,

Reuben Goh


 

    This topic has been closed for replies.
    Best answer by reubengoh95

    Hi,

    I have resolved the issue and found the root cause.. I had to do 2 things to make code execution work for STM32H745 on SDRAM.

    1. Remap the SDRAM by executing this command below in stm32h745i_discovery_sdram.c, MX_SDRAM_BANK2_init function

    /* SDRAM bank swap 0xD0000000 to 0x70000000*/
    HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

     2. Disable the configuration that disables FMC bank1 in system_stm32h7xx_dualcore_boot_cm4_cm7.c, SystemInit function

     /*
     * Disable the FMC bank1 (enabled after reset).
     * This, prevents CPU speculation access on this bank which blocks the use of FMC during
     * 24us. During this time the others FMC master (such as LTDC) cannot use it!
     */
     //FMC_Bank1_R->BTCR[0] = 0x000030D2;

     For point 1, I am not too sure why my MPU configuration does not allow 0xD0000000 to execute. But changing it works for me since 0x70000000 allows code execution. For point 2, this is crucial step. Previously when I did bank swapping I did not disable this, that's why it did not work. 

    I also realize the 100MHz clock drop to 33MHz was normal since the processor is reading from the SDRAM, hence there is some difference in the SDRAM_CLK. I know this because when I copy the code from QSPI to SDRAM, the SDRAM_CLK changes as well. 

    Thank you all for your help.

    Regards,

    Reuben Goh

    8 replies

    Visitor II
    February 14, 2025

    Try to set MPU_TEX_LEVEL1 and disabling cache for SDRAM execution:

     

    MPU_InitStruct.Number = MPU_REGION_NUMBER2;
    MPU_InitStruct.BaseAddress = 0xD0000000;
    MPU_InitStruct.Size = MPU_REGION_SIZE_64MB;
    MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; // Use level 1 for SDRAM
    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_NOT_CACHEABLE; // Try disabling cache
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

     

    Graduate II
    February 14, 2025

    Hi ahsrabrifat, 

    Thanks for the reply. I tried to add it into the MPU configuration for both the bootloader and the user application. But I encounter the same issue as above. 

    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_NUMBER1;
     MPU_InitStruct.BaseAddress = 0x90000000;
     MPU_InitStruct.Size = MPU_REGION_SIZE_128MB;
     MPU_InitStruct.SubRegionDisable = 0x00;
     MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
     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;
     MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
    
     HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
     /** Initializes and configures the Region and the memory to be protected
     */
     MPU_InitStruct.Number = MPU_REGION_NUMBER2;
     MPU_InitStruct.BaseAddress = 0xD0000000;
     MPU_InitStruct.Size = MPU_REGION_SIZE_64MB;
     MPU_InitStruct.SubRegionDisable = 0x0;
     MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; // Use level 1 for SDRAM
     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_NOT_CACHEABLE; // Try disabling cache
     MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
    
     HAL_MPU_ConfigRegion(&MPU_InitStruct);
     /* Enables the MPU */
     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    
    }

     I have attached another two images for before and after jump to SDRAM. 
    And below is my jump code.. where addr = 0xD0000000

    void app_jump(uint32_t addr)
    {
    	pFunction JumpToApplication;
    	uint32_t JumpAddress;
    
    	/* Disable Systick interrupt */
    	SysTick->CTRL = 0;
    
    	/* Jump to user application */
    	JumpAddress = *(__IO uint32_t*) (addr + 4);
    	JumpToApplication = (pFunction) JumpAddress;
    
    	/* Initialize user application's Stack Pointer */
    	__set_MSP(*(__IO uint32_t*) addr);
    
    	JumpToApplication();
    }

    Regards,
    Reuben Goh

    Technical Moderator
    February 14, 2025

    Hello,

    Are you sure the SDRAM registers were not modified or MPU config was not modified before that jump?

    Graduate II
    February 14, 2025

    Hi SofLit, 

    Yes i don't think that they are modified.. before the jump. As I do the MPU initialization and Sdram Initialization before i go into the Main_Menu function as shown below. 

    I am using the IAP program provided by ST and made some modifications. 

    switch (key)
     {
     case '1' :
     /* Download user application in the Flash */
     SerialDownload();
     break;
     case '2' :
     /* Upload user application from the Flash */
     SerialUpload();
     break;
     case '3' :
     Serial_PutString((uint8_t *)"Start program execution......\r\n\n");
     app_jump(APPLICATION_ADDRESS);
     break;
     case '4' :
     if (FlashProtection != FLASHIF_PROTECTION_NONE)
     {
     /* Disable the write protection */
     if (FLASH_If_WriteProtectionConfig(DISABLE) == HAL_OK)
     {
     Serial_PutString((uint8_t *)"Write Protection disabled...\r\n");
     Serial_PutString((uint8_t *)"System will now restart...\r\n");
     }
     else
     {
     Serial_PutString((uint8_t *)"Error: Flash write un-protection failed...\r\n");
     }
     }
     else
     {
     if (FLASH_If_WriteProtectionConfig(ENABLE) == HAL_OK)
     {
     Serial_PutString((uint8_t *)"Write Protection enabled...\r\n");
     Serial_PutString((uint8_t *)"System will now restart...\r\n");
     }
     else
     {
     Serial_PutString((uint8_t *)"Error: Flash write protection failed...\r\n");
     }
     }
     break;
     case '5' :
     	 flashdestination = QSPI_BASE_ADDRESS;
     	 serialdownloadqspi(flashdestination);
     	 break;
     case '6' :
     	 flashdestination = QSPI_BASE_ADDRESS + QSPI_SECTOR_SIZE;
     	 serialdownloadqspi(flashdestination);
     	 break;
     case '7' :
     	 Serial_PutString((uint8_t *)"Start program execution on qspi sector 0......\r\n\n");
     	 app_jump(QSPI_BASE_ADDRESS);
     	 break;
     case '8' :
    		 Serial_PutString((uint8_t *)"Start program execution on qspi sector 1......\r\n\n");
    		 app_jump(QSPI_BASE_ADDRESS + QSPI_SECTOR_SIZE);
    		 break;
     case '9' :
    		 Serial_PutString((uint8_t *)"Copying code from qspi to sdram ......\r\n\n");
    		 qspi_if_load_sdram_code();
    		 break;
     case 'a' :
     	 Serial_PutString((uint8_t *)"Start program execution on sdram.....\r\n\n");
    		 app_jump(SDRAM2_BASE_ADDRESS);
    		 break;
     default:
     Serial_PutString((uint8_t *)"Invalid Number ! ==> The number should be either 1, 2, 3, 4, 5 or 6\r");
     break;

     As shown in case '9' and 'a', I have a function to copy the qspi code to sdram and then perform the jump. I do not think any registers are modified in between since it is a closed loop? 

    Regards,
    Reuben Goh

    Graduate II
    February 14, 2025

    Hi SofLit,

    I have disabled the DEINIT functions in the sdram.c file and tried to run it. Seems to be better, as I am able to read the SDRAM after the jump. But my program still unable to execute. 

    I suspect that the MDMA interrupt might have triggered to deinit the sdram? Not sure..

    Below is my sdram.c and .h file for your reference. 

    The sdram that is attached to my board is MT48LC4M32B2. 

    Regards,

    Reuben Goh

    Technical Moderator
    February 14, 2025

    I propose to look at the SDRAM registers before and after the jump and see if they were changed.

    Graduate II
    February 17, 2025

    Hi SofLit,

     

    I have found that before and after the jump, the SDRAM_SDCLK is changed from 100MHz to 33MHz as shown in the attached screenshots. My user application might have changed the clock setting that was set by the bootloader.

    Regards,

    Reuben Goh

    Graduate II
    February 16, 2025

    Hi SofLit, 

     

    I tried to read the SDRAM register before jump using

    serial_debug_printf("%08X\n\r", FMC_Bank5_6_R->SDCR[0]);
    serial_debug_printf("%08X\n\r", FMC_Bank5_6_R->SDCR[1]);

    but how do I read the registers after jumping? 

    As nothing executes after the jump statement. 

    Regards,

    Reuben Goh

    Graduate II
    February 16, 2025

    Code and vector table is normaly compiled for defined place, and cant be simply copied and run on other.

    Graduate II
    February 16, 2025

    Hi MM..1,

    Yes I note that. When I am compiling to run the code on SDRAM, my linker script of my code section is pointing to SDRAM 0xD0000000. The Vector table is also pointing to the SDRAM 0xD00000000.

     

    So the code i copy from QSPI, the application program starts at 0xD00000000.


    Regards,

    Reuben Goh

     

     

    Technical Moderator
    February 17, 2025

    Ok. If you fix that redo the test and get back with your results.

    reubengoh95AuthorAnswer
    Graduate II
    February 18, 2025

    Hi,

    I have resolved the issue and found the root cause.. I had to do 2 things to make code execution work for STM32H745 on SDRAM.

    1. Remap the SDRAM by executing this command below in stm32h745i_discovery_sdram.c, MX_SDRAM_BANK2_init function

    /* SDRAM bank swap 0xD0000000 to 0x70000000*/
    HAL_SetFMCMemorySwappingConfig(FMC_SWAPBMAP_SDRAM_SRAM);

     2. Disable the configuration that disables FMC bank1 in system_stm32h7xx_dualcore_boot_cm4_cm7.c, SystemInit function

     /*
     * Disable the FMC bank1 (enabled after reset).
     * This, prevents CPU speculation access on this bank which blocks the use of FMC during
     * 24us. During this time the others FMC master (such as LTDC) cannot use it!
     */
     //FMC_Bank1_R->BTCR[0] = 0x000030D2;

     For point 1, I am not too sure why my MPU configuration does not allow 0xD0000000 to execute. But changing it works for me since 0x70000000 allows code execution. For point 2, this is crucial step. Previously when I did bank swapping I did not disable this, that's why it did not work. 

    I also realize the 100MHz clock drop to 33MHz was normal since the processor is reading from the SDRAM, hence there is some difference in the SDRAM_CLK. I know this because when I copy the code from QSPI to SDRAM, the SDRAM_CLK changes as well. 

    Thank you all for your help.

    Regards,

    Reuben Goh

    Graduate II
    September 3, 2025

    For me MPU works but i need to disable MPU from Application now as it is already configured from the Bootloader and gives hardfault if reenables. Maybe try that.