蓝桥杯嵌入式学习STM32之FSMC详解

我刚刚打标题才发现我好像一直打着蓝桥杯的名号写一些和比赛不是很有关的blog。
其实我早就感觉到了,我故意的
才不是为了骗访问量
好了言归正传

前排提醒,本BLOG是通过用FSMC控制LCD驱动为例讲解,并不是针对FSMC讲解


驱动原理

FSMC:灵活的静态储存控制器。
以下都是我个人的理解,可能不是很官方准确,但是绝对是人话!!!保证能看懂。
FSMC我感觉是意法半导体公司为了方便用户使用一些存储器比如SRAM ,NAND FLASH,NOR FLASH,PSRAM等等。(注意这里没有SDRAM,这个好像在4XX型号里有,反正103没有就对了。)
说起SDRAM我就想起了那段不好的回忆,当时因为FPGA比赛学这个,一节课睡了三次o( ̄▽ ̄)d~
你看到这里肯定会想了,MD,LCD又不是存储器,用个屁FSMC啊?!这个作者为了骗访问量简直丧尽天良,毫无羞耻心!

错!

这里LCD驱动还真能用FSCM,为啥呢?
因为LCD驱动的方式上一篇博客已经讲解过了。让我们来看看FSMC怎么驱动SRAM的叭。
FSMC驱动外部SRAM时,外部SRAM的控制一般有:地址线(如A0-A25)、数据线(如D0-D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。
你品,你细品!!
来看一下下面的表格

操控LCD需要的信号线 操控SRAM需要的信号线
RS ??
D0-D15 D0-D15
WR WE
RD OE
CS CS

你发现了什么?发现除了RS没有对应以外都有了对应。
这时,你可能会说:MD这不是还有一个没对应?走了走了,骗人的blog。

你没发现SRAM控制还有地址线没用么!这里有意思的来了,比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM操作的两个连续地址。
这里LCD就相当于有两个地址的SRAM!
所以我们可以通过FSMC驱动LCD。

驱动方法

STM32的FSMC将外部存储器分为4块。每块大小为256M字节
在这里插入图片描述
我们这里用第一块。
第一块里又被分成四个区…

STM32的FSMC存储块1(Bank1)用于驱动NOR FLASH/SRAM/PSRAM,被分为4个区,每个区管理64M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1的256M字节空间由28根地址线(HADDR[27:0])寻址。
这里HADDR,是内部AHB地址总线,其中,HADDR[25:0]来自外部存储器地址FSMC_A[25:0],而HADDR[26:27]对4个区进行寻址。如下表所示:
在这里插入图片描述
就是说这里28根地址线前两根已经固定是用来选择那个区的了。后面26根给外部存储器相连。
这里有一个地方要注意,虽然我也不知道啥意思,但是我查的很多资料都强调了这一点那我也不能例外,这叫专业
不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]
下面不是强调的内容啦
当Bank1接的是16位宽度存储器的时候:HADDR[25:1] -> FSMC_A[24:0]
当Bank1接的是8位宽度存储器的时候:HADDR[25:0] -> FSMC_A[25:0]
这里可能就有人要问了,你这8位一一对应我还能理解,你这16位咋要错位对应啊?

我的理解是这样子的:
网上说这叫字节寻址,不知道啥玩意儿
16位存储器,他每加一相当于加了两个字节,而我们内部都是8位的,它加一就加了一个字节。

16位存储器 8位存储器
0001(2字节) 0010(2字节)
0010(4字节) 0100(4字节)
0011(6字节) 0110(6字节)
0100(8字节) 1000(8字节)

下面我就不列举了,发现了没有,8位向右移一位(也就是除2)数值就和16位一样了。
所以要保证HADDR[25:0]和FSMC_A[24:0]代表的字节数一样的话,就要保证HADDR[25:0]右移一位和FSMC_A[24:0]一样。也就是HADDR[25:1] -> FSMC_A[24:0]一一对应。
你要是还不理解我就举个例子。
假如是甲国是16位存储器,他们这个国家以公斤为单位进行猪肉交易。
乙国是8位存储器,这个国家以斤为单位进行猪肉交易。
如果双方要进行贸易往来,交易一堆猪肉。
双方都量了一下猪肉的重量,要保证交易正确无误,那么甲国记录的猪肉重量(比如200)肯定是乙国记录的猪肉重量(这里是400)的一半。因为甲国是200公斤,乙国是400斤。

啊啊啊啊,累死我了,我好久没写这样的博客了,这个博客真的是为了教会别人东西而写的,我以前写博客是为我一个人写的,方便我以后来很快能回忆起知识点,在很多细枝末节上不会解释很多

寄存器设置

对于NOR FLASH/PSRAM控制器(存储块1),通过FSMC_BCRx、FSMC_BTRx和FSMC_BWTRx寄存器设置(其中x=1~4,对应4个区)。通过这3个寄存器,可以设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。

至于那些高低电平的时间参数看LCD的芯片手册!!(如下)
在这里插入图片描述

SRAM/NOR闪存片选控制寄存器(FSMC_BCRx)

在这里插入图片描述
EXTMOD:扩展模式使能位,控制是否允许读写不同的时序,需设置为1
WREN:写使能位。我们需要向TFTLCD写数据,故该位必须设置为1
MWID[1:0]:存储器数据总线宽度。00,表示8位数据模式;01表示16位数据模式;10和11保留。我们的TFTLCD是16位数据线,所以设置WMID[1:0]=01。
MTYP[1:0]:存储器类型。00表示SRAM、ROM;01表示PSRAM;10表示NOR FLASH;11保留。我们把LCD当成SRAM用,所以需要设置MTYP[1:0]=00。
MBKEN:存储块使能位。需设置为1

SRAM/NOR闪存片选时序寄存器(FSMC_BTRx)

在这里插入图片描述
ACCMOD[1:0]:访问模式。00:模式A;01:模式B;10:模式C;11:模式D。 (选A)
DATAST[7:0]:数据保持时间,等于: DATAST+1个HCLK时钟周期,DATAST最大为255。对ILI9341来说,其实就是RD低电平持续时间,最大为355ns。对STM32F1,一个HCLK=13.8ns (1/72M),设置为15。
ADDSET[3:0]:地址建立时间。表示:ADDSET +1个HCLK周期,ADDSET最大为15。对ILI9341来说,这里相当于RD高电平持续时间,为90ns。STM32F1的FSMC性能存在问题,即便设置为0,RD也有190ns的高电平,我们这里设置为1。(F103的性能问题,你退群把你)
如果未设置EXTMOD位,则读写共用这个时序寄存器!

SRAM/NOR闪存写时序寄存器(FSMC_BWTRx)

在这里插入图片描述
ACCMOD[1:0]:访问模式。00:模式A;01:模式B;10:模式C;11:模式D。
DATAST[7:0]:数据保持时间,等于: DATAST+1个HCLK时钟周期,DATAST最大为255。对ILI9341来说,其实就是WR低电平持续时间,为15ns,不过ILI9320等则需要50ns。考虑兼容性,对STM32F1,一个HCLK=13.8ns (1/72M),设置为3。
ADDSET[3:0]:地址建立时间。表示:ADDSET+1个HCLK周期,ADDSET最大为15。对ILI9341来说,这里相当于WR高电平持续时间,为15ns。同样考虑兼容ILI9320,对STM32F1,这里即便设置为1,WR也有100ns的高电平,我们这里设置为1。

其他说明

在ST官方库提供的的寄存器定义里面,并没有定义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]保留,没有用到。