中断与非中断API的区别
c
BaseType_t xQueueSendToBack(
QueueHandle_t xQueue,
const void *pvItemToQueue,
TickType_t xTicksToWait
);
BaseType_t xQueueSendToBackFromISR(
QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken
);
以写队列的API为例,在非中断的api中最后一项参数为等待时间,而在中断api中最后一项参数仅仅是说明有无优先级更高的任务被唤醒。
在非中断api中,执行的逻辑是这样,如果遇到更高优先级的任务被唤醒,那么更高优先级的任务将会抢占当前任务。而在中断api中,会先记录更高优先级的任务,在中断里的任务处理完成后,在中断末尾对任务进行切换。
中断的范围
在FreeRtos中,关中断并不是关闭所有中断,能够关闭的中断都是对于系统来说都是等级相对较低的,等级高的中断不能关断。因为在FrerRtos中,根本就没有涉及到高等级的中断,在操作系统的api中仅仅只包含了低级的中断。
注意:即使最低优先级的中断 也比最高优先级的任务 优先级要高
中断服务函数 xPortPendSVHandler()
在系统滴答定时器中断服务函数中调用API函数xPortSysTickHandler(),xPortSysTickHandler()函数中通过向中断和状态寄存器的bit28写入1来启动PendSV中断,具体PendSV中断服务函数是 PendSV_Handler,并且任务切换的具体任务是在PendSV中断服务函数中完成的。
c
#define xPortPendSVHandler PendSV_Handler
_asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp
isb
/* Get the location of the current TCB. */
ldr r3, =pxCurrentTCB
ldr r2, [r3]
/* Is the task using the FPU context? If so, push high vfp registers. */
tst r14, #0x10
it eq
vstmdbeq r0!, {s16-s31}
/* Save the core registers. */
stmdb r0!, {r4-r11, r14}
/* Save the new top of stack into the first member of the TCB. */
str r0, [r2]
stmdb sp!, {r3}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
dsb
isb
bl vTaskSwitchContext //在此处 调用函数vTaskSwitchContext() ,该函数用来获取下一个要运行的任务,并将 pxCurrentTCB更新为这个要运行的任务。
mov r0, #0
msr basepri, r0
ldmia sp!, {r3}
/* The first item in pxCurrentTCB is the task top of stack. */
ldr r1, [r3]
ldr r0, [r1]
/* Pop the core registers. */
ldmia r0!, {r4-r11, r14}
/* Is the task using the FPU context? If so, pop the high vfp registers
too. */
tst r14, #0x10
it eq
vldmiaeq r0!, {s16-s31}
msr psp, r0
isb
#ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata */
#if WORKAROUND_PMU_CM001 == 1
push { r14 }
pop { pc }
nop
#endif
#endif
bx r14 //至此,任务切换成功。
}
在PendSV中断服务函数中实现了一下的功能,首先保存现场,然后调用了函数vTaskSwitchContext()来获取下一个要运行的任务,也就是查找已经就绪了的优先级最高的任务,最后切换新的任务。