FreeRTOS 任务、中断解读–zynq
1. 中断中如何进行任务切换
FreeRTOS在中断返回时判断ulPortYieldRequired变量的值,如果该值为true则执行进程切换,否则不执行。所以在中断中只看到了ulPortYieldRequired变量的赋值,没有看到任务的切换,实际切换是在中断返回后的汇编代码中实现的。
FreeRTOS_IRQ_Handler:
/* Return to the interrupted instruction. */
SUB lr, lr, #4
/* Push the return address and SPSR. */
PUSH {lr}
MRS lr, SPSR
PUSH {lr}
/* Change to supervisor mode to allow reentry. */
CPS #SVC_MODE
/* Push used registers. */
PUSH {r0-r4, r12}
/* Increment nesting count. r3 holds the address of ulPortInterruptNesting
for future use. r1 holds the original ulPortInterruptNesting value for
future use. */
LDR r3, ulPortInterruptNestingConst
LDR r1, [r3]
ADD r4, r1, #1
STR r4, [r3]
LDR r1, =ulPortYieldRequired ; /*判断该变量是否为True*/
LDR r0, [r1]
CMP r0, #0
BNE switch_before_exit
exit_without_switch:
/* No context switch. Restore used registers, LR_irq and SPSR before
returning. */
POP {r0-r4, r12}
2. 代码中如何进行任务切换
代码中直接调用portYIELD(),实现任务切换,该函数实际为软中断指令,软中断中实现任务切换,portYIELD()定义如下:
#define portYIELD() __asm volatile ( "SWI 0" ::: "memory" );
//软中断中实现了任务切换
FreeRTOS_SWI_Handler:
/* Save the context of the current task and select a new task to run. */
portSAVE_CONTEXT
LDR R0, vTaskSwitchContextConst
BLX R0
portRESTORE_CONTEXT
3 外设中断向量初始化
外设中断向量初始化必须启动一个Task,在Task中初始化。
原因:FreeRTOS的任务调度是由cpu 32bit private Timer的硬件定时器中断实现,在调用xPortStartScheduler()函数启动任务的时候会对中断寄存器进行重新配置,将Tick中断使能,映射中断处理函数,这个过程会将原来的中断寄存器值覆盖掉,因此只能在Task中初始化外设中断向量,同时注意保证中断寄存器其他位的数据不变,否则可能导致Tick不工作,整个系统无法执行。