STM32-FSMC-SRAM扩展

STM32-FSMC-SRAM扩展

1、SRAM芯片

IS62WV51216BLL-55TLI相关芯片资料下载

image
image

1.1 信号线

SRAM的控制比较简单,只要控制信号线使能了访问,从地址线输入要访问的地址,即可从I/O数据线写入或读出数据。

image

1.2 SRAM芯片的存储矩阵

image

SRAM内部包含的存储阵列,可以把它理解成一张表格,数据就填在这张表格上。和表格查找一样,指定一个行地址和列地址,就可以精确地找到目标单元格,这是SRAM芯片寻址的基本原理。这样的每个单元格被称为存储单元,而这样的表则被称为存储矩阵。

1.3 地址译码器、列I/O及I/O数据电路

image

地址译码器把N根地址线转换成2N根信号线,每根信号线对应一行或一列存储单元,通过地址线找到具体的存储单元,实现寻址。

本实例中的SRAM比较小,没有列地址线,它的数据宽度为16位,即一个行地址对应2字节空间,框图中左侧的A0-A18是行址信号,19根地址线一共可以表示219=29x1024=512K行存储单元,所以它一共能访问512Kx16bits = 8 Mb = 8MB大小的空间。访问时,使用UB#或LB#线控制数据宽度,

1.4 控制电路

image

控制电路主要包含了片选、读写使能以及上面提到的宽度控制信号UB#和LB#。利用CS2或CS1#片选信号,可以把多个SRAM芯片组成一个大容量的内存条。OE#和WE#可以控制读写使能,防止误操作。

1.5 读写流程

1.5.1 读流程

image
image

1.5.2 写流程

image
image

2、STM32的FSMC

2.1 FSMC功能描述

FSMC(Flexible Static Memory Controller,灵活的静态存储控制器)具有下列主要功能:
● 具有静态存储器接口的器件包括:
─ 静态随机存储器(SRAM)
─ 只读存储器(ROM)
─ NOR闪存
─ PSRAM(4个存储器块)
● 两个NAND闪存块,支持硬件ECC并可检测多达8K字节数据
● 16位的PC卡兼容设备
● 支持对同步器件的成组(Burst)访问模式,如NOR闪存和PSRAM
● 8或16位数据总线
● 每一个存储器块都有独立的片选控制
● 每一个存储器块都可以独立配置
● 时序可编程以支持各种不同的器件:
─ 等待周期可编程(多达15个周期)
─ 总线恢复周期可编程(多达15个周期)
─ 输出使能和写使能延迟可编程(多达15周期)
─ 独立的读写时序和协议,可支持宽范围的存储器和时序
● PSRAM和SRAM器件使用的写使能和字节选择输出
● 将32位的AHB访问请求,转换到连续的16位或8位的,对外部16位或8位器件的访问
● 具有16个字,每个字32位宽的写入FIFO,允许在写入较慢存储器时释放AHB进行其它操作。在开始一次新的FSMC操作前, FIFO要先被清空。

2.2 框图

image
image

其中比较特殊的FSMC_NE是用于控制SRAM芯片的控制信号线,STM32具有FSMC_NE1/2/3/4号引脚,不同的引脚对应STM32内部不同的地址区域。

例如,当STM32访问0x68000000-0x6BFFFFFF地址空间时,FSMC_NE3引脚会自动设置为低电平,由于它连接到SRAM的CE#引脚,所以SRAM的片选被使能,而访问0x60000000-0x63FFFFFF地址时,FSMC_NE1会输出低电平。当使用不同的FSMC_NE引脚连接外部存储器时,STM32访问SRAM的地址不一样,从而达到控制多块SRAM芯片的目的。

image

2.3 存储器控制器

