return pxTopOfStack;
}
2)启动任务调度
portBASE_TYPE xPortStartScheduler( void )
{
让任务切换中断和心跳中断位于最低的优先级,使更高优先级可以抢占mcu
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
设置并启动系统的心跳时钟
prvSetupTimerInterrupt();
初始化临界区的嵌套的个数
uxCriticalNesting = 0;
启动第一个任务
vPortStartFirstTask();
执行到vPortStartFirstTask函数,内核已经开始正常的调度
return 0;
}
3)主动释放mcu使用权
void vPortYieldFromISR( void )
{
触发PendSV系统服务中断,中断到来时由汇编函数xPortPendSVHandler()处理
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
}
进入临界区时,首先关闭中断;当退出所以嵌套的临界区后再使能中断
void vPortEnterCritical( void )
{
portDISABLE_INTERRUPTS();
uxCriticalNesting++;
}
void vPortExitCritical( void )
{
uxCriticalNesting--;
if( uxCriticalNesting == 0 )
{
portENABLE_INTERRUPTS();
}
}
4)心跳时钟处理函数
void xPortSysTickHandler( void )
{
unsigned portLONG ulDummy;
如果是抢占式调度,首先看一下有没有需要调度的任务
#if configUSE_PREEMPTION == 1
*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
#endif
ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
{ 通过task.c的心跳处理函数vTaskIncrementTick(),进行时钟计数和延时任务的处理
vTaskIncrementTick();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
}
3、PORTASM.S 汇编处理部分
1)请求切换任务
xPortPendSVHandler:
保存当前任务的上下文到其任务控制块
mrs r0, psp
ldr r3, =pxCurrentTCB 获取当前任务的任务控制块指针
ldr r2, [r3]
stmdb r0!, {r4-r11} 保存R4-R11到该任务的堆栈
str r0, [r2] 将最后的堆栈指针保存到任务控制块的pxTopOfStack
stmdb sp!, {r3, r14}
关闭中断
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
切换任务的上下文,pxCurrentTCB已指向新的任务
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r3, r14}
恢复新任务的上下文到各寄存器
ldr r1, [r3]
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-33191-2.html
可以说这是在筛选优秀人人才
很难