一、前言
如图,这是一张系统架构图,数据传输过程中,会从存储器到存储器,外设到存储器,但是实际过程中芯片内部的RAM容量无法满足需求,所以会使用外设的RAM。并且如游戏有分辨率要求(正常流畅的分辨率30-60hz 高清电影达到144HZ)若分辨率高,则数据传输的速度也会快,所以此时引进了,FSMC(Flexible Static Memory Controller,灵活的静态存储器控制器),STM32可以通过FSMC与SRAM、ROM、PSRAM、Nor Flash和NandFlash存储器的引脚相连,从而进行数据的交换。要注意的是,FSMC 只能扩展静态的内存(S:static),不能是动态的内存,比如 SDRAM 就不能扩展。
FSMC把AHB总线上的数据转换为对应外设的通信协议,控制外设的访问时序,以至于我们可以直接在程序中寻址访问。
二、相关知识点介绍
2.1常见的存储器介绍
存储器是计算机结构的重要组成部分。存储器是用来存储程序代码和数据的部件,有了存储器计算机才具有记忆功能。
2.1.1RAM
(1) SRAM,Static Random-Access Memory,静态随机存取存储器,是RAM的一种。所谓的“静态”,是指这种存储器只要保持通电,里面储存的数据就可以恒常保持。
(2)动态随机存储器DRAM的存储单元以电容的电荷来表示数据,有电荷代表1,无电荷代表0。定期需要动态的吸收电荷。
2.1.2ROM
ROM 是“Read Only Memory”的缩写,意为只能读的存储器。由于技术的发展,后来设计出了可以方便写入数据的ROM,而这个“Read Only Memory”的名称被沿用下来了,现在一般用于指代非易失性半导体存储器,包括后面介绍的 FLASH 存储器
(1)MASK ROM
MASK(掩膜)ROM 就是正宗的“Read Only Memory”,存储在它内部的数据是在出厂时使用特殊工艺固化的,生产后就不可修改,
(2)PROM
PROM(ProgramableROM)为可编程ROM。但是只供用户写入一次。
(3)EPROM
EPROM(Erasable Programmable ROM)是可重复擦写的存储器,它解决了PROM芯片只能写入一次的问题。这种存储器使用紫外线照射(30分钟)芯片内部擦除数据,擦除和写入都要专用的设备。现在这种存储器基本淘汰,被EEPROM取代。
(4)EEPROM
EPROM(Electrically Erasable Programmable ROM)是电可擦除存储器。EEPROM可以重复擦写,它的擦除和写入都是直接使用电路控制,不需要再使用外部设备来擦写。而且可以按字节为单位修改数据,无需整个芯片擦除。现在主要使用的ROM芯片都是EEPROM。
(5)Flash
FLASH存储器又称为闪存,它也是可重复擦写的储器,部分书籍会把FLASH存储器称为 FLASH ROM,但它的容量一般比EEPROM大得多,且在擦除时,一般以多个字节为单位。
(6)磁盘
又称磁盘,是靠磁性来存储数据的。
2.2存储器映射
STM32中集成多种存储器(各种外设也需要分配地址),同一类型的存储器当作一组block,为每一个block分配一个数值连续、存储单元数相等、以16进制表示的自然数集合作为存储器Block的地址编码。这种自然数集合与存储器Block的对应关系就是存储器映射。
存储器映射其实就是将芯片理论上的地址分配给各个存储器。
需要注意的是:存储器映射并不是只针对SROM和片内Flash做地址映射,其实所有的片内外设(比如IO口)都需要地址,也都需要做映射。
2.3地址总线、数据总线、控制总线之间的关系
AHB 是 STM32 等 ARM 架构 MCU 的 “系统级总线架构”,而地址总线、数据总线是 AHB 架构中实现 “寻址” 和 “数据传输” 的核心组成部分,AHB 把地址、数据、控制信号封装成标准化的总线协议,统筹芯片内部的高速数据交互。
2.4 SMT32 具体存储器的映射图
芯片能访问的存储空间有多大,是由谁定的?这个是由芯片的地址总线的数量来决定的,STM32芯片内部的地址总线为32根。所以STM32有4G的地址空间。ARM把可访问的存储器空间分成8个主要块,每个块为512MB。
STM32芯片地址空间最大为4G,
将地址空间平均分为8份,每一份,称之为一块(Block),每一块的地址为512M
每一块地址空间有不同的用途,需要按照用途进行相关处理
- Block0 FLASH
2.block1 RAM
3.block2 外设
4 block 3 block4 block5
在Block3、Block4、Block5中包含了FSMC扩展区域,可用于扩展如 SRAM、NORFLASH 和NANDFLASH等的外部存储器。
2.5寄存器映射
给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
寄存器映射在ST提供的头文件stm32f10x.h中已经通过预编译的形式完全映射好了,以后如果再操作某个特定外设的时候,就不用直接操作地址,直接操作对应的寄存器名就可以了。
2.6FSMC数据操作流程
FSMC控制器主要控制1G的地址空间(Block3、Block4)
将地址空间分为4个区(Bank)
每个区扩展不同的设备,一个Bank区可以划分为4片,每一片为64M
三、HAL库实现案例
1 需求描述
使用FSMC扩展外部SRAM。然后把内存数据存储到外部SRAM中。
2 cubx实现
配置SYS、RCC、USART1
配置FSMC
3 vscode实现
四、相关寄存器了解
1.FSMC_BCR1...4 闪存片选控制寄存器
2.FSMC_BTR1..4 闪存时序寄存器
五、VACODE实现代码
主要代码是这几行,实现了初始化,但是具体引脚比较多,所以实际分函数进行配置
// FMSC的初始化
void Dri_FSMC_Init(void)
{
// GPIO的初始化 配置引脚
Dri_Gpio_Init();
// 寄存器的初始化 配置FSMC(寄存器)
Dri_FMSC_Init();
}
#include "FSMC.h" // GPIO的初始化 void Dri_Gpio_Init(void) { // 1 开时钟 // EDGF RCC->APB2ENR |= RCC_APB2ENR_IOPDEN; RCC->APB2ENR |= RCC_APB2ENR_IOPFEN; RCC->APB2ENR |= RCC_APB2ENR_IOPEEN; RCC->APB2ENR |= RCC_APB2ENR_IOPGEN; // 配置引脚 输出MODE 11 复用推勉10 // A0-A18 // D0-D15 // CS(NE3) ,NWE,NOE // UB(NBLI) ,LB(NBL0) // A0-A5 //! PF0-PF5 GPIOF->CRL |= GPIO_CRL_MODE0; GPIOF->CRL |= GPIO_CRL_CNF0_1; GPIOF->CRL &= ~GPIO_CRL_CNF0_0; GPIOF->CRL |= GPIO_CRL_MODE1; GPIOF->CRL |= GPIO_CRL_CNF1_1; GPIOF->CRL &= ~GPIO_CRL_CNF1_0; GPIOF->CRL |= GPIO_CRL_MODE2; GPIOF->CRL |= GPIO_CRL_CNF2_1; GPIOF->CRL &= ~GPIO_CRL_CNF2_0; GPIOF->CRL |= GPIO_CRL_MODE3; GPIOF->CRL |= GPIO_CRL_CNF3_1; GPIOF->CRL &= ~GPIO_CRL_CNF3_0; GPIOF->CRL |= GPIO_CRL_MODE4; GPIOF->CRL |= GPIO_CRL_CNF4_1; GPIOF->CRL &= ~GPIO_CRL_CNF4_0; GPIOF->CRL |= GPIO_CRL_MODE5; GPIOF->CRL |= GPIO_CRL_CNF5_1; GPIOF->CRL &= ~GPIO_CRL_CNF5_0; // A6-A9 // PF12-PF15 GPIOF->CRH |= GPIO_CRH_MODE12; GPIOF->CRH |= GPIO_CRH_CNF12_1; GPIOF->CRH &= ~GPIO_CRH_CNF12_0; GPIOF->CRH |= GPIO_CRH_MODE13; GPIOF->CRH |= GPIO_CRH_CNF13_1; GPIOF->CRH &= ~GPIO_CRH_CNF13_0; GPIOF->CRH |= GPIO_CRH_MODE14; GPIOF->CRH |= GPIO_CRH_CNF14_1; GPIOF->CRH &= ~GPIO_CRH_CNF14_0; GPIOF->CRH |= GPIO_CRH_MODE15; GPIOF->CRH |= GPIO_CRH_CNF15_1; GPIOF->CRH &= ~GPIO_CRH_CNF15_0; // A10-A15 // pg0-pg5 GPIOG->CRL |= GPIO_CRL_MODE0; GPIOG->CRL |= GPIO_CRL_CNF0_1; GPIOG->CRL &= ~GPIO_CRL_CNF0_0; GPIOG->CRL |= GPIO_CRL_MODE1; GPIOG->CRL |= GPIO_CRL_CNF1_1; GPIOG->CRL &= ~GPIO_CRL_CNF1_0; GPIOG->CRL |= GPIO_CRL_MODE2; GPIOG->CRL |= GPIO_CRL_CNF2_1; GPIOG->CRL &= ~GPIO_CRL_CNF2_0; GPIOG->CRL |= GPIO_CRL_MODE3; GPIOG->CRL |= GPIO_CRL_CNF3_1; GPIOG->CRL &= ~GPIO_CRL_CNF3_0; GPIOG->CRL |= GPIO_CRL_MODE4; GPIOG->CRL |= GPIO_CRL_CNF4_1; GPIOG->CRL &= ~GPIO_CRL_CNF4_0; GPIOG->CRL |= GPIO_CRL_MODE5; GPIOG->CRL |= GPIO_CRL_CNF5_1; GPIOG->CRL &= ~GPIO_CRL_CNF5_0; // A16-A18 // PD11-PD13 GPIOD->CRH |= GPIO_CRH_MODE11; GPIOD->CRH |= GPIO_CRH_CNF11_1; GPIOD->CRH &= ~GPIO_CRH_CNF11_0; GPIOD->CRH |= GPIO_CRH_MODE12; GPIOD->CRH |= GPIO_CRH_CNF12_1; GPIOD->CRH &= ~GPIO_CRH_CNF12_0; GPIOD->CRH |= GPIO_CRH_MODE13; GPIOD->CRH |= GPIO_CRH_CNF13_1; GPIOD->CRH &= ~GPIO_CRH_CNF13_0; // D0 D1 // PD14 PD15 GPIOD->CRH |= GPIO_CRH_MODE14; GPIOD->CRH |= GPIO_CRH_CNF14_1; GPIOD->CRH &= ~GPIO_CRH_CNF14_0; GPIOD->CRH |= GPIO_CRH_MODE15; GPIOD->CRH |= GPIO_CRH_CNF15_1; GPIOD->CRH &= ~GPIO_CRH_CNF15_0; // D2-D3 // PD0 PD1 GPIOD->CRL |= GPIO_CRL_MODE0; GPIOD->CRL |= GPIO_CRL_CNF0_1; GPIOD->CRL &= ~GPIO_CRL_CNF0_0; GPIOD->CRL |= GPIO_CRL_MODE1; GPIOD->CRL |= GPIO_CRL_CNF1_1; GPIOD->CRL &= ~GPIO_CRL_CNF1_0; // D4-D12 // PE7-PE15 GPIOE->CRL |= GPIO_CRL_MODE7; GPIOE->CRL |= GPIO_CRL_CNF7_1; GPIOE->CRL &= ~GPIO_CRL_CNF7_0; GPIOE->CRH |= GPIO_CRH_MODE8; GPIOE->CRH |= GPIO_CRH_CNF8_1; GPIOE->CRH &= ~GPIO_CRH_CNF8_0; GPIOE->CRH |= GPIO_CRH_MODE9; GPIOE->CRH |= GPIO_CRH_CNF9_1; GPIOE->CRH &= ~GPIO_CRH_CNF9_0; GPIOE->CRH |= GPIO_CRH_MODE10; GPIOE->CRH |= GPIO_CRH_CNF10_1; GPIOE->CRH &= ~GPIO_CRH_CNF10_0; GPIOE->CRH |= GPIO_CRH_MODE11; GPIOE->CRH |= GPIO_CRH_CNF11_1; GPIOE->CRH &= ~GPIO_CRH_CNF11_0; GPIOE->CRH |= GPIO_CRH_MODE12; GPIOE->CRH |= GPIO_CRH_CNF12_1; GPIOE->CRH &= ~GPIO_CRH_CNF12_0; GPIOE->CRH |= GPIO_CRH_MODE13; GPIOE->CRH |= GPIO_CRH_CNF13_1; GPIOE->CRH &= ~GPIO_CRH_CNF13_0; GPIOE->CRH |= GPIO_CRH_MODE14; GPIOE->CRH |= GPIO_CRH_CNF14_1; GPIOE->CRH &= ~GPIO_CRH_CNF14_0; GPIOE->CRH |= GPIO_CRH_MODE15; GPIOE->CRH |= GPIO_CRH_CNF15_1; GPIOE->CRH &= ~GPIO_CRH_CNF15_0; // D13-D15 // PD8-PD10 GPIOD->CRH |= GPIO_CRH_MODE8; GPIOD->CRH |= GPIO_CRH_CNF8_1; GPIOD->CRH &= ~GPIO_CRH_CNF8_0; GPIOD->CRH |= GPIO_CRH_MODE9; GPIOD->CRH |= GPIO_CRH_CNF9_1; GPIOD->CRH &= ~GPIO_CRH_CNF9_0; GPIOD->CRH |= GPIO_CRH_MODE10; GPIOD->CRH |= GPIO_CRH_CNF10_1; GPIOD->CRH &= ~GPIO_CRH_CNF10_0; // CS(NE3) ,NWE,NOE //PG10 PD5 PD4 GPIOG->CRH |= GPIO_CRH_MODE10; GPIOG->CRH |= GPIO_CRH_CNF10_1; GPIOG->CRH &= ~GPIO_CRH_CNF10_0; GPIOD->CRL |= GPIO_CRL_MODE4; GPIOD->CRL |= GPIO_CRL_CNF4_1; GPIOD->CRL &= ~GPIO_CRL_CNF4_0; GPIOD->CRL |= GPIO_CRL_MODE5; GPIOD->CRL |= GPIO_CRL_CNF5_1; GPIOD->CRL &= ~GPIO_CRL_CNF5_0; // UB(NBLI) ,LB(NBL0) //PE1 PE0 GPIOE->CRL |= GPIO_CRL_MODE0; GPIOE->CRL |= GPIO_CRL_CNF0_1; GPIOE->CRL &= ~GPIO_CRL_CNF0_0; GPIOE->CRL |= GPIO_CRL_MODE1; GPIOE->CRL |= GPIO_CRL_CNF1_1; GPIOE->CRL &= ~GPIO_CRL_CNF1_0; } // v寄存器的初始化 void Dri_FMSC_Init(void) { // 开时钟 RCC->AHBENR |= RCC_AHBENR_FSMCEN; // 配置引脚 BCR3 第四位 BTR3 5 FSMC_Bank1->BTCR[4] |= FSMC_BCR3_WREN; //写使能位 FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_FACCEN; //闪存访问 禁止访问FLASH FSMC_Bank1->BTCR[4] |= FSMC_BCR3_MWID_0; //总线宽度是16位 FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MWID_1; FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MTYP; //存储器类型SRAM FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MUXEN; //数据复位使能 不复位 FSMC_Bank1->BTCR[4] |= FSMC_BCR3_MBKEN; //存储器快使能位 FSMC_Bank1->BTCR[5] &= ~FSMC_BTR3_ADDSET; //地址建立时间 1个周期 FSMC_Bank1->BTCR[5] |= (71 << 8); } // FMSC的初始化 void Dri_FSMC_Init(void) { // GPIO的初始化 配置引脚 Dri_Gpio_Init(); // 寄存器的初始化 配置FSMC(寄存器) Dri_FMSC_Init(); }主函数中同HAL库中测试代码