如何从高优先级 ISR 中唤醒 FreeRtos 任务?

Posted

技术标签:

【中文标题】如何从高优先级 ISR 中唤醒 FreeRtos 任务?【英文标题】:How to wake up a FreeRtos task from a high priority ISR? 【发布时间】:2014-12-03 14:01:21 【问题描述】:

使用:

Stm32F10x、F2xx、F4xx FreeRtos 8.1.1 gcc-arm-none-eabi-4_8-2014q2

我有一个必须以高中断优先级运行的 ISR,因此禁止在此 ISR 中调用 FreeRtos Api(请参阅 here 和 here)。

在某些情况下,这些 ISR 会检测到条件,在这些条件下,休眠的 FreeRtos 任务应该以至少可能的延迟唤醒。

通常(如果由于足够低的优先级而允许 ISR 调用 FreeRtos Api)我会使用队列或信号量来解决这个问题。

但是如何通过高优先级 ISR 实现这一点?

我目前的临时方法是这样的(简要概述):

volatile int flag = 0;

void XYZ_IRQHandler() 
    if (someCondition)
        flag = 1


void FreeRtosTaskFunction(void* parameters) 
    for (;;) 
        if (flag == 1)
            doSomething();
        vTaskDelay(1);  // sleep 10ms (tick frequency is 100Hz)
    

但是这种方法有缺点:

延迟(从在 ISR 中设置标志直到任务唤醒)最多为 1 个 FreeRtos 滴答声。 需要轮询标志(浪费 CPU 周期)。

有什么建议可以更好地解决这个问题,尤其是延迟更短?

【问题讨论】:

【参考方案1】:

我有一个想法,虽然未经测试似乎应该可行。

我假设您的 ISR 具有高优先级,因为它需要极低的延迟来执行不受其他中断影响的事情(即在准确的时间进行测量),并且任务应该很快完成,但不是t 非常关键(即传输或显示值)。

在您的高优先级 ISR 中,执行时序关键功能,然后触发低优先级内部中断。

当高优先级 ISR 完成时(以及任何其他待处理),将调用低优先级 ISR。然后它可以调用 FreeRTOS API 并立即启动任务。

【讨论】:

任何想法/链接如何触发内部中断? 好的,在 st-lib 中找到 EXTI_GenerateSWInterrupt()。不幸的是,它需要浪费一条 EXTI Line 和一个 irq 通道。但我会试一试。 Here 是另一种不使用 EXTI 的方法,但由于使用了 FreeRtos 跟踪宏,这对我的项目来说有点过于 hacky。我现在将基于 EXTI 的解决方案与 FreeRtos 信号量结合使用。【参考方案2】:

解决方案是使用 FreeRTOS Task notification。

您的任务将挂起,然后在 ISR 事件发生后立即恢复/唤醒。

【讨论】:

FreeRtos 任务通知(随 FreeRtos 8.2 引入)是信号量的不错替代品。但请注意,也不允许从具有高中断优先级的 ISR 调用该 api。

以上是关于如何从高优先级 ISR 中唤醒 FreeRtos 任务?的主要内容,如果未能解决你的问题,请参考以下文章

STM32 FreeRTOS - UART延迟中断问题

STM32FreeRTOS 系统内核控制函数

小内核操作系统中中断和任务之间的信号

freeRTOS学习3--中断管理

[FreeRTOS].FreeRTOS CortexM3 M4中断优先级设置总结

STM32中用 stop 模式 配合低功耗模式下的自动唤醒(AWU) 能否实现FreeRTOS tickless 模式