STM32 FSMC/FMC原理保姆级讲解

Posted Z小旋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32 FSMC/FMC原理保姆级讲解相关的知识,希望对你有一定的参考价值。

上一话我们说了FSMC的基本原理及控制逻辑,这一讲我们来说下FSMC如何通过HAL库来进行配置,及具体参数

STM32 FSMC/FMC原理保姆级讲解(一)

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的总体初始化顺序:

  1. 使能 FSMC 和 GPIO 时钟,初始化 IO 口配置,设置映射关系
  2. 设置FSMC基本参数初始化
  3. 设置FSMC读时序/写时序初始化
  4. 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原理保姆级讲解的主要内容,如果未能解决你的问题,请参考以下文章

STM32 FSMC/FMC原理保姆级讲解

STM32 FSMC/FMC原理保姆级讲解

STM32 FMC原理详解

STM32 FMC原理详解

STM32 FMC原理详解

嵌入式STM32输出SPWM实现逆变