FreeRTOS学习(9)-任务调度汇编函数分析(难点)

前文提要
FreeRTOS学习(1)—为什么使用RTOS
FreeRTOS学习(2)-链表和节点之结构体分析
FreeRTOS学习(3)-链表和节点程序分析
FreeRTOS学习(4)-什么是任务?
FreeRTOS学习(5)-任务之静态创建函数解析
FreeRTOS学习(6)-任务之静态创建函数解析2(重点)
FreeRTOS学习(7)-任务切换理论分析(重点)
FreeRTOS学习(8)–pendsv和systick优先级分析以及任务切换场景

调度器(Scheduler)是操作系统的核心组件之一,其主要功能是管理和协调多任务的执行。它通过决定在特定时刻哪一个任务应该获得CPU的使用权,从而实现多任务的并发执行。

1、调度器的启动由 vTaskStartScheduler()函数来完成

(1)源代码

void vTaskStartScheduler( void )
{
   
    /* 手动指定第一个运行的任务 */
    pxCurrentTCB = &Task1TCB;
    
    /* 启动调度器 */
    if( xPortStartScheduler() != pdFALSE )
    {
   
        /* 调度器启动成功,则不会返回,即不会来到这里 */
    }
}

(2)代码解释

    第一个就是指定当前的任务pxCurrentTCB,我们通常通过这个全局变量 pxCurrentTCB(指向当前任务控制块的指针)来跟踪当前正在运行的任务。
    第二个就是启动调度器函数xPortStartScheduler,这个函数是里面包括汇编语言。接下来将详细解释。




2、启动调度器xPortStartScheduler函数解析

(1)函数源码

BaseType_t xPortStartScheduler( void )
{
   
    /* 配置PendSV 和 SysTick 的中断优先级为最低 */
	portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
	portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI;

	/* 启动第一个任务,不再返回 */
	prvStartFirstTask();

	/* 不应该运行到这里 */
	return 0;
}

(2)代码解析

①为什么Pendsv和SysTick的优先级设置最低,上一篇博客已经写明原因。>FreeRTOS学习(8)–pendsv和systick优先级分析以及任务切换场景
②启动第一个任务prvStartFirstTask函数,单独解析。





3、在分析第一个启动任务之前,我们先介绍一下主堆栈(Main Stack)和进程堆栈(Process Stack)

(1)主堆栈(Main Stack)

是在 ARM Cortex-M 微控制器中用来保存处理器执行期间的上下文信息(如寄存器值)的内存区域。具体来说,主堆栈是由主堆栈指针(MSP)管理的堆栈。

(2)主堆栈作用

①异常和中断处理:

主堆栈主要用于处理异常(如硬件中断)和中断服务程序(ISR)。在发生中断时,处理器会自动使用主堆栈保存当前任务的上下文信息,然后跳转到中断服务程序。
当中断服务程序执行完毕后,处理器会从主堆栈中恢复上下文信息,继续执行被中断的任务。

②系统启动和初始化:

在系统启动和初始化阶段,处理器通常会使用主堆栈。这是因为在系统启动时,还没有创建其他任务,主堆栈是唯一可用的堆栈。

③特权级别的任务:

一些操作系统内核和特权级别的任务(例如,操作系统的关键任务)可能会使用主堆栈,以确保它们在受保护的堆栈中执行。

(3)进程堆栈

进程堆栈(Process Stack)通常由普通用户任务或线程使用,每个任务或线程都有自己的堆栈空间,以实现任务间的隔离和独立。

(4)ARM Cortex-M 微控制器支持两个堆栈指针:

主堆栈指针(MSP):用于管理主堆栈。
进程堆栈指针(PSP):用于管理进程堆栈。

(5)切换堆栈指针

ARM Cortex-M 处理器可以通过修改 CONTROL 寄存器来在 MSP 和 PSP 之间切换堆栈指针。具体来说,CONTROL 寄存器的第一个位(CONTROL[1])决定当前使用的是 MSP 还是 PSP:
当 CONTROL[1] 位为 0 时,处理器使用主堆栈指针(MSP)。
当 CONTROL[1] 位为 1 时,处理器使用进程堆栈指针(PSP)。




4、prvStartFirstTask函数解析

(1)源代码

__asm void prvStartFirstTask( void )
{
   
	PRESERVE8

	/* 在Cortex-M中,0xE000ED08是SCB_VTOR这个寄存器的地址,
       里面存放的是向量表的起始地址,即MSP的地址 */
	ldr r0, =0xE000ED08
	ldr r0, [r0]
	ldr r0, [r0]

	/* 设置主堆栈指针msp的值 */
	msr msp, r0
    
	/* 使能全局中断 */
	cpsie i
	cpsie f
	dsb
	isb
	
    /* 调用SVC去启动第一个任务 */
	svc 0  
	nop
	nop
}

(2)代码解析

这段代码的主要目的是为启动第一个任务做好准备,具体步骤如下:

①从向量表读取初始主堆栈指针(MSP)并设置 MSP。

②使能全局中断,以确保中断处理可以进行。

③触发 SVC 中断,该中断处理程序将会执行第一个任务的上下文切换,从而启动第一个任务。

(3)汇编代码的逐句解析

在这里插入图片描述

在这里插入图片描述




5、 SVC 中断vPortSVCHandler函数解析

(1)源代码

__asm void vPortSVCHandler( void )
{
   
    extern pxCurrentTCB;
    
    PRESERVE8

	ldr	r3, =pxCurrentTCB	
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值