外扩 Sram配置

目录

一、SRAM

外观

接口

读写时序

读写流程

二、FSMC

地址映射

接口信号

时序

控制寄存器

三、代码实现


一、SRAM

静态随机存储器SRAM,使用锁存器来存储数据,下电数据会丢失。

主芯片内部有一定大小的RAM和FLASH空间,但随着程序的大小增加,内部Ram不够使用时,就可以使用外扩的SRAM存储器
给STM32芯片扩展内存与给PC扩展内存的原理是一样的,只是PC上一般以内存条的形式扩展,而且内存条实质是由多个内存颗粒(即SDRAM芯片)组成的通用标准模块,而STM32扩展时,直接与SRAM芯片连接。

  • 外观

  • 接口

  • 读写时序

读时序

重点时序:

  • 读周期时间(tRC)
  • 地址建立时间(tAA)
  • OE建立时间(tDOE)

地址建立时间后续配置FSMC时需要注意。

写时序

重点时序:

  • 写周期时间(tWC)
  • 地址建立时间(tSA)
  • WE脉宽(tPWE)

地址建立时间后续配置FSMC时要注意

  • 读写流程

读写时序的流程很类似,过程如下:
(1) 主机使用地址信号线发出要访问的存储器目标地址;
(2) 控制片选信号CE#使能存储器芯片;
(3) 若是要进行读操作,则控制读使能信号OE#表示要读数据,若进行写操作则控制写使能信号WE#表示要写数据;
(4) 使用掩码信号LB#与UB#指示要访问目标地址的高、低字节部分;
(5) 若是读取过程,存储器会通过数据线向主机输出目标数据,若是写入过程,主要使用数据线向存储器传输目标数据。
 

二、FSMC

STM32F4系列芯片使用FSMC外设来管理扩展的存储器,FSMC是Flexible Static Memory Controller的缩写,译为灵活的静态存储控制器。它可以用于驱动包括SRAM、NOR FLASH以及NAND FLSAH类型的存储器,不能驱动如SDRAM这种动态的存储器。而在STM32F429系列的控制器中,它具有FMC外设,支持控制SDRAM存储器。

  • 地址映射

从 FSMC 的角度,外部存储器被划分为 4 个固定大小的存储区域,每个存储区域的大小为 

256 MB,每个区都有对应的寄存器控制。通过配置片选信号使能相应的存储空间。

  • 接口信号

  • 时序

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

读时序

写时序

  • 控制寄存器

注意上面的截图是ST的PPT,因为使用的芯片不同,下面代码实现中的配置不一定保持一致。

三、代码实现

SRAM_HandleTypeDef SRAM_Handler;    //SRAM句柄

void SRAM_Init(void)
{	
	GPIO_InitTypeDef GPIO_Initure;
	FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
    
    __HAL_RCC_FSMC_CLK_ENABLE();                //使能FSMC时钟
    __HAL_RCC_GPIOD_CLK_ENABLE();               //使能GPIOD时钟
    __HAL_RCC_GPIOE_CLK_ENABLE();               //使能GPIOE时钟
    __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟
    __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟
    
	//PD0,1,4,5,8~15
    GPIO_Initure.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;              
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //推挽复用
    GPIO_Initure.Pull=GPIO_PULLUP;              //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    GPIO_Initure.Alternate=GPIO_AF12_FSMC;     	//复用为FSMC    
	HAL_GPIO_Init(GPIOD,&GPIO_Initure);     	
    
	//PE0,1,7~15
    GPIO_Initure.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_Initure);    
    
	//PF0~5,12~15
    GPIO_Initure.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_Initure);     
    
	//PG0~5,10
    GPIO_Initure.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_Initure);      
	
	SRAM_Handler.Instance=FSMC_NORSRAM_DEVICE;                
	SRAM_Handler.Extended=FSMC_NORSRAM_EXTENDED_DEVICE;    
    
	SRAM_Handler.Init.NSBank=FSMC_NORSRAM_BANK3;     					//使用NE3
	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;           	//禁止突发写
	SRAM_Handler.Init.ContinuousClock=FSMC_CONTINUOUS_CLOCK_SYNC_ASYNC;
    
	//FMC读时序控制寄存器
	FSMC_ReadWriteTim.AddressSetupTime=0x00;       	//地址建立时间(ADDSET)为1个HCLK 1/168M=6ns*16=96ns
	FSMC_ReadWriteTim.AddressHoldTime=0x00;			//地址保持时间(ADDHLD)模式A未用到
	FSMC_ReadWriteTim.DataSetupTime=0x08;			//数据保存时间为8个HCLK	=6*1=6ns
	FSMC_ReadWriteTim.BusTurnAroundDuration=0X00;
	FSMC_ReadWriteTim.AccessMode=FSMC_ACCESS_MODE_A;//模式A
	HAL_SRAM_Init(&SRAM_Handler,&FSMC_ReadWriteTim,&FSMC_ReadWriteTim);	

}

读写测试函数

//在指定地址(WriteAddr+Bank1_SRAM3_ADDR)开始,连续写入n个字节.
//pBuffer:字节指针
//WriteAddr:要写入的地址
//n:要写入的字节数
void FSMC_SRAM_WriteBuffer(u8 *pBuffer,u32 WriteAddr,u32 n)
{
	for(;n!=0;n--)
	{
		*(vu8*)(Bank1_SRAM3_ADDR+WriteAddr)=*pBuffer;
		WriteAddr++;
		pBuffer++;
	}
}

//在指定地址((WriteAddr+Bank1_SRAM3_ADDR))开始,连续读出n个字节.
//pBuffer:字节指针
//ReadAddr:要读出的起始地址
//n:要写入的字节数
void FSMC_SRAM_ReadBuffer(u8 *pBuffer,u32 ReadAddr,u32 n)
{
	for(;n!=0;n--)
	{
		*pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);
		ReadAddr++;
	}
}

