【RTOS】堆栈与任务栈
前言
本笔记基于 stm32+FreeRTOS。
概念
双堆栈指针
Cortex-M3 和 M4内核具有双堆栈指针。MSP 和 PSP
- MSP:主堆栈指针
- PSP:进程栈指针
要点
- 用户程序、中断和中断嵌套都是用 MSP。
- M3 内核所有寄存器压栈时有64B。
- M4 内核所有寄存器压栈时有200B。(因为FPU(浮点运算单元)也要压栈)
Cortex-M3寄存器介绍
寄存器图
通用寄存器组:

特殊功能寄存器组:

简要介绍
通用寄存器 R0-R7
- R0-R7被称为低组寄存器。
- 所有指令都能访问它们。
- 字长全是32位,复位后不可预料。
通用寄存器 R8-R12
- R0-R7被称为高组寄存器。
- 只有很少16位Thumb指令能访问它们,32位指令不受限制。
- 字长全是32位,复位后不可预料。
堆栈指针 R13(SP)
- CM3处理器内核中央有两个堆栈指针,分别是MSP和PSP。
- 当前使用MSP,则PSP只能通过特殊指令(MRS,MSR指令)来访问。
- MSP:主堆栈指针
- 缺省的堆栈指针,由OS内核、异常服务例程及所有需要特权访问的应用程序代码来使用。
- PSP:线程堆栈指针
- 用于常规的应用程序代码。
- 注意:并不是每个应用都需要两个堆栈指针,简单的应用程序只需要MSP即可
连接寄存器 R14(LR)
- 保存调用子程序时返回的地址
连接寄存器 R15(PC)
知识
出入栈
出入栈用于上下文切换。
- 例子:stm32F103自动出入栈的寄存器有 R0-R3,R12,LR,PC,xPSR
入栈(压栈)
入栈:上文保存
- 先自动压栈(进入异常时,硬件自动完成)
- 再手动压栈
出栈
出栈:下文加载
- 先手动出栈
- 再自动出栈(退出异常时,硬件自动完成)
重点知识
异常的响应序列*
参考《Cortex-M3 权威指南》第九章
当CM3开始响应一个中断时,会在它看不见的体内奔涌起三股暗流:
- 入栈:把8个寄存器的值压入栈(硬件完成)
- 取向量:从向量表中找出对应的服务程序入口地址
- 选择堆栈指针MSP/PSP,更新堆栈指针SP,更新连接寄存器LR,更新程序计数器PC
入栈
取向量
更新寄存器
在入栈和取向量的工作都完毕之后,执行服务例程之前,还要更新一系列的寄存器:
- SP:在入栈中会把堆栈指针(PSP或MSP)更新到新的位置。在执行服务例程后,
将由MSP负责对堆栈的访问。 - PSR:IPSR位段(地处PSR的最低部分)会被更新为新响应的异常编号。
- PC:在向量取出完毕后,PC将指向服务例程的入口地址,
- LR:LR的用法将被重新解释,其值也被更新成一种特殊的值,称为“EXC_RETURN”,并且在异常返回时使用。EXC_RETURN的二进制值除了最低4位外全为1,而其最低4位则有另外的含义。
以上是在响应异常时通用寄存器的变化。另一方面,在NVIC中,也伴随着更新了与之相关的若干寄存器。例如,新响应异常的悬起位将被清除,同时其活动位将被置位。
小结知识*
- Cortex-M3 中发生异常时,会硬件压栈;
- Cortex-M3 函数调用时是不会硬件压栈的,需要软件压栈。但是,用C语言时编译器会自动生成压栈的汇编语句。若用汇编编写,则需要手写压栈。
- 网友一句很好理解的话:
- 当程序跳到中断向量表时就会硬件自动压栈
- 网友一句很好理解的话:
- 进入异常后,异常不用LR寄存器(R14)保存返回地址,但是需要使用LR寄存器触发异常返回机制
FreeRTOS任务切换源码分析
__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp
isb
ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
ldr r2, [r3]
stmdb r0!, {r4-r11} /* Save the remaining registers. */
str r0, [r2] /* Save the new top of stack into the first member of the TCB. */
stmdb sp!, {r3, r14}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r3, r14}
ldr r1, [r3]
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */
msr psp, r0
isb
bx r14
nop
- stmdb sp!, {r3, r14}
- r3 压栈保护,因为调用函数vTaskSwitchContext时可能会用到 r3 寄存器。
- r14 压栈保护,因为调用函数vTaskSwitchContext时,r14将被改写。
话语
- 任务切换的时候,在PendSV中断函数中,由于任务使用 PSP ,中断使用 MSP。如果在中断函数中调用函数或者中断嵌套时,压栈2,会覆盖 R14。PendSV结束返回时找不到正确的返回机制。
参考
重要参考 《Cortex-M3权威指南》
主要参考野火、安富莱。
主要参考链接Cortex-M3通用寄存器
可能有用的参考中断与子程序调用问题
【RTOS】堆栈与任务栈的更多相关文章
- 什么是“堆”,"栈","堆栈","队列",它们的区别?
堆:什么是堆?又该怎么理解呢? ①堆通常是一个可以被看做一棵树的数组对象.堆总是满足下列性质: ·堆中某个节点的值总是不大于或不小于其父节点的值: ·堆总是一棵完全二叉树. 将根节点最大的堆叫做最大堆 ...
- 堆”,"栈","堆栈","队列"以及它们的区别
如果你学过数据结构,就一定会遇到“堆”,"栈","堆栈","队列",而最关键的是这些到底是什么意思?最关键的是即使你去面试,这些都还会问到, ...
- C#中堆和栈的区别分析
线程堆栈:简称栈 Stack托管堆: 简称堆 Heap 使用.Net框架开发程序的时候,我们无需关心内存分配问题,因为有GC这个大管家给我们料理一切.如果我们写出如下两段代码: 1 代码段1: 2 3 ...
- NSISの堆栈操作
一 .堆栈 堆栈是 NSIS 维护的一堆数据,你可以根据需要往堆栈中存入任意大小的数据(as big as you like),所以你可以向堆栈中推入或读取数据,堆栈只有一个,堆栈遵守 LIFO (后 ...
- 堆heap和栈Stack(百科)
堆heap和栈Stack 在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除.在单片机应用中,堆栈 ...
- 一步步写STM32 OS【三】PendSV与堆栈操作
一.什么是PendSV PendSV是可悬起异常,如果我们把它配置最低优先级,那么如果同时有多个异常被触发,它会在其他异常执行完毕后再执行,而且任何异常都可以中断它.更详细的内容在<Cortex ...
- C#中堆和栈的区别分析(有待更新总结2)
转载:http://blog.csdn.net/Zevin/article/details/5731965 线程堆栈:简称栈 Stack 托管堆: 简称堆 Heap 使用.Net框架开发程序的时候,我 ...
- KEILC51可重入函数及模拟栈浅析
MARK:文章中的红色部分是个人的理解. KEILC51可重入函数及模拟栈浅析 关键字:keilc51,模拟堆栈,可重入函数调用,参数传递,C?XBP,C?ADDXBP 摘要:本文较详细的介绍了kei ...
- Android之后台服务判断本应用Activity是否处于栈顶
在Android开发中,我们经常想知道是否自己的服务处于后台运行中,因为在后台运行的服务器优先级会降低,也就极有可能会被系统给回收掉,有什么好办法呢?Google推荐我们将服务运行到前台,如何知道服务 ...
随机推荐
- ESLint & vue
ESLint & vue { "name": "app", "version": "1.0.1", " ...
- convert URL Query String to Object All In One
convert URL Query String to Object All In One URL / query string / paramas query string to object le ...
- window resize & resize observer
window resize & resize observer https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_e ...
- 全网算力总量暴增,SPC能否成为币圈新宠?
据最新数据显示,在经历了本周初(1月11日)的下跌之后,比特币市场在本周四(1月14日)终于出现了反弹并试图突破4万美元,重新向4万美元上方发起挑战. 这也让加密市场的生态建设者重拾信心,重新对数字货 ...
- PAUL ADAMS ARCHITECT:爱丁堡的房屋价值创历史新高
近日,英国知名房产公司保罗·亚当斯公司根据一组调查报告表示,今年第三季度,爱丁堡的房价再创历史新高,并向大家分析了原因. 保罗·亚当斯公司(公司编号:07635831)是英国一家著名的房地产公司,总部 ...
- 在.NET Core 中使用 FluentValidation 进行规则验证
不用说,规则验证很重要,无效的参数,可能会导致程序的异常. 如果使用Web API或MVC页面,那么可能习惯了自带的规则验证,我们的控制器很干净: public class User { [Requi ...
- Simple: SQLite3 中文结巴分词插件
一年前开发 simple 分词器,实现了微信在两篇文章中描述的,基于 SQLite 支持中文和拼音的搜索方案.具体背景参见这篇文章.项目发布后受到了一些朋友的关注,后续也发布了一些改进,提升了项目易用 ...
- Python算法_盛最多水的容器(04)
给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0).找出其中的两条线, ...
- npm与package.json快速入门
本文转载自npm与package.json快速入门 导语 npm 是前端开发广泛使用的包管理工具,之前使用 Weex 时看了阮一峰前辈的文章了解了一些,这次结合官方文章总结一下,加深下理解吧! 读完本 ...
- SpringBoot(六):SpringBoot中如何使用Servlet?
第一种方法: 1.使用Servlet3的注解方式编写一个Servlet 2.在main方法的主类上添加注解: @ServletComponentScan(basePackages = "co ...