当前位置: 首页 > article >正文

FreeRTOS学习 --- 任务切换

任务切换的本质:就是CPU寄存器的切换。

        假设当由任务A切换到任务B时,主要分为两步:

        第一步:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场

        第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场

        对任务A保存现场,对任务B恢复现场,这个整体的过程称之为:上下文切换

         注意:任务切换过程PendSV中断服务函数里边完成

PendSV中断是如何触发的?

        1、滴答定时器中断触发PendSV中断

        2、执行FreeRTOS提供的相关API函数:portYIELD()触发PendSV中断

        本质:通过向中断控制和状态寄存器 ICSR bit28 写入 1 挂起 PendSV 来启动 PendSV 中断

上表摘取于《Cortex M3权威指南(中文)》131页。 

 查找最高优先级任务

        vTaskSwitchContext( )  /* 查找最高优先级任务 */

        taskSELECT_HIGHEST_PRIORITY_TASK( )  /* 通过这个函数完成 */

 #define taskSELECT_HIGHEST_PRIORITY_TASK()                                               \
    {                                                                                     \
        UBaseType_t uxTopPriority;                                                        \
        portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );         			  \
        configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); 	\
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );   	\
    }

获取最高优先级任务的任务控制块

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                             \
    {                                                       
        List_t * const pxConstList = ( pxList );                           		 \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;             \
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) 			 \
        {                                                                                      							 \
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       			 \
        }                                                                                      							 \		
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         			 	 \ 
    }

        通过该函数获取当前最高优先级任务的任务控制块,同时同等优先级的任务会在一个时间片后进行切换,这就是时间片调度。

任务切换具体步骤:

1.mrs r0, psp

        把psp存到r0,当前的psp是任务A的栈指针,这时的psp指向的是任务栈A中的R0

2. ldr r3, =pxCurrentTCB

    ldr r2, [ r3 ]

        获取当前运行任务的栈顶地址即R2保存的栈顶地址,注意R3等于pxCurrentTCB的地址

3.stmdb r0!, {r4-r11, r14}

        压栈,从上往下压,将r0的值,当压栈的起始地址,开始压栈(保存现场)

4.str r0, [ r2 ]

        将r0的值(前面的底部地址),写到r2地址所指向的内存中(即栈顶地址指向的内存, pxTopOfStack中)

5.stmdb sp!, {r0, r3}

        把R0和R3的值压入MSP 

6.bl vTaskSwitchContext

        通过该函数,获取下一个执行任务的任务控制块,赋值给pxCurrentTCB

7.ldmia sp!, {r0, r3}

        从sp(MSP)恢复r3,即把r3恢复成&pxCurrentTCB。后续就可以利用r3得到新的任务控制块了。

8.ldmia r0!, {r4-r11, r14}

        出栈,以寻址地址开始,从下往上进行出栈,将保存在这些地址的值恢复到寄存器里边去

9.msr psp, r0

   bx r14

        ①将r0更新给psp线程堆栈

        ②返回线程模式,执行新任务


http://www.kler.cn/a/530502.html

相关文章:

  • Workbench 中的热源仿真
  • 一种非接触式智能垃圾桶设计(论文+源码+实物)
  • [权限提升] Windows 提权 维持 — 系统错误配置提权 - Trusted Service Paths 提权
  • 2181、合并零之间的节点
  • elasticsearch8.15 高可用集群搭建(含认证Kibana)
  • 小程序的协同工作与发布
  • 网络工程师 (13)时间管理
  • 【华为OD-E卷 - 磁盘容量排序 100分(python、java、c++、js、c)】
  • IM 即时通讯系统-45-merua0oo0 IM 分布式聊天系统
  • 【Ai】DeepSeek本地部署+Page Assist图形界面
  • 【软件测试项目实战】淘宝网订单管理功能
  • 项目集成Spring Security授权部分
  • 2025年2月2日(range()函数的参数及含义)
  • 「全网最细 + 实战源码案例」设计模式——享元模式
  • 【C++面试题】malloc和new delete和delete[]
  • 在AWS上使用Flume搜集分布在不同EC2实例上的应用程序日志具体流程和代码
  • Golang 并发机制-4:用Mutex管理共享资源
  • 毕业设计:基于卷积神经网络的鲜花花卉种类检测算法研究
  • 51单片机 02 独立按键
  • 享元模式——C++实现
  • Java基础知识总结(四十)--Java.util.Properties
  • 浅析服务器虚拟化技术
  • unity学习26:用Input接口去监测: 鼠标,键盘,虚拟轴,虚拟按键
  • Leetcode:598
  • 深入核心:一步步手撕Tomcat搭建自己的Web服务器
  • Ubuntu 下 nginx-1.24.0 源码分析 ngx_debug_init();