查看原文
其他

嵌入式项目是如何评估系统所需的RAM和ROM用量的?

嵌入式ARM 2021-01-31


ROM和RAM是人尽皆知的概念。即:

RAM(random access memory)随机存储内存,这种bai存储器在断电时du将丢失其存储内容,故主要用于存储短时间使用的程序。

ROM(Read-Only Memory)只读内存,是一种只能读出事先所存数据的固态半导体存储器。

而当一个嵌入式项目在立项时,其中有个重要的环节就是对系统所需的RAM和ROM用量进行评估。

在满足系统需求的前提下,尽量降低硬件成本,据说同等大小的RAM价格大概是ROM的6倍。
 大部分的资料都宣称程序分为RO、DATA、BSS等段,RO段应该放在ROM里,DATA段放在RAM里云云。对于DATA、BSS,这些段因为有频繁的写操作,所肯定要放到RAM里,但是只读数据(包括代码段)必须放在ROM里吗?答案是不一定。 RAM和ROM等存储单元的物理地址映射是由做硬件的数字工程师确定,他们在划分时主要会考虑电路的延迟,将这些储存单元按照一定的方式挂在同一条AHB总线上。而嵌入式平台软件工程师可以通过修改链接脚本来设置哪些数据、代码在程序运行时放在ROM里,哪些放在RAM里。 这里多说一句,RAM在系统刚上电的时候,其内容是随机的。所谓的数据、代码放在RAM里,是指在初始化时,CPU从flash里读下载的bin文件,也有的平台下载的是hex文件,找出其中的ram段,以类似于memcpy的方式将数据从bin文件里的对应位置拷贝到RAM映射到的物理地址里,这才是所谓的放在RAM里. 

RAM分为很多种,关于SRAM、DRAM、SDRAM、PSRAM等等的概念。简单来说就是:

SRAM : 静态RAM,不用刷新,速度可以非常快,像CPU内部的cache,都是静态RAM,缺点是一个内存单元需要的晶体管数量多,因而价格昂贵,容量不大。
DRAM: 动态RAM,需要刷新,容量大。
SDRAM :同步动态RAM,需要刷新,速度较快,容量大。
DDR SDRAM: 双通道同步动态RAM,需要刷新,速度快,容量大。



具体来说:


RAM(Random Access Memory) 随机存储器。存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。
按照存储信息的不同,随机存储器又分为静态随机存储器(Static RAM,SRAM)和动态随机存储器(Dynamic RAM,DRAM)。
SRAM(Static RAM)不需要刷新电路即能保存它内部存储的数据。
SSRAM(Synchronous SRAM)即同步静态随机存取存储器。同步是指Memory工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;随机是指数据不是线性依次存储,而是由指定地址进行数据读写。
对于SSRAM的所有访问都在时钟的上升/下降沿启动。地址、数据输入和其它控制信号均于时钟信号相关。
这一点与异步SRAM不同,异步SRAM的访问独立于时钟,数据输入和输出都由地址的变化控制。
DRAM(Dynamic RAM)每隔一段时间,要刷新充电一次,否则内部的数据即会消失。
因此SRAM具有较高的性能,但是SRAM也有它的缺点,即它的集成度较低,相同容量的DRAM内存可以设计为较小的体积,但是SRAM却需要很大的体积,且功耗较大。所以在主板上SRAM存储器要占用一部分面积。
SRAM的速率高、性能好,它主要有如下应用:
1)CPU与主存之间的高速缓存。
2)CPU内部的L1/L2或外部的L2高速缓存。
SDRAM(Synchronous DRAM)即同步动态随机存取存储器。同步是指 Memory工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机是指数据不是线性依次存储,而是自由指定地址进行数据读写。
DRAM演进及详细分类:
A.DRAM(Dynamic Random-Access Memory),即动态随 机存储器最为常见的系统内存。DRAM 只能将数据保持很短的时间。为了保持数据,DRAM使用电容存储,所以 必须隔一段时间刷新(refresh)一 次,如果存储单元没有被刷新,存储的信息就会丢失。
B. SDRAM:Synchronous Dynamic Random Access Memory, 同步动态随机存取存储器,同步是指Memory工作需要步时钟,内部的命令的发送与数据的传输都以它为基准;动态是指存储阵列需要不断的刷新来保证数据不 丢失;随机是指数据不是线性依次存储,而是由指定地址进行数据读写。
C. DDR: SDRAM从发展到现在已经经历了四代,分别是:第一代SDR SDRAM,第二代DDR SDRAM,第三代DDR2 SDRAM,第四代DDR3 SDRAM。
第一代与第二代SDRAM均采用单端(Single-Ended)时钟信号,第三代与第四代由于工作频率比较快,所以采用可降低干扰的差分时钟信号作为同步 时钟。SDR SDRAM的时钟频率就是数据存储的频率,第一代内存用时钟频率命名,如pc100,pc133则表明时钟信号为100或 133MHz,数据读写速率也为100或133MHz。
之后的第二,三,四代DDR(Double Data Rate)内存则采用数据读写速 率作为命名标准,并且在前面加上表示其DDR代数的符号,PC-即DDR,PC2=DDR2,PC3=DDR3。如PC2700是DDR333,其工作频 率是333/2=166MHz,2700表示带宽为2.7G。
DDR的读写频率从DDR200到DDR400,DDR2从DDR2-400到DDR2-800,DDR3从DDR3-800到DDR3-1666。
很多人将SDRAM错误的理解为第一代也就是 SDR SDRAM,并且作为名词解释,皆属误导。SDR不等于SDRAM。


