LV16-24-FSMC-02-FSMC基础

本文主要是STM32开发——FSMC接口的一些相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
  • 通用
分类 网址说明
官方网站https://www.arm.com/ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档
https://www.st.com/content/st_com/zh.htmlST官方网站,在这里我们可以找到STM32的相关文档
https://www.stmcu.com.cn/意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档
http://elm-chan.org/fsw/ff/00index_e.htmlFatFs文件系统官网
教程书籍《ARM Cortex-M3权威指南》ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩
《ARM Cortex-M0权威指南》
《ARM Cortex-M3与Cortex-M4权威指南》
开发论坛http://47.111.11.73/forum.php开源电子网,正点原子的资料下载及问题讨论论坛
https://www.firebbs.cn/forum.php国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT
https://www.amobbs.com/index.php阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。
http://download.100ask.net/index.html韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。
博客参考http://www.openedv.com/开源网-原子哥个人博客
http://blog.chinaaet.com/jihceng0622博主是原Freescale现NXP的现场应用工程师
cortex-m-resources这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接)
  • STM32
STM32STM32 HAL库开发实战指南——基于F103系列开发板野火STM32开发教程在线文档
STM32库开发实战指南——基于野火霸道开发板野火STM32开发教程在线文档
  • SD卡
SD Association提供了SD存储卡和SDIO卡系统规范
点击查看相关文件下载
STM32F103xx英文数据手册STM32F103xC/D/E系列的英文数据手册
STM32F103xx中文数据手册STM32F103xC/D/E系列的中文数据手册
STM32F10xxx英文参考手册(RM0008)STM32F10xxx系列的英文参考手册
STM32F10xxx中文参考手册(RM0008)STM32F10xxx系列的中文参考手册
Arm Cortex-M3 处理器技术参考手册-英文版Cortex-M3技术参考手册-英文版
STM32F10xxx Cortex-M3编程手册-英文版(PM0056)STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版
SD卡相关资料——最新版本有关SD卡的一些资料可以从这里下载
SD卡相关资料——历史版本有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议
SD 2.0 协议标准完整版这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看