控制SRAM的有FSMC_BCR1/2/3/4控制寄存器、FSMC_BTR1/2/3/4片选时序寄存器以及FSMC_BWTR1/2/3/4写时序寄存器。每种寄存器都有4个,分别对应于4个不同的存储区域,各种寄存器介绍如下:

  • FSMC_BCR控制寄存器可配置要控制的存储器类型、数据线宽度以及信号有效极性能参数。

  • FMC_BTR时序寄存器用于配置SRAM访问时的各种时间延迟,如数据保持时间、地址保持时间等。

  • FMC_BWTR写时序寄存器与FMC_BTR寄存器控制的参数类似,它专门用于控制写时序的时间参数。

2.4 时钟控制逻辑

FSMC外设挂载在AHB总线上,时钟信号来自于HCLK(默认72MHz),控制器的同步时钟输出就是由它分频得到。例如,NOR控制器的FSMC_CLK引脚输出的时钟,它可用于与同步类型的SRAM芯片进行同步通讯,它的时钟频率可通过FSMC_BTR寄存器的CLKDIV位配置,可以配置为HCLK的1/2或1/3,也就是说,若它与同步类型的SRAM通讯时,同步时钟最高频率为36MHz。

本示例中的SRAM为异步类型的存储器,不使用同步时钟信号,所以时钟分频配置不起作用。

image

2.5 FSMC控制SRAM时序

FSMC外设支持输出多种不同的时序以便于控制不同的存储器,它具有ABCD四种模式

A模式
image
image

3、FSMC控制SRAM芯片

3.1 FSMC时序结构体

  • FSMC_NORSRAMTimingInitTypeDef
typedef struct
{
  uint32_t FSMC_AddressSetupTime;       /*设置地址建立时间,它可以被设置为0-0xF个HCLK周期数,按STM32标准库的默认配置,											   HCLK的时钟频率为72MHz,即一个HCLK周期为1/72微秒。*/

  uint32_t FSMC_AddressHoldTime;        /*设置地址保持时间,它可以被设置为0-0xF个HCLK周期数。*/

  uint32_t FSMC_DataSetupTime;          /*设置数据建立时间,它可以被设置为0-0xF个HCLK周期数。*/

  uint32_t FSMC_BusTurnAroundDuration;  /*设置总线转换周期,在NOR FLASH存储器中,地址线与数据线可以分时复用,总线转换周										   期就是指总线在这两种状态间切换需要的延时,防止冲突。控制其它存储器时这个参数无											效,配置为0即可。*/

  uint32_t FSMC_CLKDivision;         	/*设置时钟分频,它以HCLK时钟作为输入,经过FSMC_CLKDivision分频后输出FSMC_CLK										   引脚作为通讯使用的同步时钟。控制其它异步通讯的存储器时这个参数无效,配置为0即											  可。*/

  uint32_t FSMC_DataLatency;            /*设置数据保持时间,它表示在读取第一个数据之前要等待的周期数,该周期指同步时钟的周											期,本参数仅用于同步NOR FLASH类型的存储器,控制其它类型的存储器时,本参数无											  效。*/

  uint32_t FSMC_AccessMode;             /*设置存储器访问模式,不同的模式下FSMC访问存储器地址时引脚输出的时序不一样,可选											  FSMC_AccessMode_A/B/C/D模式。一般来说控制SRAM时使用A模式。*/
}FSMC_NORSRAMTimingInitTypeDef;

3.2 FSMC的SRAM初始化结构体

  • FSMC_NORSRAMInitTypeDef
