FreeRTOS - 中断

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tq384998430/article/details/87930104

中断对于嵌入式实时系统来说重要性不言而喻。在FreeRTOS系统中,突发的、周期性的、无法预期的事情称作事件Event,嵌入式系统需要对这些事件进行识别和处理,一般会使用中断的机制来检测这些事件的发生,当然也可以使用查询(标志位)的方式识别事件是否发生。通常我们需要中断处理函数ISR尽可能的简短,这个原则是在裸机应用开发中也有的,但是有的事件会触发大量的耗时的CPU运算,例如当我们收到一帧JPEG数据之后产生中断,然后需要将JPEG数据解码成原始像素信息,我们不能将所有处理都放在ISR中,因为这对于MCU系统来说会消耗很多CPU时间,并且解码JPEG很有可能不是一个很急迫的事件或者说优先级很高的事件,所以我们需要将JPEG解码放在主程序(指非ISR程序而不是main程序)中去处理,而不是在ISR中处理,这时候我们就需要确定在 ISR Code 和 NON-ISR Code 中的运行时间的分配问题以及ISR程序如何与NON-ISR程序进行通讯的问题。

需要说明一下,系统API函数和宏定义以 FromISR 和 FROM_ISR 结尾的才能在中断处理函数ISR中使用,其余的API或者宏定义如果在ISR中使用可能会导致错误。

FreeRTOS提供了一些同步机制用于实现系统的中断管理:二值信号量、计数信号量、队列。

二值信号量可以用来在发生一个中断的时候唤醒一个处于Blocked状态的任务,这个处于Block状态的任务叫做synchronized handler task,我们可以将大量的处理任务放在这个synchronized handler task中处理,而中断处理函数中只需要使用二值信号量唤醒这个任务即可,这个过程我们称作为将中断推至事件处理任务。如果这个中断属于时间敏感型,那么我们可以将handler task的优先级设置到最高,以保证当ISR返回之后可以立即发生一个任务调度及时切换到handler task,这就保证了中断事件的处理可以连续的被处理。

二值信号量的基本使用方式为 takegive。假设二值信号量是一件物品,中断的Handler task调用take就相当于要拿物品,但是现在还没有物品可以拿,所以任务就会进入Blocked状态等待有物品可拿。当发生中断调用ISR函数时,在ISR内部调用give操作会放置一个物品,然后Handler task就有物品可以拿了,就从Blocked状态转入Ready状态,注意这里Handler task拿了这个物品就会把这个物品消耗掉,这个物品就没了。如果Handler task的优先级较较高,则会在ISR返回之后立即切换到Handler task,在处理完事件之后任务就会返回到 take 操作,再次进入Blocked状态。在传统的信号量术语中,这里的take 和 give操作就相当于P() 和 V()操作。

我们可以发现,二值信号量的主要作用是用来同步中断和任务,整个过程可以简化成以下的过程:

1、中断发生。

2、执行中断处理函数,调用 give 操作唤醒Handler Task。

3、Handler Task在ISR之后立刻执行,任务做的第一件事就是 take 二值信号量,并“吃掉”这个信号量。

4、在 take 之后执行中断事件处理操作,然后再次回到 take 操作发现没有可用的信号量,又会进入到Blocked状态,等待下一个中断ISR中 give 一个信号量。

但是二值信号量只适合较低频率的中断源,如果中断源的频率过高或者Handler Task中的处理时间过长就会导致 give 操作和 take 操作无法同步,导致数据丢失,这时候我们可以使用计数信号量来解决这个问题。

计数信号量和二值信号量是非常相似的,可以把二值信号量看做是一个长度为1的一个Queue,只有 Full 和 Empty两种状态,任务读取一个Empty Queue就会进入Blocked状态,相当于 take 操作,向Empty Queue中写入数据,任务就会被唤醒,相当于 give 操作。而计数信号量相当于一个长度为 N 的Queue,可以向这个Queue中存放N个“物品”,就算Handler Task没有及时的将Queue中的物品拿走,只要Queue没有满,中断就可以继续向Queue中 give 物品,大大降低了物品丢失的风险。

 

猜你喜欢

转载自blog.csdn.net/tq384998430/article/details/87930104