• STM32笔记之 SDRAM


    写在前面:

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


    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
    SDRAM133 MT/s/pin4 Bank3.3 V
    DDR SDRAM2 预取400 MT/s/pin4 Bank2.5 V
    DDR2 SDRAM4 预取800 MT/s/pin4 or 8 Bank1.8 V (DDR2L 1.5 V)
    DDR3 SDRAM8 预取1600 MT/s/pin8 Bank1.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引脚说明
    SDCLKCLKSDRAM 时钟
    SDCKE[1 : 0]CKESDCKE0: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地址线
    NRASRAS#行地址选通
    NCASCAS#列地址选通
    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这部分参数,一般从硬件设计及 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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这部分的配置参数跟 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--;
      } 
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287

    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;
    */
      
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
  • 相关阅读:
    基于SQL语言实现机器学习以及深度学习
    京东数据平台:2023年京东营养保健品市场销售数据分析
    分享券商量化交易接口申请流程
    (附源码)计算机毕业设计SSM建筑工地环保监控系统研究
    数据结构篇:链表和树结构的操作方法
    钟珊珊:被爆锤后的工程师会起飞|OneFlow U
    >>数据管理:读书笔记|第一章 数据管理
    重磅!!!监控分布式NVIDIA-GPU状态
    excel vba 制作 kml 文档时,如何写入有引号的字符串
    二、MyBatis-Plus 主键策略
  • 原文地址:https://blog.csdn.net/qq_42992084/article/details/127822767