STM32 FSMC/FMC原理保姆级讲解
Posted Z小旋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 FSMC/FMC原理保姆级讲解相关的知识,希望对你有一定的参考价值。
上一话我们说了FSMC的基本原理及控制逻辑,这一讲我们来说下FSMC如何通过HAL库来进行配置,及具体参数
FSMC的初始化
在使用SRAM之前,我们需要对SRAM使用的FSMC BANK进行参数配置,使之与SRAM芯片的要求相符合。
FSMC所占用的引脚初始化
在STM32技术手册中,针对FSMC引脚的GPIO模式配置,已经进行了说明,具体FSMC总线配置方法如下。下表指的是整个FSMC接口的引脚初始化配置说明,应该根据实际初始化相关的引脚。
完成FSMC引脚初始化后,要配置可编程存储器的参数,包括时序,是否支持非对齐访问和等待周期管理(只针对突发模式访问PSRAM和NOR闪存)
这个我们在上一讲也都提到过了,具体来看下 其中
- 地址建立,地址保存,数据建立 这三个设置是异步存储器专属的
- 总线周转是每次操作的间隔时间
- 时钟分频比和数据延迟是同步存储器的
下面我们来看库函数中的FSMC:
如果是F1系列:FSMC 相关的库函数分布在 stm32f1xx_II_fsmc.c 文件和头文件 stm32f1xx_II_fsmc.h 中。
如果是F4系列:FSMC 相关的库函数分布在 stm32f4xx_fsmc.c 文件和头文件 stm32f4xx_fsmc.h 中。
在.h文件中,一共有几个结构体,我们来看一下:
FSMC_NORSRAMTimingInitTypeDef类型
FSMC_NORSRAMInitTypeDef类型
FSMC_NAND_PCCARDTimingInitTypeDef类型
FSMC_NANDInitTypeDef类型
FSMC_PCCARDInitTypeDef类型
这五种类型对应五种不同的存储器,看名字就可以知道
也就是有这五种不同存储器的结构体初始化,但是我们现在主流的都开始使用HAL库了,所以这里我们对标准库做个了解就好,
具体的我们以HAL库配置讲解
FSMC 接口支持多种存储器,包括 SDRAM,NOR,NAND 和 PC CARD等。HAL 库为每种支持的存储器类型都定义了一个独立的 HAL 库文件,并且在文件中定义了独立的初始化函数,这里我们就列出几种存储器的初始化函数:
HAL_SRAM_Init();//SRAM 初始化函数,省略入口参数
HAL_SDRAM_Init();//SDRAM 初始化函数,省略入口参数
HAL_NOR_Init();//NOR 初始化函数,省略入口参数
HAL_NAND_Init();//NAND 初始化函数,省略入口参数
我们以异步SRAM,hal库来说下具体的初始化流程:
HAL库中函数配置在stm32f1xx_hal_sram.c跟stm32f1xx_hal_sram.h中
这两个文件对stm32f1xx_II_fsmc.c跟stm32f1xx_II_fsmc.h中的函数做了封装,然后生成了HAL库
FSMC初始化顺序
这里我们先说下FSMC的总体初始化顺序:
- 使能 FSMC 和 GPIO 时钟,初始化 IO 口配置,设置映射关系
- 设置FSMC基本参数初始化
- 设置FSMC读时序/写时序初始化
- FSMC初始化函数
FSMC硬件层初始化
STM32的管脚排列很没有规律,而且分布在多个不同端口上,初始化要十分小心.需要用到的引脚都要先初始化成”复用功能推挽输出”模式.(GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP )
并且开启时钟 (RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE); )
使能 FSMC 和 GPIO 时钟,初始化 IO 口配置,设置映射关系
IO口的使能引脚较多,看上面的引脚模式配置即可,这里不再过多阐述。
FSMC 时钟使能:
__HAL_RCC_FSMC_CLK_ENABLE(); //使能 FSMC 时钟
void FSMC_SRAM_MspInit(void)
GPIO_InitTypeDef GPIO_Init_Structure;
/* Enable FMC clock */
__HAL_RCC_FSMC_CLK_ENABLE();
/* Enable GPios clock */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/* Common GPIO configuration */
GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP;
GPIO_Init_Structure.Pull = GPIO_PULLUP;
GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH;
/* 地址线:F0---F5,F12---F15,G0---G5,D11---D13;
数据信号线;D0,D1,D8---D10,D14,D15,E7---E15;
CS片选:G10;
WE写使能:D5;
OE读使能;D4;
UB数据掩码;E1;
LB数据掩码;E0;
*/
/* GPIOD configuration */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 |\\
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 |\\
GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOD, &GPIO_Init_Structure);
/* GPIOE configuration */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | 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;
HAL_GPIO_Init(GPIOE, &GPIO_Init_Structure);
/* GPIOF configuration */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\\
GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOF, &GPIO_Init_Structure);
/* GPIOG configuration */
GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\\
GPIO_PIN_5 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOG, &GPIO_Init_Structure);
初始化 FMC 接口读写时序参数
在完成硬件的MSP初始化之后,就要初始化SRAM了,使用的函数为 HAL_SRAM_Init
HAL_SRAM_Init(SRAM_HandleTypeDef *hsram,
FSMC_NORSRAM_TimingTypeDef *Timing,
FSMC_NORSRAM_TimingTypeDef *ExtTiming;
该函数有三个入口参数,
- 第一个参数 hsram,它是SRAM_HandleTypeDef 结构体指针类型 设置SRAM的基本参数
- 第二个参数 Timing 设置NORSRAM存储器的读时序
- 第三个参数 ExtTiming 设置NORSRAM存储器的写时序
初始化 FMC 接口基本参数
我们使用的结构体为:SRAM_HandleTypeDef
结构体 SRAM_HandleTypeDef 定义如下:
typedef struct
FMC_NORSRAM_TypeDef *Instance; //寄存器基地址
FMC_NORSRAM_EXTENDED_TypeDef *Extended; //扩展模式寄存器基地址
FMC_NORSRAM_InitTypeDef Init;
HAL_LockTypeDef Lock;
__IO HAL_SRAM_StateTypeDef State;
DMA_HandleTypeDef *hdma;
SRAM_HandleTypeDef;
- Instance: 寄存器基地址,如果读写时序一样则配置基地址就行
- Extended 扩展模式寄存器基地址 也就是读写时序不同的时候, 指定写操作时序寄存器地址
- FMC_NORSRAM_InitTypeDef Init 是 FSMC_NORSRAM_InitTypeDef 结构体指针类型,是真正用来设置 SRAM 控制接口参数的
- 成员变量 Lock 和 State 是 HAL 库处理状态标识变量
- 成员变量 hdma 在使用 DMA 时候才使用
也就是我们只需要关心前三个参数,最主要的是第三个Init ,我们来看下:
/**
* @brief FSMC NOR/SRAM Init structure definition
*/
typedef struct
uint32_t NSBank; /*设置要控制的 Bank 区域 */
uint32_t DataAddressMux; /*设置地址总线与数据总线是否复用 */
uint32_t MemoryType; /*设置存储器的类型 */
uint32_t MemoryDataWidth; /*设置存储器的数据宽度*/
uint32_t BurstAccessMode; /*设置是否支持突发访问模式,只支持同步类型的存储器 */
uint32_t WaitSignalPolarity; /*设置等待信号的极性*/
uint32_t WrapMode; /*设置是否支持对齐的突发模式 */
uint32_t WaitSignalActive; /*配置等待信号在等待前有效还是等待期间有效 */
uint32_t WriteOperation; /*设置是否写使能 */
uint32_t WaitSignal; /*设置是否使能等待状态插入 */
uint32_t ExtendedMode; /*设置是否使能扩展模式 */
uint32_t WriteBurst; /*设置是否使能写突发操作*/
uint32_t AsynchronousWait; /*设置是否使能等待信号*/
uint32_t PageSize; /*指定页的大小*/
FSMC_NORSRAM_InitTypeDef;
-
NSBank 用来指定使用到的存储块区号,
-
DataAddressMux 用来设置是否使能地址/数据复用,该变量仅对 NOR/PSRAM 有 效
-
MemoryType 用来设置存储器类型
-
MemoryDataWidth用来设置存储器数据总线宽度,可选 8 位还是 16 位,
-
WriteOperation 用来设置存储器写使能,也就是是否允许写入。毫无疑问我们会进行存储器写操作
-
ExtendedMode 用来设置是否使能扩展模式,也就是是否允许读写使用不同时序
-
ContinuousClock 用来设置启用/禁止 FSMC 时钟输出到外部存储设备 ,
其他参数 WriteBurst,BurstAccessMode,WaitSignalPolarity,WrapMode,WaitSignalActive,WaitSignal,AsynchronousWait 等是用在突发访问和同步时序情况下,这里我们不做过多讲解。
然后我们来看下其中每个参数的配置如下:
在stm32f1xx_II_fsmc.h中
- uint32_t NSBank
用于设置使用的 BANK,片选 NE1 对于 BANK1,片选 NE2 对应 BANK2,片选 NE3 对应 BANK3,NE4 对应 BANK4
#define FSMC_NORSRAM_BANK1 ((uint32_t)0x00000000U)
#define FSMC_NORSRAM_BANK2 ((uint32_t)0x00000002U)
#define FSMC_NORSRAM_BANK3 ((uint32_t)0x00000004U)
#define FSMC_NORSRAM_BANK4 ((uint32_t)0x00000006U)
- uint32_t DataAddressMux
用于设置地址线和数据线复用,可以选择使能或者禁止:
#define FSMC_DATA_ADDRESS_MUX_DISABLE ((uint32_t)0x00000000U)
#define FSMC_DATA_ADDRESS_MUX_ENABLE ((uint32_t)0x00000002U)
- uint32_t MemoryType
用于设置使用的存储器类型,具体支持的参数如下:
#define FSMC_MEMORY_TYPE_SRAM ((uint32_t)0x00000000U)
#define FSMC_MEMORY_TYPE_PSRAM ((uint32_t)0x00000004U)
#define FSMC_MEMORY_TYPE_NOR ((uint32_t)0x00000008U)
- uint32_t MemoryDataWidth
用于设置外接的存储器位宽,具体支持的参数如下:
#define FSMC_NORSRAM_MEM_BUS_WIDTH_8 ((uint32_t)0x00000000U)
#define FSMC_NORSRAM_MEM_BUS_WIDTH_16 ((uint32_t)0x00000010U)
#define FSMC_NORSRAM_MEM_BUS_WIDTH_32 ((uint32_t)0x00000020U)
- uint32_t BurstAccessMode
用于使能或者禁止突发模式,仅用于支持同步突发的存储器,具体支持的参数如下:
#define FSMC_BURST_ACCESS_MODE_DISABLE ((uint32_t)0x00000000U)
#define FSMC_BURST_ACCESS_MODE_ENABLE ((uint32_t)0x00000100U)
- uint32_t WaitSignalPolarity
用于设置等待信号的极性,仅当使能突发模式时有效,具体支持的参数如下:
#define FSMC_WAIT_SIGNAL_POLARITY_LOW ((uint32_t)0x00000000U)
#define FSMC_WAIT_SIGNAL_POLARITY_HIGH ((uint32_t)0x00000200U)
- uint32_t WrapMode
设置是否支持支持对齐的突发模式,如果不是突发模式就不需要设置
#define FSMC_WRAP_MODE_DISABLE ((uint32_t)0x00000000U)
#define FSMC_WRAP_MODE_ENABLE ((uint32_t)0x00000400U)
- uint32_t WaitSignalActive
用于在等待状态之前或等待状态期间,存储器是否在一个时钟周期内置位等待信号,仅当使能突发模
式时有效,具体支持的参数如下:
#define FSMC_WAIT_TIMING_BEFORE_WS ((uint32_t)0x00000000U)
#define FSMC_WAIT_TIMING_DURING_WS ((uint32_t)0x00000800U)
- uint32_t WriteOperation
用于使能或者禁止写保护,具体支持的参数如下:
#define FSMC_WRITE_OPERATION_DISABLE ((uint32_t)0x00000000U)
#define FSMC_WRITE_OPERATION_ENABLE ((uint32_t)0x00001000U)
- uint32_t WaitSignal
用于使能或者禁止通过等待信号来插入等待状态,仅当使能突发模式时有效,具体支持的参数如下:
#define FSMC_WAIT_SIGNAL_DISABLE ((uint32_t)0x00000000U)
#define FSMC_WAIT_SIGNAL_ENABLE ((uint32_t)0x00002000U)
- uint32_t ExtendedMode
用于使能或者禁止扩展模式,具体支持的参数如下:
#define FSMC_EXTENDED_MODE_DISABLE ((uint32_t)0x00000000U)
#define FSMC_EXTENDED_MODE_ENABLE ((uint32_t)0x00004000U)
- uint32_t WriteBurst
用于使能或者禁止异步的写突发操作:
#define FSMC_WRITE_BURST_DISABLE ((uint32_t)0x00000000U)
#define FSMC_WRITE_BURST_ENABLE ((uint32_t)0x00080000U)
- uint32_t AsynchronousWait
用于异步传输期间,使能或者禁止等待信号,仅操作异步存储器有效,具体支持的参数如下:
#define FSMC_ASYNCHRONOUS_WAIT_DISABLE ((uint32_t)0x00000000U)
#define FSMC_ASYNCHRONOUS_WAIT_ENABLE ((uint32_t)0x00008000U)
◆ uint32_t PageSize
用于设置页大小,FSMC 操作器件 Cellular RAM 1.5 时要用到,具体支持的参数如下:
#define FSMC_PAGE_SIZE_NONE ((uint32_t)0x00000000U)
#define FSMC_PAGE_SIZE_128 ((uint32_t)0x00010000U)
#define FSMC_PAGE_SIZE_256 ((uint32_t)0x00020000U)
#define FSMC_PAGE_SIZE_512 ((uint32_t)0x00030000U)
#define FSMC_PAGE_SIZE_1024 ((uint32_t)0x00040000U)
初始化 FMC 读写时序
2个参数Timing和ExtTiming,它们都是FSMC_NORSRAM_TimingTypeDef结构体指针类型,分别用来设置 FMC 接口读和写时序,主要涉及地址建立保持时间,数据建立时间等等配置,
如果是异步存储器,读写时序不一样,读写速度要求不一样,参数Timing 和 ExtTiming 需要设置了不同的值。
如果是同步存储器,读写时序设置一致就可
FMC_NORSRAM_TimingTypeDef 结构体定义如下:
typedef struct
uint32_t AddressSetupTime; //地址建立时间
uint32_t AddressHoldTime; //地址保持时间
uint32_t DataSetupTime; //数据建立时间
uint32_t BusTurnAroundDuration; //总线恢复时间
uint32_t CLKDivision; // 时钟分频因子
uint32_t DataLatency; //同步突发 NOR FLASH 的数据延迟
uint32_t AccessMode; //异步模式配置
FSMC_NORSRAM_TimingTypeDef;
具体参照下方表格即可:
- AccessMode
- 模式设置
#define FSMC_ACCESS_MODE_A ((uint32_t)0x00000000U)
#define FSMC_ACCESS_MODE_B ((uint32_t)0x10000000U)
#define FSMC_ACCESS_MODE_C ((uint32_t)0x20000000U)
#define FSMC_ACCESS_MODE_D ((uint32_t)0x30000000U)
最终初始化代码
/**
* @brief Initializes the SRAM device.
* @retval SRAM status
*/
void FSMC_SRAM_Init(void)
//结构体句柄初始化
SRAM_HandleTypeDef SRAM_Handler;
FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
FSMC_NORSRAM_TimingTypeDef FSMC_WriteTim;
//FSMC初始化寄存器
SRAM_Handler.Instance = FSMC_NORSRAM_DEVICE;
SRAM_Handler.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
SRAM_Handler.Init.NSBank=FSMC_NORSRAM_BANK4; //使用NE4
SRAM_Handler.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE; //地址/数据线不复用
SRAM_Handler.Init.MemoryType=FSMC_MEMORY_TYPE_SRAM; //SRAM
SRAM_Handler.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16; //16位数据宽度
SRAM_Handler.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE; //是否使能突发访问,仅对同步突发存储器有效,此处未用到
SRAM_Handler.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;//等待信号的极性,仅在突发模式访问下有用
SRAM_Handler.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS; //存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT
SRAM_Handler.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE; //存储器写使能
SRAM_Handler.Init.WaitSignal=FSMC_WAIT_SIGNAL_DISABLE; //等待使能位,此处未用到
SRAM_Handler.Init.ExtendedMode=FSMC_EXTENDED_MODE_DISABLE; //读写使用相同的时序
SRAM_Handler.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE; //是否使能同步传输模式下的等待信号,此处未用到
SRAM_Handler.Init.WriteBurst=FSMC_WRITE_BURST_DISABLE; //禁止突发写
//FSMC读时序控制寄存器
FSMC_ReadWriteTim.AddressSetupTime=0x06; //地址建立时间(ADDSET)为7个HCLK 13.8ns*7=96.6ns
FSMC_ReadWriteTim.AddressHoldTime=0;
FSMC_ReadWriteTim.DataSetupTime=26; //数据保存时间为27个HCLK =13.8*27=372.6ns
FSMC_ReadWriteTim.AccessMode=FSMC_ACCESS_MODE_A;//模式A
//FSMC写时序控制寄存器
FSMC_WriteTim.BusTurnAroundDuration=0; //总线周转阶段持续时间为0,此变量不赋值的话会莫名其妙的自动修改为4。导致程序运行正常
FSMC_WriteTim.AddressSetupTime=3; //地址建立时间(ADDSET)为4个HCLK =55.2ns
FSMC_WriteTim.AddressHoldTime=0;
FSMC_WriteTim.DataSetupTime=0x06; //数据保存时间为13.8ns*7个HCLK=96.6ns
FSMC_WriteTim.AccessMode=FSMC_ACCESS_MODE_A; //模式A
/* SRAM controller initialization */
FSMC_SRAM_MspInit();
HAL_SRAM_Init(& SRAM_Handler, &FSMC_ReadWriteTim, &FSMC_WriteTim);
以上是关于STM32 FSMC/FMC原理保姆级讲解的主要内容,如果未能解决你的问题,请参考以下文章