typedef struct
{
  uint32_t FSMC_Bank;                /*用于选择FSMC映射的存储区域,它的可选参数以及相应的内核地址映射范围见上面的表格*/

  uint32_t FSMC_DataAddressMux;      /*用于设置地址总线与数据总线是否复用*/

  uint32_t FSMC_MemoryType;          /*用于设置要控制的存储器类型,它支持控制的存储器类型为SRAM、PSRAM以及NOR 											   FLASH(FSMC_MemoryType_SRAM/PSRAM/NOR)。*/

  uint32_t FSMC_MemoryDataWidth;     /*用于设置要控制的存储器的数据宽度,可选择设置成8或16位(FSMC_MemoryDataWidth_8b 										/16b)。*/

  uint32_t FSMC_BurstAccessMode;     /*用于设置是否使用突发访问模式(FSMC_BurstAccessMode_Enable/Disable),突发访问										   模式是指发送一个地址后连续访问多个数据,非突发模式下每访问一个数据都需要输入一个地									   址,仅在控制同步类型的存储器时才能使用突发模式。*/
                                       
  uint32_t FSMC_AsynchronousWait;     /*本成员用于设置是否使能在同步传输时使用的等待信号  				                                          			(FSMC_AsynchronousWait_Enable/Disable),在控制同步类型的NOR或PSRAM时,存储										器可以使用FSMC_NWAIT引脚通知STM32需要等待。*/

  uint32_t FSMC_WaitSignalPolarity;  /*本成员用于设置等待信号的有效极性,即要求等待时,使用高电平还是低电平													(FSMC_WaitSignalPolarity_High/Low)。*/

  uint32_t FSMC_WrapMode;            /*本成员用于设置是否支持把非对齐的AHB突发操作分割成2次线性操作															(FSMC_WrapMode_Enable/Disable),该配置仅在突发模式下有效。*/

  uint32_t FSMC_WaitSignalActive;    /*本成员用于配置在突发传输模式时,决定存储器是在等待状态之前的一个数据周期有效还是在										等待状态期间有效																						   (FSMC_WaitSignalActive_BeforeWaitState/DuringWaitState)。*/

  uint32_t FSMC_WriteOperation;      /*这个成员用于设置是否写使能(FSMC_WriteOperation_ Enable /Disable),禁止写使能									   的话FSMC只能从存储器中读取数据,不能写入。*/

  uint32_t FSMC_WaitSignal;          /*本成员用于设置当存储器牌突发传输模式时,是否允许通过NWAIT信号插入等待状态												(FSMC_WaitSignal_Enable/Disable)。*/

  uint32_t FSMC_ExtendedMode;        /*本成员用于设置是否使用扩展模式(FSMC_ExtendedMode_Enable/Disable),在非扩展模										 式下,对存储器读写的时序都只使用FSMC_BCR寄存器中的配置,即下面的													   FSMC_ReadWriteTimingStruct结构体成员;在扩展模式下,对存储器的读写时序可以分开										  配置,读时序使用FSMC_BCR寄存器,写时序使用FSMC_BWTR寄存器的配置,即下面的											   FSMC_WriteTimingStruct结构体。*/

  uint32_t FSMC_WriteBurst;          /*是否使能写突发操作*/ 

  FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct; /*是一个指针,赋值时使用上一小节中讲解的时序结构体																		FSMC_NORSRAMInitTypeDef设置,当不使用扩展模式时,																读写时序都使用本成员的参数配置。*/  

  FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;     /*一个时序结构体的指针,只有当使用扩展模式时,本配置才有																效,它是写操作使用的时序。*/      
}FSMC_NORSRAMInitTypeDef;
  1. FSMC_Bank:用于选择FSMC映射的存储区域,它的可选参数以及相应的内核地址映射范围见上面的表格

image

3、代码实操

3.1 GPIO配置

  1. 以野火霸道的开发板为例(部分原理图),其他的开发板可根据自己的原理图。

image

/*A地址信号线*/    
#define FSMC_A0_GPIO_PORT        GPIOF
#define FSMC_A0_GPIO_CLK         RCC_APB2Periph_GPIOF
#define FSMC_A0_GPIO_PIN         GPIO_Pin_0

#define FSMC_A1_GPIO_PORT        GPIOF
#define FSMC_A1_GPIO_CLK         RCC_APB2Periph_GPIOF
#define FSMC_A1_GPIO_PIN         GPIO_Pin_1

#define FSMC_A2_GPIO_PORT        GPIOF
#define FSMC_A2_GPIO_CLK         RCC_APB2Periph_GPIOF
#define FSMC_A2_GPIO_PIN         GPIO_Pin_2