从软件的角度笼统一点,分为片内和片外ram。对于软件工程师的来说,它们的区别就是访问速度,片内ram一般用TCM(Tightly Coupled Memory)的方式集成在CPU芯片内部,有单独的数据通道,它的访问速度可以和cache相媲美,而片外ram的访问要麻烦一些,CPU发出想访问的地址给AHB总线控制器,它会知道对应的地址是在片外RAM里,将访问请求递给RAM控制器,再由RAM控制器访问RAM后将数据返回。
 大体上片内的访问速度是片外RAM的1.5~2倍。片内ram集成在CPU芯片内部,它是在CPU设计时就加上的,它使用和CPU几乎一样的制作工艺和材料,而且增加了芯片的大小,所以成本比较高,一般也就只有几十K字节,好钢当然要用在刀刃上,片内ram用来存放中断处理handler、RTOS调度器、任务上下文切换、内存分配释放等使用频率最高的代码和中断堆栈这种读写频率极高的内存区,如果有多余的部分也可以放一些经常被引用到的全局变量。 片外RAM一般就是采购的市面上的成品,如Samsung,Hynix,Apmemory等,价格相对便宜,其容量的可选范围也较为宽松,从几M到几G的都有,它可以用来存储全局变量,bss,以及我们常用到的malloc所分配的堆空间等。还有一点不同的是:片内Ram上电就可以直接使用,而片外的RAM都需要一个硬件控制器完成对其时序的控制,软件人员则需要对该控制器编写专用的控制驱动 ROM一般是有两种,一种是指集成在CPU芯片内部的一块只读存储区域,一般是几K到几十K字节大小,用来存储系统刚上电时对cpu和一些核心外设(如时钟,串口,MMU、DRAM、Flash等)进行初始化的代码,它在程序运行中也是不可写的,要对它执行写操作只能使用硬件烧写器进行,也就是一般所说的下载程序,这部分的代码在芯片测试阶段可以进行编程器下载更新,量产后一般就会固化,不能做任何修改的。 另一种指的就是flash。首先需要说明的是,很多做嵌入式应用开发的同学一直把flash比作PC上的硬盘,其实它们指的是Nand flash,而对于很多小型的嵌入式系统,就只有一个2M或者4M的Nor Flash,它和硬盘有一个显著的区别:flash里存放的代码是可以由CPU直接取指并执行的,而PC上硬盘里的程序都需要加载到内存里才能运行。 flash并不是绝对的运行时不可写,有时候应用程序需要保存一些配置信息到flash里,类似于PC程序的配置文件,以保证掉电了之后它的内容不会丢失,下次开机时可以直接从flash读取到。 不过,flash的写操作要比RAM麻烦的多了,flash在写之前需要发送多个命令字来握手,还要先对即将要写的地址所在的扇区进行整体擦除,就是把该扇区里的内容全设为1,所谓写flash就是把其中的一些bit设为0;更要命的是,flash的每个独立bit位的写次数是有上限的,市面上大部分的产品都只能写10~100万次。多说一句,每个bit位的寿命是独立的,如果一个bit位在擦除和写的动作中,它的值始终为1,则不会有影响;例如反复对一个地址写0xF0,则不会影响高4bit的寿命,而低4bit每次都要先擦成1,再写入0,这样就会降低其寿命。 现在我们讨论一下RO、DATA、BSS到底应该放在RAM里还是ROM里。 首先考虑一下,有没有什么东西必须放在ROM里?当然有,引导程序(系统的初始化代码)就必须放到ROM里。在CPU刚上电时,只能去一个默认的地址去取第一条指令,开始干活,这个地址都是映射到片内的ROM里,原因很简单,此时,作为外设的flash和DDR等都还没有初始化,CPU根本无法从它们那里读写数据,片内ROM里的这些代码就需要完成这些模块的初始化。另外,一个项目的处理器和主要外设确定了以后,这部分初始化代码在很长的时间里,都不需要做任何修改的。 那有没有什么东西必须放RAM里?当然也有,应用程序经常读写的全局变量,堆、栈等等,都需要放在RAM里,根据访问的频率,将频率最高的少量数据放到片内ram。 只读数据(代码段、程序里的const、字符串等)应该放在哪?一般来说,这些数据应该放在Flash里,因为它们不需要被修改,而且前面提到过,rom要比ram便宜的多。可能有人会有疑问,放在flash里,会不会读取的速度很慢?读ROM的速度是比读RAM的数据要慢一点,但是不要忘了,现代CPU都有强大的cache,而且数据Dcache和指令Icache都是分开的,在系统运行中,cache的命中率可以高达80~90%,所以大部分时候CPU都可以在第一时间就拿到想要的指令和数据。 最后分享两个案例:
