FSMC之NOR flash控制器学习笔记

本文详细介绍了STM32的FSMC控制器基础,包括其结构、内存映射、NOR/NAND存储配置,以及如何利用FSMC驱动LCD。重点讲解了LCD地址映射原理和软件配置步骤,适合STM32开发者深入理解外设操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、FSMC基础知识学习
FSMC,即灵活的静态存储控制器。
先看下面的FSMC框图。
图1
从上图可以了解到stm32内核访问FSMC控制器完全是通过AHB总线来实现,同时可以了解到FSMC内部有两个存储控制器,分别是NOR存储器、NAND/PC卡存储控制器,注意两个控制器公用FSMC地址线和数据线,而其中地址线26条,可以访问64MByte的内存,另外数据读写最多支持16位。
再来看看下面的内存映射图:
图2
上图展示了stm32寻址的1GB内存,这块内存的起始地址是0x60000000,结束地址是0x9FFFFFFF。而FSMC的四个BANK区映射到这块1GB的内存实现外部存储器接口,其中BANK1可以用来连接NOR、PSRAM、LCD等,BANK2~BANK3可以用来连接NAND Flash,BANK4可以用来连接PC Card。
|内部控制器 |BANK号|可管理地址范围|支持设备类型|配置寄存器||--|--|--|--|--||NOR Flash控制器|BANK1|0x6000,0000~0x6FFF,FFFF|SRAM/ROM/NOR Flash/PSRAM|FSMC_BCR1/2/3/4 FSMC_BTR1/2/3/4 FSMC_BWTR1/2/3/4 ||NAND Flash /PC Card控制器||||
从前面已经知道每个块有4个子区(region 1 ~ region 4),比如BANK1的四个子区内存分配如下:
图3
从stm32参考手册上的NOR/PSRAM地址映像介绍可以知道,HADDR是stm32内部AHB地址总线,HADDR[25:0]连接外部存储器地址FSMC_A[25:0],HADDR[26:27]对4个region分别寻址。地址线0–25刚好能访问64MB的内存,而地址线26–27又能用来区分BANK中的哪个子区。
特别注意的是,FSMC的数据总线可以配置成8/16位数据总线,当配置成16位数据总线外接16位存储器的时候,HADDR[25:1]映射到FSMC_A[24:0];当配置成8位的,HADDR[25:0]映射到FSMC_A[25:0]。
上面的这句话非常重要,在正点原子的LCD例程中,LCD当成16位外接存储器,而LCD的RS(命令/数据)控制引脚接在FSMC_A10,当FSMC_A10为0时,RS为0,写命令,反之为1,写数据。在例程上,可以看到以下这段:

