当前位置:首页 > 技术学院 > 技术前线
[导读]在嵌入式系统开发中,RAM(随机存取存储器)是决定系统性能、功能上限的核心资源。和通用PC不同,嵌入式系统的RAM资源往往非常紧张:从低端8位单片机的几百字节,到中高端MCU的几十KB几百KB,哪怕是高端嵌入式SOC也不过几GB,如何合理规划使用RAM,是每个嵌入式开发者必须掌握的核心能力。

在嵌入式系统开发中,RAM(随机存取存储器)是决定系统性能、功能上限的核心资源。和通用PC不同,嵌入式系统的RAM资源往往非常紧张:从低端8位单片机的几百字节,到中高端MCU的几十KB几百KB,哪怕是高端嵌入式SOC也不过几GB,如何合理规划使用RAM,是每个嵌入式开发者必须掌握的核心能力。

很多新手开发者对RAM的认知只停留在““存运行数据”的表层,分不清不同类型RAM的差异,在实际开发中经常踩坑:把DMA缓冲区放到CPU专属RAM导致读取错误,把大缓存放到高速RAM浪费资源,或者因为内存配置不当导致系统随机崩溃。本文从嵌入式开发的实用角度,梳理常用RAM的类型、特性、使用场景和分配技巧,帮开发者理清嵌入式RAM的核心逻辑。

一、嵌入式RAM的核心特性与分类

RAM最大的特点是掉电丢失数据,但读写速度远快于Flash、ROM等非易失性存储,是程序运行时的核心工作区,用来存动态数据、堆栈、临时缓存。嵌入式系统中常用的RAM主要分为几类,不同类型的RAM特性差异很大,适合的场景也完全不同:

1. SRAM(静态随机存取存储器)

SRAM是嵌入式系统中最常用的RAM类型,不需要刷新电路就能保持数据,读写速度快、功耗低、访问延迟小,是MCU片上RAM的主流选择。但SRAM的单元面积大,相同制程下容量比DRAM小得多,成本也更高,因此嵌入式MCU的片上SRAM一般都不大,从几KB到几MB不等。

SRAM还可以根据用途细分:

普通通用SRAM:可以被CPU、DMA等所有主设备访问,是最常用的RAM,一般用来存堆栈、全局变量、常规数据缓存;

CCM SRAM(内核耦合存储器):专门给CPU内核设计的高速SRAM,访问速度比普通SRAM更快,但一般不支持DMA访问,如果把DMA需要的缓冲区放到CCM里,DMA无法正常读取数据,这是新手非常容易踩的坑,只适合放不需要DMA访问的代码、栈和全局变量;

TCM(紧耦合存储器):在Cortex-M系列、Cortex-A系列MCU中都有,分为ITCM(指令TCM)和DTCM(数据TCM),访问速度比普通SRAM更快,延迟更低,适合放对实时性要求极高的中断服务程序、关键任务代码,能极大提升响应速度。

2. DRAM(动态随机存取存储器)

DRAM需要定时刷新才能保持数据,单元面积小,容量大成本低,但访问速度比SRAM慢,延迟高,一般用作大容量嵌入式系统的外部RAM,常见的有:

SDRAM(同步动态随机存取存储器):中高端嵌入式SOC比如STM32F4、STM32H7、全志SOC都支持外接SDRAM,容量一般从32MB到256MB不等,适合存大缓存、图片数据、系统堆空间;

DDR SDRAM:新一代的双倍速率同步DRAM,速度比普通SDRAM更快,容量更大,现在的高端嵌入式SOC比如树莓派、瑞芯微、全志的处理器都用DDR,容量从256MB到几GB不等,用来运行嵌入式Linux系统,存放应用程序数据。

和SRAM相比,DRAM容量大成本低,但功耗更高、访问速度慢,因此一般作为片外扩展内存,不会替代片上SRAM做核心的实时数据存储。

3. PSRAM(伪静态随机存取存储器)

PSRAM是一种兼具SRAM和DRAM优点的内存,工艺和DRAM类似,但芯片内部集成了刷新电路,对外接口和SRAM一样,不需要外接刷新电路,使用起来和SRAM一样简单,容量比SRAM大,成本比SRAM低,访问速度比SDRAM慢一点,适合那些需要扩展中等容量RAM,又不想设计复杂SDRAM电路的场景,比如ESP32经常外接PSRAM扩展内存,非常方便。

二、嵌入式系统RAM的基本分配逻辑

不管是裸机系统还是RTOS,嵌入式RAM的分配逻辑都遵循统一的规则,从地址空间来看,RAM从低地址到高地址一般分为五个区域,我们以最常见的C语言开发裸机系统为例梳理:

1. .data段:已初始化非零全局/静态变量

这个区域存放程序中已经初始化,且初始值不为0的全局变量和静态变量,比如uint32_t buffer = {1,2,3,4};就存放在这里。这个区域的初始值存储在Flash中,程序启动的时候由启动代码从Flash拷贝到RAM,因此同时占用Flash和RAM空间。

2. .bss段:零初始化未初始化全局/静态变量

存放未初始化,或者初始化为0的全局静态变量,程序启动的时候由启动代码把整个区域清零,不需要存储初始值,因此只占用RAM,不占用Flash空间。很多新手误以为未初始化的全局变量不占用RAM,其实所有全局静态变量都会分配RAM空间,只是零初始化的不需要占用Flash而已。

3. 堆(Heap):动态内存分配区

堆用来做动态内存分配,调用malloc()、rt_malloc()等动态分配函数的时候,就是从堆里划分空间给程序使用,用完free之后释放回堆。堆从.bss段结束地址开始,向高地址增长,大小一般由链接脚本配置,剩下的空间都给堆用。

动态分配的好处是按需分配,用完释放,提高RAM利用率,但频繁分配释放容易产生内存碎片,导致明明总空闲足够,却分配不出连续的大块内存。

4. 栈(Stack):局部变量和函数上下文存储

栈从RAM的高地址向低地址增长,用来存放函数的非静态局部变量、函数调用返回地址、中断上下文、函数参数,栈的大小由开发者配置,默认一般是几KB,要是配置太小,很容易出现栈溢出,导致程序崩溃。

5. 保留区域:特定用途专用内存

除了这四个通用区域,很多嵌入式系统还会预留一部分RAM做特定用途:比如预留一块内存给DMA专用缓冲区,预留一块给GPU显存,预留一块给蓝牙协议栈,这些区域会提前在链接脚本中划分出来,不会被通用分配占用。

我们以STM32F103C8T6的20KB RAM为例,看一个典型的分配结果:

.data段占用1KB,.bss段占用3KB,合计4KB;

栈配置为2KB,占用RAM最高地址的2KB;

剩下的14KB全部给堆,用于动态分配,符合大多数裸机程序的需求。

三、不同RAM的选型与使用技巧

不同类型的RAM特性不同,用对场景才能发挥最大价值,我们整理了不同场景下的RAM使用技巧:

1. 关键数据放对RAM类型,避免低级错误

很多新手踩坑都是因为把数据放错了RAM类型:

需要DMA访问的数据,一定不要放到CCM SRAM:CCM不支持DMA访问,放到这里DMA读不到正确数据,比如UART接收缓冲区、SPI发送缓冲区,一定要放到普通通用SRAM;

对实时性要求高的代码数据,放到TCM或者高速SRAM:比如中断服务程序、电机控制的闭环算法代码,放到TCM中可以降低访问延迟,提升响应速度,避免因为总线冲突导致响应不及时;

大的只读数据不要放RAM,放Flash:比如字库、校准参数这些只读不修改的数据,加上const关键字放到Flash的.rodata段,不占用RAM空间,这是最常用的RAM优化技巧,很多新手忘记加const,把几十KB的字库放到RAM,直接把RAM占满,导致溢出;

中等容量扩展选PSRAM,大容量选DDR/SDRAM:如果需要额外几十MB的RAM,用PSRAM比SDRAM电路简单,布线容易,成本更低,适合WiFi模块、物联网终端这些场景,要是需要几百MB以上的容量,再用SDRAM或者DDR。

