查看原文
其他

嵌入式项目立项:这两个用量评估很重要,你知道是什么吗?

2017-07-17 爱板网

一个嵌入式项目在立项时,其中有个重要的环节就是对系统所需的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的分类:

RAM分为很多种,关于SRAM、DDR、SDRAM、PSRAM等等的概念请自行百度,从软件的角度笼统一点,分为片内和片外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的分类:

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应该放在哪里

首先考虑一下,有没有什么东西必须放在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的冲突。





阅读推荐



            走过路过,不要错过这个公众号哦!

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

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