freertos笔记-任务切换

红叶何时落水

任务切换,调用PendSV
 

#define taskYIELD() portYIELD()
#define portYIELD() \
{ \
    portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ 通过向中断控制和壮态寄存器 ICSR 的 bit28 写入 1 挂起 PendSV 来启动 PendSV 中断
    \
    __dsb( portSY_FULL_READ_WRITE ); \
    __isb( portSY_FULL_READ_WRITE ); \
}

系统滴答定时器(SysTick)中断
 

void xPortSysTickHandler( void )
{
    vPortRaiseBASEPRI(); 关中断
    {
        if( xTaskIncrementTick() != pdFALSE ) //增加时钟计数器 xTickCount 的值
        {
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; 
        }
    }
    vPortClearBASEPRIFromISR(); 开中断
}

查找下一个要运行的任务
vTaskSwitchContext
见freertos笔记-各种列表运行原理.txt


任务调度
xTaskIncrementTick() 被滴答定时器调用
1. 滴答计数+1
2. 判断滴答计数是否溢出最大值
    2.1 如果溢出,代表计数值为0 调用taskSWITCH_DELAYED_LISTS();
      

  #define taskSWITCH_DELAYED_LISTS()                                                                    \
        {                                                                                                    \
            List_t *pxTemp;                                                                                    \
            pxTemp = pxDelayedTaskList;                                                                        \
            pxDelayedTaskList = pxOverflowDelayedTaskList;                                                    \
            pxOverflowDelayedTaskList = pxTemp;                                                                \
            xNumOfOverflows++;                                                                                \
            prvResetNextTaskUnblockTime();                                                                    \
        }


            2.1-prvResetNextTaskUnblockTime( void )
               

 {
                    TCB_t *pxTCB;
                    if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
                    {
                        /* The new current delayed list is empty.  Set xNextTaskUnblockTime to
                        the maximum possible value so it is    extremely unlikely that the
                        if( xTickCount >= xNextTaskUnblockTime ) test will pass until
                        there is an item in the delayed list. */
                        xNextTaskUnblockTime = portMAX_DELAY;
                    }
                    else
                    {
                        /* The new current delayed list is not empty, get the value of
                        the item at the head of the delayed list.  This is the time at
                        which the task at the head of the delayed list should be removed
                        from the Blocked state. */
                        ( pxTCB ) = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );//获取列表中的第一个任务
                        xNextTaskUnblockTime = listGET_LIST_ITEM_VALUE( &( ( pxTCB )->xStateListItem ) );
                    }
                }

3. 判断是否有任务到期 添加死循环
    3.1 获取延时列表里的第一个任务(列表是升序排列的)
    3.2 判断获取当前任务的溢出值是否大于计数值 xItemValue在xStateListItem里面放着
        是 xNextTaskUnblockTime = xItemValue;跳出 3. 循环 (一般用于死循环的第二次循环,因为第一次肯定是溢出了,但是,可能溢出的不止一个,所以要把所有溢出的都找到,最后,找到下一个溢出值)
        否 泡泡
    3.3 uxListRemove xStateListItem和xEventListItem
    3.4 添加到就绪列表中 prvAddTaskToReadyList()
       

 #define prvAddTaskToReadyList( pxTCB )                                                                \
            traceMOVED_TASK_TO_READY_STATE( pxTCB );                                                        \
            taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority );                                                \
            vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \//可以看出来任务会被添加到当前point的前一个,也就是说,后添加的后执行
            tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )


    3.5 判断是否要进行任务切换,如果溢出任务优先级高于运行任务优先级的话,会切换任务,而且切换的任务一定是是先添加进去的任务,原因1 高优先级的列表一定为空,pxIndex=>xlistend,而且添加的任务是添加到
        pxIndex前面,那就意味着,pxIndex-xlistend => pxIndex-xlistend-1 => pxIndex-xlistend-1-2 下一个执行的是任务1
4. 判断当前优先级下是否有其他就绪任务,如果是,就切换任务。作用场景为 当前任务和溢出的任务相同优先级,那么下一个执行的会是溢出的任务,当然如果列表里还有其他任务的话不一定是会执行这个溢出任务,
   这种情况的原因在于当前优先级的就绪列表中不一定只有当前任务在运行,所以任务切换后,也不一定会立马切换到溢出的任务,经过检测,没问题,会受到干扰

5. 返回任务上下文切换标志


PendSV中断

__asm void xPortPendSVHandler( void )
{
    extern uxCriticalNesting;
    extern pxCurrentTCB;
    extern vTaskSwitchContext;

    PRESERVE8

    mrs r0, psp
    isb

    ldr    r3, =pxCurrentTCB        /* Get the location of the current TCB. */当前任务结构体
    ldr    r2, [r3]

    stmdb r0!, {r4-r11}            /* Save the remaining registers. */
    str r0, [r2]                /* Save the new top of stack into the first member of the TCB. */当前任务环境保存

    stmdb sp!, {r3, r14}
    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
    msr basepri, r0
    dsb
    isb
    bl vTaskSwitchContext     //判断下一个任务是哪个
    mov r0, #0
    msr basepri, r0
    ldmia sp!, {r3, r14}

    ldr r1, [r3]
    ldr r0, [r1]                /* The first item in pxCurrentTCB is the task top of stack. */
    ldmia r0!, {r4-r11}            /* Pop the registers and the critical nesting count. */
    msr psp, r0
    isb
    bx r14
    nop
}


vTaskSwitchContext();

void vTaskSwitchContext( void )
{
    if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
    {
        xYieldPending = pdTRUE;
    }
    else
    {
        xYieldPending = pdFALSE;
        taskSELECT_HIGHEST_PRIORITY_TASK();//获取就绪最高优先级
    }
}

    #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                        \
    {                                                                                                \
    UBaseType_t uxTopPriority;                                                                        \
                                                                                                    \
        /* Find the highest priority list that contains ready tasks. */                                \
        portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                                \
        configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 );        \
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );        \
        //获取最高优先级中的任务,就是( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext执行后pxIndex的指向
    } /* 

    #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;                                            \
    }    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

红叶落水

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

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

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

打赏作者

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

抵扣说明:

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

余额充值