SIEMENS山东省济南市 西门子代理商——西门子华北一级总代理
| 更新时间 2024-06-30 07:00:00 价格 请来电询价 西门子总代理 PLC 西门子一级代 驱动 西门子代理商 伺服电机 联系电话 15903418770 联系手机 15915421161 联系人 张经理 立即询价 |
详细介绍
5.2.2 任务切换
#ifndef portYIELD_WITHIN_API #define portYIELD_WITHIN_API portYIELD#endif
/* Scheduler utilities. */#define portYIELD() \{ \ /* Set a PendSV to request a context switch. */ \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ \ /* 触发PendSV,产生上下文切换 */ \ __dsb( portSY_FULL_READ_WRITE ); \ __isb( portSY_FULL_READ_WRITE ); \}
PRESERVE8
mrs r0, psp /* 保存当前任务PSP地址到R0中 */ isb
ldr r3, =pxCurrentTCB /* 获取pxCurrentTCBConst指针地址 */ ldr r2, [r3] /* R2被赋予当前TCB地址 */
/* 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*/ mov r0, #0 msr basepri, r0 /*打开中断*/ ldmia sp!, {r3}
/* The first item in pxCurrentTCB is the task top of stack. */ ldr r1, [r3] /* R3依然是pxCurrentTCBConst指针地址,R1变为新TCB地址 */ ldr r0, [r1] /* R0值成为新TCB的栈地址(该TCB发生上一次调度的PSP值) */
/* 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}
#ifndef portYIELD_WITHIN_API #define portYIELD_WITHIN_API portYIELD#endif
/* Scheduler utilities. */#define portYIELD() \{ \ /* Set a PendSV to request a context switch. */ \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ \ /* 触发PendSV,产生上下文切换 */ \ __dsb( portSY_FULL_READ_WRITE ); \ __isb( portSY_FULL_READ_WRITE ); \}
portYIELD()任务切换函数,主要就是将PendSV的悬起位置1,在没有其它中断运行时执行PendSV中断服务函数,在这个中断函数中实现任务切换。
5.2.3 PendSV中断服务函数PendSV中断服务函数是一段汇编代码,可能不太容易看懂,该函数需要先了解如下:
外部变量pxCurrentTCB是当前正在运行的任务的任务控制块
当进入PendSV中断服务函数时,上一任务的运行环境为:xPSR,PC(任务入口地址),R14,R12,R3,R2,R1,R0(任务的形参),这些CPU寄存器的值会自动保存到任务的栈中,剩下的R4~R11需要手动保存。
总的来说,该函数实现3部分功能:上文保存,下文切换,中间调用了一个C函数vTaskSwitchContext,用于寻找要运行的任务。
PRESERVE8
mrs r0, psp /* 保存当前任务PSP地址到R0中 */ isb
ldr r3, =pxCurrentTCB /* 获取pxCurrentTCBConst指针地址 */ ldr r2, [r3] /* R2被赋予当前TCB地址 */
/* 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*/ mov r0, #0 msr basepri, r0 /*打开中断*/ ldmia sp!, {r3}
/* The first item in pxCurrentTCB is the task top of stack. */ ldr r1, [r3] /* R3依然是pxCurrentTCBConst指针地址,R1变为新TCB地址 */ ldr r0, [r1] /* R0值成为新TCB的栈地址(该TCB发生上一次调度的PSP值) */
/* 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}
相关产品