当前位置:首页 > 嵌入式 > wenzi嵌入式软件
[导读]笔者能力有限,如果文中出现不对的地方,还请各位朋友能够及时地给我指出来,我将不胜感激,谢谢~ 内存映射 在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。在对于 RAM 紧

笔者能力有限,如果文中出现不对的地方,还请各位朋友能够及时地给我指出来,我将不胜感激,谢谢~

内存映射

在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。在对于 RAM 紧缺的嵌入式系统中,是缺少 MMU 内存管理单元的。因此在一些嵌入式系统中,比如常用的 STM32 来讲,内存映射被划分为闪存段(也被称为Flash,用于存储代码和只读数据)和RAM段,用于存储读写数据。

STM32 的 Flash 和 RAM 地址范围

笔者标题所说的内存是指 STM32 的 Flash 和 RAM,下图是 ARM Cortex M3 的地址映射图:从图中我们可以看到 RAM 地址是从 0x2000 0000 开始的,Flash地址是从 0x0800 0000 开始的,笔者将在下文中着重对这两部分进行剖析。

Flash

代码和数据是存放在 flash 中的,下面是将 flash 内部进行细分之后的一张图,图中标明了代码段,数据段以及常量在 flash 中的位置。如上图所示,Flash 又可以细分为这么几个部分,分别是文本段 (Text),其中文本段中又包含可执行代码 (Executable Code)和常量 (Literal Value),在文本段之后就是只读数据区域 (Read Only Data),当然并不是所有架构的单片机都满足这样一个排布规律,这里只针对ARM Cortex M3 系列,只读数据段后面接着的就是数据复制段 (Copy of Data Section),第一次遇到这个概念的朋友看到数据复制可能会有所疑惑,其实这个段充当的作用是存放程序中初始化为非 0 值的全局变量的初始值,之所以要将初始值存放到这里,是因为全局变量是存放在 RAM 上的,RAM 上的值掉电便丢失,每次上电后这些变量是要进行重新赋值的,而重新赋的值就存放在这里。那为什么不存放初始化为 0 的全局变量初始值呢,原因也很简单,既然是初始化为 0,那么在上电后统一对存放初始化为 0 的全局变量的那块区域清0就好了。下面举一个例子分析各个变量在上述中的存储位置:

   
  1. #include <stdio.h>

  2. const int read_only_variable = 2000;

  3. int data = 500;


  4. void my_function(void)

  5. {

  6. int x = 200;

  7. char *str = "string";

  8. }

在上述代码中,read_only_variable 是一个用 const 修饰的全局变量,它是只读的,存放在 flash 中的只读数据区域,编译器会给 read_only_variable 分配一个地址,并将 2000 这个数据存放到这个位置。data 这个变量将存放到 RAM 中的RW区域中 (后面将会进行详细讲解),但是 data 后面的初始值 500 将会被存放到数据复制区域中, 也就是上图中从下往上的第三个区域。在 my_function 中的变量 x 将会被存放到 RAM 中的堆栈中,将 x 赋值为 200 ,200 将被存储到 flash 里的 Text 中的常量区 (Literal Valu) 中。str 是一个 char 型的指针变量,它指向的是字符串第一个字符存放的位置,然而对于字符串 string 来讲,它是存放在Text常量区的,所以指针变量指向这个区域的一个地址,但是因为它终归中局部变量,它指向 Flash 的一个地址,但是其本身还是存放于 RAM 中的堆栈上的。

RAM

STM32单片机的片内RAM会被链接文件“分区”为如下几个段:如上图所示,RAM 中包含了如下几个部分:

  • 栈 (Stack) : 存放局部变量和函数调用时的返回地址

  • 堆 (heap) : 由 malloc 申请,由 free 释放

  • bss : 存放未初始化或者是初始化为 0 的全局变量

  • data : 存放初始化为非 0 值的全局变量

下面举一个简单的例子来说明变量在各个段中的存储位置:

   
  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. int data_var = 500;

  4. int bss_var0;

  5. int bss_var1 = 0;

  6. static int static_var;


  7. void my_function(void)

  8. {

  9. static int static_var1 = 0;

  10. int stack = 0;

  11. char *buffer;

  12. const int value = 1;

  13. buffer = malloc(10);

  14. }

