概述

SRAM的简介

折腾过电脑的朋友都知道,当电脑运行比较卡的时候,我们可以通过给电脑加装内存条来改善电脑的性能。那么号称微型计算机的单片机能不能像电脑一样加装内存条呢?装内存条倒是不行,但是我们可以给单片机外加和内存条效果一样的SRAM来提升单片机的性能。下面以STM32F407ZGT6单片机来讲解一下来扩展外部SRAM。

原理:给STM32芯片扩展内存与给PC扩展内存的原理是一样的,只是PC上一般以内存条的形式扩展,内存条实质是由多个内存颗粒(即SRAM芯片)组成的通用标准模块,而STM32直接与SRAM芯片连接。

SRAM,型号IS62WV51216,管脚图如下:

IS62WV51216的管脚总的来说大致分为:电源线、地线、地址线、数据线、片选线、写使能端、读使能端和数据掩码信号线

从这个图中我们可以看出IS62WV51216有19根地址线和16根数据线,从这些数据中我们可以分析出IS62WV51216的存储大小为1M,那么这个1M是怎么分析出来的呢?

我们得来说说IS62WV51216的存储原理。首先,我们来谈一谈一般的SRAM的存储原理:

sram的存储模型我们可以用矩阵来说明:

SRAM内部包含的存储阵列,可以把它理解成一张表格,数据就填在这张表格上。和表格查找一样,指定一个行地址和列地址,就可以精确地找到目标单元格,这是SRAM芯片寻址的基本原理。这样的每个单元格被称为存储单元,而这样的表则被称为存储矩阵。地址译码器把N根地址线转换成2的N次方根信号线,每根信号线对应一行或一列存储单元,通过地址线找到具体的存储单元,实现寻址。如果存储阵列比较大,地址线会分成行和列地址,或者行、列分时复用同一地址总线,访问数据寻址时先用地址线传输行地址再传输列地址。

但是呢?你会发现,这个原理好像不太适用于IS62WV51216,为什么呢?

其实不然,因为我们使用的SRAM比较小,IS62WV51216没有列地址线。它只有19根行地址线,那么,我们就可以这么来解释:IS62WV51216有16根数据线,也就是说它的数据宽度为16位,一个行地址也就对应16位,即2字节空间。好,那现在来计算一下IS62WV51216有多少个行地址。2的19次方等于512K,在512K的基础之上在乘我们之前计算的2字节,不正好是1024K,也就是1M吗?1M后面的单位是B,即Byte,而不是Bit哦。这样的话你就会发现IS62WV51216这个名字中本身就包含了大量的信息:IS62WV51216共有512K个行地址,数据宽度为16位,再加以计算就可以得到它的存储大小为1M啦,有趣吧!

FSMC的简介

FSMC是Flexible StaticMemory Controller的缩写,就是灵活的静态存储控制器。它可以用于驱动包括SRAM、NOR FLASH以及NAND FLSAH类型的存储器。其他我们不用管,从上面我们可以总结的是,stm32雇佣FSMC这个管家来管理我们的IS62WV51216。来来来,我们来看看FSMC的庐山真面目:

蒙了吧!又是这么多信号线,不要怕,我们还是来总结归纳一下。我们FSMC控制SRAM为例来说明:通过查看STM32F103系列的参考手册:

你会发现居然和SRAM中的线居然高度统一(那是当然喏,我们就是讲的FSMC嘛!)

  1. FSMC_NBL[1:0]分别对应于LB#、UB#,有什么用呢?提供数据掩码信号。具体是怎么回事呢?还记得前面提到的行地址线吗?

    一根行地址线对应16位的数据,我们可以把16位的数据分为高字节和低字节。当要访问宽度为16位的数据时,使用行地址线指出地址,然后把UB#和LB#线都设置为低电平(FSMC_NBL0和FSMC_NBL1为低电平),那么I/O0-I/O15线(FSMC_D0到FSMC_D15)都有效,它们一起输出该地址的16位数据(或者接收16位数据到该地址);当要访问宽度为8位的数据时,使用行地址线指出地址,然后把UB#(FSMC_NBL0)设置为低电平,I/O8-I/O15(FSMC_D8到FSMC_D15)会对应输出该地址的高8位,I/O0-I/O7的信号无效(或者把LB#(FSMC_NBL1)设置为低电平,I/O0-I/O7(FSMC_D0到FSMC_D7)会对应输出该地址的低8位,I/O8-I/O15的信号无效。这样是不是有一部分信号没有用呢?好像被掩盖了。因此它们被称为数据掩码信号。

  2. FSMC_NE[1:4]是个很有趣的东西,它决定了FSMC可以控制多个存储器。这里就要提及FSMC的地址映射啦!

