文章目录
- 01 - 延迟中断机制
- 02 - 机制的支撑条件
- 2.1 - 信号/二值信号量
- 2.2 - 信号量/计数信号量
- 03 - 延迟中断的实时性
- 04 - 总结
上一文链接:FreeRTOS笔记(十)队列和通信
任务切换中也提到过中断,比如SysTick
中断、SVC
中断和PendSV
中断,他们都是多任务并发进行的必要中断,可以认为属于内部中断,在任务和内核之间进行的,而FreeRTOS实时操作系统需要响应外界各种事件,比如按键按下、数据源有数据到达等等,这部分属于外部中断,FreeRTOS对外部中断的处理都使用延迟中断机制
01 - 延迟中断机制
先回顾一般外部中断的执行流程,首先系统配置好中断源、中断触发方式、中断服务函数、中断屏蔽位等内容后,中断就开始工作了,当中断源满足中断触发条件(事件到达),CPU就会停下当前的工作,并保存当前工作状态,然后跳转到中断服务函数ISR
,执行完毕后再恢复工作的状态,继续当前工作
一般而言,事件到达后的处理在中断服务函数ISR
中进行,但是有个弊端,如果待处理事件的工作量很大,那么整个中断过程将占用很多时间,在这段时间内,会发生任务停滞、另一个中断得不到响应等等的情况,整个系统的执行效率就会非常低。同时这也违背了中断的概念,中断应该是处理紧急事件的,所以ISR的工作量应该尽可能小
事件的工作量不能改变,不过可以改变工作的地方,就是把工作从中断服务函数中移到任务里,中断和任务相互合作,任务可以阻塞等待中断的到来,ISR
只负责唤醒任务和少部分工作,而不做其它事情,于是延迟中断的概念就出现了
可以认为,事件的到来触发了中断,但是ISR
其实没有马上进行实质性的处理,而是先唤醒负责这个事件的任务,让任务进行实质性的工作,于是认为中断被推迟执行,FreeRTOS的外部中断处理都是基于延迟中断机制,要实现延迟中断机制,需要使用信号和信号量
02 - 机制的支撑条件
信号和信号量其实是Linux的表述,在FreeRTOS的表述上稍有不同:
二值信号量(FreeRTOS) <—> 信号(Linux)
计数信号量(FreeRTOS) <—> 信号量(Linux)
只是表述不同,概念是一样的,上一文也以及过信号和信号量,其实都是队列,不过队列长度和操作约束不一样。由于FreeRTOS都把两者称为信号量,于是他们有一样的操作句柄xSemaphoreHandle
,不过创建函数不一样
2.1 - 信号/二值信号量
二值信号量其实是一个长度为1的队列,所以队列的状态不为空即为满,只有两个状态,就称为二值,这非常合适地表达了某个外部事件的状态,就是到达和未到,所以可以直接进行映射,二值信号量为满代表事件到达,二值信号量为空代表事件未到
FreeRTOS提供的二值信号量操作API如下:
API | 功能 |
xSemaphoreCreateBinary() | 创建二值信号量 |
xSemaphoreGive() | 任务状态下给出信号量 |
xSemaphoreTake() | 任务状态下得到信号量 |
xSemaphoreTakeFromISR() | 中断状态下给出信号量 |
xSemaphoreTakeFromISR() | 中断状态下得到信号量 |
vSemaphoreDelete() | 删除信号量 |
其实除了创建函数外,其它的函数都用于信号量,比如计数信号量和互斥量。
有了二值信号量,就可以使得中断和任务同步,并且把事件工作量转移到任务上,一般的使用过程是:创建二值信号量,某个任务与某个事件挂钩,事件的执行工作在任务的任务函数中,任务阻塞获得二值信号量(take操作
),事件到达触发中断后,ISR中
给出二值信号量(give操作
),这样任务就会被解除阻塞,然后执行,执行完毕后再次阻塞等待二值信号量
2.2 - 信号量/计数信号量
使用二值信号量都是基于这样一种思想:中断到来给出了二值信号量,而任务能及时获得并处理。问题是能否真正地及时,答案是不一定,FreeRTOS是多任务并发执行,任务阻塞态的解除其实需要一段时间,并不是二值信号量一旦给出,任务就能马上获得,所以如果事件发生比较频繁,在这段时间内有多个相同的事件到达,那么中断就会发生多次,但是二值信号量只能记录一个状态,于是后来的中断就会覆盖前面的中断,发生了中断丢失,即使多个中断到达了,但是任务依然只看见一个
如果某个中断比较频繁,为了能够记录多个同样中断的到达,需要使用计数信号量,可以认为是一个数组,数组内的每一个元素都是二值信号量,计数信号量能够记录多个状态,这样即使任务没有马上获得信号量,后来的中断也不会覆盖前面的中断,中断就不会丢失
计数信号量的创建函数如下:
API | 功能 |
xSemaphoreCreateCounting() | 创建计数信号量 |
其余的操作函数和二值信号量共用
03 - 延迟中断的实时性
可能会认为延迟中断机制违背了FreeRTOS的实时操作系统的概念,其实不是,这种所谓的延迟就可以实现两种实时功能,实时分为硬实时和软实时,相同点是都必须要及时处理和必须完成,不同点是硬实时要求在某个时刻前一定要完成,而软实时要求尽可能快地完成,并没有给出绝对的时刻。
用延迟中断机制实现硬实时,其实很简单,在中断服务函数中除了给出信号量外,再把任务A的优先级置为最高,这样中断服务函数一旦结束,紧接着的就是任务A的执行,于是整体效果就是工作是在中断服务函数中执行的
而实现软实时,也可以一样地改变任务A的优先级,但不需要改为最高优先级,可以低一点,也可以不改变,这样让调度器进行调度,虽然时间并不确定,但是这个中断确实被及时”处理“了,而且只要系统运行正常,任务A确实在尽可能快地完成工作,同时一定会执行完毕,满足软实时的要求
04 - 总结
- FreeRTOS的中断处理都使用延迟中断机制
- 延迟中断机制的本质是把工作量移到任务里面
- 支撑延迟中断机制需要用到二值信号量和计数信号量
- 延迟中断机制可以实现硬实时和软实时