freertos- 任务调度器-vTaskStartScheduler()解析(笔记)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Life_Maze/article/details/84196808

1、全局状态量

系统时钟节拍计数器tick。 static volatile TickType_t xTickCount   = ( TickType_t ) 0U;
全局下一任务调度需要的阻塞时间,用于及其唤醒任务 static volatile TickType_t  xNextTaskUnblockTime  = ( TickType_t ) 0U; 
全局当前任务pcb。 TCB_t * volatile pxCurrentTCB = NULL;
全局调度器工作标志。 static volatile BaseType_t  xSchedulerRunning   = pdFALSE;
全局调度器挂起标志。 static volatile UBaseType_t  uxSchedulerSuspended    = ( UBaseType_t ) pdFALSE;

2、调度器运行状态(与调度器挂起标志、调度器运行标志有关)。

     #define taskSCHEDULER_SUSPENDED        ( ( BaseType_t ) 0 ) // 挂起
     #define taskSCHEDULER_NOT_STARTED    ( ( BaseType_t ) 1 ) // 未开启
     #define taskSCHEDULER_RUNNING        ( ( BaseType_t ) 2 )     // 运行

3、获取调度器运行状态。

    BaseType_t xTaskGetSchedulerState( void )
    {
        BaseType_t xReturn;

        if( xSchedulerRunning == pdFALSE ){
            xReturn = taskSCHEDULER_NOT_STARTED;
        } else {
            if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){
                xReturn = taskSCHEDULER_RUNNING;
            }else{
                xReturn = taskSCHEDULER_SUSPENDED

           }
        }return xReturn;
    }

4、 vTaskStartScheduler() 过程。

  •     动态创建一个"IDLE"任务:堆栈configMINIMAL_STACK_SIZE=128*4byte;任务优先级为tskIDLE_PRIORITY;任务体 prvIdleTask。
  • 如果系统使用 软件定时器;将通过xTimerCreateTimerTask()创建定时器服务任务"Tmr Svc"。堆栈2*128*4byte;任务优先级为configTIMER_TASK_PRIORITY;任务体 prvTimerTask。
  • 关闭中断portDISABLE_INTERRUPTS().用以屏蔽configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY=5中断级别以下的所有中断。(在vPortSVChandle 中断服务函数中会对其开启)
  • 设置下一任务调度需要的阻塞时间xNextTaskUnblockTime  = portMAX_DELAY =  0xffffffffUL;
  • 设置调度器工作标志 xSchedulerRunning = pdTRUE;
  • 设置初始化时钟节拍计数器xTickCount = 0;
  • 系统运行时间统计变量初始化。runtimeCounter = 0ul。
  • 开启进入第一个任务 xPortStartScheduler()

         ---设置PendSV、SysTick为最低优先级中断并开启SysTick。

        ----初始化任务临界区嵌套计数 uxCriticalNesting = 0;

        ---设置systick计时器来生成所需的tick中断频率vPortSetupTimerInterrupt()

        ----使能FPU(CP10&CP11),确保在VFP启用vPortEnableVFP()。

         ---开启第一个任务。vPortStartFirstTask()

5、prvIdleTask()任务分析

    略。

6、prvTimerTask()任务分析

    略。

7、vPortStartFirstTask() 分析

   /* Use the NVIC offset register to locate the stack. */
    ldr r0, =0xE000ED08   /* 中断向量表重定位(偏移)寄存器 VTOR.(systemInit中已经重定位到0x80000000) */
    ldr r0, [r0]   /*  读取VTOR中的值到R0,即 R0=  0x80000000 ,*/
    ldr r0, [r0]   /* 向量表起始地址存储的是MSP(系统堆栈指针)的初始值,即本处获得了MSP中的初始值(CSTACK)*/
    /* Set the msp back to the start of the stack. */
    msr msp, r0  /* 将MSP中的初始值赋值给MSP,即复位MSP ,这个初始值子在哪里赋予的呢?*/
    /* Call SVC to start the first task. */
    cpsie i
    cpsie f    /*操作 寄存器PRIMASK、FAULTMASK,使能全局中断 */
    dsb        /*数据同步隔离*/
    isb         /*指令同步隔离*/
    svc 0     /*触发SVC中断,系统调用代号为 0 ,整个freeRtos中唯一使用的地方*/

 

8、vPortSVCHandler 异常服务处理

vPortSVCHandler:
    /* Get the location of the current TCB. */
    ldr    r3, =pxCurrentTCB       /*  获取第一个任务pcb指针 到 R3*/
    ldr r1, [r3]                       /* 获取任务pcb指针的值(即PCB的存储地址) 到 R1*/
    ldr r0, [r1]                      /*  获取任务pcb 结构的第一个数据,即任务堆栈指针 到 R0 */
    /* Pop the core registers. */
    ldmia r0!, {r4-r11, r14}   /* 需要手动出栈,恢复任务的现场 ,R0~R3、xPSR(任务状态)、R12(IP)、R15(PC)中断退出后硬件自动出栈恢复;注意:R14(LR)=EXC_RETURN,在进入本中断时自动赋值为特殊含义*/
    msr psp, r0                    /*  将目前的任务栈指针赋值给进程栈指针(R13-PSP) */
    isb                                 /*指令同步隔离*/
    mov r0, #0                   /* 设置R0的的 值为 0 */
    msr    basepri, r0         /* 打开中断  */
    bx r14                           /*   跳转开始执行  */

9、异常返回值 EXC_RETURN

9、任务出栈顺序

展开阅读全文

没有更多推荐了,返回首页