cancel
Showing results for 
Search instead for 
Did you mean: 

SDRAM Read/Write stm32h743

RDock
Associate II

Hello all,

I am using the h743i eval board and trying to store a large array on the sdram.

The problem I am running into is no matter what address I write to, when I read back a value I receive the last value written. I think this may be an issue with alignment? I am not sure.

My initialization functions are:

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_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_32;
  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 = 16;
  SdramTiming.ExitSelfRefreshDelay = 16;
  SdramTiming.SelfRefreshTime = 16;
  SdramTiming.RowCycleDelay = 16;
  SdramTiming.WriteRecoveryTime = 16;
  SdramTiming.RPDelay = 16;
  SdramTiming.RCDDelay = 16;
 
  if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
  {
    Error_Handler( );
  }
 
  /* USER CODE BEGIN FMC_Init 2 */
 
  /* USER CODE END FMC_Init 2 */
}

and

static void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
  FMC_SDRAM_CommandTypeDef Command;
 
  __IO uint32_t tmpmrd =0;
  /* Step 1:  Configure a clock configuration enable command */
  Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
  Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; //FMC_SDRAM_CMD_TARGET_BANK1
  Command.AutoRefreshNumber = 1;
  Command.ModeRegisterDefinition = 0;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
  HAL_Delay(1);
 
  /* Step 3: 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;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
 
  /* Step 4 : 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;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
 
 
  /* Step 5: 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;
 
  Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
  Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
  Command.AutoRefreshNumber = 1;
  Command.ModeRegisterDefinition = tmpmrd;
 
  /* Send the command */
  HAL_SDRAM_SendCommand(hsdram, &Command, SDRAM_TIMEOUT);
 
  /* Step 6: Set the refresh rate counter */
  /* Set the device refresh rate */
  HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
 
}

Then my test code is

#define WRITE_READ_ADDR     ((uint32_t)0x0800)
#define SDRAM_BANK_ADDR                 ((uint32_t)0xC0000000)
#define SDRAM_Write32(address, value)      (*(__IO uint32_t *) (SDRAM_BANK_ADDR + (address)) = (value))
#define SDRAM_Read32(address)              (*(__IO uint32_t *) (SDRAM_BANK_ADDR + (address)))
  
uint32_t writeval1 = 2045;
uint32_t writeval2 = 7869;
uint32_t readval1 = 0;
uint32_t readval2 = 0;
 
SDRAM_Write32(WRITE_READ_ADDR, writeval1);
SDRAM_Write32(WRITE_READ_ADDR + 32, writeval2);
 
/* Read and check */
readval1 = SDRAM_Read32(WRITE_READ_ADDR);
readval2 = SDRAM_Read32(WRITE_READ_ADDR + 32);
 
sprintf(msgchar, "Val: %lu %lu\n", readval1, readval2);
CDC_Transmit_FS(msgchar, strlen(msgchar));
 

However readval1 and readval2 are always equal to 7869. By the way, I used CubeMX to generate the FMC init code. Any tips or ideas would be greatly appreciated.

1 ACCEPTED SOLUTION

Accepted Solutions

Clive, I see what you are saying I was trying to drill down from the boards datasheet to what the chip datasheet says about the address mapping.

In any event I found the root cause of the problem: the cubemx tool generated an incorrect HAL_FMC_MspInit() function. Specifically the GPIO_Init pins are wrong, however if I replace these with the GPIO pins specified in the /Examples/FMC/FMC_SDRAM project, the sdram works correctly.

Not sure if its worth letting the CubeMX team know about this but for other people facing the same issue the correct functions in stm32h7xx_hal_msp.c should read:

void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram)
{
  GPIO_InitTypeDef  GPIO_Init_Structure;
 
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* Enable GPIO clocks */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOI_CLK_ENABLE();
 
  /* Enable FMC clock */
  __HAL_RCC_FMC_CLK_ENABLE();
 
  /*##-2- Configure peripheral GPIO ##########################################*/
   /* Common GPIO configuration */
  GPIO_Init_Structure.Mode      = GPIO_MODE_AF_PP;
  GPIO_Init_Structure.Pull      = GPIO_PULLUP;
  GPIO_Init_Structure.Speed     = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_Init_Structure.Alternate = GPIO_AF12_FMC;
  
  /* GPIOD configuration */
  GPIO_Init_Structure.Pin   = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\
                              GPIO_PIN_14 | GPIO_PIN_15;
 
   
  HAL_GPIO_Init(GPIOD, &GPIO_Init_Structure);
 
  /* GPIOE configuration */  
  GPIO_Init_Structure.Pin   = GPIO_PIN_0 | GPIO_PIN_1 | 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;
      
  HAL_GPIO_Init(GPIOE, &GPIO_Init_Structure);
  
  /* GPIOF configuration */  
  GPIO_Init_Structure.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;
    
  HAL_GPIO_Init(GPIOF, &GPIO_Init_Structure);
  
  /* GPIOG configuration */  
  GPIO_Init_Structure.Pin   = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 |\
                              GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15;
  HAL_GPIO_Init(GPIOG, &GPIO_Init_Structure);
 
  /* GPIOH configuration */  
  GPIO_Init_Structure.Pin   = GPIO_PIN_5 | GPIO_PIN_6 | 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;
  HAL_GPIO_Init(GPIOH, &GPIO_Init_Structure); 
  
  /* GPIOI configuration */  
  GPIO_Init_Structure.Pin   = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\
                              GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10;
  HAL_GPIO_Init(GPIOI, &GPIO_Init_Structure);  
 
}

