cancel
Showing results for 
Search instead for 
Did you mean: 

Cannot get FMC SDRAM driver to work on stm32f429 discovery board

MLiva
Associate III

Using CubeMX configuration specific to stm32f429 discovery board which configures FMC to support SDRAM board. Have a memory test program that tests the 8Mb memory available at 0xD0000000. This program fails to run by triggering a hardware fault exception. The same program works fine with example FMC configuration which is not using CubeMX. I checked the pin configuration between the two and they seem same. Is there anything I am missing, I was expecting the CubeMX driver to work out of the box.

10 REPLIES 10

> I checked the pin configuration between the two and they seem same

Incorrectly set pins are unlikely to cause fault.

Have you read out and checked/compared the relevant FMC registers?

JW

MLiva
Associate III

The timing registers also seem to be same between the two codes.

I think the initialisation function generated by CubeMX

............

/* FMC initialization function */

static void MX_FMC_Init(void)

{

..........

is missing some further initialisation steps. These steps may be the responsibility of the application developer.

The initialisation code that I am using and working is like this

...................

void SDRAM_Init(void) {

FMC_SDRAMInitTypeDef FMC_SDRAMInitStructure;

FMC_SDRAMTimingInitTypeDef FMC_SDRAMTimingInitStructure;

/* GPIO configuration for FMC SDRAM bank */

SDRAM_GPIOConfig();

/* Enable FMC clock */

RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);

/* FMC Configuration ---------------------------------------------------------*/

/* FMC SDRAM Bank configuration */

/* Timing configuration for 84 Mhz of SD clock frequency (168Mhz/2) */

/* TMRD: 2 Clock cycles */

FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;

/* TXSR: min=70ns (6x11.90ns) */

FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 7;

/* TRAS: min=42ns (4x11.90ns) max=120k (ns) */

FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;

/* TRC: min=63 (6x11.90ns) */

FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 7;

/* TWR: 2 Clock cycles */

FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 3;

/* TRP: 15ns => 2x11.90ns */

FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;

/* TRCD: 15ns => 2x11.90ns */

FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;

/* FMC SDRAM control configuration */

FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank2_SDRAM;

/* Row addressing: [7:0] */

FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_8b;

/* Column addressing: [11:0] */

FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_12b;

FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = SDRAM_MEMORY_WIDTH;

FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;

FMC_SDRAMInitStructure.FMC_CASLatency = SDRAM_CAS_LATENCY;

FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;

FMC_SDRAMInitStructure.FMC_SDClockPeriod = SDCLOCK_PERIOD;

FMC_SDRAMInitStructure.FMC_ReadBurst = SDRAM_READBURST;

FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_1;

FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct =

&FMC_SDRAMTimingInitStructure;

/* FMC SDRAM bank initialization */

FMC_SDRAMInit(&FMC_SDRAMInitStructure);

/* FMC SDRAM device initialization sequence */

SDRAM_InitSequence();

/* Disable write protection */

FMC_SDRAMWriteProtectionConfig(FMC_Bank2_SDRAM, DISABLE);

}

......................

cannot see any code added by CubeMX that resembles the last two functions calls

......................

/* FMC SDRAM device initialization sequence */

SDRAM_InitSequence();

/* Disable write protection */

FMC_SDRAMWriteProtectionConfig(FMC_Bank2_SDRAM, DISABLE);

........................

PMath.4
Senior III

Have you started up the SDRAM refresh?

#include "sdram_fx.h"
 
static FMC_SDRAM_CommandTypeDef Command;	// local
extern SDRAM_HandleTypeDef hsdram1;			// fmc.c
 
