STM32H747 with Low-Power SDRAM (1.8V) read/write issue
Hi Everyone:
we now have a problem running STM32H747XIH6 with Low-Power SDRAM (ISSI IS42VM32160E-75BLI) when the SDRAM clock is set to 100MHz, on our customized PCBA. I'd like to check if anyone has suggestions on how to debug.
■ Description of the setup:
A. Home-made PCBA with STM32H747XIH6, VDD = 1.8V, SMPS direct supply VCORE.
B. Low-Power SDRAM is ISSI IS42VM32160E-75BLI,
133MHz, 64MB capacity with 32-bit Data Bus.
C. Our goal is to run SDRAM at 100MHz.
■ The Issue:
A. When running SDRAM at 50MHz (SDRAM clock frequency), everything goes fine, with CPU running at 200MHz.
AXI and FMC are running at 100MHz in this case.
B. When running SDRAM at 100MHz, memory read/write is incorrect.
In this case, CPU also runs at 200MHz, with AXI & FMC set to 200MHz.
C. The issue doesn't look like random error that may be caused by hardware timing problem. The following figure shows the printed test result from one memory test:
In this test, the address of each memory cell is converted to data and written to it.
In the passed case, memory address and read data are the same,
While in the failed case, the address and read data are shifted by 12.
■ Some Analysis:
In this table, Config A is 50MHz SDCLK which works fine.
Config B & C are running SDCLK at 100MHz with different CAS latency, both failed.
We do found two strange cases, with illegal settings, but actually works:
Config D is to set CAS latency of FMC and of SDRAM at different value: 3 for FMC and 2 for SDRAM (set to SDRAM mode register while initialization).
Config E is to set VOS voltage to 0. (This setting is illegal in the sense that according to data sheet, VOS 0 can only be used with LDO supply, while our board is using SMPS direct supply for VCORE power.)
■ Code Snippet
void BSP_FMC_Init(void)
{
/* USER CODE BEGIN FMC_Init 0 */
HAL_GPIO_WritePin(VDD_MEM_ON_GPIO_Port, VDD_MEM_ON_Pin, GPIO_PIN_SET);
HAL_Delay(100);
/* USER CODE END FMC_Init 0 */
FMC_SDRAM_TimingTypeDef SdramTiming = {0};
/* USER CODE BEGIN FMC_Init 1 */
/* USER CODE END FMC_Init 1 */
/** Perform the SDRAM1 memory initialization sequence
*/
hsdram1.Instance = FMC_SDRAM_DEVICE;
/* hsdram1.Init */
hsdram1.Init.SDBank = FMC_SDRAM_BANK2;
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
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_2;//FMC_SDRAM_CAS_LATENCY_2;
hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;//FMC_SDRAM_CLOCK_PERIOD_3; // FMC kernal clock / SDClockPeriod = SDRAM clock
hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;//FMC_SDRAM_RBURST_DISABLE;
hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;//FMC_SDRAM_RPIPE_DELAY_2;
/* SdramTiming */
#ifndef SDRAM_100MHz
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 4;
SdramTiming.SelfRefreshTime = 3;
SdramTiming.RowCycleDelay = 4;//7;
SdramTiming.WriteRecoveryTime = 1;//16;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
#else
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 8;
SdramTiming.SelfRefreshTime = 5;
SdramTiming.RowCycleDelay = 8;//7;
SdramTiming.WriteRecoveryTime = 2;//16;
SdramTiming.RPDelay = 3;
SdramTiming.RCDDelay = 3;
#endif
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler( );
}
}
void BSP_SDRAM_Init(SDRAM_HandleTypeDef *hsdram)
{
FMC_SDRAM_CommandTypeDef Command;
//volatile uint32_t temp = 0;
GPIO_InitTypeDef GPIO_InitStruct ={0};
__IO uint32_t tmpmrd =0;
/* Step 1: Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; //FMC_SDRAM_CMD_TARGET_BANK1
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
HAL_Delay(1);
/* Step 3: Configure a PALL (precharge all) command */
Command.CommandMode = FMC_SDRAM_CMD_PALL;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
/* Step 4 : Configure a Auto-Refresh command */
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 8;
Command.ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
/* 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_2 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpmrd;
// Send the command
HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
//HAL_Delay(1);
/* Step 6: Set the refresh rate counter */
/* Set the device refresh rate */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
// Step 7: Program the external memory extended mode register
// Tested Dummy Read at BA1 = 1, BA0 = 0 region cannot keep state of BA1 at High level (to select extended mode register).
// Need to config BA1 = FMC_A15 = GPIO PG5 as GPIO output High for extended mode register configuration.
//temp = *(uint32_t *)0xD2000000;
// Config BA1 pin to GPIO output High
HAL_GPIO_WritePin(GPIOG, GPIO_PIN_5, GPIO_PIN_SET);
GPIO_InitStruct.Pin = SDRAM_BA1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SDRAM_BA1_GPIO_Port, &GPIO_InitStruct);
// Send Extended Mode Register
tmpmrd = (uint32_t)SDRAM_DRIVE_STRENGTH_FULL | SDRAM_SELF_REFRESH_ALL_BANK;
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = tmpmrd;
// Send the command
HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
// Config BA1 back to FMC alternate function pin
GPIO_InitStruct.Pin = SDRAM_BA1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_FMC;
HAL_GPIO_Init(SDRAM_BA1_GPIO_Port, &GPIO_InitStruct);
}
