STM32 SDRAM: Why & How


Brief

This article is about how to use SDRAM on stm32, mainly, for STM32F4xx, NOT STM32F1xx.

The IDE

The using IDE is STM32CubeIDE, which has built-in STM32CubeMX.
The Version for writing this article is 1.7.0. Or the combination of System Workbench for STM32 and STM32CubeMX, it works well too.

The Board with SDRAM

After all, a STM32 board with SDRAM is needed. Here uses an old green STM32F4-Discovery(or DISCO) which has a built-in SDRAM chip of IS42S16400-7TL. Another eval board Alientek Apolo F429 from Chian just took off.
According to the datasheets, both boards are using STM42F429ZI MCU, which can run at a max speed of 180MHz, and drive the APB2 peripheral clock for SDRAM at 90Mhz. The SDRAM space is mapped to system memory space, for my board, it's BANK2. For STMF4xx MCU, the BANK2 SDRAM is mapped to address 0xD0000000. The STMF1xx MCUs use a different address mapping space, but .

Generating Project

Run STM32CubeMX or STM32CubeIDE, on the MCU/MPU Selector tab, input F429ZI, select the chips with package LQFP144. Or, on Board Selector tab, select the board. The software only show the picture of newer Nucelo F429ZI, which looks different from DISCO. when the software asking if initialize components to their preset states, click No. Unfortunately, the newer Nucelo F429FI can't generate SDRAM code correctly. The board configuration must be down by hand.

  • System Core

    • RCC

      • High Speed Clock (HSE): Crystal/Ceramic Resonator
      • Low Speed Clock (LSE): Crystal/Ceramic Rsonator
    • SYS

      • Debug: Serial Wire
      • Timebase Source: SysTick
  • Clock

    Setup clock like this:

    | Parameter | Value |
    | :----: | --- |
    | Input frequence | 8Mhz |
    | /M | /4 |
    | Main PLL | X180 for *N, /2 for /P |
    | PLLCLK | Selected |
    | SYSCLK(MHz) | 180 |
    | AHB Prescaler | /1 |
    | HCLK(MHz) | 180 |
    | APB2 Prescaler | /2 |

The APB2 periperal clocks (MHz) will run at 90MHz.

SDRAM Configuration

SDRAM is under FMC category. Select the SDRAM1.

  • SDRAM 1

    | Name | Value |
    |---|---|
    | Clock and chip enable | SDCKE1+SDNE1 |
    | Internal bank number | 4 banks |
    | Address | 12 bits |
    | Data | 16 bits|

    Check the 16-bit byte enable.

  • SDRAM Control

    | Name | Value |
    | ---- | --- |
    | Bank | SDRAM bank2 |
    | Numberof column address bits | 8 bits |
    | Number of row address bits | 12 bits |
    | CAS latency | 3 memory clock cyles |
    | Write protection | Disabled |
    | SDRAM common clock | 2 HCLK clock cycles(for 90MHz), or 3 HCLK clock cycles for 60MHz |
    | SDRAM common burst read | Disabled |
    | SDRAM common read pipe delay | 0 HCLK colck cycle |

  • SDRAM timing in memoty clock cycles
    | Name | Value |
    | --- | --- |
    | Load mode register to active delay | 2 |
    | Exit self-refresh delay | 7 |
    | Self-refresh time | 4 |
    | SDRAM common row cycle delay | 7 |
    | Write recovery time | 3 |
    | SDRAM common row precharge delay | 2 |
    | Row to column delay | 2 |

Explain about some parameters:

The reference manual is dm00031020.

  • About SDCKE1+SDNE1

    According to manual:

    • SDCKE

      • 0: SDRAM Bank 1 Clock Enable
      • 1: SDRAM Bank 2 Clock Enable
    • SDNE

      • 0: SDRAM Bank 1 Chip Enable
      • 1: SDRAM Bank 2 Chip Enable
  • Why 4 banks

    the SDRAM controller has 8/16/32 bits data bus width, 13-bits address row, 11-bits address column, 4 internal banks: 4x1Mx32bit(256MB), 4x16Mx16bit(128MB), 4x16Mx8bit(64MB). So the banks should be 4.

  • 12 bits of Address

    According to
    IS42S16400-7TL datasheet says the address line is from A0 to A11, total 12 bits.

  • 16 bits of Data

    STM32CubeMX gives highest 16 bits.

  • CAS latency: 3 memory clock cycles

    Accroding to IS42S16400 datasheet, there are two CAS latencies: 3 or 2. 3 means a time of 7ns. Also you can choose 2, which will affect the timing parameters.

  • SDRAM timing in memroy clock cycles

    To get the timing paramters, we have to do some calculations. At first, keep in mind the parameters that IS42S16400-7TL datasheet says:

    | Name | Value | Unit | Comments |
    | --- | ---: | --- | --- |
    | CAS latency = 3| 7 | ns | Clock cycle time |
    | Refresh count | 4K | 64ms | 4096 refresh cycles every 64 ms |
    | Tmrd | 2 | Cycle | Load mode register command to active or refresh command |
    | Txsr | 70 | ns | Exit Self-Refresh to Active Time |
    | Tras | 42 | ns | ACT to PRE command period |
    | Trc | 63 | ns | REF to REF/ACT to ACT command period |
    | Twr/TDPL | 2 | Cycle | Input data to precharge command delay time |
    | Trp | 15 | ns | PRE to ACT command period |
    | Trcd | 15 | ns | Active command to read/write command delay time |

    The relationship of s, ms, us and ns is:

    1s = 1 x 1000ms = 1 x 1000 x 1000us = 1 x 1000 x 1000 x 1000 ns

    The calculation of time of clock cycle is 1/Frequency.

    For 90MHz clock, one cycle takes 1/90Mhz = 11.11ns.

    For 60MHz clock, one cycle takes 1/60MHz = 16.67ns.

    STM32CubeMX generates code for FMC timing parameters like this, in a unit of clock cycle:

    /* SdramTiming */
    SdramTiming.LoadToActiveDelay = 2;
    SdramTiming.ExitSelfRefreshDelay = 7;
    SdramTiming.SelfRefreshTime = 4;
    SdramTiming.RowCycleDelay = 6;
    SdramTiming.WriteRecoveryTime = 2;
    SdramTiming.RPDelay = 2;
    SdramTiming.RCDDelay = 2;
    

    Here is the way to calculate the value of cycle:

    LoadToActiveDelay = Tmrd = 2

    ExtSelfRefreshDelay = Txsr = 70ns, 70ns/11.11ns = 6.7 ~= 7

    SelfRefreshTime = Tras = 42ns, 42ns/11.11ns = 3.78 ~= 4

    RowCycleDelay = Trc = 63ns, 63ns/11.11ns = 5.67 ~= 6

    WriteRecoveryTime = Twr = 2

    RPDelay = Trp = 15ns, 15ns/11.11ns = 1.35 ~= 2

    RCDDelay = Trcd = 15ns, 15/ns/11.11ns = 1.35 ~=2

    Samingly, for a clock of 60MHz, the values are: 1, 5, 3, 4, 1, 1, 1.

  • Refresh rate

    The refresh count is 4K/64ms, it is:
    64ms/4096 = 15.625ns

    For 90MHz, the rate is:

    15.625ns * 90MHz = 1406.25

    For 60MHz, the rate is:

    15.625ns * 60MHz = 937.5

The Trick For Hardware Fault

  • SDRAM Address

    The code generator won't give the defination of the SDRAM address. According to dm00031020, the SDRAM BANK 2 is mapped from 0xD0000000 to 0xDFFFFFFF, 256MB total. For the using board, it's 8MB total, from 0xD0000000 to 0xD08000000.

  • Initializing Commands

    To make the SDRAM work, add the following code in any place before access SDRAM, for example, between the USER CODE BEGIN/END FMC_Init 2:

    FMC_SDRAM_CommandTypeDef cmd;
    
    cmd.CommandMode= FMC_SDRAM_CMD_CLK_ENABLE;
    cmd.CommandTarget= FMC_SDRAM_CMD_TARGET_BANK2;
    cmd.AutoRefreshNumber = 1;
    cmd.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1000);
    HAL_Delay(100);
    
    cmd.CommandMode= FMC_SDRAM_CMD_PALL;
    cmd.CommandTarget= FMC_SDRAM_CMD_TARGET_BANK2;
    cmd.AutoRefreshNumber = 1;
    cmd.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1000);
    HAL_Delay(100);
    
    
    cmd.CommandMode= FMC_SDRAM_CMD_AUTOREFRESH_MODE;
    cmd.CommandTarget= FMC_SDRAM_CMD_TARGET_BANK2;
    cmd.AutoRefreshNumber = 1; // or 2, 3, 4, 8, ... you can try it.
    cmd.ModeRegisterDefinition = 0;
    HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1000);
    HAL_Delay(100);
    
    
    cmd.CommandMode= FMC_SDRAM_CMD_LOAD_MODE;
    cmd.CommandTarget= FMC_SDRAM_CMD_TARGET_BANK2;
    cmd.AutoRefreshNumber = 1;
    cmd.ModeRegisterDefinition = 0x00000221;
    HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1000);
    HAL_Delay(100);
    

Read/write SDRAM

The code of reading/writing SDRAM lists here:

#define SDRAM_ADDR 0xD0000000

**IO uint8_t* ptr = (**IO uint8_t *)SDRAM_ADDR;
**IO uint8_t* pend = ptr + 8 * 1024 * 1024; // 8MB

// Write
while(ptr < pend) {
    *ptr++ = 0xCC; // Unfamous byte.
}

// Read & verify
ptr = (_IO uint8_t *)SDRAM_ADDR;

while(ptr < pend) {
    // Verify
    if (*ptr++ != 0xCC) {
        Error_Handler();
    }
}

Other References

eevblog:STM32H7 SDRAM

STM32F429I Discovery: SDRAM

STM32F4 SDRAM configuration

Good luck.

03-05 23:23