目录
学习目标
成果展示??
硬件知识
特点
功能框图
读时序
?编辑写时序
FSMC驱动?
寄存器
闪存片选控制寄存器
硬件
?配置
代码?
总结?
学习目标
????????今天我们要学习的是有关外部SRAM实验,其实F4内部也是有一个192K字节的SRAM的,相比于51的512个字节来说,实在是好太多了,但是因为32可能需要跑一些需要大内存的场景的话可能就不够用了。所以我们就需要使用外部SRAM芯片来实现相应功能,这里我们使用的是IS62WV51216,容量为1M,这样就能满足大多数情况了。个人觉得手机电脑什么的内存应该也是使用这样的方式来组成的,但是没有过多了解,只是一个猜测。
成果展示??
硬件知识
????????IS62WV51216 是 ISSI(Integrated Silicon Solution, Inc)公司生产的一颗 16 位宽 512K(512*16 ,即 1M 字节)容量的 CMOS 静态内存芯片。
特点
- 高速。具有 45ns/55ns 访问速度。
- 低功耗。
- TTL 电平兼容。
- 全静态操作。不需要刷新和时钟电路。
- 三态输出。
- 字节控制功能。支持高/低字节控制。
功能框图
????????图中 A0~18 为地址线,总共 19 根地址线(即 2^19=512K,1K=1024);IO0~15 为数据线,总共 16 根数据线。CS2 和 CS1 都是片选信号,不过 CS2 是高电平有效 CS1 是低电平有效(不过我们没有用到CS2,只使用了CS1);OE是输出使能信号(读信号);WE 为写使能信号;UB 和 LB 分别是高字节控制和低字节控制信号,这个到后面会有所介绍。
读时序
????????我们重点来介绍一下其中几个时序,首先是读周期时序(tRC),我们是55ns,然后地址建立时间(tAA)为55ns(Max),tDOE为25ns(Max)。我们使用的是55ns的芯片,其他时间的具体值如下表所示:?
写时序
????????这个和前面一样,就不做过多介绍了。写周期时间(tWC),地址建立时间(tSA),WE脉宽(tPWE)。
FSMC驱动?
? ? ? ? 这个其实在LCD屏的时候介绍过,在此就简单的介绍一下,FSMC驱动外部SRAM时,外部SRAM的控制一般有:?地址线(如A0~A25数据线(如D0~D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。 ????????而IS62WV51246的信号我们在前面介绍过,包括:?I/O0~I/O15、A0~A18、OE、WE、CS、UB、LB等,我们将这些信号依次连接STM32?FSMC接口的D0~D15、A0~A18、OE、WE、CS、UB、LB等信号即可。
????????STM32F4 的 FSMC 支持 8/16/32 位数据宽度,我们这里用到的 LCD 是 16 位宽度的,所以在设置的时候,选择 16 位宽就 OK 了。我们再来看看 FSMC 的外部设备地址映像,STM32F4 的 FSMC 将外部存储器划分为固定大小为 256M 字节的四个存储块,如图所示:
????????这里 HADDR 是内部 AHB 地址 总线,其 中 HADDR[25:0] 来自外部存储器地址 FSMC_A[25:0],而 HADDR[26:27]对 4 个区进行寻址。如表所示:?
????????当 Bank1 接的是 16 位宽度存储器的时候:HADDR[25:1]->?FSMC_A [24:0]。 当 Bank1 接的是 8 位宽度存储器的时候:HADDR[25:0]-> FSMC_A [25:0]。
?
?
????????这个是读写时序,就不做详细介绍,LCD里面都有。??
寄存器
????????也不做详细介绍,就讲解几个重要寄存器。
闪存片选控制寄存器
硬件
- A[0:18]接 FMSC_A[0:18](不过顺序错乱了)
- D[0:15]接 FSMC_D[0:15]
- UB 接 FSMC_NBL1
- LB 接 FSMC_NBL0
- OE 接 FSMC_OE
- WE 接 FSMC_WE
- CS 接 FSMC_NE3
?配置
- 使能 FSMC 时钟,并配置 FSMC 相关的 IO 及其时钟使能。
- 设置 FSMC BANK1 区域 3 的相关寄存器。
- 使能 BANK1 区域 3。
代码?
// sram.c
#include "sram.h"
#include "usart.h"
//使用NOR/SRAM的 Bank1.sector3,地址位HADDR[27,26]=10
//对IS61LV25616/IS62WV25616,地址线范围为A0~A17
//对IS61LV51216/IS62WV51216,地址线范围为A0~A18
#define Bank1_SRAM3_ADDR ((u32)(0x68000000))
//初始化外部SRAM
void FSMC_SRAM_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOG, ENABLE);//使能PD,PE,PF,PG时钟
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);//使能FSMC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PB15 推挽输出,控制背光
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 //PB15 推挽输出,控制背光
GPIO_InitStructure.GPIO_Pin = (3<<0)|(3<<4)|(0XFF<<8);//PD0,1,4,5,8~15 AF OUT
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = (3<<0)|(0X1FF<<7);//PE0,1,7~15,AF OUT
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = (0X3F<<0)|(0XF<<12); //PF0~5,12~15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin =(0X3F<<0)| GPIO_Pin_10;//PG0~5,10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);//PD0,AF12
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);//PD1,AF12
GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource11,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);//PD15,AF12
GPIO_PinAFConfig(GPIOE,GPIO_PinSource0,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC);//PE7,AF12
GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource12,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE,GPIO_PinSource15,GPIO_AF_FSMC);//PE15,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource0,GPIO_AF_FSMC);//PF0,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource1,GPIO_AF_FSMC);//PF1,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource2,GPIO_AF_FSMC);//PF2,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource3,GPIO_AF_FSMC);//PF3,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource4,GPIO_AF_FSMC);//PF4,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource5,GPIO_AF_FSMC);//PF5,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource12,GPIO_AF_FSMC);//PF12,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource13,GPIO_AF_FSMC);//PF13,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource14,GPIO_AF_FSMC);//PF14,AF12
GPIO_PinAFConfig(GPIOF,GPIO_PinSource15,GPIO_AF_FSMC);//PF15,AF12
GPIO_PinAFConfig(GPIOG,GPIO_PinSource0,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource1,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource2,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource3,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource4,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource5,GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOG,GPIO_PinSource10,GPIO_AF_FSMC);
// 读写时序
readWriteTiming.FSMC_AddressSetupTime = 0x00; //地址建立时间(ADDSET)为1个HCLK 1/36M=27ns
readWriteTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间(ADDHLD)模式A未用到
readWriteTiming.FSMC_DataSetupTime = 0x08; 数据保持时间(DATAST)为9个HCLK 6*9=54ns
readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
readWriteTiming.FSMC_CLKDivision = 0x00;
readWriteTiming.FSMC_DataLatency = 0x00;
readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式A
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;// 这里我们使用NE3 ,也就对应BTCR[4],[5]。
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; // 地址复用没用到
FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM; //SRAM
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//存储器数据宽度为16bit
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;// 低电平有效
FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
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); // 使能BANK1区域3
}
//在指定地址(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++;
}
}
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "sram.h"
//测试用数组,定义一个数组,每个数占4个字节,数组包含250000个值,采用绝对地址定义,数组的起始地址在0x68000000。
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读到的数据
printf ("Ex Memory Test: 0KB");
printf ("\r\n\r\n");
//每隔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;//后面读出的数据一定要比第一次读到的数据大.
printf ("Ex Memory Test: %d KB",(u16)(temp-sval+1)*4);//显示内存容量
printf ("\r\n\r\n");
}
}
int main(void)
{
u8 key;
u8 i=0;
u32 ts=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
KEY_Init(); //按键初始化
FSMC_SRAM_Init(); //初始化外部SRAM
printf ("KEY0:Test Sram");
printf ("KEY1:TEST Data");
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==KEY1_PRES)//打印预存测试数据
{
for(ts=0;ts<250000;ts++)
{
printf ("%d",testsram[ts]);//显示测试数据
printf ("\r\n\r\n");
}
}else delay_ms(10);
i++;
if(i==20)//DS0闪烁.
{
i=0;
LED0=!LED0;
}
}
}
总结?
????????个人感觉这块知识应该还可以再深入学习一点,目前感觉就是皮毛。?
|