2024-01-09 09:06 AM - edited 2024-01-10 06:46 AM
Hi all!
I am struggling to couple STM32F469ZGT6 (running at 180 MHz) with SDRAM type IS42S16160J-6TL from ISSI (datasheet here: https://www.issi.com/WW/pdf/42-45S83200J-16160J.pdf ).
SDRAM is organized in 4 banks, each having 8192 rows x 512 columns x 16 bits wide data bus, and is connected to MCU like this:
FMC is configured in CubeMX like this:
…following instructions from here: https://community.st.com/t5/stm32-mcus/how-to-set-up-the-fmc-peripheral-to-interface-with-the-sdram/ta-p/49457
FMC is initialized like this (part of the code was generated by CubeMX and part was manually added, following above instructions):
/* FMC initialization function */
static void MX_FMC_Init(void)
{
/* USER CODE BEGIN FMC_Init 0 */
/* 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_BANK1;
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_16;
hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
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_2;
/* SdramTiming */
SdramTiming.LoadToActiveDelay = 2;
SdramTiming.ExitSelfRefreshDelay = 7;
SdramTiming.SelfRefreshTime = 5;
SdramTiming.RowCycleDelay = 6;
SdramTiming.WriteRecoveryTime = 3;
SdramTiming.RPDelay = 2;
SdramTiming.RCDDelay = 2;
if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{
Error_Handler( );
}
/* USER CODE BEGIN FMC_Init 2 */
FMC_SDRAM_CommandTypeDef Command;
/* Step 1 and Step 2 already done in HAL_SDRAM_Init() */
/* Step 3: Configure a clock configuration enable command */
Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; /* Set MODE bits to "001" */
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; /* <--FIXED THIS configure the Target Bank bits */
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
HAL_Delay(1); /* Step 4: Insert 100 us minimum delay - Min HAL Delay is 1ms */
/* Step 5: Configure a PALL (precharge all) command */
Command.CommandMode = FMC_SDRAM_CMD_PALL; /* Set MODE bits to "010" */
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
/* Step 6: Configure an Auto Refresh command */
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; /* Set MODE bits to "011" */
Command.AutoRefreshNumber = 8;///CHANGED: 2 -> 8/////////////////////////////////////////////////////////////////////////////////////////////////////////////
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
/* Step 7: Program the external memory mode register */
Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;/*set the MODE bits to "100" */
Command.ModeRegisterDefinition = (uint32_t)0 | 0<<3 | 2<<4 | 0<<7 | 1<<9;
HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
/* Step 8: Set the refresh rate counter - refer to section SDRAM refresh timer register in RM0455 */
/* Set the device refresh rate
* COUNT = [(SDRAM self refresh time / number of row) x SDRAM CLK] – 20
= [(64ms/8192) * 90MHz] - 20 = 703.125 - 20 ~ 683 */
HAL_SDRAM_ProgramRefreshRate(&hsdram1, 683);
/* USER CODE END FMC_Init 2 */
}
FMC should position SDRAM at address 0xC0000000.
After HAL initialization, I am running simple test code:
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_FMC_Init();
MX_I2C1_Init();
MX_QUADSPI_Init();
MX_RTC_Init();
MX_SDIO_SD_Init();
MX_SPI1_Init();
MX_SPI2_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_USART3_UART_Init();
MX_USART6_UART_Init();
MX_USB_OTG_HS_PCD_Init();
MX_DAC_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
uint32_t *pointer = (uint32_t *)0xC0000000;
*pointer = 0x111;
pointer +=1;
*pointer = 0x222;
pointer +=1;
*pointer = 0x333;
pointer = (uint32_t *)0xC0000000;
printf(" P1 = %d\r\n", *pointer);
pointer +=1;
printf(" P2 = %d\r\n", *pointer);
pointer +=1;
printf(" P3 = %d\r\n", *pointer);
.....
…. unfortunately this does not work. I get P1 = 0, P2 = 0, P3 = 0.
I was trying to solve my problem by searching the web.
There are a few suggestions which I came upon.
First, to modify scatter file, so my scatter file looks like this now:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00100000 { ; load region size_region
ER_IROM1 0x08000000 0x00100000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00050000 { ; RW data
.ANY (+RW +ZI)
}
RW_IRAM2 0x10000000 0x00010000 {
.ANY (+RW +ZI)
}
; External SDRAM
EXT_SDRAM 0xC0000000 UNINIT 0x200 {
.ANY (+RW)
}
}
…here I added uninitialized memory area “EXT_SDRAM” length of only 0x200, just for the test. This did not help.
Fun fact: When I increase length to 0x2000000 my I2C HAL initialization fails on this line of code:
/* Check the minimum allowed PCLK1 frequency */
if (I2C_MIN_PCLK_FREQ(pclk1, hi2c->Init.ClockSpeed) == 1U)
{
return HAL_ERROR;
}
…..i still have to investigate this behaviour. So far no clue.
Not to diverge from the main problem, main point is with value 0x200 I don’t have faults, but my test code is returning zeros. Used SDRAM has size 32 Mb = 33.554.432 Bytes ( 0x2000000)= 268.435.456 bits.
…..further googling led me to discovery that my system_stm32f4xx.c has commented this line
here /* #define DATA_IN_ExtSDRAM */ , which should be uncommented.
So I uncommented it.
Unfortunately to no avail. Test code still returns zeroes.
This uncommenting enabled ruining of following function: void SystemInit_ExtMemCtl(void)
….which has following lines:
...
/* Connect PDx pins to FMC Alternate function */
GPIOD->AFR[0] = 0x000000CC;
GPIOD->AFR[1] = 0xCC000CCC;
/* Configure PDx pins in Alternate function mode */
GPIOD->MODER = 0xA02A000A;
/* Configure PDx pins speed to 50 MHz */
GPIOD->OSPEEDR = 0xA02A000A;
/* Configure PDx pins Output type to push-pull */
GPIOD->OTYPER = 0x00000000;
/* No pull-up, pull-down for PDx pins */
GPIOD->PUPDR = 0x00000000;
...
…I find it strange that frequency 50 MHz is mentioned here. My SDRAM will receive clock HCLK/2 = 90 Mhz. I still need to investigate what is going on here.
I am beginning to run out of ideas what to do next, and am digging deeper and deeper into countless pages of ARM, SMT32, KEIL’s manual, without any breakthroughs.
Does anybody see what went wrong here, and what to try next?
By looking this guy https://www.youtube.com/watch?v=h28D4AaPSjg I get the impression SDRAM interfacing is plug and play. I (or he) must have missed something.
2024-01-09 09:32 AM
BANK2 != BANK1 you're sending commands to the wrong device
The "50 MHz" on the GPIO is a Slew Rate, not an absolute speed. The "100 MHz" setting is too aggressive for the load the SDRAM and traces present to the pin driver. The lesser speed causes less overshoot and ringing.
The strategy to bring up a new board/device is to walk the code configuring every pin. Establish the speed the interface is clocking, and set the parameters described in the SDRAM data sheet such that the cycles on the peripheral at least cover the minimum timing expectations of the memory.
Might take an hour or so to walk the configuration/settings to ensure they align. If that still fails you'll need to dig into the hardware.
2024-01-10 12:25 AM - edited 2024-01-10 05:12 AM
.....
2024-01-10 05:11 AM
OK thanks, this line was wrong:
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; /* configure the Target Bank bits */
...it should be:
Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; /* configure the Target Bank bits */
...however I am still seeing zeroes. Something else is still wrong.
2024-01-13 08:53 AM
…it turned up to be a hardware issue, few important pins on SDRAM chip were not properly soldered.
Test code with pointers now works, and whole 32 Mb address space is functioning correctly.
During my tests I stripped project of all not FMC related code. I also stopped using custom scatter file (ticked checkbox “Use memory layout form target dialog” in Keil) and “#define DATA_IN_ExtSDRAM” was again commented in system_stm32f4xx.c.
Basically I followed this guy: https://www.youtube.com/watch?v=h28D4AaPSjg
….and everything works.
Before moving forwards onto next task, which is to find out how to force malloc to allocate space in external and not limited internal RAM, two questions remain:
; External SDRAM
EXT_SDRAM 0xC0000000 UNINIT 0x2000000 {
.ANY (+RW)
}
…..causing HAL initialization faults. Notice 0x2000000. Code fails at different lines. Highly erratic behaviour.
….as I see it, defined DATA_IN_ExtSDRAM causes execution of SystemInit_ExtMemCtl() which configures all GPIOs, speeds, etc.
All suggestion are welcomed.