freertos 源码分析六 任务调度二

本文详细介绍了嵌入式系统中的任务调度机制,重点讨论了SysTick_Handler和PendSV_Handler中断如何控制定时器,以及xTaskIncrementTick函数用于任务延时和优先级处理。同时,文章涵盖了任务堆栈初始化的过程,确保任务切换的正确执行。
摘要由CSDN通过智能技术生成

任务调度由SysTick_Handler和 PendSV_Handler两个中断接管
系统时钟计数器按给定频率倒计时,至0触发SysTick_Handler中断,此中断函数为宏中对xPortSysTickHandler的重命名。
增加计数,置位可挂起中断。

void xPortSysTickHandler( void )
{
    portDISABLE_INTERRUPTS();
    {
        if( xTaskIncrementTick() != pdFALSE )
        {
            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
        }
    }
    portENABLE_INTERRUPTS();
}

xTaskIncrementTick 以设定频率增加计数,处理延时任务。

BaseType_t xTaskIncrementTick( void )
{
    TCB_t * pxTCB;                                                                                                                                 
    TickType_t xItemValue;
    BaseType_t xSwitchRequired = pdFALSE;

    if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
    {
        const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
        xTickCount = xConstTickCount;
        if( xConstTickCount == ( TickType_t ) 0U )
        {
            taskSWITCH_DELAYED_LISTS();  //计数溢出 交换延时链表与溢出链表
        }

        if( xConstTickCount >= xNextTaskUnblockTime )   //处理延时链表
        {
            for( ; ; )
            {
                if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )  //空
                {
                    xNextTaskUnblockTime = portMAX_DELAY;
                    break;
                }
                else  //非空
                {
                    pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
                    xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
                    if( xConstTickCount < xItemValue )
                    {                                                                                                                              
                        xNextTaskUnblockTime = xItemValue;
                        break;
                    }

                    listREMOVE_ITEM( &( pxTCB->xStateListItem ) );  //延时已过
                    if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
                    {
                        listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
                    }
                    prvAddTaskToReadyList( pxTCB );  //添至就绪链表
                    #if ( configUSE_PREEMPTION == 1 )
                    {
                        if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
                        {
                            xSwitchRequired = pdTRUE;  //优先级大于现运行任务需切换
                        }
                    }
                    #endif
                }
            }
        }
        #if ( configUSE_PREEMPTION == 1 )
        {
            if( xYieldPending != pdFALSE )
            {
                xSwitchRequired = pdTRUE;
            }
        }
        #endif

    }
    else
    {
        ++xPendedTicks;  // 增加计数
    }
    return xSwitchRequired;
}

listLIST_IS_EMPTY宏定义

#define listLIST_IS_EMPTY( pxList )   ( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE ) 

可挂起中断,此中断函数在宏中重命名为PendSV_Handler。系统时钟中断中对其置位,以低优先级运行,无高于其优先级时会调入对任务进行切换。

void xPortPendSVHandler( void )
{
    __asm volatile
    (
        "   mrs r0, psp                         \n"
        "   isb                                 \n"
        "   ldr r3, pxCurrentTCBConst           \n" //当前运行任务
        "   ldr r2, [r3]                        \n" 
        "   stmdb r0!, {r4-r11}                 \n"  //保存r4-r11 psp
        "   str r0, [r2]                        \n"  //保存当前栈顶pxTopOfStack 
        "   stmdb sp!, {r3, r14}                \n"  //保存r3 r14至msp
        "   mov r0, %0                          \n"  // 优先级
        "   msr basepri, r0                     \n"  
        "   bl vTaskSwitchContext               \n" // 在就绪链表寻找最高优先级设为当前切换任务
        "   mov r0, #0                          \n"
        "   msr basepri, r0                     \n"
        "   ldmia sp!, {r3, r14}                \n"  // 恢复 r3 lr
        "   ldr r1, [r3]                        \n"  //当前TCB指针 TCB已切换
        "   ldr r0, [r1]                        \n"  //当前TCB栈顶pxTopOfStack
        "   ldmia r0!, {r4-r11}                 \n"  //从TCB栈恢复 r4-r11 变动后指向任务参数
        "   msr psp, r0                         \n"  //psp栈指向tcb栈 
        "   isb                                 \n"  // 
        "   bx r14                              \n"  // 中断返回从PSP栈恢复寄存器值,任务回调函数指针载入PC,完成任务切换。
        "                                       \n"
        "   .align 4                            \n"
        "pxCurrentTCBConst: .word pxCurrentTCB  \n"
        ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
    );
}

参考创建任务时,任务堆栈设置

StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
                                     TaskFunction_t pxCode,
                                     void * pvParameters )
{
    pxTopOfStack--;                                                      
    *pxTopOfStack = portINITIAL_XPSR;   //thumb                                 
    pxTopOfStack--;
    *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; //task回调函数指针
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS;             /* LR */
    pxTopOfStack -= 5;                                                   /* R12, R3, R2 and R1. */
    *pxTopOfStack = ( StackType_t ) pvParameters;                        /* R0 */
    pxTopOfStack -= 8;                                                   /* R11, R10, R9, R8, R7, R6, R5 and R4. */

    return pxTopOfStack;
}
  • 31
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FreeRTOS 是一个开源的实时操作系统 (RTOS),被广泛用于嵌入式系统开发。它提供了多任务管理、内存管理、任务通信和同步等功能,适用于多种处理器架构和开发板。 如果你想进行 FreeRTOS 源码分析,以下是一些常见的步骤和建议: 1. 下载源码:你可以从 FreeRTOS 官方网站或 GitHub 上获取 FreeRTOS源码。确保下载适合你的目标硬件平台和编译器的版本。 2. 阅读文档:FreeRTOS 官方网站提供了详细的文档和用户指南,包括任务管理、内存管理、同步机制等方面的说明。阅读文档可以帮助你更好地理解系统的设计和使用方法。 3. 理解核心结构:FreeRTOS 的核心结构包括任务控制块 (TCB)、调度器、时间片和内核对象等。深入理解这些结构的作用和相互关系,可以帮助你分析系统的运行原理。 4. 调试和跟踪:使用适合你的开发环境和硬件平台的调试工具,可以对 FreeRTOS 进行调试和跟踪。你可以设置断点、监视任务状态、查看任务堆栈和中断处理等信息,以便更好地理解系统的运行过程。 5. 逐步分析代码:从 FreeRTOS 的任务入口点开始,逐步分析代码的执行流程。重点关注任务的创建、调度、挂起和恢复等关键操作。通过阅读代码和调试,你可以更深入地了解 FreeRTOS 的实现细节。 6. 查阅社区资源:FreeRTOS 社区有许多活跃的开发者和用户,他们在论坛上分享了大量的问题解答、示例代码和优化技巧。查阅社区资源可以帮助你更好地理解 FreeRTOS 的使用和调试技巧。 请注意,由于 FreeRTOS 是一个相对复杂的系统,源码分析可能需要一定的时间和经验。建议你先从简单的示例程序开始,逐步深入研究源码。另外,参考官方文档和社区资源也是非常有帮助的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yvee

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

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

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

打赏作者

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

抵扣说明:

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

余额充值