//LCD地址结构体
typedef struct
{
	vu16 LCD_REG;
	vu16 LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A10作为数据命令区分线 	    
#define LCD_BASE        ((u32)(0x6C000000|0x7FE))
#define LCD             ((LCD_TypeDef *) LCD_BASE)

为什么RS接在A10上面,LCD的基地址就是在0x6C000000基址上偏移0x7FE呢?
首先来说一下,LCD视为16位外部存储器,故HADDR[25:1]是映射到FSMC_A[24:0]上的,这里注意到FSMC_A只有0~24这25位,表示有25根地址线,这次比较特殊了,每个地址上面的数据是2BYTE/Addr的,那么有多少个地址呢?就是2^ 25=33,554,432。地址乘以一个地址拥有的字节数就有:(2^25)*2=64MB,这不就还是等于一个region的内存。其实说白了就是因为我们在程序上写的这个偏移量0x7FE是针对HADDR来写的,在STM32内部会由于HADDR与FSMC_A的映射关系自动右移一位。所以确定地址的思路是,先在纸上写FSMC_A:

A24A23A10A9A8A7A6A5A4A3A2A1A0
XX0/1XXXXXXXXXX

然后将上面的右移一位变成HADDR:

D24D23D11D10D9D8D7D6D5D4D3D2D1D0
XX0/1XXXXXXXXXXX

这时,如果用的是BANK1.Region4外接这个LCD的话,写命令寻址应该是0x6C000000,写数据寻址应该是0x6C000800。
但是由于原子例程上是将命令和数据做成一个结构体,而我们知道,结构体的成员变量在内存中是对齐连续的。比如LCD_TypeDef类型的struct_Test变量,struct_Test.LCD_REG地址在0x2000000,那么struct_Test.LCD_RAM的地址就在0x2000002。同理,0x7FE是struct_Test.LCD_REG的地址,那么struct_Test.LCD_RAM的地址就是0x800了。这种切换方法可以借鉴借鉴。
二、软件配置FSMC驱动LCD
了解了FSMC的存储器控制基础知识,接下来了解下FSMC的软件配置。
不同的存储IC他们的时序是不一样的,特别是高低电平的持续时间,在NOR Flash控制器上,FSMC定义了6种模式和定义了三个主要时间参数:地址建立时间、数据建立时间、地址保持时间来支持外接存储器的访问。下面简单做了个表格记录异步突发情况下NOR FLASH控制器的几种模式特点(本章仅对NOR FLASH控制器做笔记)。
图5
NOR flash控制器中我们只需关心3个寄存器:BCRx、BTRx、BWTRx(x=1,2,3,4)。根据英文缩写字母可以知道BCR是控制寄存器,BTR和BWTR是时间相关的寄存器,只有在BCR寄存器中使能扩展模式,才能使用BWTR寄存器。可以阅读STM32参考手册了解寄存器详细知识,这里不总结了。
stm32标准库中FSMC的NOR flash控制器封装函数及相关结构体:

void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);

上面函数的形参是个结构体类型的指针变量,结构体类型如下:

typedef struct
{
  uint32_t FSMC_Bank;                /*!< Specifies the NOR/SRAM memory bank that will be used.
                                          This parameter can be a value of @ref FSMC_NORSRAM_Bank */

  uint32_t FSMC_DataAddressMux;      /*!< Specifies whether the address and data values are
                                          multiplexed on the databus or not. 
                                          This parameter can be a value of @ref FSMC_Data_Address_Bus_Multiplexing */

  uint32_t FSMC_MemoryType;          /*!< Specifies the type of external memory attached to
                                          the corresponding memory bank.
                                          This parameter can be a value of @ref FSMC_Memory_Type */

  uint32_t FSMC_MemoryDataWidth;     /*!< Specifies the external memory device width.
                                          This parameter can be a value of @ref FSMC_Data_Width */

  uint32_t FSMC_BurstAccessMode;     /*!< Enables or disables the burst access mode for Flash memory,
                                          valid only with synchronous burst Flash memories.
                                          This parameter can be a value of @ref FSMC_Burst_Access_Mode */
                                       
  uint32_t FSMC_AsynchronousWait;     /*!< Enables or disables wait signal during asynchronous transfers,
                                          valid only with asynchronous Flash memories.
                                          This parameter can be a value of @ref FSMC_AsynchronousWait */

  uint32_t FSMC_WaitSignalPolarity;  /*!< Specifies the wait signal polarity, valid only when accessing
                                          the Flash memory in burst mode.
                                          This parameter can be a value of @ref FSMC_Wait_Signal_Polarity */

  uint32_t FSMC_WrapMode;            /*!< Enables or disables the Wrapped burst access mode for Flash
                                          memory, valid only when accessing Flash memories in burst mode.
                                          This parameter can be a value of @ref FSMC_Wrap_Mode */

  uint32_t FSMC_WaitSignalActive;    /*!< Specifies if the wait signal is asserted by the memory one
                                          clock cycle before the wait state or during the wait state,
                                          valid only when accessing memories in burst mode. 
                                          This parameter can be a value of @ref FSMC_Wait_Timing */

  uint32_t FSMC_WriteOperation;      /*!< Enables or disables the write operation in the selected bank by the FSMC. 
                                          This parameter can be a value of @ref FSMC_Write_Operation */

  uint32_t FSMC_WaitSignal;          /*!< Enables or disables the wait-state insertion via wait
                                          signal, valid for Flash memory access in burst mode. 
                                          This parameter can be a value of @ref FSMC_Wait_Signal */

  uint32_t FSMC_ExtendedMode;        /*!< Enables or disables the extended mode.
                                          This parameter can be a value of @ref FSMC_Extended_Mode */

  uint32_t FSMC_WriteBurst;          /*!< Enables or disables the write burst operation.
                                          This parameter can be a value of @ref FSMC_Write_Burst */ 

  FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct; /*!< Timing Parameters for write and read access if the  ExtendedMode is not used*/  

  FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;     /*!< Timing Parameters for write access if the  ExtendedMode is used*/      
}FSMC_NORSRAMInitTypeDef;

