cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F722 reads mostly incorrect values from SDRAM

Lars Beiderbecke
Senior III
Posted on July 03, 2018 at 12:05

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 similarly

the 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); // 2HCLK

I 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.
17 REPLIES 17
Posted on July 03, 2018 at 12:45

Make sure to do testing with caching disabled

Show schematic for SDRAM, and pin configuration code

More complex data patterns might better illustrate stuck-at faults, or shorts between bits.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on July 03, 2018 at 14:27

I'm assuming all the required trace length matching was done properly.  One suggestion is to disable the read bursting.  Another WAG would be to double everything in SdramTiming.

Lars Beiderbecke
Senior III
Posted on July 03, 2018 at 15:07

Here's the pin config code:

static void HAL_FMC_MspInit(void){

  /* USER CODE BEGIN FMC_MspInit 0 */

  /* USER CODE END FMC_MspInit 0 */

  GPIO_InitTypeDef GPIO_InitStruct;

  if (FMC_Initialized) {

   return;

  }

  FMC_Initialized = 1;

  /* Peripheral clock enable */

  __HAL_RCC_FMC_CLK_ENABLE();

/** FMC GPIO Configuration

PF0 ------> FMC_A0

PF1 ------> FMC_A1

PF2 ------> FMC_A2

PF3 ------> FMC_A3

PF4 ------> FMC_A4

PF5 ------> FMC_A5

PC0 ------> FMC_SDNWE

PC2 ------> FMC_SDNE0

PC3 ------> FMC_SDCKE0

PF11 ------> FMC_SDNRAS

PF12 ------> FMC_A6

PF13 ------> FMC_A7

PF14 ------> FMC_A8

PF15 ------> FMC_A9

PG0 ------> FMC_A10

PG1 ------> FMC_A11

PE7 ------> FMC_D4

PE8 ------> FMC_D5

PE9 ------> FMC_D6

PE10 ------> FMC_D7

PE11 ------> FMC_D8

PE12 ------> FMC_D9

PE13 ------> FMC_D10

PE14 ------> FMC_D11

PE15 ------> FMC_D12

PD8 ------> FMC_D13

PD9 ------> FMC_D14

PD10 ------> FMC_D15

PD14 ------> FMC_D0

PD15 ------> FMC_D1

PG2 ------> FMC_A12

PG4 ------> FMC_BA0

PG5 ------> FMC_BA1

PG8 ------> FMC_SDCLK

PD0 ------> FMC_D2

PD1 ------> FMC_D3

PG15 ------> FMC_SDNCAS

PE0 ------> FMC_NBL0

PE1 ------> FMC_NBL1

*/

/* GPIO_InitStruct */

GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3

|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12

|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;

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(GPIOF, &GPIO_InitStruct);

/* GPIO_InitStruct */

GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3;

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(GPIOC, &GPIO_InitStruct);

/* GPIO_InitStruct */

GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4

|GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15;

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(GPIOG, &GPIO_InitStruct);

/* GPIO_InitStruct */

GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10

|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14

|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;

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(GPIOE, &GPIO_InitStruct);

/* GPIO_InitStruct */

GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14

|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1;

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(GPIOD, &GPIO_InitStruct);

}
Lars Beiderbecke
Senior III
Posted on July 03, 2018 at 15:12

And here's my CubeMX config.  All signals are connected to the obvious counterparts, and the non-obvious ones are SDNE0 -- CS, NBLE1/0 -- DQMH/L.

0690X0000060LagQAE.png
Lars Beiderbecke
Senior III
Posted on July 03, 2018 at 15:16

I also noted something interesting.  If I replace my data by a fixed constant 0x5555, i.e.,

for (int i = 0; i < 256; ++i)

  *(__IO uint16_t*) (SDRAM_BASE + 2*i) = 0x5555;

I still get this as result:

Index 0 read 20 != 5555

Index 1 read 21 != 5555

Index 2 read 22 != 5555

Index 3 read 23 != 5555

Index 4 read 24 != 5555

Index 5 read 25 != 5555

Index 6 read 26 != 5555

Index 7 read 27 != 5555

Index 8 read 28 != 5555

Index 9 read 29 != 5555

Index a read 2a != 5555

Index b read 2b != 5555

Index c read 2c != 5555

Index d read 2d != 5555

Index e read 2e != 5555

Index f read 2f != 5555

Index 10 read 30 != 5555

Index 11 read 31 != 5555

Index 12 read 32 != 5555

Index 13 read 33 != 5555

It seems that I actually get parts of the address back -- how can that happen?

(Note: My pin assignment code seems to be waiting for moderator approval.)

Lars Beiderbecke
Senior III
Posted on July 03, 2018 at 15:17

Two posts are waiting for moderation ...

Lars Beiderbecke
Senior III
Posted on July 03, 2018 at 15:19

SDRAM schematic (9 column bits, 13 address bits):

0690X0000060LalQAE.png
Posted on July 03, 2018 at 18:38

 ,

 ,

Ok, let me see if I can stand up some code independently

Which Micron Part ♯ specifically are you using, I want to pull the data-sheet?

Can I use USART1 PA9/PA10 for debug/diagnostic output?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on July 03, 2018 at 19:24

Yes, you can use USART1.  The Micron SDRAM is part ♯  MT48LC16M16A2-7E.

Thank you so much!