上述变量的命名已经很清楚地表明了变量处于 RAM 中的哪一个段,datavar 是已经初始化的全局变量,存放在 RAM 的 data 区,bssvar0 和 bssvar1是未初始化和初始化为0的全局变量,他们都存放于 RAM 中的 bss段,由 static 修饰的staticvar 和 static_var1 都存放于 bss段,区别只在于两个变量的作用域不同。stack 是在函数内部定义的局部变量,其存放于 RAM 的栈区域,用 const 修饰的局部变量 value ,虽然他是只读的,但是它是存储于 RAM 中的栈中的,这里也说明一点,并不是所有用 const 修饰的变量都是存放于只读变量区的。buffer指针变量用 malloc 函数申请了 10 字节的内存空间,那这10字节的内存空间位于堆中。

堆栈溢出

如果在程序运行的过程中,堆的空间也一直在消耗,同时栈的空间也在增加,那么这时堆和栈如果碰到一起,那么就会造成堆栈溢出,从而导致我们的程序跑飞。

STM32中的map文件分析

在用 keil 编译 STM32 工程之后,我们会得到一个 map 文件,map 文件的最底部有这么一个信息:上图中的各个段是和上文所述是能够进行对应起来的,正如下面这张表所示:

Code RO Data RW Data ZI Data
Executable Code Read Only Data data bss

总结

对于 RAM 和 flash 空间都有限的 MCU 来讲,了解各个变量在内存中的存储位置是很有必要的,他能够很好地帮助我们去解决很多问题。

您的阅读是对我最大的鼓励,您的建议是对我最大地提升,欢迎点击下方图片进入小程序进行评论


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

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

在嵌入式系统工程领域,主要挑战在于在严格的时间约束下实现任务的确定性执行。微控制器通常需要同时执行复杂的数学运算,并管理高频的输入和输出。如果采用简单的定时方法,例如使用阻塞式的忙等待循环,常常会导致处理器饥饿问题,即一...

关键字: 信号发生器 嵌入式系统 STM32

本实验活动重点在于利用微控制器的模数转换器(ADC)外设来监测外部电压源。具体而言,该系统设计用于测量CR1220纽扣电池和5V USB总线供电电源的电压。对这些电平进行监测对于依赖电池作为备用电源的嵌入式系统非常有用,...

关键字: 电压分压器 噪声滤波器 STM32

本项目展示了我们在固件编程方面的初步工作。我们开发该项目,旨在通过实践操作更好地理解课程中的概念和应用。我们的项目名为“电子音调发生器”,通过一个小扬声器产生不同的声音。按下不同的按钮或组合按键,系统会生成不同频率,从而...

关键字: 扬声器 音频合成器 示波器 STM32

嵌入式系统,STM32内部Flash的擦写寿命始终是悬在开发者头顶的达摩克利斯之剑。STM32F103系列Flash典型擦写次数仅为10000次,若每次温度调整、参数变更都直接写入,按每日操作数十次计算,不足一年便逼近寿...

关键字: STM32 Flash

电池供电的物联网设备中,降低待机功耗是延长续航的核心课题。STM32的Stop模式提供了保留SRAM和寄存器内容的最低功耗状态,是实现“微安级待机、毫秒级唤醒”的关键技术。实测数据表明,STM32L4系列在Stop 2模...

关键字: STM32 低功耗

一切始于一个我不断在身边发现的常见问题——无论是亲密的朋友,还是我在健身训练的健身房圈子中。经过数周高强度的锻炼后,很多人都在问同一个问题:“我想要增肌的肌肉为什么没有增长,而那些我本意没想练的肌肉却反而变得酸痛?”

关键字: 可穿戴设备 机器学习 STM32

在STM32嵌入式控制中,PID控制器是温度、电机转速、平衡小车等闭环系统的核心算法。本文提供一份可直接移植的增量式PID代码模板,并分享工程中行之有效的参数整定方法。

关键字: STM32 PID控制器

在STM32软件开发中,ST官方提供两套固件库:HAL(Hardware Abstraction Layer)与LL(Low-Layer)。很多工程师困惑:两者除了API风格不同,运行效率和资源消耗究竟差多少?本文基于S...

关键字: STM32 HAL库 LL库

本项目是一个专为RT-Thread RT-Spark开发板设计的硬件与软件定制接口。它创建了一个交互式系统,通过物理输入(按钮)产生数字输出(LCD文本和LED信号)。通过连接外部面包板组件与开发板内置功能之间的桥梁,我...

关键字: LCD LED STM32

在STM32嵌入式开发中,精确延时是非常基础但又极其关键的功能。无论是驱动单总线传感器(比如DS18B20)、控制LCD屏幕时序、还是生成精确的脉冲信号,都需要用到微秒级甚至纳秒级精度的延时。很多新手刚开始使用STM32...

关键字: STM32 嵌入式
关闭