FreeRtos学习笔记(10)任务切换原理刨析

本文详细解析了STM32中MSP和PSP堆栈指针的作用,展示了RTOS任务切换如何通过控制这两个指针实现,以及PendSV中断服务函数在任务切换中的关键作用。讲解了任务控制块、栈的分配和管理,以及FreeRTOS中上下文切换的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FreeRtos学习笔记(10)任务切换原理刨析

STM32 单片机启动流程中介绍了SP和PC寄存器,
STM32单片机bootloader扫盲中说过如何通过控制SP和PC寄存器从而控制程序从bootLoader跳转到APP,RTOS任务切换和BootLoader与APP之间的跳转类似,也是通过控制SP和PC指针实现任务之间跳转。

MSP和PSP

在中断服务函数使用MSP作为堆栈指针,如果工程中没有特殊设置(即非RTOS工程)整个工程都会默认使用MSP。如果工程使用了RTOS,则除了中断服务函数外,其他任务使用PSP作为堆栈指针。

Cortex‐M3 拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个。

主堆栈指针(MSP):复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包括中断服务例程)

进程堆栈指针(PSP):由用户的应用程序代码使用。

堆栈指针的最低两位永远是 0,这意味着堆栈总是 4 字节对齐的。 在 ARM 编程领域中,凡是打断程序顺序执行的事件,都被称为异常(exception)。除了外部中断外,当有指令执行了“非法操作”,或者访问被禁的内存区间,因各种错误产生的 fault,以及不可屏蔽中断发生时,都会打断程序的执行,这些情况统称为异常。在不严格的上下文中,异常与中断也可以混用。另外,程序代码也可以主动请求进入异常状态的(常用于系统调用)。

为什么堆栈指针有两个?

  1. 可以将用户应用程序的堆栈与特权级/操作系统内核(kernel)的堆栈分开,阻止用户程序访问内核的堆栈,消除了内核数据被破坏的可能。(举个例子,windos系统下,一个软件卡死并不会使整个windos操作系统卡死)
  2. 可以使RTOS实现任务间“可抢占的系统调用”,大幅提高实时性能(中断前使用PSP,进入中断服务函数后会自动使用MSP,在中断中修改PSP值,退出中断服务函数后SP会自动切换到PSP,而PSP的值在中断中修改过,退出中断时会根据新的PSP, POP出PC寄存器及其他寄存器值,从而完成任务切换)

MSP和PSP之间如何切换?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-agGdomIW-1635424021495)(https://note.youdao.com/yws/res/788/WEBRESOURCEce164f885d4f75a261f561bd1b2c2229)]

M3权威指南中指出MSP和PSP之间的切换有两种方法:

  • 在特权级线程模式下写CONTROL[1]
  • 在中断服务函数结束时修改LR寄存器(R14),下图为LR寄存器低四位所代表的含义

在这里插入图片描述

FreeRtos中就是通过修改LR寄存器值实现从MSP切换到PSP的。

上电后默认使用MSP,然后进行外设初始化,创建任务,最后调用vTaskStartScheduler()启动RTOS,在vTaskStartScheduler()中会调用xPortStartScheduler()函数,xPortStartScheduler()函数中会调用port.c中的prvPortStartFirstTask();启动第一个任务。

prvPortStartFirstTask()为一个汇编函数,主要功能就是触发SVC中断

static void prvPortStartFirstTask( void )
{
   
    __asm volatile (
        " ldr r0, =0xE000ED08 	\n"/* Use the NVIC offset register to locate the stack. */
        " ldr r0, [r0] 			\n"
        " ldr r0, [r0] 			\n"
        " msr msp, r0			\n"/* Set the msp back to the start of the stack. */
        " cpsie i				\n"/* Globally enable interrupts. */
        " cpsie f				\n"
        " dsb					\n"
        " isb					\n"
        " svc 0					\n"/* 触发SVC异常,在SVC中断服务函数中启动第一个任务. */
        " nop					\n"
        " .ltorg				\n"
        );
}

SVC中断服务函数-- vPortSVCHandler()也是一个汇编函数,主要干了两件事,恢复任务现场(也就是将任务栈中保存的寄存器值POP到对应寄存器);将MSP切换为PSP;汇编语句具体含义可以对照M3权威指南中第四章指令集自行翻译。

void vPortSVCHandler( void )
{
   
    __asm volatile (
        "	ldr	r3, pxCurrentTCBConst2		\n"/* Restore the context.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值