打印

【连载】STM32开发指南--第四十二章 外部SRAM实验

[复制链接]
7712|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
正点原子|  楼主 | 2013-4-2 23:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
第四十二章 外部SRAM实验
STM32F103ZET6自带了64K字节的SRAM,对一般应用来说,已经足够了,不过在一些对内存要求高的场合,STM32自带的这些内存就不够用了。比如跑算法或者跑GUI等,就可能不太够用,所以战舰STM32开发板板载了一颗1M字节容量的SRAM芯片:IS62WV51216,满足大内存使用的需求。
本章,我们将使用STM32来驱动IS62WV51216,实现对IS62WV51216的访问控制,并测试其容量。本章分为如下几个部分:
42.1 IS62WV51216简介
42.2 硬件设计
42.3 软件设计
42.4 下载验证

42.1 IS62WV51216简介
IS62WV51216是ISSI(Integrated Silicon Solution, Inc)公司生产的一颗16位宽512K(512*16,即1M字节)容量的CMOS静态内存芯片。该芯片具有如下几个特点:
l  高速。具有45ns/55ns访问速度。
l  低功耗。
l  TTL电平兼容。
l  全静态操作。不需要刷新和时钟电路。
l  三态输出。
l  字节控制功能。支持高/低字节控制。
IS62WV51216的功能框图如图42.1.1所示:



图42.1.1 IS62WV51216功能框图
       图中A0~18为地址线,总共19根地址线(即2^19=512K,1K=1024);IO0~15为数据线,总共16根数据线。CS2和CS1都是片选信号,不过CS2是高电平有效CS1是低电平有效;OE是输出使能信号(读信号);WE为写使能信号;UB和LB分别是高字节控制和低字节控制信号;
战舰STM32开发板使用的是TSOP44封装的IS62WV51216芯片,该芯片直接接在STM32的FSMC上,IS62WV51216原理图如图42.1.2所示:


图42.1.2 IS62WV51216原理图
       从原理图可以看出,IS62WV51216同STM32的连接关系:
            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的BANK1 区域3来控制IS62WV51216,关于FSMC的详细介绍,我们在第十八章已经介绍过,在第十八章,我们采用的是读写不同的时序来操作TFTLCD模块(因为TFTLCD模块读的速度比写的速度慢很多),但是在本章,因为IS62WV51216的读写时间基本一致,所以,我们设置读写相同的时序来访问FSMC。关于FSMC的详细介绍,请大家看第十八章和《STM32参考手册》。
IS62WV51216就介绍到这,最后,我们来看看实现IS62WV51216的访问,需要对FSMC进行哪些配置。步骤如下:
1)使能FSMC时钟,并配置FSMC相关的IO及其时钟使能。
    要使用FSMC,当然首先得开启其时钟。然后需要把FSMC_D0~15,FSMCA0~18等相关IO口,全部配置为复用输出,并使能各IO组的时钟。