1、前面提到片内Ram是一块非常宝贵的空间,它的优点就是CPU可以在第一时间取到里面的数据。但是处于成本考虑,它的空间往往都非常有限。如果用户有两种比较耗时的业务,需要频繁的大量取指,但重点是它们不会同时运行。这种情况下,就可以在链接脚本里开辟的片内Ram空间,将该段的链接选项加上NOCROSSREFS,再将这片空间的大小定义为这两个耗时业务代码占空间较大的那个(例,业务一有1K代码,业务二有2K代码,这片空间就定义为2K),在业务一开始时,将其代码拷贝到这块片内ram里(一般是用DMA的方式),运行业务一的代码;当业务二开始时,也是拷贝其代码到片内ram里。这样,两种业务的耗时操作在运行中都可以在第一时间里取到指令,对耗时业务做了很好的优化。 2、曾经遇到过这样一个运行时死机,查看CPU寄存器可以看到是报一个取指了令异常,可是查看PC寄存器对应的地址,发现CPU正在取的一条指令是正常的,起初十分费解。后来通过仔细分析其死机前的运行情况才定位出原因,死机前一个task正在写flash,这时候来了一个中断,中断里调用了一个函数,其地址就在flash里,而此时flash处于一个不可读的状态,CPU在执行中断里的函数就拿不到指令,只能死机。 解决问题的办法有2种:一是在写flash的过程中屏蔽所有中断,这是一种很裸的方法,对于响应时间很敏感的嵌入式系统,一般都不允许随便关中断。二是将这个在flash里存储的函数放到RAM里,避免访问flash的冲突。

-END-




推荐阅读



【01】嵌入式和单片机不一样?那它们的区别在哪?【02】嵌入式开发碰到无法解决的问题?编程的凹凸性有妙用!(附C代码)【03】该不该放弃单片机、嵌入式这条路?【04】嵌入式er必知:模数采样知多少(最全总结)【05】嵌入式软件测试的10条秘诀



免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存