STM32的内存分配与堆栈

发布于:2025-09-01 ⋅ 阅读:(21) ⋅ 点赞:(0)

使用过cortex-M4内核单片机的朋友对下面这张图一定不会感到陌生,它是ST原厂手册里面的memory map,里面的信息量其实非常多,今天简单说明一部分。

我们在编写stm32代码的时候最长使用的地址有两块,第一块是0x0000 0000~0x3FFF FFFF,

第二块是0x4000 0000~0x5003 FFFF。注意,第二块地址是我们APB与AHB总线上面挂载着的各种外设的物理地址,我们想要操作外设就是配置这些寄存器地址。我们今天讨论的内存是第一块儿,可供我们进行数据存储的内存。

首先0x000 000~0x0007 FFFF并不可以用来进行用户数据存储,这一段固化的代码作用是根据BOOT引脚输入的电平高低来决定将Flash memory、System memory还是SRAM的首地址映射到起始位置。

那么在真正可供我们操作的内存空间中,首先我们来讨论SRAM,SRAM只要芯片没有下电就可以一直存储数据(除非软失效等情形发生)。

Option bytes主要可以设置对 Flash 存储器的读写保护级别,防止未经授权的程序对 Flash 中的代码和数据进行读取或修改,保障程序和数据的安全性。

System memory里面存储着ST原厂编写的bootloader,当我们无法通过工具链下载代码时,可以通过改变boot引脚高低电平的方式选择使用该段内存中的bootloader。我们经常使用的串口升级代码也存储在这一段内存中。

我们平时下载的代码主要就存储在0x0800 0000~0x0807 FFFF中,这512K的内存又可以分为两部分,代码.text段和数据.rodata段。这段内存的第一个字节(0x08000 0000~0x0800 0003)存储着至关重要的MSP指针(栈底指针);第二个字节装着PC指针,PC指针指向了我们的复位函数。

下面介绍SRAM的作用,首先最底部的.data段的数据来源自上图用户代码的.rodatda。那么我们在编程中如何定义变量会导致数据被存储在.data段内部呢?下面介绍了两种特定值可修改的变量定义方式。

int cnt3=1;
fun1(void)
{
  static int cnt=1;
}

其次.bss段存储两类内容,一类是FreeRTOS中的heap size,另外一类是其他未初始化或者初始化为0的可修改变量;第二类又可以分为3小类,第一类是如同下文中cnt那样的未初始化全局变量,第二类是初始化为0的全局变量,第三类是静态的局部变量。

int cnt;
int cnt1=0;
int fun1(char *argv)
{
  static int cnt2;
 
}

.s文件中映射单片机堆栈中的数据,msp指针向下压入数据,当msp向下生长影响到队时就会在造成栈溢出。堆中的数据则是用malloc手动分配。

那么在移植freertos的过程中,动态创建的任务与静态创建的任务分别都被存储在了哪里?都在.bss段中的freertos_heap_size中。

下面讨论上下文堆栈:

cortex-M内核拥有双堆栈机制,除了MSP指针外还有一个PSP指针。在 Cortex-M 内核中,PSP(Process Stack Pointer,进程栈指针)是专门用于应用任务(用户任务)的栈指针,与 MSP(Main Stack Pointer,主栈指针)配合实现了内核与用户任务的栈空间分离,是支持实时操作系统(如 FreeRTOS)多任务管理的核心机制之一。

机制原理

  1. 栈指针的分离设计
    Cortex-M 内核有两个栈指针:

    • MSP(主栈指针):默认用于内核模式(如中断服务程序、异常处理、内核代码),复位后默认使用 MSP。
    • PSP(进程栈指针):仅用于用户模式(应用任务),由用户任务代码使用。

    内核通过CONTROL 寄存器的 bit [1] 控制当前使用的栈指针:

    • CONTROL[1] = 0:使用 MSP(内核模式默认)。
    • CONTROL[1] = 1:使用 PSP(用户任务运行时)。
  2. 任务切换时的 PSP 作用
    当发生任务切换(如由调度器触发)时:

    • 内核先将当前任务的寄存器状态(R0-R15 等)压入该任务的 PSP 所指向的栈空间(保存上下文)。
    • 然后加载下一个任务的 PSP 值(从该任务的 TCB 中获取),并从其栈中恢复寄存器状态(恢复上下文)。
    • 最后通过修改 CONTROL 寄存器,使 CPU 切换到 PSP,运行新任务。

核心作用

  1. 实现任务栈隔离
    每个用户任务拥有独立的栈空间(由 PSP 指向),任务间的栈数据互不干扰,避免了多任务运行时的栈冲突,提高了系统稳定性。

  2. 支持实时操作系统的多任务调度
    操作系统(如 FreeRTOS)通过管理每个任务的 PSP 值(存储在 TCB 中),实现快速的任务上下文切换,是多任务并发执行的基础。

  3. 区分内核与用户权限
    MSP 用于内核和异常处理,PSP 用于用户任务,配合内核的特权模式机制,实现了系统资源的权限隔离(如某些寄存器仅能在特权模式下访问)。


网站公告

今日签到

点亮在社区的每一天
去签到