2)设置FSMC BANK1 区域3的相关寄存器。
此部分包括设置区域3的存储器的工作模式、位宽和读写时序等。本章我们使用模式A、16位宽,读写共用一个时序寄存器。
3)使能BANK1区域3
最后,只需要通过FSMC_BCR寄存器使能BANK1,区域3即可。
通过以上几个步骤,我们就完成了FSMC的配置,可以访问IS62WV51216了,这里还需要注意,因为我们使用的是BANK1的区域3,所以HADDR[27:26]=10,故外部内存的首地址为0X68000000。      
42.2 硬件设计
本章实验功能简介:开机后,显示提示信息,然后按下KEY1按键,即测试外部SRAM容量大小并显示在LCD上。按下WK_UP按键,即显示预存在外部SRAM的数据。DS0指示程序运行状态。
本实验用到的硬件资源有:
1)  指示灯DS0
2)  KEY1和WK_UP按键
3)  串口
4)  TFTLCD模块
5)  IS62WV51216
这些我们都已经介绍过(IS62WV51216与STM32的各IO对应关系,请参考光盘原理图),接下来我们开始软件设计。
42.3 软件设计
打开上一章的工程,首先在HARDWARE文件夹下新建一个SRAM的文件夹。然后新建sram.c和sram. h两个文件,将他们保存在SRAM文件夹下,并将这个文件夹加入头文件包含路径。
       打开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)
{                                          
       RCC->AHBENR|=1<<8;       //使能FSMC时钟  
       RCC->APB2ENR|=1<<5;        //使能PORTD时钟
       RCC->APB2ENR|=1<<6;        //使能PORTE时钟
      RCC->APB2ENR|=1<<7;        //使能PORTF时钟
       RCC->APB2ENR|=1<<8;        //使能PORTG时钟            
       GPIOD->CRH&=0X00000000;
       GPIOD->CRH|=0XBBBBBBBB; //PORTD复用推挽输出      
       GPIOD->CRL&=0XFF00FF00;
       GPIOD->CRL|=0X00BB00BB;               
       GPIOE->CRH&=0X00000000;
       GPIOE->CRH|=0XBBBBBBBB; //PORTE复用推挽输出  
       GPIOE->CRL&=0X0FFFFF00;
       GPIOE->CRL|=0XB00000BB;   
       GPIOF->CRH&=0X0000FFFF;
       GPIOF->CRH|=0XBBBB0000;     //PORTF复用推挽输出      
       GPIOF->CRL&=0XFF000000;
       GPIOF->CRL|=0X00BBBBBB;         
       GPIOG->CRH&=0XFFFFF0FF;
       GPIOG->CRH|=0X00000B00;     //PORTG复用推挽输出 PG10->NE3   
      GPIOG->CRL&=0XFF000000;
       GPIOG->CRL|=0X00BBBBBB;
       //寄存器清零
       //bank1有NE1~4,每一个有一个BCR+TCR,所以总共八个寄存器。
       //这里我们使用NE3 ,也就对应BTCR[4],[5]。                             
       FSMC_Bank1->BTCR[4]=0X00000000;
       FSMC_Bank1->BTCR[5]=0X00000000;
       FSMC_Bank1E->BWTR[4]=0X00000000;
       //操作BCR寄存器       使用异步模式,模式A(读写共用一个时序寄存器)
       //BTCR[偶数]:BCR寄存器;BTCR[奇数]:BTR寄存器
       FSMC_Bank1->BTCR[4]|=1<<12;//存储器写使能
       FSMC_Bank1->BTCR[4]|=1<<4; //存储器数据宽度为16bit        
       //操作BTR寄存器                                                     
       FSMC_Bank1->BTCR[5]|=3<<8;
//数据保持时间(DATAST)为4个HCLK 4/72M=55ns        
       FSMC_Bank1->BTCR[5]|=0<<4; //地址保持时间(ADDHLD)未用到         
       FSMC_Bank1->BTCR[5]|=0<<0; //地址建立时间(ADDSET)为1个HCLK
       //闪存写时序寄存器
       FSMC_Bank1E->BWTR[4]=0x0FFFFFFF;//默认值
       //使能BANK1区域3
       FSMC_Bank1->BTCR[4]|=1<<0;                                                                             
}                                                                                                  
//在指定地址(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++;
       }
}
       此部分代码包含3个函数,FSMC_SRAM_Init函数用于初始化,包括FSMC相关IO口的初始化以及FSMC配置。另外,FSMC_SRAM_WriteBuffer和FSMC_SRAM_ReadBuffer这两个函数分别用于在外部SRAM的指定地址写入和读取指定长度的数据(以字节为单位)。这里需要注意的是:FSMC当位宽为16位的时候,HADDR右移一位同地址对其,但是ReadAddr我们这里却没有加2,而是加1,是因为我们这里用的数据为宽是8位,通过UB和LB来控制高低字节位,所以地址在这里是可以只加1的。另外,因为我们使用的是BANK1,区域3,所以外部SRAM的基址为:0x68000000。