#define FSMC_A3_GPIO_PORT        GPIOF
#define FSMC_A3_GPIO_CLK         RCC_APB2Periph_GPIOF
#define FSMC_A3_GPIO_PIN         GPIO_Pin_3
………………
/*D 数据信号线*/
#define FSMC_D0_GPIO_PORT        GPIOD
#define FSMC_D0_GPIO_CLK         RCC_APB2Periph_GPIOD
#define FSMC_D0_GPIO_PIN         GPIO_Pin_14

#define FSMC_D1_GPIO_PORT        GPIOD
#define FSMC_D1_GPIO_CLK         RCC_APB2Periph_GPIOD
#define FSMC_D1_GPIO_PIN         GPIO_Pin_15

#define FSMC_D2_GPIO_PORT        GPIOD
#define FSMC_D2_GPIO_CLK         RCC_APB2Periph_GPIOD
#define FSMC_D2_GPIO_PIN         GPIO_Pin_0

#define FSMC_D3_GPIO_PORT        GPIOD
#define FSMC_D3_GPIO_CLK         RCC_APB2Periph_GPIOD
#define FSMC_D3_GPIO_PIN         GPIO_Pin_1
…………
/*控制信号线*/  
/*CS片选*/
/*NE3 ,对应的基地址0x68000000*/
#define FSMC_CS_GPIO_PORT        GPIOG
#define FSMC_CS_GPIO_CLK         RCC_APB2Periph_GPIOG
#define FSMC_CS_GPIO_PIN         GPIO_Pin_10

/*WE写使能*/
#define FSMC_WE_GPIO_PORT        GPIOD
#define FSMC_WE_GPIO_CLK         RCC_APB2Periph_GPIOD
#define FSMC_WE_GPIO_PIN         GPIO_Pin_5

/*OE读使能*/
#define FSMC_OE_GPIO_PORT        GPIOD
#define FSMC_OE_GPIO_CLK         RCC_APB2Periph_GPIOD
#define FSMC_OE_GPIO_PIN         GPIO_Pin_4


/*LB数据掩码*/
#define FSMC_UDQM_GPIO_PORT        GPIOE
#define FSMC_UDQM_GPIO_CLK         RCC_APB2Periph_GPIOE
#define FSMC_UDQM_GPIO_PIN         GPIO_Pin_1

/*UB数据掩码*/
#define FSMC_LDQM_GPIO_PORT        GPIOE
#define FSMC_LDQM_GPIO_CLK         RCC_APB2Periph_GPIOE
#define FSMC_LDQM_GPIO_PIN         GPIO_Pin_0
  1. 引脚配置
/* 通用 GPIO 配置 */
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;       //配置为复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     

根据手册:

image

3.2 FSMC配置

3.2.1 时序结构体

FSMC_NORSRAMTimingInitTypeDef

//地址建立时间(ADDSET)为1个HCLK 1/72M=14ns
readWriteTiming.FSMC_AddressSetupTime = 0x00;	
//地址保持时间(ADDHLD)模式A未用到
readWriteTiming.FSMC_AddressHoldTime = 0x00;	 
//数据保持时间(DATAST)为3个HCLK 4/72M=55ns(对EM的SRAM芯片)	
readWriteTiming.FSMC_DataSetupTime = 0x02;		  
//设置总线转换周期,仅用于复用模式的NOR操作
readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
//设置时钟分频,仅用于同步类型的存储器
readWriteTiming.FSMC_CLKDivision = 0x00;	
//数据保持时间,仅用于NOR
readWriteTiming.FSMC_DataLatency = 0x00;		
//选择匹配SRAM的模式
readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;

image

image

ADDSET和DATASET的单位是HCLK一个时钟周期
T = 1/72 MHz = 1/72000000 Hz = 1.38 * 10^(-8) s = 13.8 ns
readWriteTiming.FSMC_DataSetupTime = 2
==> DATASET = 2
==> DATASET + 1 = 2 + 1 = 3 = 3 * 13.8 = 41.4 ns > 40ns
==> 1 + 1 = 27.6ns > 25ns

