目录
一、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;
}
}
}
3833

被折叠的 条评论
为什么被折叠?