注意到结构体成员变量有FSMC_NORSRAMTimingInitTypeDef类型的指针变量。FSMC_NORSRAMTimingInitTypeDef原型如下:

typedef struct
{
  uint32_t FSMC_AddressSetupTime;       /*!< Defines the number of HCLK cycles to configure
                                             the duration of the address setup time. 
                                             This parameter can be a value between 0 and 0xF.
                                             @note: It is not used with synchronous NOR Flash memories. */

  uint32_t FSMC_AddressHoldTime;        /*!< Defines the number of HCLK cycles to configure
                                             the duration of the address hold time.
                                             This parameter can be a value between 0 and 0xF. 
                                             @note: It is not used with synchronous NOR Flash memories.*/

  uint32_t FSMC_DataSetupTime;          /*!< Defines the number of HCLK cycles to configure
                                             the duration of the data setup time.
                                             This parameter can be a value between 0 and 0xFF.
                                             @note: It is used for SRAMs, ROMs and asynchronous multiplexed NOR Flash memories. */

  uint32_t FSMC_BusTurnAroundDuration;  /*!< Defines the number of HCLK cycles to configure
                                             the duration of the bus turnaround.
                                             This parameter can be a value between 0 and 0xF.
                                             @note: It is only used for multiplexed NOR Flash memories. */

  uint32_t FSMC_CLKDivision;            /*!< Defines the period of CLK clock output signal, expressed in number of HCLK cycles.
                                             This parameter can be a value between 1 and 0xF.
                                             @note: This parameter is not used for asynchronous NOR Flash, SRAM or ROM accesses. */

  uint32_t FSMC_DataLatency;            /*!< Defines the number of memory clock cycles to issue
                                             to the memory before getting the first data.
                                             The value of this parameter depends on the memory type as shown below:
                                              - It must be set to 0 in case of a CRAM
                                              - It is don't care in asynchronous NOR, SRAM or ROM accesses
                                              - It may assume a value between 0 and 0xF in NOR Flash memories
                                                with synchronous burst mode enable */

  uint32_t FSMC_AccessMode;             /*!< Specifies the asynchronous access mode. 
                                             This parameter can be a value of @ref FSMC_Access_Mode */
}FSMC_NORSRAMTimingInitTypeDef;

看右边的注释可以知道每个成员变量的作用。这里不再累述。
初始化FSMC步骤:
1.使能FSMC,AFIO,相关GPIO的时钟。
2.将相关GPIO口设置为复用推挽输出。
3.读和写时间参数的配置(地址建立时间,数据建立时间,地址保持时间):
配置FSMC_NORSRAMTimingInitTypeDef类型的结构体成员变量。
4.配置FSMC_NORSRAMInitTypeDef类型的结构体成员变量。
5.上面步骤完成后使用void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct)函数完成初始化,使用void FSMC_NORSRAMCmd(uint32_t FSMC_Bank, FunctionalState NewState)使能FSMC。
完成了上叙步骤,接下来就容易了,只是写指令,读写数据操作。
比如要读取LCD的ID,思路是得先告诉LCD,我想读ID,怎么告诉呢?发指令0xD3过去,只需LCD->REG = 0xD3。LCD收到该指令后会给回我想要的数据,此刻只需读,rec_ID = LCD->RAM;读完之后LCD->RAM就被刷新。同样的,要想在LCD显示屏上面显示东西,这时就是写Gram(显存),发送写Gram指令,然后突发访问写显示的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值