readWriteTiming.FSMC_AddressSetupTime = 0;
==> ADDSET = 0
==> ADDSET + 1 > 0 ns
==> 0 + 1 = 13.8 ns > 0

(ADDSET + 1) + (DATASET + 1)
==> 0 + 1 + 2 + 1 = 4
==> 4 * 13.8 = 55.2ns > 55ns
readWriteTiming.FSMC_DataSetupTime = 1
==> DATASET = 1
==> DATASET + 1 > 25ns
==> 1 + 1 = 27.6ns > 25ns

readWriteTiming.FSMC_AddressSetupTime = 0;
==> ADDSET = 0
==> ADDSET + 1 > 0 ns
==> 0 + 1 = 13.8 ns > 0

(ADDSET + 1) + (DATASET + 1) + 2
==> 1 + 1 + 1 +2 = 5
==> 69ns > 55ns

3.2.2 初始化结构体

FSMC_NORSRAMInitTypeDef

// 选择FSMC映射的存储区域: Bank1 sram3
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;
//设置地址总线与数据总线是否复用,仅用于NOR
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; 
//设置要控制的存储器类型:SRAM类型
FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;   
//存储器数据宽度:16位
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; 
//设置是否使用突发访问模式,仅用于同步类型的存储器
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;
//设置是否使能等待信号,仅用于同步类型的存储器
FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
//设置等待信号的有效极性,仅用于同步类型的存储器
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
//设置是否支持把非对齐的突发操作,仅用于同步类型的存储器
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; 
//设置等待信号插入的时间,仅用于同步类型的存储器
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
//存储器写使能 
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
//不使用等待信号
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;  		
// 不使用扩展模式,读写使用相同的时序
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; 
//突发写操作
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;  
//读写时序配置
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
//读写同样时序,使用扩展模式时这个配置才有效
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming; 
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);  //初始化FSMC配置
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE);  // 使能BANK	

3.3 测试

// 选择FSMC映射的存储区域: Bank1 sram3
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;

image

// 定义基地址
#define SRAM_BASE_ADDR				(0x68000000)
// 1M字节
#define SRAM_SIZE					(1*1024*1024)
// 结束地址
#define SRAM_END_ADDR				(SRAM_BASE_ADDR + SRAM_SIZE)
uint8_t testValue __attribute__((at(SRAM_BASE_ADDR + 0x40)));
uint8_t testValue1;

void setup(void)
{
	SRAM_Init();
	Debug_USART_Config();
	printf("SRAM 程序初始化\r\n");
	
	uint8_t *p;
	uint8_t *temp;
	p = (uint8_t*)SRAM_BASE_ADDR;	
	*p = 0xDE;
	temp = (uint8_t*)SRAM_BASE_ADDR;
	printf("读出 8 位数据 ==> 0x%X, 地址 = %p\r\n", *temp, temp);
	
	uint16_t *p16;
	uint16_t *temp16;
	p16 = (uint16_t*)(SRAM_BASE_ADDR + 10);	
	*p16 = 0xDE12;
	temp16 = (uint16_t*)(SRAM_BASE_ADDR + 10);
	printf("读出 16 位数据 ==> 0x%X, 地址 = %p\r\n", *temp16, temp16);
	
	float *pF;
	float *tempF;
	pF = (float*)(SRAM_BASE_ADDR + 20);
	*pF = 0xABCD;
	tempF = (float*)(SRAM_BASE_ADDR + 20);
	printf("读出 Float 数据 ==> 0x%f, 地址 = %p\r\n", *tempF, tempF);
	
	testValue = 0xDD;
	printf("testValue = %d, testValue 地址 = %x\r\n", testValue, (unsigned int)&testValue);
	
	testValue1 = 0xCC;
	printf("testValue1 = %d, testValue 地址 = %x", testValue1, (unsigned int)&testValue1);
}
posted @ 2023-02-26 22:23  DingJie1024  阅读(269)  评论(0编辑  收藏  举报