2025-02-13 09:42 PM - edited 2025-02-13 09:59 PM
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
2025-02-13 11:17 PM
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;
2025-02-13 11:44 PM
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
2025-02-14 12:09 AM
Hello,
Are you sure the SDRAM registers were not modified or MPU config was not modified before that jump?
2025-02-14 12:33 AM
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
2025-02-14 01:01 AM
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
2025-02-14 01:07 AM
I propose to look at the SDRAM registers before and after the jump and see if they were changed.