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 ) if( xSchedulerRunning == pdFALSE ){ } |
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、任务出栈顺序