STM32学习心得三十四:外部SRAM原理及实验代码解读

记录一下,方便以后翻阅~
主要内容:
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键:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Leisure_ksj/article/details/108961902