首先,有一点我们必须明白,对于32位的stm32单片机来说,它能够管理的地址大小为4GB,而stm32将4GB的地址空间中的0x60000000到0x9FFFFFFF共1GB的空间分给外部内存,所以这1GB的空间就成了我们的小天地,供我们自由玩耍。然后强势的FSMC就接管了这1GB的空间,FSMC将图中的1GB大小的External RAM存储区域分成了4个Bank区域,每个Bank对应于stm32内部寻址空间的不同地址范围。那么为什么要分为不同的Bank区域呢?因为不同的Bank可以来管理不同的外部存储设备,比如NOR Flash及SRAM存储器只能使用Bank1的地址,NAND Flash存储器只能使用Bank2和Bank3的地址,等。

细心的你肯定还会发现,每个Bank中居然还有4x64MB这种文字,这是什么意思呢?

Bank内部的256MB空间又被分成4个小块,每块64M,各自有相应的控制引脚用于连接片选信号。FSMC_NE[4:1]信号线就分别对应图中的FSMC bank1 NOR/PSRAM4到FSMC bank1 NOR/PSRAM1。当STM32访问0x6C000000-0x6FFFFFFF地址空间时,会访问到Bank1的第3小块区域:FSMC bank1 NOR/PSRAM3相应的FSMC_NE3信号线会输出控制信号(即片选信号),如果这个时候FSMC_NE3处刚好接上IS62WV51216的CS端,那么IS62WV51216就可以任由我们摆布啦。因此,对于你使IS62WV51216来说,一定要注意你的CS端是接的FSMC的哪个FSMC_NE端,这决定你在程序访问哪个地址范围。

下面来说一下在stm32F407中SRAM的硬件连接:对于FSMC来说,它已经集成到了单片机内部,它的提供给的管脚已经确定了,是不能改动的,这个可以参考STM32对应芯片的Datasheet。唯一具有灵活性的就是FSMC_NE,具体用哪个FSMC_NE管脚来和你的SRAM相连,当然是你的自由,但是不要忘了,你要找到你选的FSMC_NE所对应的地址范围,不然写程序的时候就搞不清喏!

一、配置启动文件

我们使用官方标准库,拷贝标准库FSMC例程里面的"startup_stm32f10x_hd.s"文件(工程使用103ZE,若使用互联型芯片拷贝对应文件),替换掉我们之前工程的启动文件,如下图:

二、配置FSMC

我们使用官方标准库里面"system_stm32f10x.c"文件里面现成的函数接口(使用寄存器配置)来配置FSMC,只需要打开"system_stm32f10x.c"文件里面第122行的宏"DATA_IN_ExtSRAM",见下图:

三、分配RAM

RAM地址的分配是由编译器完成的,因此需要对工程进行相应配置,就是使用外部RAM,见下图:

四、测试函数说明

该函数位于main.c文件下面;

这个函数主要就是对上面配置及整改工程的测试。定义一个全局变量和一个局部变量,通过串口打印出他们的地址就可以判断运行内存是使用外部还是内部。

五、打印(测试)结果

看了测试函数就知道依次打印出来的数据是什么,这里我们很明显的可以看到打印出的地址是0x6800xxxx,这里的0x6800xxxx地址数据就是外部SRAM地址(不懂的话,请看昨天的讲解),说明运行内存确实是外部SRAM.

六、变量定位定义

对于一个使用单片机内部 RAM 的访问相当容易,基本上定义变量是不需要思考其定位问题的,当把外部 SRAM 考虑进来时,则需要考虑内部及外部的问题;比如,如何让一个变量定位在内部或者外部 RAM;定位于内部是如何访问,定位于外部时又如何访问。这里说的是一个变量,或者一个数组的定位问题,当涉及到一个文件或者多个文件其内部所有变量的定位问题就复杂得多了。变量定位定义的一般方法(使用__attribute__)。

一般的定义方法如下图:

图1

定义了 3 数组(属于公共变量),现在检查下对应的 map 文件如下图所示:

图2

