2014-12-07 12:12 PM
Hello everyone,
I have used STM32F429 device along with two SDRAMs AS4C16M16S mapped to the two available banks. When the FMC controller was initialized using the generated code from STM32CubeMX with BANK1 initialized before BANK2, I got an error when reading from the BANK1 device (starting at address 0xC0000000) - it was returning only 2 times the LSB instead of MSB:LSB (e.g. I wrote 0x1234 and I read back 0x3434). I was inspecting my PCB many times, looking at the signals with my scope (unfortunately I do not have a logical analyzer), but everything seemed ok to me.When I was only using the BANK1 device or only BANK2 device (the other one was left uninitialized), everything worked properly, but when I wanted to use both devices, I had to initialize first the BANK2 and then the BANK1 device. Here is my code:/* FMC initialization function */void MX_FMC_Init(void){ FMC_SDRAM_TimingTypeDef SdramTiming; /** Perform the SDRAM2 memory initialization sequence */ hsdram2.Instance = FMC_SDRAM_DEVICE; /* hsdram2.Init */ hsdram2.Init.SDBank = FMC_SDRAM_BANK2; hsdram2.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; hsdram2.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; hsdram2.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; hsdram2.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; hsdram2.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; hsdram2.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; hsdram2.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; hsdram2.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; hsdram2.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; /* SdramTiming */ SdramTiming.LoadToActiveDelay = 3; SdramTiming.ExitSelfRefreshDelay = 8; SdramTiming.SelfRefreshTime = 4; SdramTiming.RowCycleDelay = 7; SdramTiming.WriteRecoveryTime = 4; SdramTiming.RPDelay = 3; SdramTiming.RCDDelay = 3; HAL_SDRAM_Init(&hsdram2, &SdramTiming); /** 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_3; 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 = 3; SdramTiming.ExitSelfRefreshDelay = 8; SdramTiming.SelfRefreshTime = 4; SdramTiming.RowCycleDelay = 7; SdramTiming.WriteRecoveryTime = 4; SdramTiming.RPDelay = 3; SdramTiming.RCDDelay = 3; HAL_SDRAM_Init(&hsdram1, &SdramTiming); SDRAM_Initialization_Sequence();}void SDRAM_Initialization_Sequence(void){&sharpdefine SDRAM_TIMEOUT ((uint32_t)0xFFFF)&sharpdefine REFRESH_COUNT ((uint32_t)0x050C) /* SDRAM refresh counter (84MHz SD clock) */&sharpdefine SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)&sharpdefine SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)&sharpdefine SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)&sharpdefine SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)&sharpdefine SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)&sharpdefine SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)&sharpdefine SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)&sharpdefine SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)&sharpdefine SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)&sharpdefine SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)&sharpdefine SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) __IO uint32_t tmpmrd =0; FMC_SDRAM_CommandTypeDef cmd; /* Step 3: Configure a clock configuration enable command */ cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; cmd.AutoRefreshNumber = 1; cmd.ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &cmd, 0x1000); /* Step 4: Insert 100 ms delay */ HAL_Delay(100); /* Step 5: Configure a PALL (precharge all) command */ cmd.CommandMode = FMC_SDRAM_CMD_PALL; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; cmd.AutoRefreshNumber = 1; cmd.ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &cmd, 0x1000); /* Step 6 : Configure a Auto-Refresh command */ cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; cmd.AutoRefreshNumber = 1; cmd.ModeRegisterDefinition = 0; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &cmd, 0x1000); /* 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_3 | SDRAM_MODEREG_OPERATING_MODE_STANDARD | SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; cmd.AutoRefreshNumber = 4; cmd.ModeRegisterDefinition = tmpmrd; /* Send the command */ HAL_SDRAM_SendCommand(&hsdram1, &cmd, 0x1000); /* Step 8: Set the refresh rate counter */ /* (15.62 us x Freq) - 20 */ /* Set the device refresh counter */ HAL_SDRAM_ProgramRefreshRate(&hsdram1, REFRESH_COUNT);}I hope it helps somebody, I will be happy for any feedback.The probem is solved for my, but I would like to help others, since the ST forum has helped me a lot of times.Have a nice day, OK2NMZ #stm32f429 #sdram #stm32 #cubemx2014-12-07 11:46 PM
Hi Marek,
This forum is mostly ignored by ST staff. As this sounds to be a genuine silicon bug, could you please report it through the online support ( https://my.st.com/onlinesupport/app?page=onlineSupport , but as the ST web tends to change in surprising ways, you may need to click through Support in top menu -> Online support it left menu). JW2014-12-09 06:22 AM
2014-12-09 12:26 PM
> I was actually doing a read after write, which means I was getting directly the data prom the
> FMC controller and not physically from the SDRAM... I don't understand why would read data be different from what was written. What was your method and what were your findings? And, if it was the case, what was exactly the cause, and what did you do to correct that behaviour? Thanks, JW PS. //For reasons unknown the write to GPIOB->AFR does not occur without a DMB //in the middle __DMB(); I'd like to see the (dis)assembler, without the memory barrier, resulting in the unexpected result (and with the barrier, for comparison, too).