[FreeRTOS]Day13FreeRTOS中的两套函数
两套函数
在任务函数中,可以调用各类API函数,比如队列操作函数xQueueSendToBack(),但是在中断服务程序ISR(Interrupt Service Routine)中不能使用这个函数,而应该使用xQueueSendToBackFromISR(),表示在中断中给队列发送数据。
为什么要有两套函数?
很多API函数会导致调用该函数的任务进入阻塞状态,比如任务A调用
xQueueSendToBack()写队列,此时队列满,任务A就会进入阻塞状态。但如果是ISR,由于ISR不是任务,不能进入阻塞,所以要加以区分
两套函数的区别:中断要尽快处理完
/* 等同于xQueueSendToBack
* 往队列尾部写入数据,如果没有空间,阻塞时间为xTicksToWait
*/
BaseType_t xQueueSend(
QueueHandle_t xQueue,
const void *pvItemToQueue,
TickType_t xTicksToWait
);
/*
* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞
*/
BaseType_t xQueueSendToBackFromISR(
QueueHandle_t xQueue,
const void *pvItemToQueue,
BaseType_t *pxHigherPriorityTaskWoken
);
以写队列函数为例,在任务中写入xQueueSend()时可以指定超时时间,假设xTicksToWait = 100,那么在不发生唤醒更高优先级任务的情况下,任务A执行xQueueSend()完成的耗时为0 - 100个Tick,如果写入队列后唤醒了更高优先级的任务B,那么耗时会更长,这在中断服务程序ISR中是不允许的
在中断中使用xQueueSend(Queue, Val, 0)能否替代xQueueSendToBackFromISR()呢?答案是不能,xTicksToWait = 0仅仅指定了队列满时不进入阻塞,直接返回,但是如果队列不满,写入操作成功,并且发现有更高优先级的任务正在等待该队列数据时,会在函数内部主动发起任务切换请求,这在ISR中是不允许的。xQueueSendToBackFromISR()使用pxHigherPriorityTaskWoken参数标记一个状态,等退出ISR时,手动调用portYIELD_FROM_ISR()进行安全的任务切换。
改进实时性
当前game1框架

以IRReceiver为例,在中断服务程序IRReceiver_IRQ_Callback()中调用IRReceiver_IRQTimes_Parse(),在其中调用DispatchKey(),使用xQueueSendFromISR()写队列,整体结构为

xQueueSendFromISR()中可能唤醒更高优先级任务,但是不发生调度,这会导致任务A中断中唤醒的高优先级任务B不能在中断结束之后得到响应,而是需要等到下一个Tick中断来时才能发生调度,运行任务B

正确的流程应该是:任务A在中断服务程序中唤醒了高优先级任务B,但是不立刻调度,而是在中断函数即将退出时,发起调度使任务B得到响应,这样既保证了中断函数执行尽可能快,又保证了高优先级任务得到响应尽可能快
如何切换任务?使用portYIELD_FROM_ISR()
void XXX_ISR()
{
int i;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
for (i = 0; i < N; i++)
{
xQueueSendToBackFromISR(..., &xHigherPriorityTaskWoken); /* 被多次调用 */
}
/* 最后再决定是否进行任务切换
* xHigherPriorityTaskWoken 为 pdTRUE 时才切换
*/
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
优化后的DispatchKey()使用xHigherPriorityTaskWoken标记写队列过程中是否唤醒了更高优先级任务,在中断服务程序退出时,由portYIELD_FROM_ISR()根据它的值判断是否需要发起调度
static void DispatchKey(struct ir_data *pidata)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
int i;
for (i = 0; i < g_queue_cnt; i++)
{
xQueueSendFromISR(g_xQueues[i], pidata, &xHigherPriorityTaskWoken);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)