记录一下,方便以后翻阅~
主要内容:
1) IS62WV51216简介;
2) FSMC简介及相关寄存器介绍;
3) 相关实验代码解读。
参考手册:《STM32中文参考手册_V10》-第19章 灵活的静态存储器控制器(FSMC);外部SRAM芯片资料 IS62WV51216.pdf。
硬件连接:
IS62WV51216原理图如下所示,具体连接关系为:
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。
实验功能:程序开启后,按下KEY0键,测试外部SRAM容量大小并发送至串口端;按下KEY1键,显示预存在外部SRAM的数据。DS0指示程序运行状态。
1. IS62WV51216简介
1.1 IS62WV51216是ISSI(Integrated Silicon Solution, Inc)公司生产的一颗16位宽512K(512*16,即1M字节)容量的CMOS静态内存(SRAM)芯片。
1.2 特点
1) 高速。具有45ns/55ns访问速度(开发版采用55ns型号);
2) 低功耗。操作时:36mW;待机时:12uW;
3) 兼容TTL电平,兼容5V电压;
4) 全静态操作,不需要刷新和时钟电路;
5) 三态输出;
6) 字节控制功能。支持高/低字节控制。
1.3 框图
图中A0~18为地址线,总共19根地址线(即2^19=512K,1K=1024);
I/O0~15为数据线,总共16根数据线;
CS2和CS1都是片选信号,CS2是高电平有效,CS1是低电平有效(开发板采用CS1);
OE是输出使能信号(读信号);
WE为写使能信号;
UB和LB分别是高字节控制和低字节控制信号(设0有效,设1无效)。
1.4 IS62WV51216读时序
IS62WV51216芯片的8080并口读时序如下图所示:
重点时序:读周期时间(tRC);地址建立时间(tAA);OE建立时间(tDOE)。
开发板使用55ns的IS62WV51216,tRC=55ns,tAA=55ns(Max),tDOE=25ns(Max)。
1.5 IS62WV51216写时序
IS62WV51216芯片的8080并口写时序如下图所示:
重点时序:写周期时间(tWC),地址建立时间(tSA),WE脉宽(tPWE)。
开发板使用55ns的IS62WV51216,tWC=55ns,tSA=0ns,tPWE=45ns(min)。
2. FSMC简介
FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡连接,STM32的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存储器(不支持SDRAM)。FSMC的框图如下图所示:
2.1 FSMC驱动IS62WV51216原理
FSMC驱动外部SRAM时,外部SRAM的控制一般有:
1) 地址线(如A0~A25);
2) 数据线(如D0~D15);
3) 写信号(WE,即WR);
4) 读信号(OE,即RD);
5) 片选信号(CS);
6) 如果SRAM支持字节控制,还有UB/LB信号。
IS62WV51216的信号包括:
1) 地址线A0~A18;
2) 数据线I/O0~I/O15;
3) 写信号WE;
4) 读信号OE;
5) 片选信号CS;
6) 字节控制UB、LB等。
将这些信号依次连接STM32 FSMC接口的A0-A18、D0-D15、WE、OE、CS、UB、LB等信号即可。
2.2 NOR / PSRAM外设接口
STM32的FSMC支持8/16位数据宽度,我们这里用到的SRAM是16位宽度的,所以在设置的时候,选择16位宽就OK了。FSMC的外部设备地址映像,STM32的FSMC将外部存储器划分为固定大小为256M字节的四个存储块(注意每个块的起始地址!)。
2.3 NOR / PSRAM存储块1 操作简介
STM32的FSMC存储块1(Bank1)用于驱动NOR FLASH/SRAM/PSRAM,被分为4个区,每个区管理64M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1的256M字节空间由28根地址线(HADDR[27:0])寻址。
这里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],
不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]。
2.4 NOR PSRAM存储块1 访问模式
STM32的FSMC存储块1 支持的异步突发访问模式包括:模式1、模式A~D等多种时序模型,驱动SRAM时一般使用模式1或者模式 A,这里使用模式A来驱动SRAM,其他模式说明详见:STM32中文参考手册-FSMC章节。
模式A支持读写时序分开设置!(可针对一些读写时序不一样的设备分开设置),
对STM32F4仅写时序DATAST需要+1(F1按上图要求即可)。
2.5 FSMC寄存器介绍
对于NOR FLASH/PSRAM控制器(存储块1),通过FSMC_BCRx、FSMC_BTRx和FSMC_BWTRx(仅读写时序不一致时才设置)寄存器设置(其中x=1~4,对应4个区)。通过这3个寄存器,可以设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。
2.5.1 SRAM/NOR闪存片选控制寄存器(FSMC_BCRx)
EXTMOD:扩展模式使能位,控制是否允许读写不同的时序,设置为0(读写相同时序);
WREN:写使能位。我们需要向SRAM写数据,故该位必须设置为1;
MWID[1:0]:存储器数据总线宽度。00,表示8位数据模式,01表示16位数据模式,10和11保留。我们的SRAM是16位数据线,所以设置WMID[1:0]=01;
MTYP[1:0]:存储器类型。00表示SRAM、ROM,01表示PSRAM,10表示NOR FLASH,11保留。我们驱动的芯片为SRAM,所以需要设置MTYP[1:0]=00;
MBKEN:存储块使能位。需设置为1,使能相应的存储块。
2.5.2 SRAM/NOR闪存片选时序寄存器(FSMC_BTRx)
ACCMOD[1:0]:访问模式。00:模式A,01:模式B,10:模式C,11:模式D。
DATAST[7:0]:数据保持时间,等于: DATAST(+1)个HCLK时钟周期(F4只有写的时候要+1),DATAST最大为255。对IS62WV51216来说,其实就是OE/WE低电平持续时间,最大为55ns。对STM32F1,一个HCLK=13.8ns (1/72M),设置为3(13.8×(3+1)≈55.2ns)。对STM32F4,一个HCLK=6ns(1/168M),设置为8(有点超频)。
ADDSET[3:0]:地址建立时间。表示:ADDSET (+1)个HCLK周期(F1不需要+1),ADDSET最大为15。对IS62WV51216来说,访问周期最快为55ns,之前的设置,已经可以保证访问周期不小于55ns,因此这个地址建立时间,直接设置为0即可。
本实验因为EXTMOD位设置为0,所以读写时序共用这个时序寄存器!
2.5.3 SRAM/NOR闪存写时序寄存器(FSMC_BWTRx)
若EXTMOD位设置为1,读写时序分开,则用该寄存器设置写时序。
ACCMOD[1:0]:访问模式。00:模式A;01:模式B;10:模式C;11:模式D。
DATAST[7:0]:数据保持时间,等于:
DATAST(+1)个HCLK时钟周期,DATAST最大为255。
ADDSET[3:0]:地址建立时间。表示:ADDSET+1个HCLK周期,ADDSET最大为15。
本实验因为EXTMOD位设置为0,所以用不到该寄存器!
2.5.4 SRAM/NOR闪存片选寄存器组合说明
在ST官方库提供的的寄存器定义里面,并没有定义FSMC_BCRx、FSMC_BTRx、FSMC_BWTRx等这些单独的寄存器,而是将他们进行了一些组合。规律如下:
1)FSMC_BCRx和FSMC_BTRx,组合成BTCR[8]寄存器组,对应关系如下:
BTCR[0]对应FSMC_BCR1,BTCR[1]对应FSMC_BTR1;
BTCR[2]对应FSMC_BCR2,BTCR[3]对应FSMC_BTR2;
BTCR[4]对应FSMC_BCR3,BTCR[5]对应FSMC_BTR3;
BTCR[6]对应FSMC_BCR4,BTCR[7]对应FSMC_BTR4。
2)FSMC_BWTRx则组合成BWTR[7],对应关系如下:
BWTR[0]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2,
BWTR[4]对应FSMC_BWTR3,BWTR[6]对应FSMC_BWTR4,
BWTR[1]、BWTR[3]和BWTR[5]保留,没有用到。
3. 相关代码解读
3.1 sram.h头文件代码解读
/**
******************************** STM32F10x *********************************
* @文件名称: sram.h
* @作者名称: Aaron
* @库版本号: V3.5.0
* @工程版本: V1.0.0
* @开发日期: 2020年10月7日
* @摘要简述: SRAM头文件
******************************************************************************/
/*----------------------------------------------------------------------------
* @更新日志:
* @无
* ---------------------------------------------------------------------------*/
#ifndef __SRAM_H
#define __SRAM_H
/* 包含的头文件 ---------------------------------------------------------------*/
#include "sys.h"
/* 函数申明 -------------------------------------------------------------------*/
void FSMC_SRAM_Init(void);
void FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 NumHalfwordToWrite);
void FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 NumHalfwordToRead);
#endif /* __SRAM_H */
/****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
3.2 sram.c文件代码解读
/**
******************************** STM32F10x *********************************
* @文件名称: sram.c
* @作者名称: Aaron
* @库版本号: V3.5.0
* @工程版本: V1.0.0
* @开发日期: 2020年10月7日
* @摘要简述: SRAM源文件,使用NOR/SRAM的 Bank1.sector3,地址位HADDR[27,26]=10,
* 对IS62WV51216,地址线范围为A0~A18
******************************************************************************/
/*----------------------------------------------------------------------------
* @更新日志:
* @无
* ---------------------------------------------------------------------------*/
/* 包含的头文件 --------------------------------------------------------------*/
#include "sram.h"
#include "usart.h"
/* 定义常量 ------------------------------------------------------------------*/
#define Bank1_SRAM3_ADDR ((u32)(0x68000000))
/************************************************
函数名称:FSMC_SRAM_Init()
函数功能:初始化外部SRAM
入口参数:无
返回参数:无
开发作者:Aaron
*************************************************/
void FSMC_SRAM_Init(void)
{
/* 定义结构体 */
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能相关IO口 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOF|RCC_APB2Periph_GPIOG,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);
GPIO_InitStructure.GPIO_Pin = 0xFF33; /* PD0-1,PD4-5,PD8-15 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* 复用推挽输出 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0xFF83; /* PE0-1,PE7-15 */
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0xF03F; /* PF0-5,PF12-15 */
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0x043F; /* PG0-5,PG10 */
GPIO_Init(GPIOG, &GPIO_InitStructure);
/* 读写时序结构体初始化 */
readWriteTiming.FSMC_AddressSetupTime = 0x00; /* 地址建立时间(ADDSET)为1个HCLK 1/36M=27ns */
readWriteTiming.FSMC_AddressHoldTime = 0x00; /* 地址保持时间(ADDHLD)模式A未用到 */
readWriteTiming.FSMC_DataSetupTime = 0x03; /* 数据保持时间(DATAST)为3个HCLK 4/72M≈55ns(对EM的SRAM芯片) */
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; /* 存储器类型SRAM */
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; /* 存储器数据宽度为16bit */
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =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); /* 使能BANK3 */
}
/**********************************************************************
函数名称:FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 n)
函数功能:在指定地址开始,连续写入n个字节
入口参数:pBuffer:字节指针,首地址;WriteAddr:要写入的地址;n:要写入的字节数
返回参数:无
开发作者:Aaron
***********************************************************************/
void FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 n)
{
for(;n!=0;n--)
{
*(vu8*)(Bank1_SRAM3_ADDR+WriteAddr)=*pBuffer; /* Bank1_SRAM3_ADDR ((u32)(0x68000000)) */
WriteAddr++;
pBuffer++;
}
}
/**********************************************************************
函数名称:FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 n)
函数功能:在指定地址开始,连续读出n个字节
入口参数:pBuffer:字节指针,首地址;ReadAddr:要写入的地址;n:要读出的字节数
返回参数:无
开发作者:Aaron
***********************************************************************/
void FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 n)
{
for(;n!=0;n--)
{
*pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);
ReadAddr++;
}
}
/****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
3.3 main.c文件代码解读
/**
******************************** STM32F10x *********************************
* @文件名称: main.c
* @作者名称: Aaron
* @库版本号: V3.5.0
* @工程版本: V1.0.0
* @开发日期: 2020年10月7日
* @摘要简述: 主函数
******************************************************************************/
/*----------------------------------------------------------------------------
* @更新日志:
* @无
* ---------------------------------------------------------------------------*/
/* 包含的头文件 --------------------------------------------------------------*/
#include "sram.h"
#include "led.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
/* 定义一个数组testsram[],u32表示每个数占4个字节,数组包含250000个值,*/
/* 采用绝对地址定义,数组的起始地址在0x68000000 */
u32 testsram[250000] __attribute__((at(0X68000000)));
/**********************************************************************
函数名称:fsmc_sram_test()
函数功能:外部内存测试(最大支持1M字节内存测试)
入口参数:无
返回参数:无
开发作者:Aaron
***********************************************************************/
void fsmc_sram_test(void)
{
u32 i=0;
u8 temp=0; /* 0≤temp≤255 */
u8 sval=0; /* 在地址0读到的数据 */
printf("外部内存测试:0KB\r\n");
/* 每隔4K个字节,写入一个数据,总共写入256个数据,刚好是1M字节 */
for(i=0;i<1024*1024;i+=4096)
{
FSMC_SRAM_WriteBuffer(&temp,i,1);
temp++; /* for循环运行完后,temp值为0 */
}
/* 依次读出之前写入的数据,进行校验 */
for(i=0;i<1024*1024;i+=4096)
{
FSMC_SRAM_ReadBuffer(&temp,i,1);
if(i==0) /* 将第一次的temp值赋给sval,即sval=temp=0 */
sval=temp;
else if(temp<=sval)
break; /* 本程序设计思路,后面读出的数据一定比第一次读到的数据大 */
printf("内存容量为:%dKB\r\n",(temp-sval+1)*4);
}
}
/**********************************************************************
函数名称:main()
函数功能:主函数
入口参数:无
返回参数:无
开发作者:Aaron
***********************************************************************/
int main(void)
{
u8 key;
u8 i=0;
u32 ts=0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();
KEY_Init();
FSMC_SRAM_Init();
for(ts=0;ts<250000;ts++)testsram[ts]=ts; /* 预存测试数据 */
while(1)
{
key=KEY_Scan(0); /* 不支持连按 */
if(key==KEY0_PRES)
fsmc_sram_test(); /* 测试SRAM容量 */
else if(key==KEY1_PRES) /* 打印预存测试数据 */
{
for(ts=0;ts<250000;ts++)
printf("显示测试数据testsram[%d]=%d\r\n",ts,testsram[ts]);
}
else
delay_ms(10);
i++;
if(i==20)
{
i=0;
LED0=!LED0;
}
}
}
/****** Copyright (C)2020 Aaron. All Rights Reserved ****** END OF FILE *******/
4. 实验结果
按KEY0键:
按KEY1键: