本章参考资料:《 STM32F4xx 参考手册 2》、《 STM32F4xx 规格书》、库帮助文档
《 stm32f4xx_dsp_stdperiph_lib_um.chm》。
关于 SDRAM 存储器,请参考前面的“ 常用存储器介绍”章节,实验中 SDRAM 芯片
的具体参数,请参考其规格书《 IS42-45S16400J》 来了解。
SDRAM 控制原理
STM32 控制器芯片内部有一定大小的 SRAM 及 FLASH 作为内存和程序存储空间,但
当程序较大,内存和程序空间不足时,就需要在 STM32 芯片的外部扩展存储器了。
STM32F429 系列芯片扩展内存时可以选择 SRAM 和 SDRAM,由于 SDRAM 的“容量
/价格”比较高,即使用 SDRAM 要比 SRAM 要划算得多。我们以 SDRAM 为例讲解如何
为 STM32 扩展内存。
给 STM32 芯片扩展内存与给 PC 扩展内存的原理是一样的,只是 PC 上一般以内存条
的形式扩展,内存条实质是由多个内存颗粒(即 SDRAM 芯片)组成的通用标准模块,而
STM32 直接与 SDRAM 芯片连接。见图 26-2,这是一种型号为 IS42-45S16400J 的 SDRAM
芯片内部结构框图,以它为模型进行学习。
控制逻辑
SDRAM 内部的“控制逻辑”指挥着整个系统的运行,外部可通过 CS、 WE、 CAS、
RAS 以及地址线来向控制逻辑输入命令,命令经过“命令器译码器”译码,并将控制参数
保存到“模式寄存器中”,控制逻辑依此运行。
地址控制
SDRAM 包含有“ A”以及“ BA”两类地址线, A 类地址线是行(Row)与列(Column)共
用的地址总线, BA 地址线是独立的用于指定 SDRAM 内部存储阵列号(Bank)。在命令模式
下, A 类地址线还用于某些命令输入参数。
SDRAM 内部包含的存储阵列,可以把它理解成一张表格,数据就填在这张表格上。
和表格查找一样,指定一个行地址和列地址,就可以精确地找到目标单元格,这是
SDRAM 芯片寻址的基本原理。这样的每个单元格被称为存储单元,而这样的表则被称为
存储阵列(Bank),目前设计的 SDRAM 芯片基本上内部都包含有 4 个这样的 Bank,寻址时
指定 Bank 号以及行地址,然后再指定列地址即可寻找到目标存储单元。 SDRAM 内部具有
多个 Bank 时的结构见图 26-4。
SDRAM 芯片向外部提供有独立的 BA 类地址线用于 Bank 寻址,而行与列则共用 A 类
地址线。
图 26-2 标号4中表示的就是它内部的存储阵列结构, 通讯时当 RAS 线为低电平, 则
“行地址选通器”被选通,地址线 A[11:0]表示的地址会被输入到“行地址译码及锁存器”
中,作为存储阵列中选定的行地址,同时地址线 BA[1:0]表示的 Bank 也被锁存,选中了要
操作的 Bank 号;接着控制 CAS 线为低电平,“列地址选通器”被选通,地址线 A[11:0]表
示的地址会被锁存到“列地址译码器”中作为列地址,完成寻址过程。
数据输入输出
若是写 SDRAM 内容,寻址完成后, DQ[15:0]线表示的数据经过图 26-2 标号5中的输
入数据寄存器,然后传输到存储器阵列中,数据被保存;数据输出过程相反。
本型号的 SDRAM 存储阵列的“数据宽度”是 16 位(即数据线的数量),在与 SDRAM
进行数据通讯时, 16 位的数据是同步传输的,但实际应用中我们可能会以 8 位、 16 位的宽
度存取数据,也就是说 16 位的数据线并不是所有时候都同时使用的,而且在传输低宽度数
据的时候,我们不希望其它数据线表示的数据被录入。如传输 8 位数据的时候,我们只需
要 DQ[7:0]表示的数据,而 DQ[15:8]数据线表示的数据必须忽略,否则会修改非目标存储
空间的内容。所以数据输入输出时,还会使用 DQM[1:0]线来配合,每根 DQM 线对应 8 位 数据,如“ DQM0(LDQM)”为低电平, “ DQM1(HDQM)” 为高电平时,数据线 DQ[7:0]
表示的数据有效, 而 DQ[15:8]表示的数据无效。
1. 命令禁止
只要 CS 引脚为高电平,即表示“命令禁止” (COMMAND INHBIT),它用于禁止
SDRAM 执行新的命令,但它不能停止当前正在执行的命令。
2. 空操作
“ 空操作” (NO OPERATION), “命令禁止”的反操作, 用于选中 SDRAM,以便接
下来发送命令。
3. 行有效
进行存储单元寻址时,需要先选中要访问的 Bank 和行,使它处于激活状态。该操作
通过“行有效” (ACTIVE)命令实现,见图 26-5,发送行有效命令时, RAS 线为低电平,
同时通过 BA 线以及 A 线发送 Bank 地址和行地址。
4. 列读写
行地址通过“行有效”命令确定后,就要对列地址进行寻址了。“读命令” (READ)和
“写命令” (WRITE)的时序很相似,见图 26-6,通过共用的地址线 A 发送列地址,同时使
用 WE 引脚表示读/写方向, WE 为低电平时表示写,高电平时表示读。数据读写时,使用
DQM 线表示有效的 DQ 数据线。
本型号的 SDRAM 芯片表示列地址时仅使用 A[7:0]线,而 A10 线用于控制是否“自动预充电”,该线为高电平时使能,低电平时关闭。
预充电
SDRAM 的寻址具有独占性,所以在进行完读写操作后,如果要对同一个 Bank 的另
一行进行寻址,就要将原来有效( ACTIVE)的行关闭,重新发送行/列地址。 Bank 关闭当
前工作行,准备打开新行的操作就是预充电( Precharge)。
预充电可以通过独立的命令控制,也可以在每次发送读写命令的同时使用“ A10”线
控制自动进行预充电。实际上,预充电是一种对工作行中所有存储阵列进行数据重写,并
对行地址进行复位,以准备新行的工作。
独立的预充电命令时序见图 26-7。该命令配合使用 A10 线控制,若 A10 为高电平时,
所有 Bank 都预充电; A10 为低电平时,使用 BA 线选择要预充电的 Bank。
6.刷新
SDRAM 要不断进行刷新(Refresh)才能保留住数据,因此它是 DRAM 最重要的操作。
刷新操作与预充电中重写的操作本质是一样的。
但因为预充电是对一个或所有 Bank 中的工作行操作,并且不定期,而刷新则是有固
定的周期,依次对所有行进行操作,以保证那些久久没被访问的存储单元数据正确。
刷新操作分为两种:“自动刷新”( Auto Refresh)与“自我刷新” (Self Refresh),发
送命令后 CKE 时钟为有效时(低电平),使用自动刷新操作,否则使用自我刷新操作。不论
是何种刷新方式,都不需要外部提供行地址信息,因为这是一个内部的自动操作。
对于“自动刷新”, SDRAM 内部有一个行地址生成器(也称刷新计数器)用来自动
地依次生成行地址,每收到一次命令刷新一行。 在刷新过程中,所有 Bank 都停止工作,
而每次刷新所占用的时间为 N 个时钟周期(视 SDRAM 型号而定,通常为 N=9), 刷新结束
之后才可进入正常的工作状态,也就是说在这 N 个时钟期间内,所有工作指令只能等待而
无法执行。一次次地按行刷新,刷新完所有行后,将再次对第一行重新进行刷新操作,这
个对同一行刷新操作的时间间隔,称为 SDRAM 的刷新周期,通常为 64ms。 显然刷新会对
SDRAM 的性能造成影响, 但这是它的 DRAM 的特性决定的, 也是 DRAM 相对于 SRAM
取得成本优势的同时所付出的代价。
“自我刷新”则主要用于休眠模式低功耗状态下的数据保存,也就是说即使外部控制
器不工作了, SDRAM 都能自己确保数据正常。在发出“自我刷新”命令后,将 CKE 置于
无效状态(低电平),就进入自我刷新模式,此时不再依靠外部时钟工作,而是根据 SDRAM
内部的时钟进行刷新操作。在自我刷新期间除了 CKE 之外的所有外部信号都是无效的,只
有重新使 CKE 有效才能退出自我刷新模式并进入正常操作状态。
7. 加载模式寄存器
前面提到 SDRAM 的控制逻辑是根据它的模式寄存器来管理整个系统的,而这个寄存
器的参数就是通过“加载模式寄存器”命令(LOAD MODE REGISTER)来配置的。发送该
命令时,使用地址线表示要存入模式寄存器的参数“ OP-Code”,各个地址线表示的参数
见图 26-8。
SDRAM 的初始化流程
最后我们来了解 SDRAM 的初始化流程。 SDRAM 并不是上电后立即就可以开始读写
数据的,它需要按步骤进行初始化,对存储矩阵进行预充电、刷新并设置模式寄存器,见
图 26-10。
该流程说明如下:
(1) 给 SDRAM 上电,并提供稳定的时钟,至少 100us;
(2) 发送“空操作” (NOP)命令;
(3) 发送“预充电” (PRECHARGE)命令,控制所有 Bank 进行预充电,并等待 tRP 时间,
tRP 表示预充电与其它命令之间的延迟;
(4) 发送至少 2 个“自动刷新” (AUTO REFRESH)命令,每个命令后需等待 tRFC 时间, tRFC
表示自动刷新时间;
(5) 发送“加载模式寄存器” (LOAD MODE REGISTER)命令,配置 SDRAM 的工作参数,
并等待 tMRD 时间, tMRD 表示加载模式寄存器命令与行有行或刷新命令之间的延迟;
(6) 初始化流程完毕,可以开始读写数据。
其中 tRP、 tRFC、 tMRD 等时间参数跟具体的 SDRAM 有关,可查阅其数据手册获知,STM32 FMC 访问时配置需要这些参数。
SDRAM 的读写流程
初始化步骤完成,开始读写数据,其时序流程见图 26-11 及图 26-12。
(1) 发送“行有效” (ACTIVE)命令,发送命令的同时包含行地址和 Bank 地址,然后
等待 tRCD 时间, tRCD 表示行有效命令与读/写命令之间的延迟;
(2) 发送“读/写” (READ/WRITE)命令,在发送命令的同时发送列地址,完成寻址的
地址输入。对于读命令,根据模式寄存器的 CL 定义,延迟 CL 个时钟周期后,
SDRAM 的数据线 DQ 才输出有效数据,而写命令是没有 CL 延迟的,主机在发送
写命令的同时就可以把要写入的数据用 DQ 输入到 SDRAM 中,这是读命令与写
命令的时序最主要的区别。图中的读/写命令都通过地址线 A10 控制自动预充电,
而 SDRAM 接收到带预充电要求的读/写命令后,并不会立即预充电,而是等待
tWR 时间才开始, tWR 表示写命令与预充电之间的延迟;
(3) 执行“预充电” (auto precharge)命令后,需要等待 tRP时间, tRP 表示预充电与其它
命令之间的延迟;
(4) 图中的标号处的 tRAS,表示自刷新周期,即在前一个“行有效”与 “预充电”
命令之间的时间;
(5) 发送第二次“行有效” (ACTIVE)命令准备读写下一个数据,在图中的标号处的
tRC,表示两个行有效命令或两个刷新命令之间的延迟。
其中 tRCD、 tWR、 tRP、 tRAS 以及 tRC 等时间参数跟具体的 SDRAM 有关,可查阅其数据
手册获知, STM32 FMC 访问时配置需要这些参数。
FMC 简介
STM32F429 使用 FMC 外设来管理扩展的存储器, FMC 是 Flexible Memory Controller
的缩写,译为可变存储控制器。它可以用于驱动包括 SRAM、 SDRAM、 NOR FLASH 以及
NAND FLSAH 类型的存储器。在其它系列的 STM32 控制器中,只有 FSMC 控制器
(Flexible Static Memory Controller),译为可变静态存储控制器,所以它们不能驱动 SDRAM
这样的动态存储器,因为驱动 SDRAM 时需要定时刷新, STM32F429 的 FMC 外设才支持
该功能,且只支持普通的 SDRAM,不支持 DDR 类型的 SDRAM。我们只讲述 FMC 的
SDRAM 控制功能。
时钟控制逻辑
FMC 外设挂载在 AHB3 总线上,时钟信号来自于 HCLK(默认 180MHz),控制器的时
钟输出就是由它分频得到。如 SDRAM 控制器的 FMC_SDCLK 引脚输出的时钟,是用于与
SDRAM 芯片进行同步通讯,它的时钟频率可通过 FMC_SDCR1 寄存器的 SDCLK 位配置,
可以配置为 HCLK 的 1/2 或 1/3,也就是说,与 SDRAM 通讯的同步时钟最高频率为
90MHz。
FMC 的地址映射
FMC 连接好外部的存储器并初始化后,就可以直接通过访问地址来读写数据,这种地
址访问与 I2C EEPROM、 SPI FLASH 的不一样,后两种方式都需要控制 I2C 或 SPI 总线给
存储器发送地址,然后获取数据;在程序里,这个地址和数据都需要分开使用不同的变量
存储,并且访问时还需要使用代码控制发送读写命令。而使用 FMC 外接存储器时,其存
储单元是映射到 STM32 的内部寻址空间的;在程序里,定义一个指向这些地址的指针,然
后就可以通过指针直接修改该存储单元的内容, FMC 外设会自动完成数据访问过程,读写
命令之类的操作不需要程序控制。 FMC 的地址映射见图 26-14。
中左侧的是 Cortex-M4 内核的存储空间分配,右侧是 STM32 FMC 外设的地址映射。
可以看到 FMC 的 NOR/PSRAM/SRAM/NAND FLASH 以及 PC 卡的地址都在 External RAM
地址空间内,而 SDRAM 的地址是分配到 External device 区域的。正是因为存在这样的地
址映射,使得访问 FMC 控制的存储器时,就跟访问 STM32 的片上外设寄存器一样(片上外
设的地址映射即图中左侧的“Peripheral”区域)。
External RAM 与 External device 的区别
比较遗憾的是 FMC 给 SDRAM 分配的区域不在 External RAM 区,这个区域可以直接
执行代码,而 SDRAM 所在的 External device 区却不支持这个功能。这里说的可直接执行
代码的特性就是在“常用存储器”章节介绍的 XIP(eXecute In Place)特性,即存储器上若存
储了代码, CPU 可直接访问代码执行,无需缓存到其它设备上再运行;而且 XIP 特性还对
存储器的种类有要求, SRAM/SDRAM 及 NOR Flash 都支持这种特性, 而 NAND FLASH
及 PC 卡是不支持 XIP 的。结合存储器的特性和 STM32 FMC 存储器种类的地址分配,就
发现它的地址规划不合理了, NAND FLASH 和 PC 卡这些不支持 XIP 的存储器却占据了
External RAM 的空间,而支持 XIP 的 SDRAM 存储器的空间却被分配到了 Extern device 区。
为了解决这个问题,通过配置“SYSCFG_MEMRMP”寄存器的“SWP_FMC”寄存器位可
用于交换 SDRAM 与 NAND/PC 卡的地址映射,使得存储在 SDRAM 中的代码能被执行,
只是由于 SDRAM 的最高同步时钟是 90MHz,代码的执行速度会受影响。
本章主要讲解当 STM32 的片内 SRAM 不够用时使用 SDRAM 扩展内存,但假如程序
太大,它的程序空间 FLASH 不够用怎么办呢?首先是裁剪代码,目前 STM32F429 系列芯
片内部 FLASH 空间最高可达 2MB,实际应用中只要我们把代码中的图片、字模等占据大
空间的内容放到外部存储器中,纯粹的代码很难达到 2MB。如果还不够用,非要扩展程序
空间的话,一种方法是使用 FMC 扩展 NOR FLASH,把程序存储到 NOR 上,程序代码能
够直接在 NOR FLASH 上执行。另一种方法是把程序存储在其它外部存储器,如 SD 卡,
需要时把存储在 SD 卡上的代码加载到 SRAM 或 SDRAM 上,再在 RAM 上执行代码。
如果 SDRAM 不是用于存储可执行代码,只是用来保存数据的话,在 External RAM 或
Exteranl device 区域都没有区别,不需要与 NAND 的映射地址交换。
要想把SDRAM程序从头写到尾,实在不现实,这个底层其实直接用现成的就行了,主要是先了解FMC可以做什么。了解FMC的初始化结构体,一开始就想什么都自己写,时间精力也不允许。并不是说这个难,而是对照手册,写这么多寄存器和时序实在太浪费时间,懂得取舍,时间不等人了。