2. RAM大小计算与规划,提前避免溢出

开发前期一定要提前估算RAM占用,避免做到一半发现RAM不够,我们可以用这个方法估算:

先算全局静态变量:所有全局数组、全局结构体加起来,大概计算总大小,每个变量按声明的大小计算,比如uint8_t buffer就是1KB;

加上栈的大小:一般裸机配2~4KB,RTOS每个线程配单独的栈,每个线程栈大小按最大局部变量加上上下文保存空间计算,一般小任务配1KB,大任务配4~8KB;

剩下的空间都给堆,动态分配,要是剩下的空间不够,就要优化全局变量,或者换更大RAM的芯片。

现在的开发环境编译完成后都会输出RAM占用,MDK编译后会直接输出RW-data + ZI-data,就是已经分配的.data+.bss大小,总RAM减去这个值,剩下的就是堆和栈可用的空间,非常方便查看。

3. RAM优化技巧:小RAM也能实现大功能

对于RAM紧张的嵌入式项目,可以用这些技巧优化RAM占用:

复用缓冲区:不同功能模块分时复用同一个大缓冲区,比如串口接收完数据处理完,SPI发送可以复用同一个缓冲区,不需要每个模块开一个,能节省很多空间;

用合适的数据类型:能使用uint8_t就不用uint32_t,标志位用位域存储,一个字节能存8个标志,比用8个bool节省7字节;

大数组不要放栈:很多新手喜欢在函数里面定义uint8_t buffer,这个数组放在栈上,很容易导致栈溢出,超过几百字节的数组都要定义成全局,或者动态分配;

动态分配随用随释放:不需要一直占用的内存,处理完就释放,不要一直占着,比如升级固件的时候才需要的升级缓冲区,升级完成就释放,把空间还给系统;

把不常用的大数据放到外部RAM:比如图片、日志这些,放到外接的PSRAM/SDRAM,把片上高速RAM让给实时性要求高的数据。

4. RTOS系统中的RAM分配特殊点

如果使用RTOS,和裸机比RAM分配有一些不同需要注意:

每个任务都有独立的栈空间,任务栈大小要根据任务实际需求配置,不要所有任务都配成最大,浪费RAM;

RTOS的堆一般从剩下的RAM空间中划分,要保证总RAM足够容纳所有任务栈加上全局变量加上堆,否则会出现分配失败;

很多RTOS支持把不同任务的栈放到不同RAM,比如把高优先级实时任务的栈放到高速SRAM,把低优先级任务的栈放到外部RAM,兼顾性能和RAM利用率。

四、RAM常见问题排查

嵌入式开发中RAM相关问题排查难度比较大,我们整理了最常见的问题和解决方法:

1. 栈溢出:程序随机崩溃进入HardFault

栈溢出是最常见的RAM问题,表现为程序随机崩溃、全局变量被莫名修改,进入HardFault异常,常见原因是栈配置太小、函数内定义大数组、递归太深。 解决方法:

先把栈改大一点,比如从1KB改成4KB,看问题是否解决;

检查所有函数,把超过200字节的局部数组改成全局或者动态分配;

检查递归函数,控制递归深度,避免过深递归占用太多栈空间。

2. 堆分配失败:malloc返回NULL

常见原因是总RAM不够,或者内存碎片化,解决方法:

调整堆和栈的大小,如果用不到太大的栈,就把栈缩小,把空间让给堆;

减少动态分配,固定大小的缓冲区尽量静态分配,避免碎片化;

使用内存池分配固定大小的块,减少碎片化,提高分配成功率。

3. DMA数据错误,结果不对

很多时候就是把DMA缓冲区放到了不支持DMA的CCM SRAM,把缓冲区移到普通SRAM就能解决,还有的情况是缓冲区没有按要求对齐,比如DMA要求4字节对齐,把缓冲区加上对齐属性__attribute__((aligned(4)))就能解决。

4. 编译提示RAM溢出,链接报错