保存sram.c文件,并加入到HARDWARE组下,然后打开sram.h,在该文件里面输入如下代码:
#ifndef __SRAM_H
#define __SRAM_H                                                                                                           
#include <stm32f10x_map.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
保存此部分代码。最后,打开test.c文件,修改代码如下:
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;
      Stm32_Clock_Init(9);           //系统时钟设置
       uart_init(72,9600);             /串口初始化为9600
       delay_init(72);                         //延时初始化
       LED_Init();                        //初始化与LED连接的硬件接口
       LCD_Init();                       //初始化LCD
       usmart_dev.init(72);             //初始化USMART      
      KEY_Init();                         //按键初始化
      FSMC_SRAM_Init();           //初始化外部SRAM
      POINT_COLOR=RED;         //设置字体为红色
       LCD_ShowString(60,50,200,16,16,"WarShip STM32");   
       LCD_ShowString(60,70,200,16,16,"SRAM TEST");
       LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
       LCD_ShowString(60,110,200,16,16,"2012/9/16");
       LCD_ShowString(60,130,200,16,16,"KEY1:Test Sram");
       LCD_ShowString(60,150,200,16,16,"WK_UP:TEST Data");
      POINT_COLOR=BLUE;//设置字体为蓝色
       for(ts=0;ts<250000;ts++)testsram[ts]=ts;//预存测试数据   
      while(1)
       {   
              key=KEY_Scan(0);//不支持连按
              if(key==KEY_DOWN)fsmc_sram_test(60,170);//测试SRAM容量
              else if(key==KEY_UP)//打印预存测试数据
              {
                     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;
             }
       }      
}
       此部分代码除了mian函数,还有一个fsmc_sram_test函数,该函数用于测试外部SRAM的容量大小,并显示其容量。main函数则比较简单,我们就不细说了。
此段代码,我们定义了一个超大数组testsram,我们指定该数组定义在外部sram起始地址(__attribute__((at(0X68000000)))),该数组用来测试外部SRAM数据的读写。注意该数组的定义方法,是我们推荐的使用外部SRAM的方法。如果想用MDK自动分配,那么需要用到分散加载还需要添加汇编的FSMC初始化代码,相对来说比较麻烦。而且外部SRAM访问速度又远不如内部SRAM,如果将一些需要快速访问的SRAM定义到了外部SRAM,将会严重拖慢程序运行速度。而如果以我们推荐的方式来分配外部SRAM,那么就可以控制SRAM的分配,可以针对性的选择放外部还是放内部,有利于提高程序运行速度,使用起来也比较方便。

42.4 下载验证
在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,得到如图42.4.1所示界面:


图42.4.1 程序运行效果图
此时,我们按下KEY1,就可以在LCD上看到内存测试的画面,同样,按下WK_UP,就可以看到LCD显示存放在数组testsram里面的测试数据,如图42.4.2所示:

图42.4.2 外部SRAM测试界面
       该实验我们还可以借助USMART来测试,只需要在usmart_nametab里面添加读写SRAM的两个函数,就可以用USMART来测试外部SRAM了。
实验37 外部SRAM实验.rar (185.05 KB)

《STM32开发指南》第四十二章 外部SRAM实验.rar (575.77 KB)





沙发
不爱说话| | 2013-4-3 11:24 | 只看该作者
不错。讲得很简明。
好多人不知道怎么用STM32 外扩的RAM

使用特权

评论回复
板凳
yuxuefly| | 2014-4-13 22:56 | 只看该作者
为什么我的只读出了436k呢?1M的SRAM!

使用特权

评论回复
地板
longfenghugui| | 2014-8-21 15:24 | 只看该作者

使用特权

评论回复
5
jjjkkk00| | 2014-11-20 22:13 | 只看该作者
MARK

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:我的STM32开发板店铺:http://openedv.taobao.com 我的技术论坛论坛:www.openedv.com

91

主题

264

帖子

71

粉丝