gentleman 发表于 2024-3-3 12:32:43

FreeRTOS for STC32G12K128内核代码解读(二)任务调度(中)

本帖最后由 gentleman 于 2024-3-3 15:03 编辑

FreeRTOS for STC32G12K128内核代码解读(二)任务调度(中)
任务轮询


2.1 调整中断堆栈内容
上次我们成功启动了 第一个任务
    如果 任务中,它不挂起自己,或进入延时状态。 (正常不会这么干,下期会讲)
    那么 任务会执行到 1tick后
    cpu进入定时器0中断
   

    配置定时器0 中断函数
    vTimer0ISR()
    跳进去
   
    180行    portNORMALIZE_INTERRUPT_STACK();
   再跳进去
   
      发现 它执行了一系列 出栈 入栈 操作
    目的是什么
    因为中断的栈 格式是不一样的

    我们可通过对比 RETI 与 ERET 来比较
      

       很明显 中断栈顶元素 是PC15~8
         而函数栈顶元素是PC7~0
   所以这里 将几个栈元素都 弹出来
         按照函数栈 顺序 重新入一遍栈
2.2寄存器入栈 配置Tick计数器


         将寄存器入栈
       继续看代码
         

      接下来进入到这个函数
         

         
            const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
         将tick计数器+1
         freeRTOS 就是靠这个计数器计时的
      xConstTickCount == ( TickType_t ) 0U
   
      计数器什么时候==0
      溢出的时候
      切换 延时任务列表 (看过之前的文章知道,这列表有两个)
      关于延时任务部分 下期再说
      这期主要看轮询
2.3保存当前任务堆栈指针


             阅读过之前内容
             就知道 DR60 是SP指针指向堆栈的栈顶
             这里把 SP指针 保存到了当前任务TCB(pxTopOfStack)中

         DR0 与WR2 ,DR4 与WR6 的关系大家应该都清楚吧,不多解释了
2.4取出下个任务

   返回去
      
       跳入这个函数
      
         判读了一下 任务调度是否启动
      启动了就执行这个函数
      

          while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \

      {                                                                     \
            configASSERT( uxTopPriority );                                    \
            --uxTopPriority;                                                \
      }                                                                     \



         优先级列表空就看下个优先级列表
      listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );
   取出下一个任务的PCB这块展开讲内容也有点多,后面我会画张图,补充在本贴下面3L
2.5恢复到新任务栈顶指针
      好的,现在已经获取到了下个任务的TCB
      回到这里
      
      portRESTORE_SPX()             
      这里和上期一样, 修改SP 为 新任务的TCB(pxEndOfStack)
      让SP指向新任务的(堆)栈
2.6出(新任务)栈


      弹出新任务用的寄存器
2.7压入RETI需要的栈元素 ,调用RETI退出中断


       $ 指当前行
   $+10 指的是哪一行
   我们来分析一下
   这是PUSH
   
          指令长度3 (因为立即数也要占一个)
       3条PUSH 长度9   
      
         而RETI 长度1
      所以$+10 就是 RETI 的下一条指令
      同理 +7 +4 也是
   最后调用RETI 退出中断
         至于为啥要这么干,用RETI 清楚标志位,退出中断。不然下次就不进中断了,CPU认为还在中断内部。
2.8ERET 进入新任务函数

         
            这部分也和上期一样
      
       通过ERET 修改PC指针
         让PC指针指向新的任务入口
         到此完成了新任务的切换






gentleman 发表于 2024-3-3 12:33:09

本帖最后由 gentleman 于 2024-3-28 10:50 编辑


上期:任务调度 (上)   FreeRTOS for STC32G12K128内核代码解读(二)任务调度(上) - FreeRTOS/实时操作系统/文件系统/嵌入式系统软件,TFT-GUI/uGFX - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)

下期:
5.任务调度(中下)FreeRTOS for STC32G12K128内核代码解读(二)任务调度(中下) - FreeRTOS/实时操作系统/文件系统/嵌入式系统软件,TFT-GUI/uGFX - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)



gentleman 发表于 2024-3-3 14:59:51

本帖最后由 gentleman 于 2024-3-4 10:47 编辑

补充 FreeRTOS (xLIST)链表结构内容

    便于大家理解在任务就绪链表取出下个任务TCB过程
   

   下图为FreeRTOS 三个链表的定义
   

   xLIST 中包含 xMINI_LIST_ITEM与xLIST_ITEM
   即
   pxReadyTasksLists]中 包含pxIndex 与xListEnd
而在任务就绪链表链表初始化时




   可以看到初始化 时把pxIndex 设为了 xListEnd
   
   新建任务时
    插入链表尾部的函数
   把 新项 的下一项 设为 pxIndex (初始化时为xListEnd)
   前项 设为 pxIndex(初始化时为xListEnd)的前一项(就是上个任务)
            
   这里可以看第一张图 去理解


   
   取出下个任务
   还是对照图来看
   很清晰的看出 pxIndex 的pxNext 是哪一项
   当pxNext 为 xListEnd 时 就再取pxNext一遍

   
   
   

gentleman 发表于 2024-3-4 10:48:41

3L 用了补充了一些内容

再占一楼
页: [1]
查看完整版本: FreeRTOS for STC32G12K128内核代码解读(二)任务调度(中)