UCOS-III 系统启动接口OSStart详解

        在实时操作系统 uC/OS-III 中,OSStart 函数是启动多任务处理的关键步骤。它让 uC/OS-III 管理已经创建的任务。在调用 OSStart 之前,必须先调用 OSInit 并至少创建一个应用任务。本文将详细解析 OSStart 函数的工作原理。

1. OSStart 函数概述

OSStart 函数主要完成以下任务:

  1. 检查操作系统是否已初始化
  2. 计算内核任务的数量
  3. 检查是否有应用任务已创建
  4. 设置最高优先级任务
  5. 启动最高优先级任务
  6. 错误处理

2. OSStart 函数流程图

345fce7de16c4375b61f40673d3de61a.png

3. OSStart 函数详细解析

3.1 检查操作系统是否已初始化

OSStart 函数中,首先检查操作系统是否已初始化。如果操作系统未初始化,则返回错误。

if (OSInitialized != OS_TRUE) {
    *p_err = OS_ERR_OS_NOT_INIT;
    return;
}

3.2  计算内核任务的数量并检查是否有应用任务已创建

计算内核任务(如统计任务、定时器任务和空闲任务)的数量,并检查是否有应用任务创建

kernel_task_cnt = 0u;
#if (OS_CFG_STAT_TASK_EN > 0u)
    kernel_task_cnt++;
#endif
#if (OS_CFG_TMR_EN > 0u)
    kernel_task_cnt++;
#endif
#if (OS_CFG_TASK_IDLE_EN > 0u)
    kernel_task_cnt++;
#endif
if (OSTaskQty <= kernel_task_cnt) {
    *p_err = OS_ERR_OS_NO_APP_TASK;
    return;
}

3.3. 设置最高优先级任务

设置当前最高优先级任务

if (OSRunning == OS_STATE_OS_STOPPED) {
    OSPrioHighRdy   = OS_PrioGetHighest();
    OSPrioCur       = OSPrioHighRdy;
    OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
    OSTCBCurPtr     = OSTCBHighRdyPtr;
    OSRunning       = OS_STATE_OS_RUNNING;
}


3.4  调用OSStartHighRdy启动就绪任务

OSStartHighRdy();  /* Execute target specific code to start task */
*p_err = OS_ERR_FATAL_RETURN;

4. 如何启动第一个就绪任务

 调用OSStartHighRdy 启动第一个就绪任务。该函数的主要作用是触发一个 PendSV 异常,从而引发上下文切换,开始执行第一个任务。函数的主要步骤包括设置 PendSV 异常优先级、初始化堆栈指针、获取当前高优先级任务、恢复任务上下文等

4.1 OSStartHighRdy 流程图

20503da15aee40a790996c53a21ddff4.png

4.2 详细解析

4.2.1 禁止中断

通过禁止中断(CPSID I 指令),防止在上下文切换期间发生中断

CPSID   I

4.2.2 设置 PendSV 异常优先级

设置 PendSV 异常优先级为最低优先级,确保任务切换不会中断其他更高优先级的中断服务程序

MOV32   R0, NVIC_SYSPRI14
MOV32   R1, NVIC_PENDSV_PRI
STRB    R1, [R0]

4.2.3  初始化 PSP 

将 PSP(进程堆栈指针)设置为 0,用于初始上下文切换调用

MOVS    R0, #0
MSR     PSP, R0

4.2.4  初始化 MSP

将 MSP(主堆栈指针/中断堆栈指针)初始化为 OS_CPU_ExceptStkBase

MOV32   R0, OS_CPU_ExceptStkBase
LDR     R1, [R0]
MSR     MSP, R1

4.2.5 调用 OSTaskSwHook

调用 OSTaskSwHook 函数,用于执行其他操作

BL      OSTaskSwHook

4.2.6 设置当前优先级

设置当前优先级(OSPrioCur)为最高优先级(OSPrioHighRdy)

MOV32   R0, OSPrioCur
MOV32   R1, OSPrioHighRdy
LDRB    R2, [R1]
STRB    R2, [R0]

4.2.7 设置当前任务控制块指针

设置当前任务控制块指针(OSTCBCurPtr)为最高优先级任务控制块指针(OSTCBHighRdyPtr)

MOV32   R0, OSTCBCurPtr
MOV32   R1, OSTCBHighRdyPtr
LDR     R2, [R1]
STR     R2, [R0]

4.2.8 加载 PSP

从最高优先级任务控制块指针(OSTCBHighRdyPtr)中加载新的进程堆栈指针(PSP)

LDR     R0, [R2]
MSR     PSP, R0

4.2.9 更新 CONTROL 寄存器

更新 CONTROL 寄存器,确保使用 PSP 作为堆栈指针并禁用浮点协处理器。

MRS     R0, CONTROL
ORR     R0, R0, #2
BIC     R0, R0, #4
MSR     CONTROL, R0
ISB

4.2.10 恢复任务上下文

从堆栈中恢复任务的寄存器上下文,使能中断,并跳转到任务的程序计数器

LDMFD    SP!, {R4-R11, LR}
LDMFD    SP!, {R0-R3}
LDMFD    SP!, {R12, LR}
LDMFD    SP!, {R1, R2}
CPSIE    I
BX       R1

5. 为什么设置PendSV异常优先级为最低优先级

       PendSV通常用于实现上下文切换,即从一个任务切换到另一个任务。以下是设置 PendSV 异常优先级为最低优先级的几个原因:

5.1. 确保任务切换在所有其他中断处理之后进行

        PendSV 的主要用途是触发任务切换。通过将 PendSV 的优先级设置为最低,可以确保它在所有其他中断处理完成之后才被执行。以确保系统中更高优先级的中断能够及时处理,不会被任务切换延迟。

5.2. 避免中断嵌套

        如果 PendSV 异常的优先级高于某些中断,那么在这些中断处理过程中可能会发生任务切换,从而导致中断嵌套和处理复杂性增加。将 PendSV 的优先级设置为最低,可以避免这种情况,确保任务切换在所有中断处理完成后进行,简化了中断处理逻辑。

5.3. 优化系统实时性

        系统的实时性要求某些关键中断必须尽快得到响应。通过将 PendSV 的优先级设置为最低,可以确保这些关键中断优先得到处理,从而提高系统的实时性。

5.4. 避免中断响应时间过长

        在嵌入式系统中,某些中断(如定时器中断、外部事件中断等)的响应时间非常关键。如果 PendSV 的优先级高于这些中断,那么在处理任务切换时可能会延迟这些中断的响应,导致系统性能下降或数据丢失。将 PendSV 的优先级设置为最低,可以避免这种情况,确保关键中断得到及时响应。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechIoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值