2. MCU存储器接口基础:FSMC/FMC接口原理、地址线与数据线映射、时序参数

各位同学,咱们今天聊聊MCU怎么跟外部存储器打交道。说白了,就是MCU内部那点RAM和Flash不够用了,得外挂一片SRAM、NOR Flash或者NAND Flash。这时候,FSMC(Flexible Static Memory Controller)或者FMC(Flexible Memory Controller)就派上用场了。

我个人习惯把FSMC/FMC看作是MCU的“外交官”——它负责把MCU内核的访问请求,翻译成外部存储器能听懂的电信号。你想想看,内核要读一个地址的数据,它只需要告诉FSMC:“我要读0x6000 0000这个地址”。剩下的地址建立、数据采样、时序控制,全是FSMC帮你搞定。

2.1 FSMC/FMC接口原理

FSMC和FMC本质上是一回事。ST早期的STM32叫FSMC,后来在F4/H7系列上改名叫FMC,功能更强了一些,但核心思想没变。它们都支持三种存储器类型:SRAM/PSRAM、NOR Flash、NAND Flash。我这里重点讲SRAM和NOR Flash,因为这是工业现场用得最多的。

接口原理其实不复杂。FSMC内部有一个地址生成器、一个数据缓冲器,还有一套时序状态机。当CPU发起一次外部访问时,FSMC会按照你配置好的时序参数,依次拉低片选信号(NEx)、输出地址、输出控制信号(NWE写使能、NOE读使能),然后在数据线上读写数据。

核心要点:FSMC把外部存储器映射到MCU的地址空间中。你操作一个外部地址,就像操作内部SRAM一样简单。比如你定义了一个指针 uint16_t *p = (uint16_t *)0x60000000;,然后 *p = 0x55AA;,FSMC就会自动完成所有时序操作。

我记得有一次调试一个工业数据采集板,外挂了一片512KB的SRAM。程序跑起来后,往SRAM里写数据再读回来,发现某些地址的数据总是错的。查了半天,最后发现是FSMC的地址线映射搞错了——我把A0接到了SRAM的A1上,导致地址错位。嗯,这种低级错误,犯过一次就再也不会忘了。

2.2 地址线与数据线映射

地址线和数据线的映射,是FSMC/FMC接口设计中最容易出问题的地方。我见过不少工程师在这里翻车。

先讲数据线。FSMC的数据总线宽度可以配置为8位、16位或32位。如果你用的是16位宽的SRAM,那就用FSMC的D[15:0];如果是8位,就用D[7:0]。这个没什么好说的,一一对应就行。

地址线就有点讲究了。对于16位宽的外部存储器,FSMC内部的地址线A[25:0]对应的是字节地址。但外部SRAM的地址线A[18:0]通常是以16位字为单位的。所以,FSMC的A0实际上没有连接到外部SRAM,而是用A1连接外部SRAM的A0,A2连接A1,以此类推。

避坑指南:我曾经遇到过一位同事,他把FSMC的A0直接连到了SRAM的A0上,结果发现读出来的数据总是错位。原因就是:对于16位宽的存储器,FSMC内部会自动将地址右移一位。你写0x6000 0000,FSMC实际输出的地址是0x3000 0000(右移了一位)。所以硬件连接上,FSMC的A1必须接SRAM的A0。

下面我画了一张图,帮你理清FSMC与外部SRAM的连接关系:

MCU (STM32F4) FSMC 控制器 A[25:1] → D[15:0] ↔ NEx (片选) → NWE (写使能) → NOE (读使能) → 外部 SRAM IS62WV51216 ← A[18:0] ↔ D[15:0] ← CE# (片选) ← WE# (写使能) ← OE# (读使能) 注意:FSMC的A1连接SRAM的A0 FSMC的A2连接SRAM的A1,以此类推 图2-1 FSMC与外部SRAM连接示意图

这张图里,我特意标出了地址线的偏移关系。FSMC的A[25:1]对应SRAM的A[18:0],因为FSMC内部已经帮你把最低位A0处理掉了。对于8位宽的存储器,A0是有效的,直接连接即可。

2.3 时序参数:建立时间、保持时间、访问周期

时序参数是FSMC配置中最关键的部分,也是坑最多的地方。说白了,就是你要告诉FSMC:外部存储器需要多长时间才能准备好数据。

三个核心参数:

  • 建立时间(Setup Time):地址和控制信号稳定后,到片选信号有效之间的时间。我习惯叫它“给存储器一点准备时间”。
  • 保持时间(Hold Time):数据采样完成后,地址和控制信号还需要维持的时间。相当于“别急着撤,让存储器把数据送稳”。
  • 访问周期(Access Cycle):从片选有效到数据有效的时间。这是存储器的核心参数,数据手册上一定会标。

为什么会这样?因为外部存储器是慢速设备,MCU是高速设备。MCU的主频可能跑到168MHz甚至更高,但外部SRAM的访问时间可能只有55ns或70ns。如果不做时序匹配,MCU读到的数据就是错的。

警告:时序参数配置过紧,会导致数据读写出错;配置过松,会降低系统性能。我见过有人把时序配得特别宽松,结果系统跑起来慢得像蜗牛。工业现场对实时性要求高,这种浪费是不能接受的。

下面是一个典型的FSMC时序配置表,以STM32F4系列驱动IS62WV51216(55ns SRAM)为例:

参数名称 FSMC寄存器位 推荐值 说明
地址建立时间 ADDSET[3:0] 0x1 (2个HCLK周期) 地址信号稳定到NEx有效
数据建立时间 DATAST[7:0] 0x4 (5个HCLK周期) NEx有效到数据采样
总线恢复时间 BUSTURN[3:0] 0x0 (1个HCLK周期) 两次访问之间的间隔
保持时间 (由HCLK自动保证) 1个HCLK周期 数据采样后地址保持

这里HCLK是FSMC的工作时钟,通常等于AHB总线时钟。如果HCLK=168MHz,一个周期约5.95ns。那么地址建立时间就是2×5.95≈11.9ns,数据建立时间是5×5.95≈29.75ns。加起来约41.65ns,小于SRAM的55ns访问时间,留有一定余量。

个人经验:我一般会把时序参数配置得比理论计算值多1-2个HCLK周期。为什么?因为PCB走线会有延迟,温度变化也会影响时序。我曾经在一个高温老化测试中,发现SRAM偶尔读错数据,就是因为时序余量留得太少。后来加了一个HCLK周期,问题就解决了。记住:工业现场,稳定第一,性能第二。

最后,我建议你在调试FSMC时,先用逻辑分析仪抓一下波形。看看片选信号、地址信号、数据信号之间的时序关系是否满足存储器的要求。不要完全相信理论计算,实际波形才是王道。

嗯,关于FSMC/FMC接口的基础知识,就讲到这里。下一节我们会深入具体的驱动代码实现,到时候我会带着你一步步配置寄存器、编写读写函数。


公众号:蓝海资料掘金营,微信deep3321