2018-02-19 08:03 AM
Hi,
I am university student from Finland and I am doing school project with STM32F769IIT6 MCU and Alliance AS4C1M16S-C&I SDRAM. End goal is to use SDRAM as framebuffer for MIPI-DSI interface. We have custom PCB and previous and current revisions of PCB have proven that MCU it self is working and power etc. lines are OK. Serial and GPIO configurations do work. Problem that I am facing is when initializing SDRAM and FMC. I have ST-LinkV2 so I can see whats happening in registers. Problem:
### CODE SNIPPLET ###
//MAIN
int main(void)
{ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FMC_Init();/* USER CODE BEGIN 2 */
SDRAM_Init(&hsdram1, &SDRAM_DebugFlag, &SDRAM_InitFlag); MainDebugFlag = 4;MainDebugFlag = 5;
while (1){ MainDebugFlag = 6; HAL_Delay(100);}
// CUBEMX
static void MX_FMC_Init(void)
{ FMC_SDRAM_TimingTypeDef 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_8; hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_8; hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_2; 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 = 7; SdramTiming.SelfRefreshTime = 4; SdramTiming.RowCycleDelay = 6; SdramTiming.WriteRecoveryTime = 2; SdramTiming.RPDelay = 2; SdramTiming.RCDDelay = 2;if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{ _Error_Handler(__FILE__, __LINE__); }}
void SDRAM_Init(SDRAM_HandleTypeDef *hsdram1, uint8_t *SDRAM_DebugFlag, uint8_t *SDRAM_InitFlag){
FMC_SDRAM_CommandTypeDef cmd;
uint32_t SDRAMTimeout = 50;
//Step 1 - clock cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; cmd.AutoRefreshNumber = 1; HAL_SDRAM_SendCommand(&hsdram1, &cmd, SDRAMTimeout);*SDRAM_DebugFlag = 1;
//Step 2 - delay
HAL_Delay(SDRAMTimeout);*SDRAM_DebugFlag = 2;
//Step 3 - PALL
cmd.CommandMode = FMC_SDRAM_CMD_PALL; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; HAL_SDRAM_SendCommand(&hsdram1, &cmd, SDRAMTimeout);*SDRAM_DebugFlag = 3;
//Step 4 - Auto-Refresh
cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd.AutoRefreshNumber = 2; HAL_SDRAM_SendCommand(&hsdram1, &cmd, SDRAMTimeout);*SDRAM_DebugFlag = 4;
//Step 5 - External memory mode register
cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd.ModeRegisterDefinition = 0x0220; HAL_SDRAM_SendCommand(&hsdram1, &cmd, SDRAMTimeout);*SDRAM_DebugFlag = 5;
// Step 6 - refresh counter //
// 64ms for 4092 = 15.625us // // 15.625us * 10MHz - 20 = 136.25 = 0x88 // HAL_SDRAM_ProgramRefreshRate(&hsdram1, 0x88);*SDRAM_DebugFlag = 6;
*SDRAM_InitFlag = 1;}So, first is main where CubeMX's configs are run first and after that SDRAM_Init function. There is also couple of debug flags there. I am not able to get anything reacting with current code. With ST-Links I can see that SdramTiming values do change in hsdram1 expression, but when I examine SDRAM1 control and timing registers there is nothing (all zeroes). Seems like that the whole pheriable is not responding (incorrect clock config? Clock config is made by CubeMX). What am I missing?
As an attachment there are couple of screenshots from debugger, from variables that do change and registers that stay 0
Sorry for broken English
2018-02-19 08:16 AM
Make sure the clocks to the FMC, etc are enabled so the peripheral/bus is usable.
2018-02-19 12:53 PM
1. Make sure that you are enabling the GPIO clocks and configuring the GPIOs correctly.
2. Configure the FMC with correct configuration wait states, data and address width.
3. Cube is missing the external SDRAM initialization step. Add that part of the code.
/* Initialize the SDRAM controller */
if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) { /* Initialization Error */ Error_Handler(); }/* Program the SDRAM external device */
BSP_SDRAM_Initialization_Sequence(&hsdram, &command);Please look at
example: \Projects\STM32FXXXI-Discovery\Examples\FMC\FMC_SDRAM
2018-02-23 07:19 AM
Hi,
Thank you a lot guys. Couple of days I have tried to solve problem. Here where I am standing now:
Solved compiler warnings and cleaned up code but thats about it. I already had that BSP_SDRAM_Initialization function, but only named SDRAM_Init. I did play around it's placement, when to run it. Changing position to the end of Cube's SDRAM procedure as Sree suggested did not change a thing. (It should not matter if function is run from Main or from Cube's init function?) I can still see good values at Expressions, but on registers there is nothing. I did study that example and that rised some good questions:
1)
//FROM EXAMPLE
/* 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;//AND
/* Step 8: Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */ /* Set the device refresh counter */ hsdram->Instance->SDRTR |= ((uint32_t)((1292)<< 1));These two steps. How documents I had previosly seen just told to pass ModeRegisterDefinition as 0x0220. Is that the same thing. Im not too sure whats happening there.
Also step 8, where refresh rate is calculated. Also the same documents I have previosly seen tell to use solution like this:// Step 6 - refresh counter //
// 64ms for 4092 = 15.625us // // 15.625us * 10MHz - 20 = 136.25 = 0x88 // HAL_SDRAM_ProgramRefreshRate(hsdram1, 0x88);I have configured SYSCLK to 10MHz just for debuggins purposes and to minimize impedance issues. Going to go full 214MHz when design is proven good. If I calculate examples CLK. It is told to be 200MHz, but if you solve (15.62 * X) - 20 = 1292 you get x = 83MHz. What am I getting wrong?.
Current code looks like this:
void SDRAM_Init(SDRAM_HandleTypeDef *hsdram1, FMC_SDRAM_CommandTypeDef *cmd){
uint32_t SDRAMTimeout = 50;
//Step 1 - clock cmd->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; cmd->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd->ModeRegisterDefinition = 0; cmd->AutoRefreshNumber = 1; HAL_SDRAM_SendCommand(hsdram1, cmd, SDRAMTimeout);//Step 2 - delay
HAL_Delay(1);//Step 3 - PALL
cmd->CommandMode = FMC_SDRAM_CMD_PALL; cmd->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd->AutoRefreshNumber = 1; cmd->ModeRegisterDefinition = 0; HAL_SDRAM_SendCommand(hsdram1, cmd, SDRAMTimeout);//Step 4 - Auto-Refresh
cmd->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; cmd->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd->AutoRefreshNumber = 8; HAL_SDRAM_SendCommand(hsdram1, cmd, SDRAMTimeout);//Step 5 - External memory mode register
cmd->CommandMode = FMC_SDRAM_CMD_LOAD_MODE; cmd->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; cmd->ModeRegisterDefinition = 0x0220; cmd->AutoRefreshNumber = 1; HAL_SDRAM_SendCommand(hsdram1, cmd, SDRAMTimeout);// Step 6 - refresh counter //
// 64ms for 4092 = 15.625us // // 15.625us * 10MHz - 20 = 136.25 = 0x88 // HAL_SDRAM_ProgramRefreshRate(hsdram1, 0x88);}
static void MX_FMC_Init(void){ FMC_SDRAM_TimingTypeDef 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_8; hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_8; hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_2; 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 = 7; SdramTiming.SelfRefreshTime = 4; SdramTiming.RowCycleDelay = 6; SdramTiming.WriteRecoveryTime = 2; SdramTiming.RPDelay = 2; SdramTiming.RCDDelay = 2;if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
{ _Error_Handler(__FILE__, __LINE__); } SDRAM_Init(&hsdram1, &cmd); // HERE IS THE SDRAM_INIT}
int main(void){
//JUST LED BLINK
HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FMC_Init();uint16_t x = 1000;
while (1){
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
HAL_Delay(x);}
Example had MPU configs and CPU_CACHE functions. Cube does those ready for you right away, right?
I hope someone takes time to help me
--Eetu
2018-02-23 09:22 AM
How is it going to run at 200 MHz? The math here is for 84 MHz, should probably be using 100 MHz, but refreshing more frequently (in cycles) should not cause a problem. No idea where the 10 MHz number was pulled from.
From Data Sheet
'The maximum FMC_CLK/FMC_SDCLK frequency for synchronous accesses is HCLK/2'
ST has assorted examples running things at 168, 180, 200 and 216 MHz depending on needs of other peripherals in the system and due to the integer dividers used everywhere. There is thus some fluidity in the code/comments with these things as they are manually edited, and that is tedious when dozens of lines/comments are involved.
The settings for memory and the controller need to get goosed slightly to translate the timing parameters in the docs vs the speed your specific system is engineered to run at. Tends to be highly board and component specific.
Probably hard to buy 66 or 100 MHz SDRAM at this point most will be 133 or 166 MHz max, and be clockable slower with less aggressive settings. For a board running at 216 MHz, SDRAM timings will be 108 MHz.
The Refresh is using a cycle counter to force a bus transaction episodically even when no other bus traffic is occurring, and is dependent on the array geometry, and the quoted time to complete a full refresh.
My preference with SDRAM is to get it set up in the SystemInit() code path, which sets up the clocks and external pins, buses and memories *before* the C runtime code tries to initialize the statics.
If I were you, I'd repeat your analysis with the STM32F769I-DISCO board and compare/contrast my experience/observations with the SDRAM on that, vs the custom board.
This being a good 200 MHz example using SDRAM, DSI and SDMMC
\STM32Cube_FW_F7_V1.9.0\Projects\STM32F769I-Discovery\Examples\JPEG\JPEG_DecodingUsingFs_DMA
2018-02-23 09:56 AM
Ok, so it is better to go full clock speed right away. Allthou I am not in a point yet that I could get signals out of the MCU. Alliance's SDRAM says 166/143MHz. I have never really had anything to do with memories before. I had the same belive that clock speeds can be toned down, but maximum values are absolute. (but that is secondary issue since it seems that the whole pheriable refuses to work with me) Heres a screen grab from the datasheet if it matters.
I don't have access to any developement/evaluation boards. Idea of buying one has crossed my mind.
Have to keep working on studying that jpeg example.
2018-02-23 11:12 AM
How exactly is this wired up?
hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8;
hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; // Isn't it 11hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_8; // Isn't it 16hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_2;A10 is a bank switch
2018-02-23 12:11 PM
Oh yes, I had old configs left there, my bad to cause confusion. I have been testing different things with CubeMX and forgot to reconfig everything back as they were. Yes, A0:10 and A11 as bank switch, D0:15 and L/UDQM enabled. Heres is PDF of schematics:
https://www.dropbox.com/s/r8hi3rfyiaxumij/FSO_mittaristo_v2.pdf?dl=0