@EFM32JG移植FreeRTOS
1、任务调度器
1)创建空闲任务,优先级为0,表示最低优先级,在无其他高优先级任务的情况下,执行空闲任务,若打开configUSE_IDLE_HOOK,则可以再空闲任务中增加自己想要执行的代码,定义勾子函数void vApplicationIdleHook( void )。
2)变量 xSchedulerRunning 设置为 pdTRUE,表示调度器开始运行。
3)设置 PendSV、滴答定时器 的中断优先级,为最低优先级。所以若为事件调度,需要关闭滴答定时器,在优先级最高的任务循环之前加入: SysTick->CTRL = 0,即可关闭。
4)利用SVC异常来启动第一个任务,SVC 中断服务函数应该为 SVC_Handler(),但是FreeRTOSConfig.h 中通过#define 的方式重新定义为了 xPortPendSVHandler()。
2、任务创建
1)为堆栈申请任务内存,大小为分配的值*4
2)为任务控制块申请内存
3)使用函数 prvInitialiseNewTask()初始化任务
A、若使能了互斥信号量功能,则初始化相应字段
B、初始化列表项 xStateListItem 和 xEventListItem
C、设置列表项xEventListItem的字段xItemValue,值越大,优先级就越小,在插入列表时需要排序
D、调用函数 pxPortInitialiseStack()初始化任务堆栈
4)任务创建完成以后就会被添加到就绪列表 pxReadyTasksLists[]中
A、变量 uxCurrentNumberOfTasks 为全局变量,用来统计任务数量,若为1,则表示创建第一个任务,需要初始化相应列表。
B、若新创建的任务优先级比正在运行的任务优先级高,需要修改 pxCurrentTCB 为新
建任务的任务控制块。
C、调用函数 prvAddTaskToReadyList()将任务添加到就绪列表中
D、如果该任务的任务优先级最高,而且调度器已经开始正常运行了,那么就调用函数taskYIELD_IF_USING_PREEMPTION()完成一次任务切换。
3、任务切换
1)任务切换是使用PendSV来切换任务的,它是不精确的
通过向中断控制和壮态寄存器 ICSR 的 bit28 写入 1 挂起 PendSV 来启动 PendSV 中断。
任务切换的场合是执行一次系统调用,或系统滴答定时器中断。
为了解决上下文切换与中断的冲突问题,防止中断被打断而造成异常,因此上下文切换放到中断中完成。
2)任务切换函数taskYIELD()
此函数使用时,会直接切换成优先级最高的任务,当任务优先级一致的时候,会切换为别的任务,但是当优先级不一致,当前任务优先级最高,而且任务还没有挂起,会导致重新运行该任务,不会切换为别的任务。
所以我是用的事件触发的任务切换使用延时函数切换,vTaskDelay(1),可将任务阻塞,并执行下个任务。在使用事件去切换任务时,当注意控制好该延时,1表示一次事件周期,需保证一次事件周期可以让任务都执行一遍,防止把低优先级任务饿死。
3)滴答定时器中断
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
HAL_IncTick();
}
当利用事件触发任务时,使用下面的代码即可,添加到事件中,每次事件达成,即开启一次任务调度,否则可以在低功耗模式下休眠,以降低功耗。
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
宏configUSE_TIME_SLICING虽然在例程的FreeRTOSConfig.h 文件中未定义,但是默认为1,表示在同一优先级下可进行任务切换
函数xPortSysTickHandler()调用xTaskIncrementTick,进行时钟节拍计数,并检查是否有任务需要解除阻塞。当计数溢出时,切换延时列表,实现计数溢出切换,此方法可在其他地方借鉴使用!!!!!
解除延时阻塞,可以是任务延时,也可以是事件超时退出。直接将任务添加到就绪列表中。并判断当前任务优先级,使用优先级最高的任务。
4)延时函数(相对延时)
将任务加入延时列表,计算出唤醒时间,xTimeToWake = xConstTickCount + xTicksToWait;,xConstTickCount=xTickCount,xTickCount 是时钟节拍计数器,每次调用xTaskIncrementTick时xTickCount 都会加一。
当溢出时,会将任务放入溢出的延时列表,当计数溢出时,切换列表则可以实现翻转计数。
将任务阻塞后,开始进行任务切换。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)