来源于小伙伴提问。
以下是我的一些看法。
MCU中的程序通常可以直接在FLASH中运行,但在对性能有特殊需求或需要动态修改代码的情况下,可以将程序搬到RAM中执行。
同时,片内与片外存储器在速度和访问延迟上确实存在明显差异,这会影响系统的设计决策。
1
程序从FLASH执行还是搬到RAM执行?
一般情况下,嵌入式系统的程序代码是存储在片内的FLASH中的。
在MCU上电复位后,系统的启动过程大致如下:
上电复位(Power-on Reset):MCU会进入复位状态,内部电路开始初始化。
启动代码(Boot Code):上电后,芯片的启动代码会被执行。这个启动代码可能是由芯片厂家提供的ROM引导代码,负责初始化时钟、栈指针等关键硬件资源,并将程序计数器(PC指针)指向FLASH中预定的入口点(通常是复位向量)。
执行用户代码: 此时,程序开始从FLASH中读取指令,并由处理器逐条执行。
2
FLASH中的代码是如何运行的?
当程序计数器(PC)指向FLASH中某个地址时,处理器会从该地址读取指令,解码后执行。也就是说,程序实际上可以直接从FLASH中运行,不一定需要搬到RAM。
对于绝大多数嵌入式应用来说,这是最常见的做法,因为这样可以节省宝贵的RAM空间。
在大多数ARM或PowerPC架构的MCU中,启动流程是:
复位向量:通常是FLASH的起始地址或者某个固定位置,用于存放初始PC值(也就是程序入口地址)。
程序计数器(PC)的设置:上电时,PC由启动代码或复位向量设定为FLASH中的起始地址,之后按顺序读取FLASH中的指令。
3
必须搬到RAM中才能运行吗?不这样做有什么不妥?
虽然代码可以直接从FLASH中执行,但有时搬到RAM中运行更具优势,主要有以下几种原因:
执行速度:RAM的访问速度通常比FLASH更快。如果对性能要求较高,可以将部分代码(如关键中断服务程序)加载到RAM中运行,能显著提升执行效率。
写入或擦除FLASH的限制:在执行写入或擦除FLASH操作时,往往会阻塞对FLASH的读访问。因此,为了避免程序运行中出现问题,有时需要将代码搬到RAM中执行,以便在对FLASH进行操作时仍能正常运行。
代码自修改:某些高级应用中,程序可能会修改自身的指令。这种情况下,代码必须位于可写的存储器(如RAM)中,因为FLASH不支持动态修改。
4
片内和片外存储的区别
片内RAM/FLASH:通常片内存储器的访问速度更快,延迟更低,因为它们直接与处理器内核集成在一起。片内RAM通常用于高速缓存或需要高频访问的数据,而片内FLASH用于存储稳定的程序代码。
片外RAM/FLASH:片外存储器通过外部总线连接,访问速度和片内相比会稍慢,尤其在使用串行总线(如SPI FLASH)时延迟更大。如果程序和数据需要频繁访问片外存储器,性能会明显下降。
因此,一般情况下,片外存储更多是作为数据存储或者大容量扩展,而不是执行的主要位置。
5
如果程序大小超过RAM怎么办?
在程序代码超过RAM可用空间时,通常不会整个搬移,而是采用分段加载或“XIP”(Execute In Place,原地执行)技术:
XIP(原地执行): 直接从FLASH中读取和执行指令,不需要搬到RAM。绝大多数MCU都支持这种方式。
分页加载或分段执行:在一些高级系统(如操作系统驱动的系统)中,可以将程序分割为多个段,按需加载到RAM中执行。但这对于资源受限的MCU来说,通常不会这么复杂。
6
片外FLASH和SRAM的速度差异
片外FLASH和SRAM相对片内存储器,访问速度会更慢。
主要原因包括:
访问延迟:片外存储器需要通过总线协议进行数据传输,可能涉及地址解码和等待周期。
带宽限制:外部存储器的读写带宽通常不如片内存储器高,如果是串行接口(如SPI FLASH),带宽瓶颈会更明显。
内存控制器的影响:外部存储器访问可能还依赖于内存控制器的配置,访问速度受限于控制器的性能。