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()的中断安全版本
如果xHigherPriorityTaskWoken参数是pdFALSE则不会发生上下文切换,否则发生。
大部分平台允许在中断中的任意位置调用portYIELD_FROM_ISR(),但是有些只能在ISR末尾调用。
中断处理延迟 Deferred Interrupt Processing
中断所需的任何其他处理通常可以在任务中执行,从而允许ISR尽可能快地退出——这就是中断处理延迟。
这样也可使得处理任务和其他任务的执行按照优先级进行。如果处理任务优先级高于其他任务,当中断退出后它可以直接执行。
对于哪些处理被延时并没有严格的规定,一般遵循以下几点:
- 如果处理并不繁琐,可以在ISR中进行,比如说,简单的模数转换。但是,如果是滤波操作,则应该defer在新的任务中执行。
- 不能在中断中进行的操作,比如说,内存分配等,应该defer到task执行
- 处理时间不确定的操作应该defer到task执行
二值信号量同步操作
二值信号量用来defer中断的处理。
如图,我们可以用一个二值信号量来避免之前所说的,等待中断数据任务不被运行的情况。我们在ISR中添加一个信号量,t1时刻Task1运行,在t2时刻中断发生,此时中断得到了数据并释放信号量,Task2得到信号量立即运行。t4时刻Task1继续运行。
图解
API
xSemaphoreCreateBinary()
xSemaphoreTake()
xSemaphoreGiveFromISR()
示例 1 只适用于低频率中断
运行结果
图解:
示例 2 适用于高频中断
示例1的问题:
当中断速度很快,而数据处理速度很慢时,会造成数据的丢失!!
解决方案:取一次信号量就要处理完当前所有数据。
计数信号量 Counting Semaphores
configUSE_COUNTING_SEMAPHORES = 1启用计数信号量
计数信号量主要应用于两个方面:
- 计数事件
-
资源管理
如图所示:
API
xSemaphoreCreateCounting()
示例 利用计数信号量与中断同步
延迟到RTOS Daemon任务
API
xTimerPendFunctionCallFromISR()
示例
图解:
在ISR中使用队列
队列虽然能将数据从中断发送到任务中,但是如果数据频率很高,这个方法并不是很高效。
更加高效的方式有:
- 使用DMA(Direct Memory Access)接收,这样不会造成软件过载。然后使用任务通知解除阻塞任务。
- 将接收到的数据复制到一个安全的RAM缓冲区,然后使用任务通知。。。
- 直接在ISR中处理接收到的数据,然后使用一个队列将结果发送出ISR。
中断嵌套
任务优先级和中断优先级之间经常出现混淆。本节讨论中断优先级,即中断服务例程(ISR)相对彼此执行的优先级。分配给任务的优先级与分配给中断的优先级没有任何关系。硬件决定ISR何时执行,而软件决定任务何时执行。为响应硬件中断而执行的ISR将中断任务,但任务不能抢占ISR。
配置
数字优先级和逻辑优先级
-
数字优先级
数字优先级是分配各中断优先级数值。如果中断的优先级为7,则其数字优先级为7。同样,如果中断被赋予200的优先级,则其数字优先级为200。 -
逻辑优先级
中断的逻辑优先级描述了该中断相对于其他中断的优先级。如果两个不同优先级的中断同时发生,则处理器将对两个中断中逻辑优先级较高的中断执行ISR。中断可以嵌套具有较低逻辑优先级的任何中断,但中断不能嵌套具有相等或较高逻辑优先级的任何中断。
中断的数字优先级和逻辑优先级之间的关系取决于处理器体系结构;在某些处理器上,分配给中断的数字优先级越高,中断的逻辑优先级就越高,在其他处理器架构上,分配给中断的数字优先级越高,该中断的逻辑优先级就越低。