主函数

u32 testsram[250000] __attribute__((at(0X68000000)));//测试用数组
//外部内存测试(最大支持1M字节内存测试)	    
void fsmc_sram_test(u16 x,u16 y)
{  
	u32 i=0;  	  
	u8 temp=0;	   
	u8 sval=0;	//在地址0读到的数据	  				   
  	LCD_ShowString(x,y,239,y+16,16,"Ex Memory Test:   0KB"); 
	//每隔4K字节,写入一个数据,总共写入256个数据,刚好是1M字节
	for(i=0;i<1024*1024;i+=4096)
	{
		FSMC_SRAM_WriteBuffer(&temp,i,1);
		temp++;
	}
	//依次读出之前写入的数据,进行校验		  
 	for(i=0;i<1024*1024;i+=4096) 
	{
  		FSMC_SRAM_ReadBuffer(&temp,i,1);
		if(i==0)sval=temp;
 		else if(temp<=sval)break;//后面读出的数据一定要比第一次读到的数据大.	   		   
		LCD_ShowxNum(x+15*8,y,(u16)(temp-sval+1)*4,4,16,0);//显示内存容量  
 	}					 
}	

int main(void)
{
	u8 key;		 
 	u8 i=0;	     
	u32 ts=0;
	
    HAL_Init();                   	//初始化HAL库    
    Stm32_Clock_Init(336,8,2,7);  	//设置时钟,168Mhz
	delay_init(168);               	//初始化延时函数
	uart_init(115200);             	//初始化USART
	usmart_dev.init(84); 		    //初始化USMART
	LED_Init();						//初始化LED	
	KEY_Init();						//初始化KEY
	LCD_Init();                     //初始化LCD
	
	SRAM_Init();					//初始化外部SRAM  
 	POINT_COLOR=RED;//设置字体为红色 
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"SRAM TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2017/4/18");   
	LCD_ShowString(30,130,200,16,16,"KEY0:Test Sram");
	LCD_ShowString(30,150,200,16,16,"KEY_UP:TEST Data");
 	POINT_COLOR=BLUE;//设置字体为蓝色  
	for(ts=0;ts<250000;ts++)testsram[ts]=ts;//预存测试数据	 
  	while(1)
	{	
		key=KEY_Scan(0);//不支持连按	
		if(key==KEY0_PRES)fsmc_sram_test(60,170);//测试SRAM容量
		else if(key==WKUP_PRES)//打印预存测试数据
		{
			for(ts=0;ts<250000;ts++)LCD_ShowxNum(60,190,testsram[ts],6,16,0);//显示测试数据	 
		}else delay_ms(10);   
		i++;
		if(i==20)//DS0闪烁.
		{
			i=0;
			LED0=!LED0;
 		}
	}
}

### STM32设初始化延迟及SRAM解决方案 #### 设初始化延迟问题分析与解决 STM32微控制器的设初始化过程中,可能会出现延迟现象。这种延迟通常由时钟配置、总线负载、寄存器访问时间以及软件初始化逻辑等因素引起[^1]。 - **时钟配置**:设依赖于系统时钟(SYSCLK)或特定的设时钟进行工作。如果时钟配置不正确或不稳定,可能导致设初始化延迟。确保在初始化设之前,时钟树已正确配置,并且所有相关的时钟源都已启用。 ```c // 确保时钟稳定 while (!(RCC->CR & RCC_CR_HSERDY)) {} ``` - **总线负载与传输延迟**:通过AHB/APB总线连接设时,总线负载过重或数据传输速率不足可能引发延迟。减少同时初始化的设数量,避免总线过载,并调整设优先级以优化性能[^1]。 - **寄存器访问时间**:某些设的寄存器访问时间较长,特别是在初始化阶段。例如,Flash存储器的编程或擦除操作需要一定的时间完成。在初始化代码中加入适当的等待循环,确保寄存器写入操作完成后再继续执行。 ```c // 等待寄存器写入完成 while ((GPIOA->BSRR & GPIO_BSRR_BS0) != 0) {} ``` - **软件初始化逻辑复杂性**:复杂的初始化逻辑可能导致延迟问题。优化初始化代码,移除不必要的函数调用或重复操作。如果性能要求较高,可以考虑直接使用寄存器操作代替HAL库函数[^1]。 ```c // 直接操作寄存器 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 启用GPIOA时钟 GPIOA->MODER |= GPIO_MODER_MODER0_0; // 配置PA0为输出模式 ``` --- #### SRAM解决方案 当STM32内部的SRAM和FLASH容量不足以满足程序需求时,可以通过FSMC接口SRAM作为内存。以下是实现SRAM的具体方法: - **FSMC初始化**:FSMC(Flexible Static Memory Controller)用于控制部存储器。由于变量拷贝到RAM中的初始化过程发生在进入`main`函数之前,因此FSMC的初始化必须在启动文件`LDR R0, =__main`之前完成。可以选择通过`SystemInit`函数中的`SystemInit_ExtMemCtl`函数配置寄存器来完成初始化[^4]。 ```c // FSMC初始化示例 FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef Timing; FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &Timing; FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); ``` - **SRAM芯片选择与特性**:选择合适的SRAM芯片对于性能至关重要。例如,IS61LV25616是一款常见的SRAM芯片,具有高速访问时间和大容量(256K * 16bit)的特点[^3]。 - **硬件连接**:STM32SRAM时,直接与SRAM芯片连接。确保信号完整性良好,并根据SRAM芯片的数据手册配置相应的时序参数[^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值