写在前面:

本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

目录

  • SDRAM芯片
  • 简知
  • 类型
  • 引脚定义
  • 内存容量
  • 硬件设计
  • 芯片引脚对应
  • 特殊脚 BA(Bank地址线)
  • 关于数据线交换问题
  • 几个重要结构体
  • 初始化结构体
  • 时序结构体
  • 示例代码
  • API 版本:
  • Register 版本:
  • SDRAM芯片

    简知

    SDRAM (Synchronous Dynamic RandomAccess Memory),同步动态随机存储器。同步是指其时钟频率与CPU的前端总线的系统时间频率相同,并且他的内部命令的发送与数据的传输都是以这个时钟为基准的,动态是指存储阵列需要不断的刷新才能保证数据的不丢失。随机是指数据不是线性存储的,是可以自由指定地址进行数据读写。

    以常见的 SDRAM芯片为例,一般单片机外围搭配用 TSOP-54pin的 SDRAM,当然也有其他封装的,像 BGA/FBGA这种,这里以 TSOP封装的为例子吧,其它的信息其实都大体相同的。如下图:TSOP-54pin中 8bit data width(左边)和 16bit data width(右边)

    上图两个之间的区别是(非引脚结构层面上)左边的一次操作 8bit(一个字节)的数据,而右边的一次可操作 16bit(双字节)的数据,所以从操作上,右边处理数据比左边的要快一倍;而对于 32bit data width 的 SDRAM芯片,则比前面的处理更快了。

    类型

    类型 预取 数据速率示例 Banks 数量 VDD
    SDRAM 133 MT/s/pin 4 Bank 3.3 V
    DDR SDRAM 2 预取 400 MT/s/pin 4 Bank 2.5 V
    DDR2 SDRAM 4 预取 800 MT/s/pin 4 or 8 Bank 1.8 V (DDR2L 1.5 V)
    DDR3 SDRAM 8 预取 1600 MT/s/pin 8 Bank 1.5 V (DDR3L 1.35 V)

    引脚定义

    对于 SDRAM芯片,无论是多少数据位宽的,它的信号引脚分类都是如下几种:

    引脚 说明
    A[0 : x] 地址输入
    DQ[0 : x] 数据输入 / 输出
    BA[0 : x] Bank选择地址,选择要控制的 Bank
    CLK 同步时钟信号,所有输入信号都在 CLK为上升沿时被采集
    CKE 时钟使能信号,禁止时钟信号时 SDRAM会启动自动刷新操作
    CS# 片选信号,低电平有效
    RAS# 行地址选通,为低电平时地址线输入信号表示为行地址
    CAS# 列地址选通,为低电平时地址线输入信号表示为列地址
    DQM[0 : x] 数据输入 / 输出掩码信号,表示 DQ信号的有效部分

    note:

  • DQM[0 : x]:掩码控制位,在 SDRAM 中每个 DQM 引脚控制 8bit Data。在读操作的时候没多大影响,比如读 32bit 数据位宽的 SDRAM,但只要其中的 8bit 数据,则只须先读出 32bit 数据,再在软件里将其余的 24bit 和 0 作 “与” 操作即可,有没有 DQM 关系不大;但在执行写操作时,如果没有 DQM 就麻烦了,可能在软件上是写一个 8bit 数据,但实际上 32 根数据线是物理上连接到 SDRAM 的,只要 WR 信号一出现,这 32bit 数据就会写 SDRAM 中去,而多余的 24bit 数据将会被覆盖,如果通过使用 DQM 就可以将其对应的 24bit 屏蔽,不会因为写操作而覆盖数据了。对于 16bit 数据位宽的 SDRAM,一般描述为 LDQM 和 UDQM 或者是 DQML 和 DQMH,嘛一般看 datasheet知道对应哪个就行了。

  • BA[0 : x]:BA 信号决定了激活哪一个 Banks,一般 SDRAM多为 4-Bank。BA 信号的多少基本决定了 Banks 的多少,例如,BA[0 : 1] -> 2^2 = 4-Bank。8-Bank可以看下 https://www.micross.com/pdf/MYX4DD3256M16GB_DS_REV-1.pdf 的 datasheet,看 BA 信号有多少个引脚。

  • 内存容量

    IS42S16160J datasheet 中的 16Meg x16为例。

    从右上角的方框中,我们可以直接获取到该芯片内存容量为 256Mb = 16MB(Mb表示 M bit,MB表示 M byte),但往往有些 datasheet并没有直观表示容量,那么可以考虑另一种获取的方法。

    内存容量除了从 datasheet中直接获取,你也可以直接从 16M x 16 或者 4M x 16 x 4 Banks 来直接计算,单位为 bit,这都是可以的;在这里,更推荐从 SDRAM 的 Bank、行地址、列地址及数据地址数量来获取,因为内存容量由存储深度和存储宽度决定,这是任何存储芯片存储容量的定义:

  • Bank:BA[0 : 1] -> 2^2 = 4 Banks
  • Row addr:A[0 : 12] -> 2^13 = 8192 Rows
  • Column addr:A[0 : 8] -> 2^9 = 512 Coulumns
  • 当它是 16bit data width(也有 8bit data width,即 54 pin TSOP – Type II for x8封装芯片,后面实例用到),

    存储深度: IS42S16160J for x16 内部有 4个 Bank,每个 Bank 有行地址 13bit、列地址 9bit;所以每个 Bank 就有 2^13 * 2^9 = 8192 * 512 = 4194304 个存储单元,4个 Bank 就有 4 * 4194304 = 16777216 个存储单元。

    存储宽度: 该 SDRAM 的数据位宽为 16bit。

    存储容量: 16777216 * 16bit = 268435456bit,就是 32MB。

    即:4 * 8192 * 512 * 16 = 2^28 = 256 Mbit = 32MByte

    对此它的计算方法可以归算为:Bank、行地址、列地址及数据地址数量彼此之间的乘积。

    硬件设计

    芯片引脚对应

    FMC引脚 SDRAM引脚 说明
    SDCLK CLK SDRAM 时钟
    SDCKE[1 : 0] CKE SDCKE0:SDRAM 存储区域 1 时钟使能
    SDCKE1:SDRAM 存储区域 2 时钟使能
    SDNE[1 : 0] CS# SDNE0:SDRAM 存储区域 1 芯片使能
    SDNE1:SDRAM 存储区域 2 芯片使能
    A[12 : 0] A[0 : x] 行 / 列地址线
    D[31 : 0] DQ[0 : x] 双向数据总线
    BA[1 : 0] BA[0 : x] Bank地址线
    NRAS RAS# 行地址选通
    NCAS CAS# 列地址选通
    SDNWE 写入使能(当使用两个存储区域时需要)
    NBL[3 : 0] DQM[0 : x] 写访问的输出字节屏蔽

    特殊脚 BA(Bank地址线)

    对于某些芯片来说,可能并没有标出 BA[0 : x] 引脚,对于这种,要么手册上有说明,要么给出引脚连接图,像 NXP LPC某些系列中:

    可以看到并没有标出 BA[0 : x] 引脚,但手册另外有说明:

    在 S3C2440芯片中则给出连接示意图:

    关于数据线交换问题

    能交换的原因来源于其数据访问的特性,并且命令操作不需要涉及到数据信号线,一般是用地址线配合其他控制线来访问(某些特殊的除外),因此地址万万不能交换,而且数据线交换也是有条件的,如下说明。

    通常以最小访问位宽,一般八个起始连续位(一个字节)为一组;组内可交换,但不能跨组交换;整组间可交换,但同时还要交换对应控制脚 DQMx。

    例如: 16位 SDRAM 有 UDQM 和 LDQM 控制高 8位和低 8位掩码。

    对于组内交换,其实也挺简单,就是不管你怎么变的,CPU放进去的是 0xF0 ,读出来的也是 0xF0 就行了,你变了顺序的话,只是 0xF0 这个数在 RAM 中存的形式不同;假设你高四位和低四位换了,CPU写进去时是 0xF0 (11110000b) ,但到了 RAM 存在形式是 00001111 ,而你 CPU 再读取到寄存器后还是 0xF0,这就够了。也就是说负负得正,错错得对,明白了吧,调了线序,写进去数据会错位,但读出来也错一次,所以就没有问题了。。。只是改变了在 RAM中的存在格式。所以 DQ0 ~ DQ7 之间可以任意交换,DQ8 ~ DQ15 之间可以任意交换,但像 D8 和 D0 ~ D7 里的数据线就不能交换(即不能跨组交换)。

    对于整组间交换,即 D0 ~ D7 整组与 D8 ~ D15 整组进行交换,由于最小访问位宽为 8bit,因此当以 8bit 访问读写时是没有任何数据错乱问题的,但当访问 16bit 以上多字节访问时就会出现错误,这是由于 DQMx 掩码的关系,当进行访问的时候,因为只对数据组交换,而 DQMx 掩码没交换,就会出现对端数据访问交换。

    几个重要结构体

    初始化结构体

    /* @brief
     * FMC SDRAM 初始化结构体类型定义
     */
    typedef struct
    {
        uint32_t FMC_Bank;                /* 选择 FMC的 SDRAM存储区域 */
        uint32_t FMC_ColumnBitsNumber;    /* 定义 SDRAM的列地址宽度 */
        uint32_t FMC_RowBitsNumber;       /* 定义 SDRAM的行地址宽度 */
        uint32_t FMC_SDMemoryDataWidth;   /* 定义 SDRAM的数据宽度 */
        uint32_t FMC_InternalBankNumber;  /* 定义 SDRAM内部的 Bank数目 */
        uint32_t FMC_CASLatency;          /*定义 CASLatency的时钟个数 */
        uint32_t FMC_WriteProtection;     /* 定义是否使能写保护模式  */
        uint32_t FMC_SDClockPeriod;       /* 配置同步时钟 SDCLK的参数 */
        uint32_t FMC_ReadBurst;           /* 是否使能突发读模式*/
        uint32_t FMC_ReadPipeDelay;       /* 定义在 CAS个延迟后再等待多少个 HCLK时钟才读取数据 */
    FMC_SDRAMTimingInitTypeDef* FMC_SDRAMTimingStruct; /* 定义 SDRAM的时序参数
    
    } FMC_SDRAMInitTypeDef;
    

    这部分参数,一般从硬件设计及 SDRAM芯片选型中就能确认了,不需要怎么翻看 datasheet,就算需要查看,在首页产品介绍中也能看到。

  • FMC_Bank: FMC映射到 SDRAM 有两个 bank 可以选择;根据外围 SDRAM硬件连接来决定选择。选择不同的 Bank,SDRAM 需要接到 MCU 不同的

    SDNE 以及 SDCKE 引脚,并且访问的地址也不同,如下图所示:


  • FMC_ColumnBitsNumber、FMC_RowBitsNumber、FMC_SDMemoryDataWidth、FMC_InternalBankNumber: 这几项分别对应列地址、行地址、数据位宽、Bank的数量,这里可以从上面内存容量贴的那张图可以了解到,就不再过多阐述了。

  • FMC_CASLatency: 可以设置 Latency1,Latency2 和 Latency3,具体选择哪个,可从下图中选择跟自己设计相匹配的参数,并且这个参数将决定后面时序结构的参考选择

    一般来讲都是选择 Latency3,143MHz,速度等级是 -7。

  • FMC_WriteProtection: 决定是否使用写保护。

  • FMC_SDClockPeriod: 输出到 SDRAM CLK的时钟分频因子配置,同样的这个参数将决定后面时序结构的参考选择。而 FMC 的工作时钟来自 HCLK,如下图;一般来说 F429 的主频可以到 168/180M,那么 HCLK 就是 168/180M,参数可选 2 / 3分频,由于上面 FMC_CASLatency 的配置,SDRAM 支持的最大时钟频率达 143MHz,因此大多数 FMC 时钟分频比选择最小的 2分频,则在主频 180M 时,FMC 频率就是 90M。

  • FMC_ReadBurst、FMC_ReadPipeDelay: 这两个是根据实际读写情况来配置的,前者用于突发读处理,后者定义了在 CAS 延时期间预测延后多少个 SDRAM 时钟周期才读取数据。

  • 时序结构体

    /* @brief
     * 控制SDRAM的时序参数,这些参数的单位都是“周期”
     * 各个参数的值可设置为 1 - 16个 Clock cycles。
     */
    typedef struct
    {
        uint32_t FMC_LoadToActiveDelay;    /* TMRD */
        uint32_t FMC_ExitSelfRefreshDelay; /* TXSR */
        uint32_t FMC_SelfRefreshTime;      /* TRAS */
        uint32_t FMC_RowCycleDelay;        /* TRC */
        uint32_t FMC_WriteRecoveryTime;    /* TWR */
        uint32_t FMC_RPDelay;              /* TRP */
        uint32_t FMC_RCDDelay;             /* TRCD */
    } FMC_SDRAMTimingInitTypeDef;
    

    这部分的配置参数跟 datasheet 息息相关,并且在 STM32F4中,官方把这几个参数统一存放到如下的一个寄存器中:

    那么这几个参数到底从何而来呢?继续使用 IS42S16160J 的 datasheet,然后逐个分析,首先得获取信息的所在位置,如下图:

    第一张图,是该芯片的电气特性参数,第二张是基于第一张给出的参考配置数据(看绿框中的描述),也就是说,你可以直接用现成的第二张的数据填到属性配置中,但是,话都撂这儿了,不解释一下好像有点不好意思。。

    FMC_SDRAMTimingInitTypeDef 时序结构体中,里面的参数都是以 cycle 为单位

  • FMC_LoadToActiveDelay: 对应 tMRD(TMRD)参数;TMRD 定义模式寄存器设置命令或刷新命令所需时间。
  • FMC_ExitSelfRefreshDelay: 对应 tXSR(TXSR)参数;TXSR 定义从退出自刷新命令到发出活动命令之间的时间。
  • FMC_SelfRefreshTime: 对应 tRAS(TRAS)参数;TRAS 定义从活动命令到预充电命令所需时间。
  • FMC_RowCycleDelay: 对应 tRC(TRC)参数;TRC 定义刷新命令之间或者活动命令之间的时间。
  • FMC_WriteRecoveryTime: 对应 tDAL(TWR)参数;在 SDRAM手册上并没有 TWR 这样的标识,但是根据定义的涵义,表明:从输入数据到活动命令或者刷新命令所需的时间。因此能从 datasheet 中找到相应的 tDAL 参数;这也就说明了,有时候软件配置参数中并没有清楚写出 tMRD,tRAS 等字样,而是需要自己去了解每个配置参数的意义,才能从 SDRAM 的手册中找到对应的参数填充。
  • FMC_RPDelay: 对应 tRP(TRP)参数;TRP 定义从预充电命令到活动命令所需时间,刚好跟 tRAS 相反。
  • FMC_RCDDelay: 对应 tRP(TRP)参数;TRP 定义从活动命令到读 /写命令所需时间。
  • 好了,解释完参数后,就来计算一下怎么把时间参数转换成所需的周期参数配置吧。至于你说为什么不像前面说的那样直接用第二张给出的书呢?一是,细心的可能会发现并没有给出 tXSR;二是选取不同的设计参数,将导致不一样的周期参数配置,还记得上面初始化结构体说的 FMC_CASLatencyFMC_SDClockPeriod 将决定时序周期数吧。

    怎么算?其实很简单:

    这里以 HCLK 为 168MHz 为例,FMC_SDClockPeriod = FMC_SDClock_Period_2 即对 HCLK 进行二分频,得到输出给 SDRAM CLK 的频率为 84MHz;而 FMC_CASLatency = FMC_CAS_Latency_3,对应 datasheet 选为常见的 Latency3143MHz,速度等级是 -7(这里的 143MHz 为 SDRAM 最大支持频率,但实际我们就只用到了 84MHz)。然后以其中的一个时序配置参数 tRC 为例:

    从上图可以看到,在 -7 等级中,tRC 的时间参数只有最小值是值得关注的,对于 配置的 FMC 驱动频率 84MHz,则一个 SDRAM 周期时间约为 11.90ns(即结构体参数的单位都是 11.90ns),那么在 datasheet 中限定 tRC > 60ns,要使得满足条件,只有 FMC_RowCycleDelay >= 6 时方可满足,因此我们只需取其最靠近的值即可,这样就能在满足条件的情况下也不会丢失时间性能(当然是在稳定的前提下),其余的值计算等同,就不再阐述了,自己验算。最终得到的数据,看下面的代码示例吧。

    示例代码

    驱动 IS42S16160J for x8(4-Bank & 8bit data width & 9bit column addr & 13bit row addr)

    API 版本:

    /* Private defines -----------------------------------------------------------*/
    #define SDRAM_BANK_ADDR                 ((uint32_t)0xC0000000)
    
    #define SDRAM_MEMORY_WIDTH            FMC_SDMemory_Width_8b
    /* #define SDRAM_MEMORY_WIDTH            FMC_SDMemory_Width_16b */
    /* #define SDRAM_MEMORY_WIDTH            FMC_SDMemory_Width_32b */ 
    
    /* #define SDRAM_CAS_LATENCY             FMC_CAS_Latency_1 */
    /* #define SDRAM_CAS_LATENCY             FMC_CAS_Latency_2 */
    #define SDRAM_CAS_LATENCY             FMC_CAS_Latency_3
    
    #define SDCLOCK_PERIOD                FMC_SDClock_Period_2
    /* #define SDCLOCK_PERIOD                FMC_SDClock_Period_3 */
    
    #define SDRAM_TIMEOUT     ((uint32_t)0xFFFF) 
    
    #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) 
    
    /**
      * @brief  FMC SDRAM Configuration
      * @param  None
      * @retval None
      */
    static void FMC_Config(void)
    {  
      GPIO_InitTypeDef            GPIO_InitStructure;
      FMC_SDRAMInitTypeDef        FMC_SDRAMInitStructure;
      FMC_SDRAMTimingInitTypeDef  FMC_SDRAMTimingInitStructure;
      FMC_SDRAMCommandTypeDef     FMC_SDRAMCommandStructure;
      
      uint32_t tmpr = 0;
      uint32_t timeout = SDRAM_TIMEOUT;
    
      /* GPIO configuration ------------------------------------------------------*/ 
      /* Enable GPIOs clock */
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE | 
                             RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOH | 
                             RCC_AHB1Periph_GPIOI, ENABLE);
                             
      /* Common GPIO configuration */
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
      
      /* GPIOD configuration */
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC);
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0  |GPIO_Pin_1  |GPIO_Pin_8 |GPIO_Pin_9 |
                                    GPIO_Pin_10 |GPIO_Pin_14 |GPIO_Pin_15;
    
      GPIO_Init(GPIOD, &GPIO_InitStructure);
    
      /* GPIOE configuration */
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource0 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource1 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource7 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource8 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource9 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource10 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource11 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource12 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource13 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource14 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOE, GPIO_PinSource15 , GPIO_AF_FMC);
    
      GPIO_InitStructure.GPIO_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;
    
      GPIO_Init(GPIOE, &GPIO_InitStructure);
    
      /* GPIOF configuration */
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource0 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource1 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource2 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource3 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource4 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource5 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource11 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource12 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource13 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource14 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOF, GPIO_PinSource15 , GPIO_AF_FMC);
    
      GPIO_InitStructure.GPIO_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;      
    
      GPIO_Init(GPIOF, &GPIO_InitStructure);
    
      /* GPIOG configuration */
      GPIO_PinAFConfig(GPIOG, GPIO_PinSource0 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOG, GPIO_PinSource1 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOG, GPIO_PinSource4 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOG, GPIO_PinSource5 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOG, GPIO_PinSource8 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOG, GPIO_PinSource15 , GPIO_AF_FMC);
      
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1 |GPIO_Pin_4 |GPIO_Pin_5 |
                                    GPIO_Pin_8 | GPIO_Pin_15;
    
      GPIO_Init(GPIOG, &GPIO_InitStructure);
       
      /* GPIOH configuration */
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource2 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource3 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource5 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource8 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource9 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource10 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource11 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource12 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource13 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource14 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOH, GPIO_PinSource15 , GPIO_AF_FMC);
      
    
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2  | GPIO_Pin_3  | 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;      
    
      GPIO_Init(GPIOH, &GPIO_InitStructure);
    
      /* GPIOI configuration */
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource0 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource1 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource2 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource3 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource4 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource5 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource6 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource7 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource9 , GPIO_AF_FMC);
      GPIO_PinAFConfig(GPIOI, GPIO_PinSource10 , GPIO_AF_FMC);
    
      GPIO_InitStructure.GPIO_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; 
      
      GPIO_Init(GPIOI, &GPIO_InitStructure);
          
      /* Enable FMC clock */
      RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
      
      /* FMC SDRAM device initialization sequence --------------------------------*/ 
      /* Step 1 ----------------------------------------------------*/ 
      /* Timing configuration for 84 Mhz of SD clock frequency (168Mhz/2) */
      /* TMRD: min=14ns (2x11.90ns) */
      FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay    = 2;      
      /* TXSR: min=70ns (6x11.90ns) */
      FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 6;
      /* TRAS: min=42ns max=100Kns (4x11.90ns) */
      FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime      = 4;
      /* TRC:  min=60ns (6x11.90ns) */        
      FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay        = 6;         
      /* TWR:  min=30ns (2x11.90ns) */
      FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime    = 2;      
      /* TRP:  min=15ns (2x11.90ns) */
      FMC_SDRAMTimingInitStructure.FMC_RPDelay              = 2;                
      /* TRCD: min=315ns (2x11.90ns) */
      FMC_SDRAMTimingInitStructure.FMC_RCDDelay             = 2;
      
      /* Step 2 ----------------------------------------------------*/
      /* FMC SDRAM control configuration */
      FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank1_SDRAM;
      
      /* Row addressing: [8:0] */
      FMC_SDRAMInitStructure.FMC_ColumnBitsNumber   = FMC_ColumnBits_Number_9b;
      /* Column addressing: [12:0] */
      FMC_SDRAMInitStructure.FMC_RowBitsNumber      = FMC_RowBits_Number_13b;
      FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth  = SDRAM_MEMORY_WIDTH;
      FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
      /* CL: Cas Latency = 3 clock cycles */
      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          = FMC_Read_Burst_Disable;
      FMC_SDRAMInitStructure.FMC_ReadPipeDelay      = FMC_ReadPipe_Delay_0;
      FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct  = &FMC_SDRAMTimingInitStructure;
      /* FMC SDRAM bank initialization */
      FMC_SDRAMInit(&FMC_SDRAMInitStructure);
      
    /* Step 3 --------------------------------------------------------------------*/
      /* Configure a clock configuration enable command */
      FMC_SDRAMCommandStructure.FMC_CommandMode            = FMC_Command_Mode_CLK_Enabled;
      FMC_SDRAMCommandStructure.FMC_CommandTarget          = FMC_Command_Target_bank1;
      FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 1;
      FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
      /* Wait until the SDRAM controller is ready */ 
      while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
      {
        timeout--;
      }
      /* 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_bank1;
      FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 1;
      FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
      
      /* Wait until the SDRAM controller is ready */  
      timeout = SDRAM_TIMEOUT; 
      while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
      {
        timeout--;
      }
      /* 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_bank1;
      FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 8;
      FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = 0;
      
      /* Wait until the SDRAM controller is ready */ 
      timeout = SDRAM_TIMEOUT; 
      while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
      {
        timeout--;
      }
      /* Send the command */
      FMC_SDRAMCmdConfig(&FMC_SDRAMCommandStructure);
      
    /* Step 7 --------------------------------------------------------------------*/
      /* Program the external memory mode register */
      tmpr = (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;
      
      /* Configure a load Mode register command*/ 
      FMC_SDRAMCommandStructure.FMC_CommandMode            = FMC_Command_Mode_LoadMode;
      FMC_SDRAMCommandStructure.FMC_CommandTarget          = FMC_Command_Target_bank1;
      FMC_SDRAMCommandStructure.FMC_AutoRefreshNumber      = 1;
      FMC_SDRAMCommandStructure.FMC_ModeRegisterDefinition = tmpr;
      
      /* Wait until the SDRAM controller is ready */ 
      timeout = SDRAM_TIMEOUT; 
      while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
      {
        timeout--;
      }
      /* 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(636);
      
      /* Wait until the SDRAM controller is ready */ 
      timeout = SDRAM_TIMEOUT; 
      while((FMC_GetFlagStatus(FMC_Bank1_SDRAM, FMC_FLAG_Busy) != RESET) && (timeout > 0))
      {
        timeout--;
      } 
    }
    
    

    Register 版本:

    /**
      * @brief  Setup the external memory controller.
      *         Called in startup_stm32f4xx.s before jump to main.
      *         This function configures the external SDRAM mounted on STM324x9I_EVAL board
      *         This SDRAM will be used as program data memory (including heap and stack).
      * @param  None
      * @retval None
      */
    void SystemInit_ExtMemCtl(void)
    {
      __IO uint32_t tmp = 0x00;
      register uint32_t tmpreg = 0, timeout = 0xFFFF;
      register __IO uint32_t index;
    
    /*-- GPIOs Configuration -----------------------------------------------------*/
    /*
     +-------------------+--------------------+------------------+--------------+
     +                       SDRAM pins assignment                               +
     +-------------------+--------------------+------------------+--------------+
     | PC0  <-> FMC_SDNWE  | PD0  <-> FMC_D2  | PE0  <-> FMC_NBL0 | PF0  <-> FMC_A0     | PG0  <-> FMC_A10    | 
     | PC2  <-> FMC_SDNE0  | PD1  <-> FMC_D3  | PE1  <-> FMC_NBL1 | PF1  <-> FMC_A1     | PG1  <-> FMC_A11    | 
     | PC3  <-> FMC_SDCKE0 | PD8  <-> FMC_D13 | PE7  <-> FMC_D4   | PF2  <-> FMC_A2     | PG2  <-> FMC_A12    | 
     |                     | PD9  <-> FMC_D14 | PE8  <-> FMC_D5   | PF3  <-> FMC_A3     | PG4  <-> FMC_BA0    | 
     |                     | PD10 <-> FMC_D15 | PE9  <-> FMC_D6   | PF4  <-> FMC_A4     | PG5  <-> FMC_BA1    | 
     |                     | PD14 <-> FMC_D0  | PE10 <-> FMC_D7   | PF5  <-> FMC_A5     | PG8  <-> FMC_SDCLK  | 
     |                     | PD15 <-> FMC_D1  | PE11 <-> FMC_D8   | PF11 <-> FMC_SDNRAS | PG15 <-> FMC_SDNCAS | 
     |                     |                  | PE12 <-> FMC_D9   | PF12 <-> FMC_A6     |---------------------+
     |                     |                  | PE13 <-> FMC_D10  | PF13 <-> FMC_A7     |
     |                     |                  | PE14 <-> FMC_D11  | PF14 <-> FMC_A8     | 
     |                     |                  | PE15 <-> FMC_D12  | PF15 <-> FMC_A9     | 
     +---------------------+------------------+-------------------+---------------------+
    */
    
    #if defined(STM32F446xx)
      /* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface
          clock */
      RCC->AHB1ENR |= 0x0000007D;
    #else
      /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface 
          clock */
      RCC->AHB1ENR |= 0x000001FC;
    #endif /* STM32F446xx */  
      /* Delay after an RCC peripheral clock enabling */
      tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
      
    #if defined(STM32F446xx)
      /* Connect PAx pins to FMC Alternate function */
      GPIOA->AFR[0]  |= 0xC0000000;
      GPIOA->AFR[1]  |= 0x00000000;
      /* Configure PDx pins in Alternate function mode */
      GPIOA->MODER   |= 0x00008000;
      /* Configure PDx pins speed to 50 MHz */
      GPIOA->OSPEEDR |= 0x00008000;
      /* Configure PDx pins Output type to push-pull */
      GPIOA->OTYPER  |= 0x00000000;
      /* No pull-up, pull-down for PDx pins */
      GPIOA->PUPDR   |= 0x00000000;
    
      /* Connect PCx pins to FMC Alternate function */
      GPIOC->AFR[0]  |= 0x00CC0000;
      GPIOC->AFR[1]  |= 0x00000000;
      /* Configure PDx pins in Alternate function mode */
      GPIOC->MODER   |= 0x00000A00;
      /* Configure PDx pins speed to 50 MHz */
      GPIOC->OSPEEDR |= 0x00000A00;
      /* Configure PDx pins Output type to push-pull */
      GPIOC->OTYPER  |= 0x00000000;
      /* No pull-up, pull-down for PDx pins */
      GPIOC->PUPDR   |= 0x00000000;
    #else  
      /* Connect PCx pins to FMC Alternate function */
      GPIOC->AFR[0]  = 0x0000CC0C;
      GPIOC->AFR[1]  = 0x00000000;
      /* Configure PCx pins in Alternate function mode */  
      GPIOC->MODER   = 0x000000A2;
      /* Configure PCx pins speed to 50 MHz */  
      GPIOC->OSPEEDR = 0x000000A2;
      /* Configure PCx pins Output type to push-pull */  
      GPIOC->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PCx pins */ 
      GPIOC->PUPDR   = 0x00000000;
    #endif /* STM32F446xx */
    
      /* Connect PDx pins to FMC Alternate function */
      GPIOD->AFR[0]  = 0x000000CC;
      GPIOD->AFR[1]  = 0xCC000CCC;
      /* Configure PDx pins in Alternate function mode */  
      GPIOD->MODER   = 0xA02A000A;
      /* Configure PDx pins speed to 50 MHz */  
      GPIOD->OSPEEDR = 0xA02A000A;
      /* Configure PDx pins Output type to push-pull */  
      GPIOD->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PDx pins */ 
      GPIOD->PUPDR   = 0x00000000;
    
      /* Connect PEx pins to FMC Alternate function */
      GPIOE->AFR[0]  = 0xC00000CC;
      GPIOE->AFR[1]  = 0xCCCCCCCC;
      /* Configure PEx pins in Alternate function mode */ 
      GPIOE->MODER   = 0xAAAA800A;
      /* Configure PEx pins speed to 50 MHz */ 
      GPIOE->OSPEEDR = 0xAAAA800A;
      /* Configure PEx pins Output type to push-pull */  
      GPIOE->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PEx pins */ 
      GPIOE->PUPDR   = 0x00000000;
    
      /* Connect PFx pins to FMC Alternate function */
      GPIOF->AFR[0]  = 0x00CCCCCC;
      GPIOF->AFR[1]  = 0xCCCCC000;
      /* Configure PFx pins in Alternate function mode */   
      GPIOF->MODER   = 0xAA800AAA;
      /* Configure PFx pins speed to 50 MHz */ 
      GPIOF->OSPEEDR = 0xAA800AAA;
      /* Configure PFx pins Output type to push-pull */  
      GPIOF->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PFx pins */ 
      GPIOF->PUPDR   = 0x00000000;
    
      /* Connect PGx pins to FMC Alternate function */
      GPIOG->AFR[0]  = 0xCCCCCCCC;
      GPIOG->AFR[1]  = 0xCCCCCCCC;
      /* Configure PGx pins in Alternate function mode */ 
      GPIOG->MODER   = 0xAAAAAAAA;
      /* Configure PGx pins speed to 50 MHz */ 
      GPIOG->OSPEEDR = 0xAAAAAAAA;
      /* Configure PGx pins Output type to push-pull */  
      GPIOG->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PGx pins */ 
      GPIOG->PUPDR   = 0x00000000;
    
    #if defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F469_479xx)
      /* Connect PHx pins to FMC Alternate function */
      GPIOH->AFR[0]  = 0x00C0CC00;
      GPIOH->AFR[1]  = 0xCCCCCCCC;
      /* Configure PHx pins in Alternate function mode */ 
      GPIOH->MODER   = 0xAAAA08A0;
      /* Configure PHx pins speed to 50 MHz */ 
      GPIOH->OSPEEDR = 0xAAAA08A0;
      /* Configure PHx pins Output type to push-pull */  
      GPIOH->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PHx pins */ 
      GPIOH->PUPDR   = 0x00000000;
      
      /* Connect PIx pins to FMC Alternate function */
      GPIOI->AFR[0]  = 0xCCCCCCCC;
      GPIOI->AFR[1]  = 0x00000CC0;
      /* Configure PIx pins in Alternate function mode */ 
      GPIOI->MODER   = 0x0028AAAA;
      /* Configure PIx pins speed to 50 MHz */ 
      GPIOI->OSPEEDR = 0x0028AAAA;
      /* Configure PIx pins Output type to push-pull */  
      GPIOI->OTYPER  = 0x00000000;
      /* No pull-up, pull-down for PIx pins */ 
      GPIOI->PUPDR   = 0x00000000;
    #endif /* STM32F427_437xx || STM32F429_439xx || STM32F469_479xx */
      
    /*-- FMC Configuration ------------------------------------------------------*/
      /* Enable the FMC interface clock */
      RCC->AHB3ENR |= 0x00000001;
      /* Delay after an RCC peripheral clock enabling */
      tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
    
      /* Configure and enable SDRAM bank1 */
    #if defined(STM32F446xx)
      FMC_Bank5_6->SDCR[0] = 0x00001954;
    #else  
      FMC_Bank5_6->SDCR[0] = 0x000009C9;
    #endif /* STM32F446xx */
      FMC_Bank5_6->SDTR[0] = 0x01115351;      
      
      /* SDRAM initialization sequence */
    #if 1
      /* Clock enable command */
      FMC_Bank5_6->SDCMR = 0x00000011; 
      tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
      while((tmpreg != 0) && (timeout-- > 0))
      {
        tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
      }
    
      /* Delay */
      for (index = 0; index<1000; index++);
      
      /* PALL command */
      FMC_Bank5_6->SDCMR = 0x00000012;           
      tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
      timeout = 0xFFFF;
      while((tmpreg != 0) && (timeout-- > 0))
      {
        tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
      }
      
      /* Auto refresh command */
    #if defined(STM32F446xx)
      FMC_Bank5_6->SDCMR = 0x000000F3;
    #else  
      FMC_Bank5_6->SDCMR = 0x00000073;
    #endif /* STM32F446xx */
      tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
      timeout = 0xFFFF;
      while((tmpreg != 0) && (timeout-- > 0))
      {
        tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
      }
     
      /* MRD register program */
    #if defined(STM32F446xx)
      FMC_Bank5_6->SDCMR = 0x00044014;
    #else  
      FMC_Bank5_6->SDCMR = 0x00046014;
    #endif /* STM32F446xx */
      tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
      timeout = 0xFFFF;
      while((tmpreg != 0) && (timeout-- > 0))
      {
        tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
      } 
      
      /* Set refresh count */
      tmpreg = FMC_Bank5_6->SDRTR;
    #if defined(STM32F446xx)
      FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1));
    #else    
      FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
    #endif /* STM32F446xx */
      
      /* Disable write protection */
      tmpreg = FMC_Bank5_6->SDCR[0]; 
      FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
    
      tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
      timeout = 0xFFFF;
      while((tmpreg != 0) && (timeout-- > 0))
      {
        tmpreg = FMC_Bank5_6->SDSR & 0x00000020; 
      } 
    #endif
      (void)(tmp); 
      
    /*
      Bank1_SDRAM is configured as follow:
    
      FMC_SDRAMTimingInitStructure.FMC_LoadToActiveDelay = 2;      
      FMC_SDRAMTimingInitStructure.FMC_ExitSelfRefreshDelay = 6;  
      FMC_SDRAMTimingInitStructure.FMC_SelfRefreshTime = 4;        
      FMC_SDRAMTimingInitStructure.FMC_RowCycleDelay = 6;         
      FMC_SDRAMTimingInitStructure.FMC_WriteRecoveryTime = 2;      
      FMC_SDRAMTimingInitStructure.FMC_RPDelay = 2;                
      FMC_SDRAMTimingInitStructure.FMC_RCDDelay = 2;               
    
      FMC_SDRAMInitStructure.FMC_Bank = FMC_Bank1_SDRAM;
      FMC_SDRAMInitStructure.FMC_ColumnBitsNumber = FMC_ColumnBits_Number_9b;
      FMC_SDRAMInitStructure.FMC_RowBitsNumber = FMC_RowBits_Number_13b;
      FMC_SDRAMInitStructure.FMC_SDMemoryDataWidth = FMC_SDMemory_Width_8b;
      FMC_SDRAMInitStructure.FMC_InternalBankNumber = FMC_InternalBank_Number_4;
      FMC_SDRAMInitStructure.FMC_CASLatency = FMC_CAS_Latency_3; 
      FMC_SDRAMInitStructure.FMC_WriteProtection = FMC_Write_Protection_Disable;
      FMC_SDRAMInitStructure.FMC_SDClockPeriod = FMC_SDClock_Period_2;
      FMC_SDRAMInitStructure.FMC_ReadBurst = FMC_Read_Burst_disable;
      FMC_SDRAMInitStructure.FMC_ReadPipeDelay = FMC_ReadPipe_Delay_1;
      FMC_SDRAMInitStructure.FMC_SDRAMTimingStruct = &FMC_SDRAMTimingInitStructure;
    */
      
    }
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32笔记之 SDRAM

    发表评论