链接的时候提示RAM超出范围,说明全局变量加栈加堆的总大小已经超过芯片RAM容量,这时候要么优化RAM占用,去掉不必要的全局变量,缩小缓冲区,要么换更大RAM的芯片,没有其他办法。

总结

嵌入式RAM的核心逻辑其实很简单:不同类型RAM有不同的特性,放对适合的数据,合理规划分配,提前优化就能避开大多数坑。SRAM速度快适合做实时核心存储,DRAM/SDRAM容量大适合做大容量扩展,PSRAM适合中等容量简单扩展,只要分清不同RAM的使用限制,不要把DMA缓冲区放到CCM,不要把大数组放到栈,就能解决大多数常见问题。

对于嵌入式开发者来说,RAM永远是不够用的,养成提前规划、随时看RAM占用的习惯,掌握常用的优化技巧,就能在有限的RAM资源里实现更多功能,尤其是小RAM的MCU,合理优化往往能放下比预期多很多的功能,充分发挥芯片的潜力。 以上是根据你的要求生成的内容,如需修改可继续提出。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

在STM32嵌入式开发中,RAM(随机存取存储器)是程序运行时存储动态数据、堆栈、全局变量的核心资源,直接决定了程序能实现的功能复杂度。很多开发者都遇到过莫名的程序崩溃、硬件异常,追根溯源往往是RAM分配错误、占用溢出:...

关键字: RAM STM32

在嵌入式系统中,RAM(随机存取存储器)是支撑系统运行的核心硬件之一。与通用计算机动辄数GB的内存不同,嵌入式RAM通常以KB或MB为单位,其性能、功耗和成本直接决定了系统的整体表现。从早期的8位单片机到如今的32位、6...

关键字: SRAM 内存

在基于STM32的嵌入式开发中,RAM(随机存取存储器)是影响系统性能和稳定性的核心资源之一。与PC端动辄数GB的内存不同,STM32系列微控制器的RAM容量通常在几KB到几百KB之间,部分高端型号可达数MB。有限的资源...

关键字: RAM 微控制器

模型规模没变,利用率却总上不去,很多时候不是算力单元太少,而是片上缓存先被撑爆。AI芯片一旦把局部存储和分块调度看得过于理想,乘加阵列就会反复等数据,而不是持续吃满。

关键字: AI 芯片 SRAM

在嵌入式开发的世界里,MCU的RAM资源如同沙漠中的绿洲,珍贵且有限。当项目推进到后期,功能不断叠加,代码量持续增长,RAM空间告急的警报往往会突然响起。这不仅可能导致系统崩溃、功能异常,甚至可能让整个项目陷入停滞。

关键字: MCU RAM

在嵌入式系统与物联网技术飞速发展的当下,LED作为一种高效、节能的照明与显示器件,其应用场景正不断拓展。从智能家居的氛围调节到工业设备的状态指示,从户外照明的智能管控到消费电子的交互反馈,LED的灵活控制成为了系统设计中...

关键字: LED RAM

量产测试最容易给人错觉的数据,就是那串看起来很高的故障覆盖率。覆盖率数字漂亮,不代表缺陷真的被看见,压缩链路和未知态处理稍有失衡,就会把漏测藏在统计表里。

关键字: 芯片 覆盖率 SRAM

芯片一旦把供电继续往下压,最先紧张的往往不是算术单元,而是密度最高的SRAM阵列。低压稳定性问题如果只盯平均功耗,读写窗口会比预期更早塌下来。

关键字: 芯片 SRAM 读扰动

在计算机系统的存储架构中,随机存取存储器(RAM)是支撑系统高速运行的核心组件,而其中的静态随机存取存储器(SRAM)和动态随机存取存储器(DRAM),就像一对性格迥异却又默契十足的双子星,各自在不同的领域发挥着关键作用...

关键字: SRAM DRAM

在STM32开发中,一个看似简单的排序算法选择,可能因内存布局差异产生200%的性能波动。某工业物联网项目曾遭遇这样的困境:基于STM32F103的传感器数据处理器,在实验室环境下混合排序算法仅需1.2ms完成1000个...

关键字: Flash SRAM
关闭