STM32控制器芯片内部有一定大小的SRAM及FLASH作为内存和程序存储空间,但当程序较大,内存和程序空间不足时,就需要在 STM32芯片的外部扩展存储器了。
扩展内存时一般使用SRAM和SDRAM存储器,但STM32F407系列的芯片不支持扩展 SDRAM(STM32F429系列支持),它仅支持使用FSMC外设扩展 SRAM,我们以SRAM为例讲解如何为STM32扩展内存。
给STM32芯片扩展内存与给PC扩展内存的原理是一样的,只是PC上一般以内存条的形式扩展,内存条实质是由多个内存颗粒(即SRAM芯片)组成的通用标准模块,而STM32直接与SRAM 芯片连接。
大家都知道,当电脑运行比较卡的时候,我们可以通过给电脑加装内存条来改善电脑的性能。那么号称微型计算机的单片机能不能像电脑一样加装内存条呢?装内存条倒是不行,但是我们可以给单片机外加和内存条效果一样的SRAM来提升单片机的性能。下面以STM32F407ZGT6单片机来讲解一下来扩展外部SRAM。
原理:给STM32芯片扩展内存与给PC扩展内存的原理是一样的,只是PC上一般以内存条的形式扩展,内存条实质是由多个内存颗粒(即SRAM芯片)组成的通用标准模块,而STM32直接与SRAM芯片连接。
SRAM,型号IS62WV51216,管脚图如下:
IS62WV51216的管脚总的来说大致分为:电源线、地线、地址线、数据线、片选线、写使能端、读使能端和数据掩码信号线。
什么是数据掩码信号呢UB#和LB#?
用UB#或LB#线控制数据宽度,例如,当要访问宽度为16位的数据时,使用行地址线指出地址,然后把UB#和LB#线都设置为低电平,那么 I/O0-I/O15线都有效,它们一起输出该地址的16位数据(或者接收16位数据到该地址);当要访问宽度为 8位的数据时,使用行地址线指出地址,然后把UB#或LB#其中一个设置为低电平,I/O会对应输出该地址的高8位和低8位数据,因此它们被称为数据掩码信号。如果不太明白接着往下看。
因为IS62WV51216是有LB和UB引脚的,可以控制字节的有效性,所以编程操作的时候我们是可以进行任意字节位宽的数据操作的。如果换作其他不支持字节通道访问的芯片的话,那就需要对齐芯片的数据位宽进行数据操作了。在网上查资料时看到有人问“在操作不同的数据位宽时,FSMC_NBL1,FSMC_NBL0是受什么控制输出高低电平给UB,LB的?”,这个应该是属于硬件自动实现的,是FSMC的硬件机制。
从这个图中我们可以看出IS62WV51216有19根地址线和16根数据线,从这些数据中我们可以分析出IS62WV51216的存储大小为1M,那么这个1M是怎么分析出来的呢?我们得来说说IS62WV51216的存储原理。首先,我们来谈一谈一般的RAM的存储原理。
“CPU编址以字节(8bit)为单位。存储器编址:以其位宽为单位,也就是说每个存储器地址下的数据位数为位宽。芯片有19根数据线,那么它的芯片的可寻址空间大小就是
”2^19=254288=512K
,又因为它的数据位宽位16(16根数据线),所以这个芯片的容量位512KB*16bit=8192Kbit=1024KByte=1MByte
。
RAM是“Random Access Memory”的缩写,被译为随机存储器。所谓随机存取,指的是当存储器中的消息被读取或写入时,所需要的时间与这段信息所在的位置无关。根据 RAM的存储机制,又分为动态随机存储器 DRAM(Dynamic RAM)以及静态随机存储器 SRAM(Static RAM)两种。不管是DRAM还是SRAM他们都是在RAM前面加了一个头而已。
静态随机存储器SRAM(Static RAM)顾名思义电路结构不需要定时刷新充电,就能保持状态(当然,如果断电了,数据还是会丢失的),因为不需要定时刷心充电,所以SRAM的存储单元以锁存器来存储数据,这种存储器被称为“静态(Static)”RAM。
而动态随机存储器DRAM(Dynamic RAM)顾名思义电路结构是需要定时刷新充电,因为需要定时刷心充电所以DRAM的存储单元以电容的电荷来表示数据,这种存储器被称为“动态(Dynamic)”RAM。
从他们的存储单元的结构图我们就知道DRAM的结构比SRAM的结构简单的多,所以所以生产相同容量的存储器,DRAM 的成本要更低,且集成度更高。而DRAM中的电容结构则决定了它的存取速度不如SRAM。这种结论是不需要死记硬背的,看结构图就知道了。
但是我们可能还听说过SDRAM,我们把它叫做同步动态随机存储器SDRAM(Synchronous DRAM),同步顾名思义就是利用时钟进行同步的通讯时序,它在时钟的上升沿表示有效数据。
SRAM的存储模型我们可以用矩阵来说明:
SRAM内部包含的存储阵列,可以把它理解成一张表格,数据就填在这张表格上。和表格查找一样,指定一个行地址和列地址,就可以精确地找到目标单元格,这是SRAM芯片寻址的基本原理。这样的每个单元格被称为存储单元,而这样的表则被称为存储矩阵。地址译码器把N根地址线转换成2的N次方根信号线,每根信号线对应一行或一列存储单元,通过地址线找到具体的存储单元,实现寻址。如果存储阵列比较大,地址线会分成行和列地址,或者行、列分时复用同一地址总线,访问数据寻址时先用地址线传输行地址再传输列地址。
但是呢?你会发现,这个原理好像不太适用于IS62WV51216,为什么呢?
其实不然,因为我们使用的SRAM比较小(IS62WV51216容量是1MB),IS62WV51216没有列地址线。它只有19根行地址线,那么,我们就可以这么来解释:IS62WV51216有16根数据线,也就是说它的数据宽度为16位,一个行地址也就对应16位,即一个行地址对应 2字节空间。好,那现在来计算一下IS62WV51216有多少个行地址。2的19次方等于512K,在512K的基础之上在乘我们之前计算的2字节,不正好是1024K,也就是1M吗?1M后面的单位是B,即Byte,而不是Bit哦。这样的话你就会发现IS62WV51216这个名字中本身就包含了大量的信息:IS62WV51216共有512K个行地址,数据宽度为16位,再加以计算就可以得到它的存储大小为1M啦,有趣吧!另外,该芯片支持两种不同的高速访问时间,分别为45ns和55ns,该时间表示进行一次数据读写的最短时间要求,本文选择55ns的模式。
异步通讯,无须时钟,无须刷新,与STM32F407单片机通过FSMC接口相连。
读写时序的流程很类似,下面我们统一解说:
(1) 主机使用地址信号线发出要访问的存储器目标地址;
(2) 控制片选信号 CS1#及 CS2#使能存储器芯片;
(3) 若是要进行读操作,则控制读使能信号OE#表示要读数据,若进行写操作则控制写使能信号 WE#表示要写数据;
(4) 使用掩码信号LB#与UB#指示要访问目标地址的高、低字节部分;
(5) 若是读取过程,存储器会通过数据线向主机输出目标数据,若是写入过程,主要使用数据线向存储器传输目标数据。
在读写时序中,有几个比较重要的时间参数,在使用 STM32 控制的时候需要参考。
FSMC的本质就是内核想要访问存储器,但是内核不能生成硬件时序,FSMC外设就帮忙做了这个硬件时序这个事情。有了这个外设我们操作外部SRAM就不需要自己在那里写读写时序了,FSMC就帮我们解决了。怎么解决的?它有各种寄存器结构体啊,直接按照要求配置就可以了。
STM32F407或STM32F417系列芯片都带有FSMC接口,FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡连接,STM32F4的FSMC 接口支持包括SRAM、NAND FLASH、NOR FLASH和 PSRAM 等存储器。**注意:FSMC不能驱动如SDRAM 这种动态的存储器,而在STM32F429系列的控制器中,它具有FMC外设,支持控制 SDRAM 存储器**。其他我们不用管,从上面我们可以总结的是,STM32雇佣FSMC这个管家来管理我们的IS62WV51216。来来来,我们来看看FSMC的庐山真面目:
FSMC 的框图如图所示:
蒙了吧!又是这么多信号线,不要怕,我们还是来总结归纳下。我们FSMC控制SRAM为例来说明:通过查看STM32F407xx参考手册。
上图打码的地方是PSRAM伪静态随机存储器的引脚,不需要理会,只需要看SRAM的部分即可。
你会发现居然和SRAM中的线居然高度统一(那是当然喏,我们就是讲的FSMC嘛!)
1、FSMC_NBL[1]、FSMC_NBL[0]分别对应于LBn、UBn,有什么用呢?提供数据掩码信号。貝体是怎么回事昵?还记得前面提到的行地址线吗?
一根行地址线对应16位的数据,我们可以把16位的数据分为高字节和低字节。当要访问宽度为16位的数据时,使用行地址线指出地址,然后把UBn(n表示低电平有效)和LBn线都设置为低电平(FSMC_NBL0和 FSMC_NBL为低电平),那么I/O0-I/O15线(FSMC_D0到 FSMC_D15)都有效,它们一起输出该地址的16位数据(或者接收16位数据到该地址);当要访问宽度为8位的数据时,使用行地址线指出地址,然后把UBn(FSMC_NBL0)设置为低电平,I/O0-I/O15(FSMC_D8到 FSMC_D15)会对应输出该地址的高8位,l/O0-I/O7的信号无效(或者把LBn(FSMC_NBL1)设置为低电平,I/O0-/O7(FSMC_D0到SMCD7)会对应输出该地址的低8位,I/O8-/I/O15的信号无效。这样是不是有部分信号没有用呢?好像被掩盖了。因此它们被称为数据掩码信号。
要注意的是FSMC_NBL[1]、FSMC_NBL[0]分别对应于LBn、UBn,这两个引脚的电平不是我们用程序控制的,如果用程序控制就太麻烦了,这两个引脚应该是FSMC的内部硬件机制完成的,不需要我们人为操作。
2、FSMC_NE[1:4]是个很有趣的东西,它决定了FSMC可以控制多个存储器。这里就要提及FSMC的地址映射啦!
首先,有一点我们必须明白,对于32位的STM32单片机来说,它能够管理的地址大小为4GB,而STM32将4GB的地址空间中的0X60000到0X9FFFF共1GB的空间分给外部内存,所以这1GB的空间就成了我们的小天地,供我们自由玩耍。
然后强势的FSMC就接管了这1GB的空间,FSMC将图中的1GB大小的外部RAM存储区域分成了4个Bank区域,每个Bank对应于STM32内部寻址空间的不同地址范围。
那么为什么要分为不同的Bank区域呢?
因为不同的Bank可以来管理不同的外部存储设备,比如NOR_Flash及SRAM存储器只能使用Bank1的地址,NAND_Flash存储器只能使用Bank2和Bank3的地址等。
细心的你肯定还会发现,每个Bank中居然还有4x64MB这种文宇,这是什么意思呢?
Bank内部的256MB空间又被分成4个小块,每块64M,各自有相应的控制引脚用于连接片选信号。FSMC_NE[4:1]信号线就分别对应图中的 FSMC bank1 NOR/PSRAM4到FSMC bank1 NOR/PSRAM1。当STM32访问0×6800000—0x6BFFF址空间时,会访问到Bank1的第3小块区域:FSMC bank1 NOR/PSRAM3,相应的FSMC_NE3信号线会输出控制信号(即片选信号),如果这个时候FSMC_NE3
处刚好接上IS62WV51216
的CS端,那么IS62WV51216
就可以任由我们摆布啦。因此,对于你使IS62WV51216
来说,一定要注意你的CS端是接的FSMC的哪个FSMC_NE端,这决定你在程序访问哪个地址范围。
STM32F4 的 FSMC 存储块 1(Bank1)被分为 4 个区,每个区管理64M 字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1 的 256M 字节空间由28根地址线(HADDR[27:0])寻址。
“为什么是28根地址线?因为2^28=268435456B=262144KB=256MB,正好管理这Bank1的256M 字节空间。
”
当Bank1接的是16位宽度存储器的时候:HADDR[25:1]→FSMC_A[24:0]。当Bank1接的是8位宽度存储器的时候:HADDR[25:0]→ FSMC_A[25:0]。不论外部接8位/16位宽设备,FSMC_A0永远接在外部设备地址A[0]。
这里感觉很不好理解,简单地分析如下:
“对于16位SRAM,FSMC地址线要向右移一位(非常重要)。
”
以0x6800 0000
这个地址为例,它分解成二进制是0110 1000 0000 0000 0000 0000 0000 0000,由于一个BANK是64M的地址空间,而2^25=64M,故0x6800 0000的位[25:0]是FSMC向外部SRAM传递的真实地址,对于0x6800 0000,FSMC向外部SRAM发的地址是位[25:0],即00 0000 0000 0000 0000 0000 0000,这很好理解。
同理,对于0x6800 0002
,FSMC向外部SRAM发送的地址是00 00000000 0000 0000 0000 0010。若FSMC不自动右移一位,这个地址明显发错了,因为期望读取的SRAM地址为0x0000 0001中的数据。
为了解决这一问题,当在初始化FSMC时,若选择外部SRAM为16位,则FSMC在向外部SRAM发地址时,会自动右移一位,例如刚才的0x6800 0002
,FSMC在向外部发SRAM地址时,00 0000 0000 0000 0000 0000 0010会自动右移一位,变成00 0000 00000000 0000 0000 0001,即0x0000 0001,该地址正好是期望的外部SRAM地址。接着,外部SRAM从地址为0x0000 0001中取出16位数据传送给FSMC,由FSMC将这个16位数据保存在以映射地址0x6800 0002
起始的两个8位存储单元中。
地址映射如下:
这样的话,当16位数据宽度时,地址的问题解决了,还有一个问题,是往高字节写入还是低字节写入呢?
这也就是NBL0和NBL1的作用了,如果你要进行字节操作 :如stm32发送地址0x0001读取一个字节。右移一位对应的是sram地址0x0000处的16位数据, FSMC会根据A0(最后一根地址线)来控制NBL0和NBL1。当A0 = 1时,读取高字节数据(仅NBL1有效);A0 = 0时,读取低字节数据仅NBL0有效),当进行16位读写时,NBL0和NBL1都有效。
经过了上面的分析,再来重新观察数据的写入过程:
当地址为0x6800 0000,会访问到SRAM的第0个16位地址,而此时A0 = 0(低字节有效),实际会访问的是16位 0地址的低字节;当地址为0x6800 0001时,A0 = 1,访问16位 0地址的高字节。依次。
因此,想让地址线的最后一位产生0或1,应该在前一位做出改变(stm32会自动右移):
参考内容:https://blog.csdn.net/dingyc_ee/article/details/100703685
我们的SRAM芯片使用的是Bank1 的第三个区,即使用FSMC_NE3
来连接外部设备的时候,即对应了HADDR[27:26]=10(这是内部硬件配置,不需要我们管),我们要做的就是配置对应第3区的寄存器组,来适应外部设备即可。
STM32F4的FSMC各Bank配置寄存器如下表
STM32的FSMC存储块1支持的异步突发访问模式包括:模式1、模式A~D等多种时序模型,驱动SRAM时一般使用模式1或者模式A,这里我们使用模式A来驱动SRAM用,其他模式说明详见:STM32中文参考手册-FSMC章节。
FSMC外设支持输出多种不同的时序以便于控制不同的存储器,它具有 ABCD 四种模式,下面我们仅针对控制 SRAM 使用的模式 A进行讲解。
对于NOR FLASH/PSRAM(包括SRAM)控制器(存储块1),通过FSMC_BCRX
、FSMC_BTRX
和FSMCBWTRx
寄存器设置(其中x=1~4,对应4个区)。由于我们硬件是把blank的第三个区给外部SRAM使用,所以对于SRAM芯片的片选引脚为FSMC_NE3。所以就要配置FSMC_BCR3
、FSMC_BTR3
和FSMCBWTR3
这3个寄存器。正点原子F407板子的SRAM的片选引脚是FSMC_NE3
,LCD显存芯片的片选引脚是FSMC_NE4
。
在MDK
的寄存器定义里面,并没有定义FSMC_BCRx
、FSMC_BTRx
、FSMC_BWTRx
等这个单独的寄存器,而是将他们进行了一些组合。
FSMC_BCRx
和FSMC_BTRx
,组合成BTCR[8]
寄存器组,他们的对应关系如下:
BTCR[0] 对应 FSMC_BCR1,BTCR[1] 对应 FSMC_BTR1 BTCR[2] 对应 FSMC_BCR2,BTCR[3] 对应 FSMC_BTR2 BTCR[4] 对应 FSMC_BCR3,BTCR[5] 对应 FSMC_BTR3 BTCR[6] 对应 FSMC_BCR4,BTCR[7] 对应 FSMC_BTR4
FSMC_BWTRx
则组合成BWTR[7]
,他们的对应关系如下:
BWTR[0]对应 FSMC_BWTR1,BWTR[2]对应 FSMC_BWTR2, BWTR[4]对应 FSMC_BWTR3,BWTR[6]对应 FSMC_BWTR4, BWTR[1]、BWTR[3]和 BWTR[5]保留,没有用到。
本篇到此结束,下一篇将讲解FSMC的先关代码,并使用STM32CubeMX进行配置,敬请期待!
END
来源:果果小师弟
版权归原作者所有,如有侵权,请联系删除。
▍推荐阅读
文章引用微信公众号"嵌入式微处理器",如有侵权,请联系管理员删除!