如上图的 2998 行 3012 行 3013 行可见与上面定义的位置是对应的,所以这样实现了变量定义的定位功能;当内部 RAM 不足时或者有意定义一个变量定位到外部 RAM 中就可以采用这种方法(使用外部 RAM 有前提条件这里就不说了)。

七、批量定义变量到外部 SRAM

如何实现批量的变量定义到外部 RAM 呢?除了批量地使用__attribute__定义变量,还是有更快捷的方法的。

配置外部 SRAM 可用起始地址及大小—如下图:

图3

图4

如上图 所示,最左最右边的小方框不要打勾…千万不要打勾,开始地址及大小必须如实填写(Size 的值可以小于但绝对不能大于实际外置芯片值),开始地址安装原理图连线确定其值。

八、定义一个文件内的所有变量于外部SRAM

首先定一个小目标:确定你要一个所有变量需要定位于外部 SRAM 的文件,接着按照下图来配置(这里让 main.c 这个文件,让里面定义的所有变量均定位于外部SRAM 中)在工程窗口选择 main.c 点鼠标右键如下图:

图5

菜单选择第一行"Options for File 'main.c' "之后显示如下图:

图6

如上图我们仅需关注"Memory Assignment"组,Code/Const 定义代码及 const 的定位,Zero Initialized Data 及 Other Data 是变量的定位,此处我们关心的仅数据(变量)部分的定位。定位设置如下图:

图7

至此,main.c 文件内部的所有变量均已定位到外部 SRAM 中(前提是没忘记点 OK 按钮),到这里应该会发现一个问题如图 7 每一项都有一个<default>选项;在 keil 的工程里每个文件的变量安排都会有一个默认选项,当这里选择<default>时则会启用如图3 所示的默认选项,可以看到图 4 那里,说到千万不要打勾的那里。打勾的话那里就变成了第一默认选项,那么图 7 的配置就多余了。这个是可以验证的。那么再回头验证一下图 7 的配置是否实现了将 main.c 文件中的变量定位到外部 SRAM…..同样查看MAP 文件验证一下。首先在 main.c 中定义变量如下图:

图8

如上图所示定义了一个结构体实例,两个 16 的数组,对应 map 文件如下图:

图9

如上图所示, 3009 行 3010 行使用__attribute__定义占用了外部 SRAM的部分地址,《main.c》文件中并没有使用__attribute__来定义变量,其定位也处于外部 SRAM 中,其数组的大小定义与 map

文件是一致的,在此证明经过配置之后,在 main.c 文件中定义的变量均会被定位到外部 SRAM 中。再验证 GraphicsDac_t 的大小。printf(" GraphicsDac_t size=%d \r\n",sizeof(GraphicsDac_t));

图 10(可见 printf 的大小与 map 的大小是一致的)

九、将变量定义到内部SRAM

参考图 3,将内部 SRAM 的《default》打勾,之后将图 7 的下两个选项配置为《default》即可,这样实现一个文件其变量定位的切换。多个外部 SRAM 芯片时适当参考配置。

十、定位到外部 SRAM的变量的访问方法

方法一、一般访问外部 SRAM 的方法

首先使用 SRAM_Init();之后使用下面两个函数读写外部 SRAM:

SRAM_ReadBuffer(uint16_t* pBuffer, uint32_t ReadAddr, uint32_t NumHalfwordToRead)

SRAM_WriteBuffer(uint16_t* pBuffer, uint32_t WriteAddr, uint32_t NumHalfwordToWrite)

方法二、编译器

如第 3 节变量定位定义方法,变量的访问就由编译器自己搞定了(关于这一点还没有实际硬件验证---这里仅是理所当然的推测,至于还要使用方法一是不可思议的),变量的读写就和内部变量一样操作。

备注:文件内部函数内部的变量被定义在堆栈里,同时说明上面所说的定位到外部 SRAM 的变量均为全局变量,其文件内的局部变量还是在堆栈里(此处为我的推测,没经过验证)。