void SDRAM_Initialization_sequence(uint32_t RefreshCount)
{
  __IO uint32_t tmpmrd =0;
 
  /* Step 1:  Configure a clock configuration enable command */
  Command.CommandMode             = FMC_SDRAM_CMD_CLK_ENABLE;	// CubeMX
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK2; // CubeMX
  Command.AutoRefreshNumber       = 1;
  Command.ModeRegisterDefinition  = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); 	// BSP: 0xFFFF
 
  /* Step 2: Insert 100 us minimum delay */
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(1);
 
  /* Step 3: Configure a PALL (precharge all) command */
  Command.CommandMode             = FMC_SDRAM_CMD_PALL;			// CubeMX
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK2; // CubeMX
  Command.AutoRefreshNumber       = 1;
  Command.ModeRegisterDefinition  = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); // BSP: 0xFFFF
 
  /* Step 4: Configure an Auto Refresh command */
  Command.CommandMode             = FMC_SDRAM_CMD_AUTOREFRESH_MODE; // CubeMX
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK2; 	// CubeMX
  Command.AutoRefreshNumber       = 4;
  Command.ModeRegisterDefinition  = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); // BSP: 0xFFFF
 
  /* Step 5: Program the external memory mode register */
  tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |// BSP
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |// BSP
                     SDRAM_MODEREG_CAS_LATENCY_3           |// BSP
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD |// BSP
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;	// BSP
 
  Command.CommandMode             = FMC_SDRAM_CMD_LOAD_MODE;	// CubeMX
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK2;	// CubeMX
  Command.AutoRefreshNumber       = 1;
  Command.ModeRegisterDefinition  = tmpmrd;					// local
 
  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT); // BSP
 
  /* Step 6: Set the refresh rate counter */
  /* Set the device refresh rate */
  HAL_SDRAM_ProgramRefreshRate(&hsdram1, RefreshCount);		// local
}
/*
	SDRAM FX
	nützliche Routinen für die SDRAM Initialisation
 
	Markus Horbach
	04.09.2016
 
	für STM32CubeMX
*/
 
#include <stdlib.h>
#include "stm32f4xx_hal.h"
 
/**
  * @brief  FMC SDRAM Bank address
  */
#define SDRAM_DEVICE_ADDR         ((uint32_t)0xD0000000)
#define SDRAM_DEVICE_SIZE         ((uint32_t)0x800000)  /* SDRAM device size in MBytes */
 
/* Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
#define REFRESH_COUNT           ((uint32_t)1386)   /* SDRAM refresh counter */
#define SDRAM_TIMEOUT           ((uint32_t)0xFFFF)
 
/**
  * @brief  FMC SDRAM Mode definition register defines
  */
#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)
 
void SDRAM_Initialization_sequence(uint32_t RefreshCount);

MLiva
Associate III

Hi thanks,

I was in the process to port the following function to HAL which is similar to what you just publish here.

I assume CubeMX does not have a magic button that will have this generated automatically!!!

Here is the function that works in the none CubeMX code.

/**

 * @brief Executes the SDRAM memory initialization sequence.

 * @param None.

 * @retval None.

 */

void SDRAM_InitSequence(void) {

FMC_SDRAMCommandTypeDef FMC_SDRAMCommandStructure;

uint32_t tmpr = 0;

/* Step 3 --------------------------------------------------------------------*/

/* Configure a clock configuration enable command */

FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_CLK_Enabled;

FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;

FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;

FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;

/* Wait until the SDRAM controller is ready */

while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) {

}

/* Send the command */

FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

/* Step 4 --------------------------------------------------------------------*/

/* Insert 100 ms delay */

__Delay(10);

/* Step 5 --------------------------------------------------------------------*/

/* Configure a PALL (precharge all) command */

FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_PALL;

FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;

FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;

FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;

/* Wait until the SDRAM controller is ready */

while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) {

}

/* Send the command */

FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

/* Step 6 --------------------------------------------------------------------*/

/* Configure a Auto-Refresh command */

FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_AutoRefresh;

FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;

FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 4;

FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;

/* Wait until the SDRAM controller is ready */

while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) {

}

/* Send the first command */

FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

/* Wait until the SDRAM controller is ready */

while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) {

}

