ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0!, {r4-r11} /* Pop the registers. */
msr psp, r0
bx r14
2.)中断允许和关闭的实现,通过BASEPRI屏蔽相应优先级的中断源
vPortSetInterruptMask:
push { r0 }
mov R0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr BASEPRI, R0
pop { R0 }
bx r14
vPortClearInterruptMask:
PUSH { r0 }
MOV R0, #0
MSR BASEPRI, R0
POP { R0 }
bx r14
3)直接切换任务,用于vPortStartFirstTask第一次启动任务时初始化堆栈和各寄存器
vPortSVCHandler;
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
ldmia r0!, {r4-r11}
msr psp, r0
mov r0, #0
msr basepri, r0
orr r14, r14, #13
bx r14
4)启动第一个任务的汇编实现
vPortStartFirstTask
通过中断向量表的定位堆栈的地址
ldr r0, =0xE000ED08 向量表偏移量寄存器 (VTOR)
ldr r0, [r0]
ldr r0, [r0]
msr msp, r0 将堆栈地址保存到主堆栈指针msp中
触发SVC软中断,由vPortSVCHandler()完成第一个任务的具体切换工作
svc 0
FreeRTOS内核调度器启动的流程如下:
以上3个文件实现了FreeRTOS内核调度所需的底层接口,相关代码十分精简。
二、创建测试任务:下面创建第一个测试任务,LED测试
int main( void )
{
设置系统时钟,中断向量表和LED使用的GPIO
使用stm32的固件包提供的初始化函数,具体说明见相关手册
prvSetupHardware();
通过xTaskCreate()创建4个LED任务vLEDFlashTask(),
每个任务根据各自的频率闪烁,分别对应开发板上的4个LED
vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );
? 创建一个IDLE任务后,通过xPortStartScheduler启动调度器
vTaskStartScheduler();
调度器工作不正常时返回
return 0;
}
portTASK_FUNCTION()是FreeRTOS定义的函数声明,没特殊作用
static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
{
……省略……,具体为计算各LED的闪烁频率
for(;;)
{
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
vParTestToggleLED( uxLED );
vTaskDelayUntil()的延时时间xFlashRate,是从上一次的延时时间xLastFlashTime算起的,
相对vTaskDelay()的直接延时更为精准。
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-33191-3.html
不管是老旧舰还是新锐舰或航母舰
在南海依旧畅通无阻
故意用一艘老军舰来挑衅中国