2025-02-03 11:54 PM - edited 2025-02-04 03:51 AM
Hello,
I am using STM32F469BIT with W9812G6KH-6I TR SDRAM and no matter what I did, I could not write to or read from SDRAM since MCU goes into hardfault whenever i want to access SDRAM. I configured FMC according to this article. I am running SDRAM @84MHz and here's my configuration:
According to the datasheet:
There are 4 banks. 12 address pins and 16 data bits. Also there are UDQM and LDQM pins so i set 16 bit byte enable.
Number of column address bits: 512 column, 9 bit
Number of row address bits: 4096 row, 12 bit
CAS Latency: 3 for 166MHz operation. I run my SDRAM @84MHz.
84MHz period: 11.9047619 ns
Load mode register active delay: tRSC: 2 clock cycle
Exit self-refresh delay: tXSR: 72ns / 11.9 = 6.05. I set it as 7
Self-refresh time: tRAS: 42ns / 11.9 = 3.52. I set it as 4
SDRAM common row cycle delay: tRC: 60ns / 11.9 = 5.04 = I set it as 6
Write recovery time: tWR: 2 clock cycles
SDRAM common row precharge delay: 15ns / 11.9 = 1.26. I set it as 2
Row to column delay: 15ns / 11.9 = 1.26. I set it as 2
After that configuration, I wrote the SDRAM initialization sequence according to the article:
/* 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_BANK2; /* configure the Target Bank bits */
Command.AutoRefreshNumber = 1;
Command.ModeRegisterDefinition = 0;
HAL_SDRAM_SendCommand(&hsdram2, &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(&hsdram2, &Command, 0xfff);
/* Step 6: Configure an Auto Refresh command */
Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; /* Set MODE bits to "011" */
Command.AutoRefreshNumber = 2;
HAL_SDRAM_SendCommand(&hsdram2, &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(&hsdram2, &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/4096) * 100MHz] - 20 = 1562.5 - 20 ~ 1542 */
HAL_SDRAM_ProgramRefreshRate(&hsdram2, 1292);
/* USER CODE END FMC_Init 2 */
My SDRAM traces are using 3 bottom side layers of the PCB. At the very bottom (L6) and at layer 4, there are my SDRAM traces. L5 is used solid ground reference. Here are my trace lengths (in mils):
SDRAM_D7 | 852.581 |
SDRAM_D11 | 1039.912 |
SDRAM_D5 | 1132.215 |
SDRAM_D9 | 1262.056 |
SDRAM_D10 | 1275.214 |
SDRAM_D4 | 1349.673 |
SDRAM_D6 | 1360.237 |
SDRAM_D8 | 1411.807 |
SDRAM_D12 | 1518.199 |
SDRAM_D14 | 1559.54 |
SDRAM_D13 | 1611.611 |
SDRAM_D15 | 1820.164 |
SDRAM_D1 | 1828.286 |
SDRAM_A10 | 1977.895 |
SDRAM_A7 | 2220.33 |
SDRAM_SDCLK | 2242.717 |
SDRAM_D0 | 2287.159 |
SDRAM_BA0 | 2332.913 |
SDRAM_A11 | 2350.832 |
SDRAM_SDNRAS | 2441.158 |
SDRAM_BA1 | 2466.166 |
SDRAM_A9 | 2526.322 |
SDRAM_D2 | 2563.21 |
SDRAM_A8 | 2604.551 |
SDRAM_SDNE | 2629.602 |
SDRAM_A6 | 2672.078 |
SDRAM_D3 | 2894.197 |
SDRAM_SDNCAS | 3008.92 |
SDRAM_A3 | 3367.106 |
SDRAM_A0 | 3637.23 |
SDRAM_A2 | 3613.267 |
SDRAM_NBL0 | 3637.636 |
SDRAM_NBL1 | 3649.59 |
SDRAM_A1 | 3674.717 |
SDRAM_A4 | 3817.872 |
SDRAM_SDNWE | 3924.864 |
SDRAM_A5 | 4001.376 |
SDRAM_SDCKE | 4026.356 |
After all these configurations, i wrote this code to test the SDRAM:
/* USER CODE BEGIN PV */
uint8_t *externalRAM = (uint8_t*)0xC0000000;
const uint32_t size = 16 * 1024 * 1024; //16MB
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
//write external RAM
for (uint32_t i = 0; i < size; i++) {
externalRAM[i] = i % 256;
}
//read external RAM
for (uint32_t i = 0; i < size; i++) {
if (externalRAM[i] != i % 256) {
asm("nop");
// insert error handling logic here
}
}
/* USER CODE END 2 */
Now, the code executes fine but in the for loop where i read the data back from SDRAM, all of the data seems to be wrong. When i check the memory in each execution cycle of write operation, i don't see any change.
I can see the clock generated for SDRAM is exactly 84MHz on the oscilloscope.
I don't know what am i doing wrong. We designed a board with STM32H723 before with IS42S16400J-5TL SDRAM and it also did not work but when i soldered STM32F429, the SDRAM just worked fine. Since these MCU's are not pin compatible, we had to revise the board but we did not touched any SDRAM lines because they were already pin to pin and with STM32f429, it worked just fine.
The issue on the previous board was definitely not caused by the PCB; otherwise, the second MCU wouldn’t have worked properly. I don't think on the new board the problem is caused by the PCB but I don't know how to debug such a problem. Any help would greatly appreciated.
2025-02-04 02:16 AM
UPDATE
My screenshot from oscilloscope was bandwidth limited. Actual clock signal is down below