and

void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram)
{
  /*## Disable peripherals and GPIO Clocks ###################################*/
  /* Configure FMC as alternate function  */
  HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3| GPIO_PIN_4 | GPIO_PIN_5     |\
                         GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |\
                         GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
  
  HAL_GPIO_DeInit(GPIOE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3| GPIO_PIN_4 | 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);
 
  HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4     |\
                         GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
 
  HAL_GPIO_DeInit(GPIOG, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\
                         GPIO_PIN_5 | GPIO_PIN_10);
}

View solution in original post

13 REPLIES 13

Try the prebuilt BSP examples, rather than the CubeMX output, some human might actually have tested those.

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

Clive,

Thanks for the response. I have compared my code with the example code in /STM32H743I-EVAL/Examples/FMC/FMC_SDRAM and I do not see any obvious differences. Unfortunately this example project will not load in CubeIDE on my machine so I cannot test it. Are there other gotchas to look out for? Clock setup? Address alignment? etc?

The examples are small enough that they should compile and debug in the evaluation/lite versions of Keil. https://www.keil.com/demo/eval/arm.htm

At least with a working example you could drill into the RCC, GPIO and FMC settings and compare/contrast.

ST's code frequently has errors, so you get back to going a pin at a time through the data sheet and board schematic.

It shouldn't be difficult to build a project from scratch in the IDE. If need be, make CubeMX fashion you something where the USART works, or some other shell of a project, and then pull in the BSP files for the SDRAM, and merge the code from the examples in.

The address alignment should be transparent. The cache is also hide small read/write interactions. When testing SDRAM I tend to fill them with "random" patterns in one pass, and verify in others. If the geometry is totally off the in FMC, you'll get Hard Faults. Timing parameters will be more subtle.

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

there was a gotcha on the F7 series, the SDRAM would only run at 200MHz not 216 as you would expect.

was seeing a hundred random errors per Mbyte and gave up on that board, later to find out it SDRAM is not stable on the F7 series above 200MHz.

what speed ram is it ?

increase CAS and RAS latency slow down the clocks.

RDock
Associate II

Trevor,

Thanks for the tip. The datasheet claims the sdram can run at 200, 166, or 143 Mhz. I currently have a 160Mhz HCLK3 attached to the FMC which I believe means the sdram is getting a 160 Mhz clock signal

Also based on the datasheet I believe my timing configuration should be as follows:

Tmrd: 2

Txsr: 12

Tras: 7

Trc: 10

Twr: 4

Trp: 3

Trcd: 3

But changing those values didn't seem to solve my problem.

I also set the CAS latency to 3 cycles which didn't seem to help.

I am wondering if the SDRAM 1 address is not actually 0xC0000000 or some other mapping has been used.

Reference: https://www.mouser.com/datasheet/2/198/42-45S32800G-258457.pdf

As I recall the F7 clocks the SDRAM at half the HCLK rate, so 108 MHz, should be within the realm of a -100 SDRAM, and certainly a -133 one.

One doesn't however set the slew-rate to 100 MHz, but rather 50 MHz, as the leads are short, and capacitive load is low.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
/**
  * @brief  Initializes SDRAM MSP.
  * @param  hsdram: SDRAM handle
  * @param  Params
  * @retval None
  */
