FreeRTOS 中断管理

时间:2024-03-13 12:30:05

FreeRTOS 中断管理

一般来说,嵌入式系统有两种方式感知事件:轮询和中断
二者相比,中断对事件的响应更加快速,但同时,由于中断是硬件层的机制,一旦发生多少会造成系统影响。而在中断服务函数中,如果有time-consuming的任务,就会影响整个系统的实时性。所以,应该尽可能减少在ISR中的操作。

FreeRTOS API在ISR中的使用

中断安全API The Interrupt Safe API

不要尝试在ISR中调用非“FromISR”的FreeRTOS API。一般来说,所有的中断安全的函数都会有FromISR的后缀!

xHigherPriorityTaskWoken参数

如果中断导致上下文切换,在中断退出和进入时的运行的任务可能是有区别的——当中断打断一个任务执行完成后,可能会返回到另一任务。

xHigherPriorityTaskWoken的使用是可选的,如果不用,请设置为NULL

上下文切换何时发生,取决于API从什么地方被调用:

  • 从Task调用
    如果configUSE_PREEMPTION设为1,则切换发生在调用API之前
  • 从中断调用
    切换不会在中断中发生,但是,xHigherPriorityTaskWoken会被置为pdTRUE来指示上下文切换应该发生。
    每次检测时,xHigherPriorityTaskWoken必须事先初始化为pdFALSE

为什么上下文切换不在中断中进行?

  • 避免不必要的切换
    一个中断可能会在需要处理前发生很多次,多次的上下文切换是time-consuming的。
  • 可靠性
    中断可能发生在任意时刻,它是不可预知的,我们不希望上下文切换是不可预知的。
  • 兼容性
    在中断外执行切换,可以很好适配其他的硬件平台。
  • 效率
    有些小的处理器结构只允许上下文切换发生在ISR结束后,修改规则是个很麻烦的事情。

portYIELD_FROM_ISR()和portEND_SWITCHING_ISR() 宏定义

这两个宏是都用来在中断中请求上下文切换的,作用相同!
portYIELD_FROM_ISR() 和 portEND_SWITCHING_ISR()是taskYIELD()的中断安全版本
FreeRTOS 中断管理
如果xHigherPriorityTaskWoken参数是pdFALSE则不会发生上下文切换,否则发生。
大部分平台允许在中断中的任意位置调用portYIELD_FROM_ISR(),但是有些只能在ISR末尾调用。

中断处理延迟 Deferred Interrupt Processing

中断所需的任何其他处理通常可以在任务中执行,从而允许ISR尽可能快地退出——这就是中断处理延迟
这样也可使得处理任务和其他任务的执行按照优先级进行。如果处理任务优先级高于其他任务,当中断退出后它可以直接执行。
FreeRTOS 中断管理
对于哪些处理被延时并没有严格的规定,一般遵循以下几点:

  • 如果处理并不繁琐,可以在ISR中进行,比如说,简单的模数转换。但是,如果是滤波操作,则应该defer在新的任务中执行。
  • 不能在中断中进行的操作,比如说,内存分配等,应该defer到task执行
  • 处理时间不确定的操作应该defer到task执行

二值信号量同步操作

二值信号量用来defer中断的处理。
FreeRTOS 中断管理
如图,我们可以用一个二值信号量来避免之前所说的,等待中断数据任务不被运行的情况。我们在ISR中添加一个信号量,t1时刻Task1运行,在t2时刻中断发生,此时中断得到了数据并释放信号量,Task2得到信号量立即运行。t4时刻Task1继续运行。
图解
FreeRTOS 中断管理

API

xSemaphoreCreateBinary()

FreeRTOS 中断管理

xSemaphoreTake()

FreeRTOS 中断管理
FreeRTOS 中断管理

xSemaphoreGiveFromISR()

FreeRTOS 中断管理
FreeRTOS 中断管理

示例 1 只适用于低频率中断

FreeRTOS 中断管理
FreeRTOS 中断管理
FreeRTOS 中断管理
FreeRTOS 中断管理
运行结果
FreeRTOS 中断管理
图解:
FreeRTOS 中断管理

示例 2 适用于高频中断

示例1的问题:
FreeRTOS 中断管理
当中断速度很快,而数据处理速度很慢时,会造成数据的丢失!!

解决方案:取一次信号量就要处理完当前所有数据。
FreeRTOS 中断管理

计数信号量 Counting Semaphores

configUSE_COUNTING_SEMAPHORES = 1启用计数信号量
计数信号量主要应用于两个方面:

  • 计数事件
  • 资源管理
    如图所示:
    FreeRTOS 中断管理

API

xSemaphoreCreateCounting()

FreeRTOS 中断管理
FreeRTOS 中断管理

示例 利用计数信号量与中断同步

FreeRTOS 中断管理
FreeRTOS 中断管理

延迟到RTOS Daemon任务

API

xTimerPendFunctionCallFromISR()

FreeRTOS 中断管理
示例
FreeRTOS 中断管理
FreeRTOS 中断管理
FreeRTOS 中断管理
图解:
FreeRTOS 中断管理

在ISR中使用队列

FreeRTOS 中断管理
队列虽然能将数据从中断发送到任务中,但是如果数据频率很高,这个方法并不是很高效。
更加高效的方式有:

  • 使用DMA(Direct Memory Access)接收,这样不会造成软件过载。然后使用任务通知解除阻塞任务。
  • 将接收到的数据复制到一个安全的RAM缓冲区,然后使用任务通知。。。
  • 直接在ISR中处理接收到的数据,然后使用一个队列将结果发送出ISR。

中断嵌套

任务优先级和中断优先级之间经常出现混淆。本节讨论中断优先级,即中断服务例程(ISR)相对彼此执行的优先级。分配给任务的优先级与分配给中断的优先级没有任何关系。硬件决定ISR何时执行,而软件决定任务何时执行。为响应硬件中断而执行的ISR将中断任务,但任务不能抢占ISR。

配置

FreeRTOS 中断管理

数字优先级和逻辑优先级

  • 数字优先级
    数字优先级是分配各中断优先级数值。如果中断的优先级为7,则其数字优先级为7。同样,如果中断被赋予200的优先级,则其数字优先级为200。
  • 逻辑优先级
    中断的逻辑优先级描述了该中断相对于其他中断的优先级。如果两个不同优先级的中断同时发生,则处理器将对两个中断中逻辑优先级较高的中断执行ISR。中断可以嵌套具有较低逻辑优先级的任何中断,但中断不能嵌套具有相等或较高逻辑优先级的任何中断。

中断的数字优先级和逻辑优先级之间的关系取决于处理器体系结构;在某些处理器上,分配给中断的数字优先级越高,中断的逻辑优先级就越高,在其他处理器架构上,分配给中断的数字优先级越高,该中断的逻辑优先级就越低。