/* Send the second command */

FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

/* Step 7 --------------------------------------------------------------------*/

/* Program the external memory mode register */

tmpr = (uint32_t) SDRAM_MODEREG_BURST_LENGTH_2 |

SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |

SDRAM_MODEREG_CAS_LATENCY_3 |

SDRAM_MODEREG_OPERATING_MODE_STANDARD |

SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

/* Configure a load Mode register command*/

FMC_SDRAMCommandStructure.FMC_CommandMode = FMC_Command_Mode_LoadMode;

FMC_SDRAMCommandStructure.FMC_CommandTarget = FMC_Command_Target_bank2;

FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber = 1;

FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;

/* Wait until the SDRAM controller is ready */

while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) {

}

/* Send the command */

FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);

/* Step 8 --------------------------------------------------------------------*/

/* Set the refresh rate counter */

/* (7.81 us x Freq) - 20 */

/* Set the device refresh counter */

FMC_SetRefreshCount(683);

/* Wait until the SDRAM controller is ready */

while (FMC_GetFlagStatus(FMC_Bank2_SDRAM, FMC_FLAG_Busy) != RESET) {

}

}

MLiva
Associate III

Can confirm that porting my function (SDRAM refresh):

void SDRAM_InitSequence(void) 

to HAL api and calling it in the CubeMX SDRAM initialisation code completes the initialisation and SDRAM can then be accessed correctly.

Code below shows CubeMX initialisation code calling at the end SDRAM refresh function.

/* FMC initialization function */

static void MX_FMC_Init(void)

{

 /* USER CODE BEGIN FMC_Init 0 */

 /* USER CODE END FMC_Init 0 */

 FMC_SDRAM_TimingTypeDef SdramTiming = {0};

 /* USER CODE BEGIN FMC_Init 1 */

 /* USER CODE END FMC_Init 1 */

 /** Perform the SDRAM1 memory initialization sequence

 */

 hsdram1.Instance = FMC_SDRAM_DEVICE;

 /* hsdram1.Init */

 hsdram1.Init.SDBank = FMC_SDRAM_BANK2;

 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_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_DISABLE;

 hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;

 /* SdramTiming */

 SdramTiming.LoadToActiveDelay = 2;

 SdramTiming.ExitSelfRefreshDelay = 7;

 SdramTiming.SelfRefreshTime = 4;

 SdramTiming.RowCycleDelay = 7;

 SdramTiming.WriteRecoveryTime = 3;

 SdramTiming.RPDelay = 2;

 SdramTiming.RCDDelay = 2;

 if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)

 {

  Error_Handler( );

 }

 /* USER CODE BEGIN FMC_Init 2 */

/* FMC SDRAM device initialization sequence */

SDRAM_InitSequence();

 /* USER CODE END FMC_Init 2 */

}

The SDRAM refresh function is essentially the same as the one posted here by peter

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* Set the refresh rate counter */

/* (15.62 us x Freq) - 20 */

//#define REFRESH_COUNT      ((uint32_t)1386)  /* SDRAM refresh counter from forum*/

#define REFRESH_COUNT      ((uint32_t)683)  /* SDRAM refresh counter old setting */

#define SDRAM_TIMEOUT      ((uint32_t)0xFFFF)

/**

 * @brief FMC SDRAM Mode definition register defines

 */

#define SDRAM_MODEREG_BURST_LENGTH_1       ((uint16_t)0x0000)

#define SDRAM_MODEREG_BURST_LENGTH_2       ((uint16_t)0x0001)

#define SDRAM_MODEREG_BURST_LENGTH_4       ((uint16_t)0x0002)

#define SDRAM_MODEREG_BURST_LENGTH_8       ((uint16_t)0x0004)

#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   ((uint16_t)0x0000)

#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED   ((uint16_t)0x0008)

#define SDRAM_MODEREG_CAS_LATENCY_2       ((uint16_t)0x0020)

