Cortex-M 内核的 OS 特性


一、通用堆栈知识

在前面讲解 STM32 启动文件的时候就已经提到过,有关堆栈大小的设置是在启动文件中设置的:

Heap 主要用于 Malloc、Free,动态内存申请和释放。

Stack 也非常重要,程序编译后所包含的大量 PUSHPOP 指令操作,系统根据 SP(堆栈指针) 寄存器访问当前对应栈内存,通过栈保存临时数据。大部分的栈都是向下生长的(也有向上生长的)。M 内核的栈是从高地址向低地址生长的,下面通过一个例子演示一下:

__IO uint32_t a = 0x11111111;
__IO uint32_t b = 0x22222222;
__IO uint32_t c = 0x33333333;
__IO uint32_t d = 0x44444444;
__IO uint32_t e = 0x55555555;
__IO uint32_t f = 0x66666666;
__IO uint32_t g = 0x77777777;
__IO uint32_t h = 0x88888888;

在这里插入图片描述

然后进入调试状态,可以看到现在 SP 指针是 0x20000618

可当我们实际点击单步调试的时候,SP 指针现在又变成了 0x200005F80x20000618 - 0x200005F8 等于十进制的 32。也就是说少了 32 个字节。这里是因为程序一来就把这 8 个数据,共 32 个字节的内存分配好了。

当你把 __IO 去掉后,就不会出现以上的情况。__IO 其实就是 volatile,所以在这里就是告诉编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。

下面继续执行,可以看到,数据是从高地址向低地址存储的。

当然,内存空间只是连续字节数据的抽象,本身并不区分堆和栈的概念,它做的只是存储和读写信息。因此,如何定义堆栈、初始化建立堆栈环境,在嵌入式软件运行前便显得尤为重要。这涉及到处理器提供的堆栈机制、操作系统内存管理和进程切换等方方面面。

二、双堆栈用法

下图取自权威指南:

在搭载实时操作系统内核的嵌入式软件中,栈往往分为两大类,除了满足系统基本的主栈(main stack)外,往往还需要进程/线程栈(process stack)。这两部分内存空间是独立存在的:

  • 主栈位于系统的栈区(stack)
  • 而线程堆栈往往定义在堆区(heap)或静态区(static)

无论是静态还是动态创建,线程栈都不会占用栈区的主栈空间。即线程栈并不在栈区,可能在数据区或堆区,再次说明主栈和线程栈内存空间独立。

理解这一点,是理解 MCU 堆栈的关键前提。

所谓双堆栈,本质上都是 R13,不过在不同的运行状态下使用的栈是不同的,并且在同一时刻,只有其中的一个栈可用。在系统复位后、进入线程环境前,默认使用主堆栈,中断服务程序(ISR)中也是使用主堆栈。RTOS 各线程中的应用代码,则使用线程堆栈。

  • 如果使用了双堆栈,那么在中断里只能使用 MSP;而在中断以外,可以使用 MSP,也可以使用 PSP。(不过在 RTOS 里,中断以外全部使用 PSP,后面讲原因)。

上电后,系统仅初始化了 MSP,需要通过额外的汇编代码建立完整的双堆栈系统,当实时内核准备就绪,线程调度正常运行,双堆栈机制开始工作。进中断时系统根据当前状态自动切换堆栈,进程上下文切换时会更新不同线程的 PSP,通过修改 EXC_RETURN 可以手动切换 MSP/PSP

双堆栈机制使得内核/ISR 堆栈和线程应用堆栈分开管理,通过不同的堆栈指针寄存器完成切换,大大提高了系统的效率,在绝大部分的嵌入式实时操作系统中,都使用了双堆栈机制,如 ucos、FreeRTOS、RT-Thread 等。

在一些简单的应用中,例如裸机程序,可以从头到尾都只使用主堆栈,只要确保分配足够的空间即可。

还是一样,通过例程来看,在刚才的程序下面添加:

__set_PSP(__get_MSP()); /* 设置PSP位置 */
__set_CONTROL(0x02);    /* bit1 = 1表示使用PSP,bit1 = 0表示使用MSP */ 
{
   
   
    __IO uint32_t a1 = 0x11111111;
    __IO uint32_t b1 = 0x22222222;
    __IO uint32_t c1 
评论 16
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值