STM32F722 reads mostly incorrect values from SDRAM
I'm using a custom board with F722 running at 160 MHz and a Micron 16 x 4 x 16 SDRAM presumably at 80 MHz. The following test program, however, yields wrong, but not entirely wrong values:
#define SDRAM_BASE ((uint32_t)0x60000000)
for (int i = 0; i < 256; ++i) *(__IO uint16_t*) (SDRAM_BASE + 2*i) = (i << 8) + i; for (int i = 0; i < 256; ++i) { int x = *(__IO uint16_t*) (SDRAM_BASE + 2*i); if (x != (i << 8) + i) printf('Index %x read %x != %x', i, x, (i << 8) + i); }The output for this is
Index 0 read 20 != 0
Index 1 read 21 != 101 Index 2 read 22 != 202 Index 3 read 23 != 303 ... Index f read 2f != f0f Index 10 read 30 != 1010 Index 11 read 31 != 1111 Index 12 read 32 != 1212 Index 13 read 33 != 1313 Index 14 read 34 != 1414 ... Index 1f read 3f != 1f1f Index 20 read 20 != 2020 Index 21 read 21 != 2121 Index 22 read 22 != 2222 Index 23 read 23 != 2323 Index 24 read 24 != 2424 ... Index 2f read 2f != 2f2f Index 30 read 30 != 3030 Index 31 read 31 != 3131 Index 32 read 32 != 3232 Index 33 read 33 != 3333 ...Some bit seems stuck, and the upper byte is missing completely. I also tried disabling byte access and set NBL[1:0], which is connected to DMQH/DMQL, to HIGH, but this didn't have any effect. The result is also stable, i.e. I can reproduce it by re-running the test.
If I enlarge the range and change my code from words to bytes,
for (int i = 0; i < 8192; ++i)
*(__IO uint8_t*) (SDRAM_BASE + i) = i % 256; // read bytes similarlythe test suddenly
succeeds
. But if I spread out the test to even addresses,for (int i = 0; i < 8192; ++i) {
*(__IO uint8_t*) (SDRAM_BASE +2*i
) = i % 256;I get errors again:
Index 0 read 20 != 0
Index 1 read 21 != 1 Index 2 read 22 != 2 Index 3 read 23 != 3 ... Index f read 2f != f Index 10 read 30 != 10 Index 11 read 31 != 11 Index 12 read 32 != 12 Index 13 read 33 != 13 ...I built two boards, and both behave the same. My configuration was generated by CubeMX:
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_0; /* SdramTiming */ SdramTiming.LoadToActiveDelay = 2; SdramTiming.ExitSelfRefreshDelay = 6; SdramTiming.SelfRefreshTime = 3; SdramTiming.RowCycleDelay = 5; SdramTiming.WriteRecoveryTime = 2; SdramTiming.RPDelay = 2; SdramTiming.RCDDelay = 2;I added the SDRAM config sequence from the FMC example:
__IO uint32_t tmpmrd =0;
/* Step 3: 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; HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 4: Insert 100 us minimum delay */ HAL_Delay(1); /* Step 5: 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; HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 6 : Configure a Auto-Refresh command */ Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; Command.AutoRefreshNumber = 8; Command.ModeRegisterDefinition = 0; HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 7: 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_BANK1; Command.AutoRefreshNumber = 1; Command.ModeRegisterDefinition = tmpmrd; HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); /* Step 8: Set the refresh rate counter: (64 ms / 8192 x Freq) - 20 */ hsdram1.Instance->SDRTR |= ((uint32_t)605); // 2HCLKI also triedlarger timings,and CL=3, but nothing helped.
My PCB has 4 layers, the SDRAM signals are separated intothree groups:
second layer: addresses, lengths 3-9 mm
third layer: data, lengths 2-1 mm
bottom layer: control, lengths 0-6
CLK length: 0 mm
Iwould suspect either some misconfiguration or bad signal tracing, but I just don't know how to examinemy problemany further than this.
#sdram #fmc Note: this post was migrated and contained many threaded conversations, some content may be missing.