#define SDRAM_MODEREG_CAS_LATENCY_3       ((uint16_t)0x0030)

#define SDRAM_MODEREG_OPERATING_MODE_STANDARD  ((uint16_t)0x0000)

#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)

#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE   ((uint16_t)0x0200)

void SDRAM_InitSequence(void) {

FMC_SDRAM_CommandTypeDef FMC_SDRAMCommandStructure;

uint32_t tmpr = 0;

/* Step 3 --------------------------------------------------------------------*/

/* Configure a clock configuration enable command */

FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;

FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;

FMC_SDRAMCommandStructure.AutoRefreshNumber = 1;

FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0;

HAL_SDRAM_SendCommand(&hsdram1, &FMC_SDRAMCommandStructure, SDRAM_TIMEOUT);

/* Step 4 --------------------------------------------------------------------*/

/* Inserted delay is equal to 1 ms due to systick time base unit (ms) */

HAL_Delay(1);

/* Step 5 --------------------------------------------------------------------*/

/* Configure a PALL (precharge all) command */

FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_PALL;

FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;

FMC_SDRAMCommandStructure.AutoRefreshNumber = 1;

FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0;

HAL_SDRAM_SendCommand(&hsdram1, &FMC_SDRAMCommandStructure, SDRAM_TIMEOUT);

/* Step 6 --------------------------------------------------------------------*/

/* Configure a Auto-Refresh command */

FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;

FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;

FMC_SDRAMCommandStructure.AutoRefreshNumber = 4;

FMC_SDRAMCommandStructure.ModeRegisterDefinition = 0;

HAL_SDRAM_SendCommand(&hsdram1, &FMC_SDRAMCommandStructure, SDRAM_TIMEOUT);

/* Step 7 --------------------------------------------------------------------*/

/* Program the external memory mode register */

tmpr = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1     |// BSP

      SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL  |// BSP

      SDRAM_MODEREG_CAS_LATENCY_3      |// BSP

      SDRAM_MODEREG_OPERATING_MODE_STANDARD |// BSP

      SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; // BSP

/* Configure a load Mode register command*/

FMC_SDRAMCommandStructure.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;

FMC_SDRAMCommandStructure.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;

FMC_SDRAMCommandStructure.AutoRefreshNumber = 1;

FMC_SDRAMCommandStructure.ModeRegisterDefinition = tmpr;

HAL_SDRAM_SendCommand(&hsdram1, &FMC_SDRAMCommandStructure, SDRAM_TIMEOUT);

/* Step 8 --------------------------------------------------------------------*/

/* Set the refresh rate counter */

/* (7.81 us x Freq) - 20 */

/* Set the device refresh counter */

HAL_SDRAM_ProgramRefreshRate(&hsdram1, REFRESH_COUNT); // local

}

/* USER CODE END 0 */

See also BSP code and examples in the repository

STM32Cube\Repository\STM32Cube_FW_F4_V1.24.1\Drivers\BSP\STM32F429I-Discovery\stm32f429i_discovery_sdram.c

STM32Cube\Repository\STM32Cube_FW_F4_V1.24.1\Drivers\BSP\STM32F429I-Discovery\stm32f429i_discovery_sdram.h

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
MLiva
Associate III

Thanks Clive,

Looks same as what i did. This information would have made my task much easier.

Regards,

Makis

Richard Delorme
Associate II

Thank you for this, I spent a couple days trying to work around this as I'm sure many others have. It's a shame ST still hasn't fixed this as their documentation clearly states it is supposed to perform these last couple tasks.

The HAL/Cube stuff is very ugly.

Many years ago I posted initialization code where the F429I-DISCO SDRAM was brought up properly in SystemInit() where CMSIS expects it to be, so the startup code can unpack the load regions and statics properly.

ST has always focused on the EVAL boards.

I think you'll find given the age of the F429I-DISCO most of the engineering resources are thrown at the newer boards, it was a very frustratingly limited board design.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..