目录
一.FSMC功能描述
1.FSMC:灵活的静态存储器控制器 (可以控制扩展的内存).
2.FSMC具有的静态存储器接口包括 :
─ 静态随机存储器(SRAM)
─ 只读存储器(ROM)
─ NOR闪存
─ PSRAM(4个存储器块)
(FSMC通过接口与相应的内存模块连接就可以控制相应的内存模块。)
二.FSMC框图
1.在野火指南者lcd的应用中只使用NOR/PSRAM信号和公用信号的引脚。
2.AHB 接口:
AHB接口为内部CPU和其它总线控制设备访问外部静态存储器提供了通道。
AHB操作被转换到外部设备的操作。当选择的外部存储器的数据通道是16或8位时,在AHB上的
32位数据会被分割成连续的16或8位的操作。
AHB时钟(HCLK)是FSMC的参考时钟。
(通俗理解:CPU通过AHB跟FSMS建立通信,FSMS又可以连接外部存储器,AHB上的数据位可以是8位,16位和32位,外部存储器接收或发送数据是固定的,FSMS可以对数据进行拼接和分割)
3.引脚作用:
FSMC信号名称 | 信号方向 | 功能 |
NE[X] | 输出 | 片选,x = 1...4 |
NL(=NADV) | 输出 | 锁存使能(某些NOR闪存器件命名该信号为地址有效,NADV) |
NBL[1] | 输出 | 高字节使能(存储器信号名称为:NUB) |
NBL[0] | 输出 | 低字节使能(存储器信号名称为:NLB |
CLK | 输出 | 时钟(同步突发模式使用) |
FSMC信号名称 | 信号方向 | 功能 |
A[25:0] | 输出 | 地址总线 |
D[15:0] | 输入/输出 | 双向数据总线 |
NOE | 输出 | 输出使能 |
NWE | 输出 | 写使能 |
NWAIT | 输入 | X闪存要求FSMC等待的信号,X=NOR,PSRAM... |
三.外部设备地址映像
1.从FSMC的角度看,可以把外部存储器划分为固定大小为256M字节的四个存储块
● 存储块1用于访问最多4个NOR闪存或PSRAM存储设备。这个存储区被划分为4个
NOR/PSRAM区并有4个专用的片选。
● 存储块2和3用于访问NAND闪存设备,每个存储块连接一个NAND闪存。
● 存储块4用于访问PC卡设备
每一个存储块上的存储器类型是由用户在配置寄存器中定义的
(野火指南者lcd中只用到了块1)
FSMC存储块:
FSMC通过时序来控制内存。
四.FSMC时序:
1.FSMC 外设支持输出多种不同的时序以便于控制不同的存储器,它具有 ABCD 四种模式,下面
仅针对控制异步 NOR FLASH 使用的模式 B 进行讲解。
FSMC 读 NOR FLASH 的时序图:
FSMC 写 NOR FLASH 的时序图:
2.野火指南者lcd中利用了, FSMC 模拟 8080 时序:
FSMC 模式 B 时序与 8080 时序对比
对比 FSMC NOR/PSRAM 中的模式 B 时序与 ILI9341 液晶控制器芯片使用的 8080 时
序可发现,这两个时序是十分相似的 (除了 FSMC 的地址线 A 和 8080 的 D/CX 线,可以说是完全一样)
1. 对于 FSMC 和 8080 接口,前四种信号线都是完全一样的,仅仅是 FSMC 的地址信号线 A[25:0] 与8080 的数据/命令选择线 D/CX 有区别。而对于 D/CX 线,它为高电平的时候表示数值,为低电平的时候表示命令,如果能使用 FSMC 的 A 地址线根据不同的情况产生对应的电平,那么就完
全可以使用 FSMC 来产生 8080 接口需要的时序了。
2.把 FSMC 的 A0 地址线 (也可以使用其它 A1/A2 等地址线) 与ILI9341 芯片 8080 接口的 *D/CX 信号线连接 ,那么当 A0 为高电平时 (即 D/CX 为高电平),数据线 D[15:0] 的信号会被 ILI9341 理解为数值,若 A0 为低电平时 (即 D/CX 为低电平),传输的信号则会被理解为命令
液晶屏的信号线及 8080 时序:
液晶屏引出的信号线说明:
这些信号线即 8080 通讯接口,X 的表示低电平有效,通讯的内容主要包括命令和显存数据.
1. 写命令时序由片选信号 CSX 拉低开始,对数据/命令选择信号线 D/CX 也置低电平表示写入的是命令地址,以写信号 WRX 为低读信号 ,RDX 为高表示数据传输方向为写入,同时,在数据线 D[17:0](或 D[15:0]) 输出命令地址,在第二个传输阶段传送的是命令的参数,所以 *D/CX 要置高电平 *,表示写入的是数据,数据是某些指令带有的参数。
2.当需要把像素数据写入 GRAM 时,过程很类似,把片选信号 CSX 拉低后,再把数据/命令选择信号线 D/CX 置为高电平,这时由 D[17:0] 传输的数据则会被 ILI9341 保存至它的 GRAM 中。
-
五.CubeMX配置FSMC的初始化过程:
六.FSMC初始化代码:
1.FSMC初始化配置函数 :
void MX_FSMC_Init(void)
{
FSMC_NORSRAM_HandleTypeDef hsram1;
SRAM_TimingTypeDef Timing = {0};
/** 执行SRAM1内存初始化顺序*/
hsram1.Instance = FSMC_NORSRAM_DEVICE; //基地址
hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; //扩展模式寄存器地址
/* hsram1.Init */
hsram1.Init.NSBank = FSMC_NORSRAM_BANK1; //设置要控制的块区域
hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; //设置地址总线与数据总线是否复用
hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_NOR ; //设置存储器的类型
hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; //设置存储器的数据宽度
hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; //设置是否支持突发访问模式
hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;//设置等待信号的极性
hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE; //设置是否支持对齐的突发模式
hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; //配置等待信号在等待前有效还是等待期间有效
hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; //设置是否写使能
hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; //设置是否使能等待状态插入
hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE; //设置是否使能扩展模式
hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; //设置是否使能等待信号
hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; //设置是否使能写突发操作
/* 时间设置 */
Timing.AddressSetupTime = 15; //地址建立时间
Timing.AddressHoldTime =15; //地址保持时间
Timing.DataSetupTime = 255; //数据建立时间
Timing.BusTurnAroundDuration = 10; //总线转换周期
Timing.CLKDivision = 16; //时钟分频因子
Timing.DataLatency = 2; //数据延迟时间
Timing.AccessMode = FSMC_ACCESS_MODE_A;
/* ExtTiming */
if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
{
Error_Handler( );
}
/** 断开NADV
*/
__HAL_AFIO_FSMCNADV_DISCONNECTED();
}
2.FSMC_GPIO初始化函数 :
static uint32_t FSMC_Initialized = 0;
/* FSMC初始化硬件层配置函数 */
static void HAL_FSMC_MspInit(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (FSMC_Initialized) {
return;
}
FSMC_Initialized = 1;
/* 使能时钟 */
__HAL_RCC_FSMC_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/** FSMC GPIO配置
PE7 ------> FSMC_D4
PE8 ------> FSMC_D5
PE9 ------> FSMC_D6
PE10 ------> FSMC_D7
PE11 ------> FSMC_D8
PE12 ------> FSMC_D9
PE13 ------> FSMC_D10
PE14 ------> FSMC_D11
PE15 ------> FSMC_D12
PD8 ------> FSMC_D13
PD9 ------> FSMC_D14
PD10 ------> FSMC_D15
PD11 ------> FSMC_A16
PD14 ------> FSMC_D0
PD15 ------> FSMC_D1
PD0 ------> FSMC_D2
PD1 ------> FSMC_D3
PD4 ------> FSMC_NOE
PD5 ------> FSMC_NWE
PD7 ------> FSMC_NE1
*/
/* GPIO_Init结构体 */
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14
|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* GPIO_Init结构体 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*配置GPIO引脚 :
PD12------>LCD_BL //控制背光
*/
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*配置GPIO引脚 :
PE1 ------>LCD_RST //控制复位
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP ;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
以上代码我存放在Gitee上:驱动模块: 平常练习中对一些,代码模块化处理https://gitee.com/xuji-group_0/driver-module.git
文件名为FSMC.