cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F7 FMC SDRAM error after reinit

LFeld.1
Associate

I have a custom board. There I have an issue with the FMC SDRAM after the HAL_SDRAM_Init call when calling it a subsequent(!!!) time. It works when doing the call the first time. I then deinit the SDRAM because of some current consumption tasks. When calling it again, the reads and writes on the SDRAM cause issues.

My Setup

STM32F756NG MCU

AS4C4M32S SDRam for LCD Frame Buffers (2 Frame Buffers, called Doublebuffer) and other GUI Buffers

CubeMX version 6.6.1 generated codebase

MPU setup posted below

FreeRTOS and of course other hardware and middlewares which do not seem to be of relevance.

Problem description

On startup I initialize the FMC SDRAM like in the example of the CubeMX. (See code below.) After that I do the Initialize sequence like the datasheet of the used SDRAM requires. And it just works. I can write and read just fine. The LTDC is set up to use the frame buffers. The application works, the display does as well. Debugging is also working fine. After some timeouts without any user input I deinit all hardware needed for the display to save battery. That includes the SDRAM (I do send the FMC_SDRAM_CMD_POWERDOWN_MODE command before the deinit. Maybe that is important?). The display goes blank (because it is switched off) like it should.

Now the problem arises when I want to initialize everything for the second time.

I have 2 use cases, where in one my application does not work and in the other it does work. I also seem to have found a solution (workaround) of which I have no idea why that resolves my problem.

Case 1, it magically works:

The display was on and has shown content before switching off (=LTDC has accessed the frame buffers). If that happens, the second init causes the FMC to report back that it is in power down mode when calling the HAL_SDRAM_GetModeStatus. But despite this fact, writing and reading to the SDRAM works like it used to.

Case 2, it does not work:

If for some reason the display does not get active (but write and reads of some memory on the SDRAM were performed anyways). The second INIT just works as well, also the HAL_SDRAM_GetModeStatus also reports power down. But now, the content of the SDRAM seems corrupted as for some reasons some memory areas do get written to and read back from correctly, some do not. And because there are also pointers there, I will very quickly get the IMPRECISE MEMORY ACCESS HARD FAULT. Because pointers do point to wrong places.

Workaround I have found accidentally:

If I do read from a random SDRAM memory address strictly after initializing the sdram (see the comment in the drv_FMC_Init method), the memory does not get corrupted. As if I have to access the SDRAM content before sending FMC SDRAM commands to the sdram (because of initializing the external component). Why is that? I do not know.

void drv_FMC_Init ( void ) {
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
 
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 5;
SdramTiming.RowCycleDelay = 7;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
	Error_Handler( );
}
// WORKAROUND: Read a ramdom memory address here. Something in the likes of:
// __unused volatile uint32_t foo = *(uint32_t*)0xC0000000;
}

void drv_MPU_Config(void) {
/* 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 = 0x0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_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 = 0x20000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256KB;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
 
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 = 0x20040000;
MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;
 
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER3;
MPU_InitStruct.BaseAddress = 0xC0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
 
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Number = MPU_REGION_NUMBER4;
MPU_InitStruct.BaseAddress = 0x08000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_1MB;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
 
HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
/* Enables the MPU */
HAL_MPU_Enable(MPU_HFNMI_PRIVDEF_NONE);
}
void bsp_SDRAM_Init(void){
drv_FMC_Init ( );
 
/* Step 1: Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
 
/* Send the command */
if ( false == drv_FMC_SendCommand ( &Command, SDRAM_TIMEOUT ) )
{
	Error_Handler( );
}
 
/* Step 2: Insert 100 us minimum delay */
/* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
HAL_Delay ( 1 );
 
/* Step 3: Configure a PALL (precharge all) command */
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
 
/* Send the command */
if ( false == drv_FMC_SendCommand ( &Command, SDRAM_TIMEOUT ) )
{
	Error_Handler( );
}
 
/* Step 4: Configure an Auto Refresh command */
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
 
/* Send the command */
if ( false == drv_FMC_SendCommand ( &Command, SDRAM_TIMEOUT ) )
{
	Error_Handler( );
}
 
/* Step 5: Program the external memory mode register */
tmpmrd = ( uint32_t ) SDRAM_MODEREG_BURST_LENGTH_1 | SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | SDRAM_MODEREG_CAS_LATENCY_3 | SDRAM_MODEREG_OPERATING_MODE_STANDARD
		| SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
 
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpmrd;
 
/* Send the command */
if ( false == drv_FMC_SendCommand ( &Command, SDRAM_TIMEOUT ) )
{
	Error_Handler( );
}
 
/* Step 6: Set the refresh rate counter */
/* Set the device refresh rate */
if ( false == drv_FMC_ProgramRefreshRate ( REFRESH_COUNT ) )
{
	Error_Handler( );
}
}
 
void bsp_SDRAM_PowerDown(void){
FMC_SDRAM_CommandTypeDef Command;
Command.CommandMode = FMC_SDRAM_CMD_POWERDOWN_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
 
/* Send the command */
drv_FMC_SendCommand ( &Command, SDRAM_TIMEOUT );
}

0 REPLIES 0