STM32F103_外部RAM用作运存的更多相关文章

  1. STM32F103_外部RAM用作运存---IS62WV51216

    https://www.cnblogs.com/lilto/p/9548736.html STM32F103_外部RAM用作运存   概述 SRAM的简介 折腾过电脑的朋友都知道,当电脑运行比较卡的时 ...

  2. keil程序在外部RAM中调试的问题总结(个人的一点经验总结)

    keil程序在内部RAM调试的基本步骤网上已经有非常多了,我就不再赘述,大家能够在网上搜到非常多. 可是有些时候内部RAM并不够用,这就须要将程序装入外部RAM中调试,而在这个过程中可能会出现各种各样 ...

  3. Tomcat配置JVM运存

    setenv.bat set "JAVA_OPTS=-server -Xms256M -Xmx1024M -XX:PermSize=256m -XX:MaxPermSize=1024m&qu ...

  4. USB小白学习之路(3) 通过自定义请求存取外部RAM

    通过自定义请求存取外部RAM 1. 实验简述 此实验是对自定义的供应商特殊命令(vendor specific command bRequest = 0xA3)进行解析,程序中的read me说明如下 ...

  5. 通过PCI9030向外部RAM写数据失败现象

    我们的系统方案是:以9030作为PCI接口芯片,本地端映射了一片IDT70V06的双端口RAM.进行数据传输压力测试时,发现PC机向IDT70V06写数据偶尔会失败.这一问题是什么原因造成的呢? 最初 ...

  6. java程序运存扩容

    线上程序随着业务增多,运行的越来越慢,初步判定是因为内存分配的太小导致频繁的进行GC和OOM,于是着手增加内存上限. 增加内存上限都知道是修改java启动的opt,因为服务容器是tomcat 首先是在 ...

  7. 宏旺半导体浅谈存储芯片LPDDR4X与UFS2.1的差别

    现在市面上手机参数动不动就是8GB+128GB,手机的这些参数是越大越好吗?这些数字代表什么?宏旺半导体ICMAX给大家科普下. 手机的运行内存RAM——LPDDR4X LPDDR4X为RAM(运存) ...

  8. 单片微机原理P3:80C51外部拓展系统

    外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC.   0. IO接口电路概念与存储器拓展 1. 为什 ...

  9. RAM和ROM的区别

    区别如下: 1.概念 RAM(random access memory)即随机存储内存,这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序.ROM(Read-Only Memory)即 ...

随机推荐

  1. ASP.NET Core Web API 控制器与方法返回输出

    DATA ACCESS LAYER 在一些不同的示例教程中,我们可能看到 DAL 的实现在主项目中,并且每个控制器中都有实例.我们不建议这么做. 当我们编写 DAL 时,我们应该将其作为一个独立的服务 ...

  2. IntelliJ IDEA 2017.3尚硅谷-----安装

    选择路径 安装目录 bin目录下的文件 启动文件 虚拟机的配置信息 -Xms128m 初始内存 -Xmx750m 最大内存-XX:ReservedCodeCacheSize=240m 可保留代码缓存的 ...

  3. node学习之express(1)

    1.前提是你安装了node,npm 2.此次我学习的网站是 汇智网 3.创建一个项目学习: npm init 按照提示,输入/不输入 项目的一些信息 安装express模块:npm install e ...

  4. CentOS7服务器状态下安装xampp

    遇到的问题 1.远程不能访问phpmyadmin,只能在本地访问,但是本地为命令行模式. 需要修改一下服务器端的配置,我们找到 /opt/lampp/etc/extra/httpd-xampp.con ...

  5. Codeforces Round #599 (Div. 2) A. Maximum Square

    Ujan decided to make a new wooden roof for the house. He has nn rectangular planks numbered from 11  ...

  6. [LEETCODE] 初级算法/数组 1.1删除排序数组中的重复项

    题目: 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. ...

  7. 插入数据:insert,replace

    *insert高级用法* 1.语法:insert into tbname(字段列表) values 值列表; 1.1可以不将所有的字段都插入数据.如果说需要完成部分字段的插入,需要必须存在字段列表. ...

  8. 南京邮电大学网络攻防平台(NCTF)-MD5-Writeup

    南京邮电大学网络攻防平台-MD5-Writeup 题干如下: 分析: 遍历 TASC?O3RJMV?WDJKX?ZM(?替换为其他),找到md5为e9032???da???08????911513?0 ...

  9. 虚拟机安装archLinux+xfce桌面教程(更新时间2017-5-8)

    本教程转自http://blog.sina.com.cn/u/5692023517 感谢大神写出如此详细的教程并允许转载 本教程的目的:为了让新手安装arch不再那么难, 一个好的教程可以少走很多弯路 ...

  10. Java 前加加和后加加 总结

    public class Test { public static void main(String[] args) { int age = 6; //先自加,再使用(age先自加1,然后再打印age ...