这一部分我们可以参考 [STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的 19 灵活的静态存储器控制器(FSMC) 一节。

一、FSMC简介

FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和 16 位 PC 存储器卡连接,STM32F1 的 FSMC 接口支持包括 SRAM、 NAND FLASH、 NOR FLASH 和 PSRAM 等存储器,但是不能驱动如SDRAM这种动态的存储器。 而在STM32F429系列的控制器中,它具有FMC外设,支持控制SDRAM存储器。

STM32F103ZET6的内部有64KB的SRAM,可以满足大部分的应用场景,但在一些采集数据比较多的项目、应用算法或GUI( Graphical User Interface,图形用户界面) 等应用场景,内部SRAM可能就不够了,此时就需要外部扩展SRAM。

STM32F103系列中, 100脚及以上的MCU,都有一个FSMC( Flexible Static Memory Controller,灵活的静态存储器控制器) , 该外设是STM32设计的一种存储器控制技术,仅适用STM32系列的MCU。 它可以驱动SRAM、 NOR Flash、 NAND Flash等存储器,但不能驱动SDRAM等动态存储器。

二、FSMC框图分析

1. FSMC框图

在[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的 19.2 框图一节,我们可以看到FSMC结构框图如下:

image-20230503121218218

从上图可以看出,STM32 的 FSMC 将外部设备分为 3 类: NOR/PSRAM 设备、 NAND设备、 PC 卡设备。他们共用地址数据总线等信号,他们具有不同的 CS 以区分不同的设备,

2. 接口信号

这一部分我们可以查看[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的 19.5.1 外部存储器接口信号。下边我们一起来看一下与NOR闪存和PSRAM接口的典型信号。注意:具有前缀 “ N ” 的信号表示低有效信号。这里说一下下边的复用和非复用是什么意思:

  • 非复用模式:16位数据线及26位地址线分开始用。推荐在144脚及以上的STM32产品上使用该模式。

  • 复用模式:低16位数据/地址线复用。在该模式下,推荐使用地址锁存器以区分数据与地址。

2.1 NOR闪存,非复用接口

FSMC信号名称 信号方向 功能
CLK 输出 时钟信号( 用于同步访问的外部存储器)
A[25:0] 输出 地址总线
D[15:0] 输入/输出 数据总线
NEx 输出 Bank1区域内片选信号, x=1~4,每个区域大小为64MB
NOE 输出 读使能信号
NWE 输出 写使能信号
NWAIT 输入 NOR闪存要求FSMC等待的信号

NOR闪存存储器是按16位的字寻址,最大容量达64M字节(26条地址线)。

2.2 NOR闪存,复用接口

FSMC信号名称 信号方向 功能
CLK 输出 时钟信号( 用于同步访问的外部存储器)
A[25:16] 输出 地址总线
AD[15:0] 输入/输出 16位复用的,双向地址/数据总线
NEx 输出 Bank1区域内片选信号, x=1~4,每个区域大小为64MB
NOE 输出 读使能信号
NWE 输出 写使能信号
NL(=NADV) 输入 锁存使能(某些NOR闪存器件命名该信号为地址有效,NADV,也可以叫地址有效信号)
NWAIT 输入 NOR闪存要求FSMC等待的信号

NOR闪存存储器是按16位的字寻址,最大容量达64M字节(26条地址线)。

2.3 PSRAM,非复用接口

非复用信号的PSRAM接口信号如下:

FSMC信号名称 信号方向 功能
CLK 输出 时钟信号( 用于同步访问的外部存储器)
A[25:0] 输出 地址总线
D[15:0] 输入/输出 双向数据总线
NEx 输出 Bank1区域内片选信号, x=1~4,每个区域大小为64MB (PSRAM称其为NCE(Cellular RAM既CRAM))
NOE 输出 读使能信号
NWE 输出 写使能信号
NL(=NADV) 输出 地址有效信号(存储器信号名称为:NADV)
NWAIT 输入 PSRAM要求FSMC等待的信号
NBL[1] 输出 高字节使能(存储器信号名称为:NUB)
NBL[0] 输出 低字节使能(存储器信号名称为:NLB)

PSRAM存储器是按16位的字寻址,最大容量达64M字节(26条地址线)。

2.4 与SRAM的接线?

我们上一节学习 IS62WV51216BLL这款SRAM的一些基础知识,我们学习FSMC就是来驱动这个SRAM芯片的,那么SRAM这么多引脚是如何与SRAM引脚对应的呢?我来看一下 FSMC 与 SRAM 引脚对照表 :

image-20230514192501538

也就是如下表所示:

FSMC引脚名称 对应的FSMC引脚名 说明
FSMC_NBL[1:0] LB#,UB# 数据掩码信号
FSMC_A[18:0] A[18:0] 行地址线,这里FSMC有25根,但只使用了19根
FSMC_D[15:0] I/O[15:0] 数据线,一共16根
FSMC_NWE WE# 写入使能信号线
FSMC_NOE OE# 输出使能信号线(读使能)
FSMC_NE[1:4] CE# 片选信号

由于大部分地址线 FSMC_A 都是使用到了 GPIOF、 GPIOG 端口,而 STM32VET6 等 144脚以下型号的芯片不具有这些端口,因此对于 144 脚以下的 STM32 芯片,无法扩展外部 SRAM,STM32ZET6 或以上型号的芯片具有 GPIOF、 GPIOG 等端口,因此想要扩展外部 SRAM 的时候,需要注意 STM32 芯片的选型。

其中比较特殊的 FSMC_NE 是用于控制 SRAM 芯片的片选控制信号线, STM32 具有FSMC_NE1/2/3/4 号引脚,不同的引脚对应 STM32 内部不同的地址区域。例如,当 STM32 访问 0x68000000-0x6BFFFFFF 地址空间时, FSMC_NE3 引脚会自动设置为低电平,由于它连接到 SRAM 的 CE# 引脚,所以 SRAM 的片选被使能,而访问 0x60000000-0x63FFFFFF 地址时,FSMC_NE1 会输出低电平。当使用不同的 FSMC_NE 引脚连接外部存储器时, STM32 访问 SRAM的地址不一样,从而达到控制多块 SRAM 芯片的目的。各引脚对应的地址会在后面 四、NOR/PSRAM控制器 小节说明。

3. 时钟控制逻辑

image-20230514165853284

FSMC外设挂载在AHB总线上,时钟信号来自于HCLK(默认72MHz),控制器的同步时钟输出就是由它分频得到。例如,NOR控制器的FSMC_CLK引脚输出的时钟,它可用于与同步类型的SRAM芯片进行同步通讯,它的时钟频率可通过FSMC_BTR寄存器的CLKDIV位配置,可以配置为HCLK的1/2或1/3,也就是说,若它与同步类型的SRAM通讯时,同步时钟最高频率为36MHz。我们将要驱动的SRAM为异步类型的存储器,不使用同步时钟信号,所以时钟分频配置不起作用。

4. 存储器控制器

面不同类型的引脚是连接到FSMC内部对应的存储控制器中的。NOR/PSRAM/SRAM设备使用相同的控制器,NAND/PC卡设备使用相同的控制器,不同的控制器有专用的寄存器用于配置其工作模式。

控制SRAM的有FSMC_BCR1/2/3/4控制寄存器、FSMC_BTR1/2/3/4片选时序寄存器以及FSMC_BWTR1/2/3/4写时序寄存器。每种寄存器都有4个,分别对应于4个不同的存储区域,各种寄存器介绍如下(后边还会再说明):

  • FSMC_BCR控制寄存器可配置要控制的存储器类型、数据线宽度以及信号有效极性能参数。
  • FMC_BTR时序寄存器用于配置SRAM访问时的各种时间延迟,如数据保持时间、地址保持时间等。
  • FMC_BWTR写时序寄存器与FMC_BTR寄存器控制的参数类似,它专门用于控制写时序的时间参数。

三、存储器映射?

FSMC连接好外部的存储器并初始化后,就可以直接通过访问地址来读写数据。FSMC访问存储器的方式与I2C EEPROM、SPI FLASH的不一样,后两种方式都需要控制I2C或SPI总线给存储器发送地址,然后获取数据;在程序里,这个地址和数据都需要分开使用不同的变量存储,并且访问时还需要使用代码控制发送读写命令。而使用FSMC外接存储器时,其存储单元是映射到STM32的内部寻址空间的;在程序里,定义一个指向这些地址的指针,然后就可以通过指针直接修改该存储单元的内容,FSMC外设会自动完成数据访问过程,读写命令之类的操作不需要程序控制

作为STM32的外设,FSMC被映射在哪里?我们来回顾一下STM32的存储器映像:

image-20230514170837547

图中左侧的是Cortex-M3内核的存储空间分配,右侧是STM32 FSMC外设的地址映射(我们可以查看STM32F103xx数据手册的4 Memory mapping)。可以看到FSMC的NOR/PSRAM/SRAM/NAND FLASH以及PC卡的地址都在External RAM地址空间内。正是因为存在这样的地址映射,使得访问FSMC控制的存储器时,就跟访问STM32的片上外设寄存器一样。FSMC把整个External RAM存储区域分成了4个Bank区域,并分配了地址范围及适用的存储器类型,如NOR及SRAM存储器只能使用Bank1的地址。

由图可知, 0x6000 00000x9FFF FFFF共计1GB空间为FSMC的存储器映射范围。 FSMC把这1GB空间,分为了4个固定大小的存储区域( Bank14),每个大小为256MB, 每个Bank都由一组独立的配置寄存器控制,相互之间不受干扰, 如下图:

image-20230503124949215

(1)Bank1( 0x6000 000~0x6FFF FFFF): 用于NOR/PSRAM设备, 该区域又被分为4块,每块64MB,可连接4个NOR Flash设备或PSRAM设备,每个区域通过片选引脚NE[4:1]进行选择;

(2)Bank2( 0x7000 000~0x7FFF FFFF): 用于NAND Flash设备,每个存储块连接一个NAND闪存。

(3)Bank3( 0x8000 000~0x8FFF FFFF): 用于NAND Flash设备,每个存储块连接一个NAND闪存。

(4)Bank4( 0x9000 000~0x9FFF FFFF): 用于PC卡设备;

四、NOR/PSRAM控制器

由于我们后边要学习的如何驱动SRAM,因此重点分析NOR/PSRAM控制器,即Bank1。

1. Bank1的四个区

STM32 的 FSMC 存储块 1(Bank1)被分为 4 个区,每个区管理 64M 字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。 CPU需要28根AHB地址总线,才能寻址完Bank1的256MB空间( 2^28=256MB),这里用HADDR[27:0]表示需要的地址总线。 HADDR[25:0]对应连接外部存储器的FSMC_A[25:0], HADDR[26:27]对应片选信号引脚NE[4:1],这两个位主要是用于选择四个存储块之一。

Bank1所选区域 地址范围 片选引脚信号 HADDR[27:26] HADDR[25:0]
存储块1 NOR/PSRAM 1 0x6000 0000~0x63FF FFFF FSMC_NE1 00 FSMC_A[25:0]
存储块2 NOR/PSRAM 2 0x6400 0000~0x67FF FFFF FSMC_NE2 01 FSMC_A[25:0]
存储块3 NOR/PSRAM 3 0x6800 0000~0x6BFF FFFF FSMC_NE3 10 FSMC_A[25:0]
存储块4 NOR/PSRAM 4 0x6C00 0000~0x6FFF FFFF FSMC_NE4 11 FSMC_A[25:0]
image-20230514171230341

如上图,当STM32访问0x68000000-0x6BFFFFFF地址空间时,会访问到Bank1的第3小块区域,相应的FSMC_NE3信号线会输出控制信号。

2. 地址映像

这一部分可以看[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的19.4.1 NOR和PSRAM地址映像一节。CPU访问一个地址,只能读取一字节( 8位 )数据, 因此当外部存储器数据宽度不同时, 实际向存储器发送的地址也将有所不同。HADDR[25:0]包含外部存储器地址。HADDR是字节地址,而存储器访问不都是按字节访问,因此接到存储器的地址线依存储器的数据宽度有所不同

存储器数据宽度 向存储器发送的地址 存储器最大容量
8位 HADDR[25:0] 64 Mbyte x 8 = 512 Mbit
16位 HADDR[25:1] >> 1 64 Mbyte/2 x 16 = 512 Mbit

当Bank1接的是8位宽度存储器的时候:HADDR[25:0]→FSMC_A[25:0],当Bank1接的是16位宽度存储器的时候:HADDR[25:1]→ FSMC_A[24:0],HADDR[0]未接。需要注意的是,不论外部接8位/16位宽设备,**FSMC_A[0]永远接在外部设备地址A[0]**。

我们来看一下分别接8位和16位的时候,地址是怎么对应的:

(1)假设某8位数据宽度的外部存储器接在Bank1的第一区,则FSMC_NE1连接该外部存储器片选,此时HADDR[26:27]值为0x00; FSMC_A[25:0]连接该外部存储器地址引脚。此时一个地址对应一字节( 8位)数据,通过HADDR[25:0]寻址该外部存储器,得到8位数据。

(2)假设某16位数据宽度的外部存储器接在Bank1的第二区,则FSMC_NE2连接该外部存储器片选,此时HADDR[26:27]值为0x01, FSMC_A[25:0]连接该外部存储器地址引脚。此时一个地址对应两字节( 16位)数据,通过HADDR[25:1]>>1寻址该外部存储器,得到16位数据。

为什么对于16位数据宽度的外部存储器,要使用HADDR[25:1]>>1寻址?假设CPU想访问存储器0x0b0000地址数据,得到16位数据,此时CPU一次只能获取此16位的低8位。接着想通过0x0b0001地址访问剩下的8位,这个时候却访问的是下一个16位数据。但如果将访问地址右移1位,即无论是0x0b0000还是0x0b0001,都是0b0000,再通过NBLx切换高低8位,即可完整的获取存储器0x0b0000处的16位数据:

image-20230503145932595

上边分析的这个过程,其实都是FSMC自动完成的,我们在编写程序的时候其实直接读写我们想要读写的地址,在FSMC内部会自动帮我们完成对存储器指定地址的访问。

3. 同步与异步访问

3.1 不同的模式

NOR/PSRAM控制器支持同步访问和异步访问,这里的同步、异步概念,与前面“ 同步/异步通信 ”的概念类似。

  • 同步访问需要一个时钟信号作为收发双方的参考信号, FSMC使用HCLK分频后的时钟,作为与外部存储器的时钟同步信号FSMC_CLK。

  • 异步访问无需时钟信号,通过提前制定规则保证数据传输的准确, 因此FSMC需要设置多个时间参数,比如数据建立时间( Data-Phase Duration, DATAST)、 地址保持时间( Address-hold Phase Duration, ADDHLD)和地址建立时间( Address Setup Phase Duration , ADDSET) 。

NOR/PSRAM控制器支持的器件类型众多, 不同的器件读写操作时序会有差异,因此控制器通过切换不同的模式,以使用不同的时序来支持不同的器件,我们后边多还是使用异步访问,NOR/PSRAM 控制器的异步访问模式和同步访问模式如下表:

访问模式描述需设置参数
同步模式根据同步时钟 FSMC_CK 读取多个顺序单元的数据CLKDIV、 DATLAT
非扩展模式(异步)模式1适合SRAM/PSRAM(CRAM)的时序DATAST、 ADDSET
模式2/B适合NOR Flash的时序DATAST、 ADDSET
扩展模式(异步)模式A 适合SRAM/PSRAM (CRAM) , NOE片选 翻转的时序DATAST、 ADDSET
模式2/B 适合NOR Flash的时序DATAST、 ADDSET
模式C适合NOR Flash , NOE片选翻转的时序DATAST、 ADDSET
模式D适合带扩展地址的异步访问DATAST、 ADDSET、 ADDHLD

【说明】ADDSET——地址建立时间 (Address setup phase duration) ,DATAST——数据保持时间 (Data-phase duration),ADDHLD——地址保持时间 (Address-hold phase duration) 。

在非扩展模式下( FSMC_BCRx寄存器的EXTMOD位置0),如果连接的是SRAM/PSRAM,则默认访问模式为模式1,如果连接的是NOR Flash,则默认访问模式为模式2。在扩展模式下( FSMC_BCRx寄存器的EXTMOD位置1),支持四种扩展模式:模式A、模式B、模式C和模式D。 也可以混合使用模式A、 B、 C、 D的读写操作,比如可以使用模式A进行读,模式B进行写。 我们后边学习的是SRAM,因此后边将会介绍模式1和模式A的时序。

3.2 寄存器配置?

这么多的模式,都是通过寄存器配置来实现的,在[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)19.5.3 时序规则一节介绍的各种模式的时序图的后边,会有配置寄存器相关位的表格,我们可以参考这些表格来配置寄存器,使用不同的模式,例如:

image-20230514173201606

4. 模式1时序

这一部分我们可以看[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的19.5.4 NOR闪存和PSRAM控制器时序图一节。

4.1 读时序

image-20230503153017891

FSMC读外部存储器时,首先Bank1区域内片选信号引脚NEx拉低,选中外部存储器所在Bank;同时读使能信号引脚NOE拉低, 写使能信号引脚NWE保持高电平;接着地址总线A[25:0]在高低字节选择信号NBL[1:0]的配合下寻址, 经历( ADDSET+1)个HCLK周期完成寻址; 在随后的( DATASET+1) 个HCLK周期里, 外部存储器控制数据总线D[15:0]发送数据;最后,再经历2个HCLK周期后, Bank区域内片选信号引脚NEx和读使能信号引脚NOE都恢复为高电平。

4.2 写时序

image-20230503153039615

FSMC写外部存储器时,首先Bank区域内片选信号引脚NEx拉低,选中外部存储器所在Bank;同时读使能信号引脚NOE拉高,写使能信号引脚NEW先暂时保持高电平;接着地址总线A[25:0]在高低字节选择信号NBL[1:0]的配合下寻址,经历( ADDSET+1)个HCLK周期完成寻址; 然后写使能信号引脚NWE拉低, 在随后的( DATASET+1)个HCLK周期里, FSMC控制数据总线D[15:0]发送数据, 使能信号引脚NEW提前1个HCLK周期拉高;最后, Bank区域内片选信号引脚NEx恢复为高电平, 读使能信号引脚NOE都恢复为低电平。

在写操作的最后一个HCLK周期可以保证NWE上升沿后地址和数据的保持时间,因为存在这个 HCLK周期,DATAST的数值必须大于0(DATAST > 0)。

5. 模式A时序

这一部分我们可以看[STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001)的19.5.4 NOR闪存和PSRAM控制器时序图一节。这一部分我们结合上一节学习的SRAM的时序图来学习,看完之后我们也就可以理解FSMC如何驱动SRAM了。

5.1 读时序

当内核发出访问某个指向外部存储器地址时, FSMC 外设会根据配置控制信号线产生时序访问存储器,下图中的是访问外部 SRAM 时 FSMC 外设的读写时序。

image-20230515121834603

该图表示一个存储器操作周期由地址建立周期 (ADDSET)、数据建立周期(DATAST) 以及 2 个 HCLK 周期组成。在地址建立周期中,地址线发出要访问的地址,数据掩码信号线指示出要读取地址的高、低字节部分,片选信号使能存储器芯片;地址建立周期结束后读使能信号线发出读使能信号,接着存储器通过数据信号线把目标数据传输给 FSMC, FSMC 把它交给内核。模式A读写访问外部存储器的时序和模式1基本类似, 如图所示。 主要区别在于FSMC读外部存储器时, 读使能信号引脚NOE不是一开始就拉高, 而是等寻址完后才拉低。

我们具体看一下它与SRAM的时序图的对应关系:

(1)FSMC的存储器操作周期就相当于SRAM的tRC(读取周期时间),这段时间FSMC与SRAM的关系就是tRC对应(ADDSET+1)+(DATAST+1)+2这样一个时间段;

(2)我们看一下FSMC读时序标号①的地方,这里是从地址建立,到NOE拉低的时间,对应到SRAM的读时序中,就是图中字母A的位置,在SRAM中这个时间并没有明确的说明,不过可以参考比A处时间稍长一些的时间来确定这个标号①处的时间。

(2)SRAM的tAA(地址访问)时间,对应到FSMC的读时序中就如上图标注,它在FSMC中应该是(ADDSET+1)+(DATAST+1)这段时间。

(3)我们查看SRAM的手册知道当输出使能引脚OE#拉低后tODE时间后开始,SRAM将会输出数据,时间我们查询SRAm手册后发现是25ns,数据会保持所以我们在OE#拉低25ns之后采样即可,对应到FSMC的时序图中,我门们可以看到NOE信号拉低 (DATAST+1)个HCLK 时间后进行数据采样,也就是标号为②的这段时间,我们保证FSMC的这段时间大于25ns,这样就可以读取到SRAM的数据了。

(4)对于其他地方的一些小的区别,其实问题也不大,那些时间都非常短,对于这个HCLK,一般我们AHB总线时钟都是72M,所以一个HCLK时间就是1/72M啦,计算出来的话大概就是13.8ns。

关于ADDSET和DATAST详细的确定过程可以看后边的读写外部SRAM实例,我在那篇笔记对照SRAM和FSMC时序详细分析了一下这两个参数如何确定。

5.2 写时序

image-20230514201220924

写时序类似,区别是它的一个存储器操作周期仅由地址建立周期 (ADDSET) 和数据建立周期(DATAST) 组成,且在数据建立周期期间写使能信号线发出写信号,接着 FSMC 把数据通过数据线传输到存储器中。 模式A与模式1的区别是NOE的变化和相互独立的读写时序。从模式 A 的读写时序图,我们可以看出,读操作还存在额外的 2 个 HCLK 周期,用于数据存储,所以同样的配置读操作一般比写操作会慢一点。

FSMC的写时序与SRAM的写时序也是对应的,这就就不再详细画图了,跟读时序一样的对应方式。我们注意观察这里,写时序使用的也是片选时序寄存器的ADDSET和DATAST位,这是同一个寄存器的同一个位,我们在进行读写的时候不会有问题嘛?一般来讲读写时序都差不多,所以可以用成同一个,但是若是读写时序要求的时长不同的话,我们还有一个寄存器可用,那就是写时序寄存器FSMC_BWTRx)。只需要在片选控制寄存器 1…4 (FSMC_BCR1…4)中开EXTMOD 位,也就是扩展模式使能 (Extended mode enable),这样读写时序就可以使用不同的寄存器了。

6. 相关寄存器

6.1 配置寄存器表

相关的寄存器我们可以看 [STM32中文参考手册](https://www.stmcu.com.cn/Designresource/detail/localization_document /710001) 的19.7 FSMC寄存器地址映象(原英文手册没有这一节,中文手册翻译者整理添加的这一节)。STM32 的 FSMC 各 Bank 配置寄存器如下表:

内部控制器存储块管理的地址范围支持的设备类型配置寄存器
NOR FLASH 控制器Bank10X60000000~0X6FFFFFFFSRAM/ROM、NOR FLASH、PSRAMFSMC_BCR1/2/3/4
FSMC_BTR1/2/2/3
FSMC_BWTR1/2/3/4
NAND FLASH/PC CARD控制器Bank20X70000000~0X7FFFFFFFNAND FLASHFSMC_PCR2/3/4
FSMC_SR2/3/4
FSMC_PMEM2/3/4
FSMC_PATT2/3/4
FSMC_PIO4
Bank30X80000000~0X8FFFFFFF
Bank40X90000000~0X9FFFFFFFPC Card

对于 NOR FLASH 控制器,主要是通过 FSMC_BCRx、 FSMC_BTRx 和 FSMC_BWTRx 寄存器设置(其中 x=1~4,对应 4 个区)。 通过这 3 个寄存器, 可以设置 FSMC 访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。 FSMC 的 NOR FLASH 控制器支持同步和异步突发两种访问方式。选用同步突发访问方式时, FSMC 将 HCLK(系统时钟)分频后,发送给外部存储器作为同步时钟信号 FSMC_CLK。 此时需要的设置的时间参数有 2 个:

(1)HCLK 与 FSMC_CLK 的分频系数(CLKDIV),可以为 2~16 分频;

(2)同步突发访问中获得第 1 个数据所需要的等待延迟(DATLAT)。

对于异步突发访问方式, FSMC 主要设置 3 个时间参数:地址建立时间(ADDSET)、数据建立时间(DATAST)和地址保持时间(ADDHLD)。 FSMC 综合了 SRAM/ ROM、 PSRAM 和 NORFlash 产品的信号特点,定义了 4 种不同的异步时序模型。 选用不同的时序模型时,需要设置不同的时序参数 ,这个在上一小节的笔记已经说过了可以看3. 同步与异步访问 这一小节的笔记。

在实际扩展时,根据选用存储器的特征确定时序模型,从而确定各时间参数与存储器读/写周期参数指标之间的计算关系;利用该计算关系和存储芯片数据手册中给定的参数指标,可计算出 FSMC 所需要的各时间参数,从而对时间参数寄存器进行合理的配置。

6.2 闪存片选控制寄存器FSMC_BCRx

image-20230503160527408

该寄存器我们在SRAM中用到的设置有: EXTMOD、 WREN、 MWID、 MTYP 和 MBKEN 这几个设置。

(1)EXTMOD:bit[14],扩展模式使能位,也就是是否允许读写不同的时序,很明显,我们本章需要读写不同的时序,故该位需要设置为 1。为什么有这样一个位?为什么有扩展模式?前边在介绍模式A的读写时序的时候我们详细分析过,读写时序使用的都是片选时序寄存器的ADDSET和DATAST位,这是同一个寄存器的同一个位。一般来讲读写时序都差不多,可以用成同一个,但是若是读写时序要求的时长不同的话,我们还有一个寄存器可用,那就是写时序寄存器FSMC_BWTRx)。所以这个位就为使用不同的读写时序提供了配置方法。

(2)WREN:bit[12],写使能位。我们需要向 SRAM 写数据,故该位必须设置为 1。

(3)MWID[1:0]:bit[5:4],存储器数据总线宽度。 00,表示 8 位数据模式; 01 表示 16 位数据模式; 10 和 11 保留。

(4)MTYP[1:0]:bit[3:2],存储器类型。 00 表示 SRAM、 ROM; 01 表示 PSRAM; 10 表示 NOR FLASH;11保留。

(5)MBKEN:bit[0],存储块使能位。我们需要用到该存储块控制 SRAM,当然要使能这个存储块了。

6.3 闪存片选时序寄存器(FSMC_BTRx)

image-20230503160912905

这个寄存器包含了每个存储器块的控制信息,可以用于 SRAM、 ROM 和 NOR 闪存存储器。如果 FSMC_BCRx 寄存器中设置了 EXTMOD 位,则有两个时序寄存器分别对应读(本寄存器)和写操作(FSMC_BWTRx 寄存器)。因为我们要求读写分开时序控制,所以 EXTMOD 是使能了的,也就是本寄存器是读操作时序寄存器,控制读操作的相关时序。 我们驱动SRAM要用到的设置有:ACCMOD、 DATAST 和 ADDSET 这三个设置。

(1)ACCMOD[1:0]:访问模式。 00 表示访问模式 A; 01 表示访问模式 B; 10 表示访问模式 C;11 表示访问模式 D,我们用到模式 A,故设置为 00。

(2)DATAST[7:0]:数据保持时间。 0 为保留设置,其他设置则代表保持时间为: DATAST + 1 个 HCLK 时钟周期,最大为 255 个 HCLK 周期。对IS62WV51216 来说,其实就是OE#或者WE#低电平持续时间,最大为55ns。对STM32F1,一个HCLK=13.8ns (1/72M),设置为3;对STM32F4,一个HCLK=6ns(1/168M) ,设置为8。

(3)ADDSET[3:0]:地址建立时间。其建立时间为: ADDSET + 1 个 HCLK 周期,最大为 15 个 HCLK周期。对IS62WV51216来说,访问周期最快位55ns,而我们前面的设置,已经可以保证访问周期不小于55ns,因此这个地址建立时间,我们可以直接设置为0即可。

【注意】如果未设置 FSMC_BCRx 寄存器的EXTMOD位,则读写共用这个时序寄存器。

6.4 闪存写时序寄存器FSMC_BWTRx)

image-20230503161418932

该寄存器在本章用作写操作时序控制寄存器,需要用到的设置同样是: ACCMOD、 DATAST和 ADDSET 这三个设置。这三个设置的方法同 FSMC_BTRx 一模一样,只是这里对应的是写操作的时序,

(1)ACCMOD[1:0]:访问模式。00 模式A;01 模式B;10 模式C;11 模式D。

(2)DATAST[7:0]:数据保持时间,等于: DATAST(+1)个HCLK时钟周期,DATAST最大为255。考虑兼容性,对STM32F1,一个HCLK=13.8ns (1/72M),设置为3;对STM32F4,一个HCLK=6ns(1/168M) ,设置为9。

(3)ADDSET[3:0]:地址建立时间。表示:ADDSET+1个HCLK周期,ADDSET最大为15。

7. NOR/PSRAM访问参数

对于不同类型的存储器,地址建立时间、地址保持时间等参数可能不一样,这些是我们需要配置的,下图是STM32提供的一些时间的可配置范围。具体配置成多少我们还是要看对应的存储器的芯片手册的时序。

image-20230514172825795

五、HAL库函数

1. 库中的寄存器

在 MDK 的寄存器定义里面,并没有定义 FSMC_BCRx、 FSMC_BTRx、 FSMC_BWTRx 等这个单独的寄存器,而是将他们进行了一些组合。FSMC_BCRx 和 FSMC_BTRx,组合成 BTCR[8]寄存器组,他们的对应关系如下:

1
2
3
4
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],他们的对应关系如下:

1
2
3
BWTR[0]--->FSMC_BWTR1, BWTR[2]--->FSMC_BWTR2
BWTR[4]--->FSMC_BWTR3, BWTR[6]--->FSMC_BWTR4
BWTR[1]、 BWTR[3]和 BWTR[5]保留,没有用到

其实我们使用的是库函数,这里不需要太深究。

2. 初始化结构体

2.1 结构体定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct
{
uint32_t NSBank; // BANKx(NORSRAM)的区域(1-4)
uint32_t DataAddressMux; // 设置地址总线与数据总线是否复用,仅用于 NOR
uint32_t MemoryType; // 存储器类型
uint32_t MemoryDataWidth; // 数据宽度位数
uint32_t BurstAccessMode; // 设置是否使用突发访问模式,仅用于同步类型的存储器
uint32_t WaitSignalPolarity; // 等待信号的极性,仅用于同步类型的存储器
uint32_t WrapMode; // 设置是否支持把非对齐的突发操作,仅用于同步类型的存储器
uint32_t WaitSignalActive; // 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能 NWAIT,仅用于同步类型的存储器
uint32_t WriteOperation; // 存储器写使能
uint32_t WaitSignal; // 等待使能位,适用于突发模式访问
uint32_t ExtendedMode; // 是否启用扩展模式
uint32_t AsynchronousWait; // 是否使能异步传输模式下的等待信号
uint32_t WriteBurst; // 禁止突发写,适用于突发模式访问
uint32_t PageSize;
} FSMC_NORSRAM_InitTypeDef;

2.2 成员说明

(1)NSBank :用于选择 FSMC 映射的存储区域,它的可选参数以及相应的内核地址映射范围见表 :

image-20230520131132638

(2)DataAddressMux :用于设置地址总线与数据总线是否复用 (Enable /Disable),在控制 NOR FLASH 时,可以地址总线与数据总线可以分时复用,以减少使用STM32 信号线的数量。

(3)MemoryType :用于设置要控制的存储器类型,它支持控制的存储器类型为 SRAM、 PSRAM以及 NOR FLASH 。

(4)MemoryDataWidth :用于设置要控制的存储器的数据宽度,可选择设置成8或16位。

(5)BurstAccessMode :用于设置是否使用突发访问模式 ,突发访问模式是指发送一个地址后连续访问多个数据,非突发模式下每访问一个数据都需要输入一个地址,仅在控制同步类型的存储器时才能使用突发模式。

(6)WaitSignalPolarity :用于设置等待信号的有效极性,即要求等待时,使用高电平还是低电平。

(7)WrapMode :用于设置是否支持把非对齐的 AHB 突发操作分割成 2 次线性操作,该配置仅在突发模式下有效。

(8)WaitSignalActive :用于配置在突发传输模式时,决定存储器是在等待状态之前的一 个数据周期有效还是在等待状态期间有效。

(9)WriteOperation:用于设置是否写使能,禁止写使能的话 FSMC 只能从存储器中读取数据,不能写入。

(10)WaitSignal:用于设置当存储器处于突发传输模式时,是否允许通过 NWAIT 信号插入等待状态。

(11)ExtendedMode:用于设置是否使用扩展模式,在非扩展模式下,对存储器读写的时序都只使用 FSMC_BCR 寄存器中的配置;在扩展模式下,对存储器的读写时序可以分开配置,读时序使用 FSMC_BCR 寄存器,写时序使用 FSMC_BWTR 寄存器的配置。

(12)AsynchronousWait:用于设置是否使能在同步传输时使用的等待信号,在控制同步类型的 NOR 或 PSRAM时,存储器可以使用 FSMC_NWAIT 引脚通知 STM32 需要等待。

3. 时序控制结构体

3.1 结构体定义

1
2
3
4
5
6
7
8
9
10
typedef struct
{
uint32_t AddressSetupTime; // 地址建立时间 ADDSET 范围:0~15 (模式 A 需要设置)
uint32_t AddressHoldTime; // 地址保持时间 ADDHLD 范围:1~15,模式 A 未用到
uint32_t DataSetupTime; // 数据建立时间 DATAST 范围:1~255 (模式 A 需要设置)
uint32_t BusTurnAroundDuration; // 总线恢复时间 BUSTURN 范围:0~15,设置总线转换周期,仅用于复用模式的 NOR 操作
uint32_t CLKDivision; // 时钟分频因子 CLKDIV 范围:2~16,仅用于同步类型的存储器
uint32_t DataLatency; // 数据产生时间 ACCMOD 范围:2~17,仅用于 NOR
uint32_t AccessMode; // FSMC的模式
} FSMC_NORSRAM_TimingTypeDef;

3.2 成员说明

(1)AddressSetupTime :设置地址建立时间,即 FSMC 模式 A 的读时或者写时序 中的 ADDSET值,它可以被设置为 0-0xF 个 HCLK 周期数,按默认配置, HCLK 的时钟频率为 72MHz,即一个 HCLK 周期为 1/72 微秒。

(2)AddressHoldTime :设置地址保持时间,它可以被设置为 0-0xF 个 HCLK 周期数。

(3)DataSetupTime :设置数据建立时间,即 FSMC 模式 A 的读时序或者写时序 中的 DATAST值,它可以被设置为 0-0xF 个 HCLK 周期数。

(4)BusTurnAroundDuration :设置总线转换周期,在 NOR FLASH 存储器中,地址线与数据线可以分时复用,总线转换周期就是指总线在这两种状态间切换需要的延时,防止冲突。控制其它存储器时这个参数无效,配置为 0 即可。

(5) CLKDivision :设置时钟分频,它以 HCLK 时钟作为输入,经过 CLKDivision 分频后输出到 FSMC_CLK 引脚作为通讯使用的同步时钟。控制其它异步通讯的存储器时这个参数无效,配置为 0 即可。

(6)DataLatency :设置数据保持时间,它表示在读取第一个数据之前要等待的周期数,该周期指同步时钟的周期,本参数仅用于同步 NOR FLASH 类型的存储器,控制其它类型的存储器时,本参数无效。

(7)AccessMode :设置存储器访问模式,不同的模式下 FSMC 访问存储器地址时引脚输出的时序不一样,可选 FSMC_AccessMode_A/B/C/D 模式。一般来说控制 SRAM 时使用 A 模式。

3.3 时序参数的确定

在这个时序结构体配置中,由于我们要控制的是 SRAM,所以选择 FSMC 为模式 A,在该模式下配置 FSMC 的控制时序结构体中,实际上只有地址建立时间 FSMC_AddressSetupTime(即 ADDSET 的值)以及数据建立时间 ,FSMC_DataSetupTime(即 DATAST 的值)成员的配置值是有效的,其它 SRAM 没使用到的成员值全配置为 0 即可。而且,这些成员值使用的单位为: 1 个 HCLK 的时钟周期,而 HCLK 的时钟频率为 72MHz,对应每个时钟周期为 1/72 us。

  • 读时序参数要满足的条件
image-20230515223604789

从上边的时序图中,我们得到如下关系:

image-20230515223612792

根据 FSMC 配置表达式的配置要求把时间单位 1/72 微秒 (即 1000/72 纳秒) 代入,可求得 ADDSET= 0, DATAST=1 时即可符合要求。如:

1
2
tRC=ADDSET+1+DATAST+1+2 =( 0+1+1+1+2 )*1000/72 = 69 ns > 55 ns
tDOE=DATAST+1 = (1+1)*1000/72 = 27.7 > 25 ns

不过,经实验总结出该配置在连续读取多个数据的时候会出现问题,更正确的配置为 ADDSET=0,DATAST=2,而这样的配置与写时序是一致的

  • 写时序参数要满足的条件
image-20230515223752604

从上边的时序图中,我们得到如下关系:

image-20230515223802706

根据 FSMC 配置表达式的配置要求把时间单位 1/72 微秒 (即 1000/72 纳秒) 代入,可求得 ADDSET= 0, DATAST=2 时即可符合要求。如:

1
2
tWC = ADDSET+1+DATAST+1 =( 0+1+2+1 )*1000/72 = 55.555 ns > 55 ns
tPWB = DATAST+1 = (2+1) *1000/72 = 41.6666 > 40 ns

把计算得的参数赋值到时序结构体中的 FSMC_AddressSetupTime(即 ADDSET 的值)及FSMC_DataSetupTime(即 DATAST 的值)中,然后再把时序结构体作为指针赋值到下面的 FSMC初始化结构体中,作为读写的时序参数,最后再调用 FSMC_NORSRAMInit 函数即可把参数写入到相应的寄存器中。

后边在读写外部SRAM实例中还会详细去学习时间参数怎么确定。