__weak void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef  *hsdram, void *Params)
{
  static DMA_HandleTypeDef dma_handle;
  GPIO_InitTypeDef gpio_init_structure;
 
  /* Enable FMC clock */
  __HAL_RCC_FMC_CLK_ENABLE();
 
  /* Enable chosen DMAx clock */
  __DMAx_CLK_ENABLE();
 
  /* Enable GPIOs clock */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOI_CLK_ENABLE();
 
  /* Common GPIO configuration */
  gpio_init_structure.Mode      = GPIO_MODE_AF_PP;
  gpio_init_structure.Pull      = GPIO_PULLUP;
  gpio_init_structure.Speed     = GPIO_SPEED_FAST; // Not HIGH
  gpio_init_structure.Alternate = GPIO_AF12_FMC;
 
  /* GPIOD configuration */
  gpio_init_structure.Pin   = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\
                              GPIO_PIN_14 | GPIO_PIN_15;
 
 
  HAL_GPIO_Init(GPIOD, &gpio_init_structure);
..

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

What board do you have?

The STM32H743I-EVAL has it's SDRAM at 0xD0000000, and at 400 MHz runs the memory at 100 MHz

STM32Cube_FW_H7_V1.5.0\Drivers\BSP\STM32H743I_EVAL\stm32h743i_eval_sdram.h

...
/** @defgroup STM32H743I_EVAL_SDRAM_Exported_Constants SDRAM Exported Constants
  * @{
  */
#define SDRAM_DEVICE_ADDR  ((uint32_t)0xD0000000)
#define SDRAM_DEVICE_SIZE  ((uint32_t)0x2000000)  /* SDRAM device size in Bytes (32MB)*/
 
/* #define SDRAM_MEMORY_WIDTH            FMC_SDRAM_MEM_BUS_WIDTH_8  */
/* #define SDRAM_MEMORY_WIDTH            FMC_SDRAM_MEM_BUS_WIDTH_16 */
#define SDRAM_MEMORY_WIDTH               FMC_SDRAM_MEM_BUS_WIDTH_32
 
#define SDCLOCK_PERIOD                   FMC_SDRAM_CLOCK_PERIOD_2
/* #define SDCLOCK_PERIOD                FMC_SDRAM_CLOCK_PERIOD_3 */
 
#define REFRESH_COUNT                    ((uint32_t)0x0603)   /* SDRAM refresh counter (100Mhz FMC clock) */
 
#define SDRAM_TIMEOUT                    ((uint32_t)0xFFFF)
...
/**
  * @brief  Initializes the SRAM device.
  * @retval SRAM status
  */
uint8_t BSP_SRAM_Init(void)
{
  static uint8_t sram_status = SRAM_ERROR;
  /* SRAM device configuration */
  sramHandle.Instance = FMC_NORSRAM_DEVICE;
  sramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
 
  /* SRAM device configuration */
  /* Timing configuration derived from system clock (up to 400Mhz)
     for 100Mhz as SRAM clock frequency */
  Timing.AddressSetupTime      = 2;
  Timing.AddressHoldTime       = 1;
  Timing.DataSetupTime         = 2;
  Timing.BusTurnAroundDuration = 1;
  Timing.CLKDivision           = 2;
  Timing.DataLatency           = 2;
  Timing.AccessMode            = FMC_ACCESS_MODE_A;
 
  sramHandle.Init.NSBank             = FMC_NORSRAM_BANK3;
  sramHandle.Init.DataAddressMux     = FMC_DATA_ADDRESS_MUX_DISABLE;
  sramHandle.Init.MemoryType         = FMC_MEMORY_TYPE_SRAM;
  sramHandle.Init.MemoryDataWidth    = SRAM_MEMORY_WIDTH;
  sramHandle.Init.BurstAccessMode    = SRAM_BURSTACCESS;
  sramHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
  sramHandle.Init.WaitSignalActive   = FMC_WAIT_TIMING_BEFORE_WS;
  sramHandle.Init.WriteOperation     = FMC_WRITE_OPERATION_ENABLE;
  sramHandle.Init.WaitSignal         = FMC_WAIT_SIGNAL_DISABLE;
  sramHandle.Init.ExtendedMode       = FMC_EXTENDED_MODE_DISABLE;
  sramHandle.Init.AsynchronousWait   = FMC_ASYNCHRONOUS_WAIT_DISABLE;
  sramHandle.Init.WriteBurst         = SRAM_WRITEBURST;
  sramHandle.Init.ContinuousClock    = CONTINUOUSCLOCK_FEATURE;
  sramHandle.Init.WriteFifo          = FMC_WRITE_FIFO_DISABLE;
  sramHandle.Init.PageSize           = FMC_PAGE_SIZE_NONE;
 
  /* SRAM controller initialization */
  BSP_SRAM_MspInit(&sramHandle, NULL); /* __weak function can be rewritten by the application */
  if(HAL_SRAM_Init(&sramHandle, &Timing, &Timing) != HAL_OK)
  {
    sram_status = SRAM_ERROR;
  }
  else
  {
    sram_status = SRAM_OK;
  }
  return sram_status;
}

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

Thanks for the help. I will take a look at that example. From the datasheet it looks like there are two SDRAM's one at 0xC000000 and one at 0xD000000, but perhaps I am reading that wrong.

 Additionally the eval board datasheet claims that the SDRAM is connected to the SDRAM bank1 of the FMC interface of the STM32H7x3XI microcontroller. The STM32H7x3XI datasheet claims that the SDRAM bank 1 is at address 0xC0000000. This is perhaps why I am confused by the example code which references SDRAM 2 and address 0xD0000000.