FreeRTOS的中断管理

事件

嵌入式实时系统必须对源自环境的事件采取行动。例如,到达以太网外围设备的数据包(事件)可能需要传递到TCP/IP堆栈进行处理(动作)。非普通系统必须为来自多个来源的事件提供服务,所有这些事件都有不同的处理开销和响应时间要求。在每种情况下,都必须判断最佳的事件处理实施策略:
1.应该如何检测事件?通常使用中断,但也可以轮询输入。
2.使用中断时,应在中断服务例程(ISR)内部执行多少处理,在外部执行多少处理?通常希望每个ISR尽可能短。
3.事件如何传达给主(非ISR)代码,以及如何构建此代码以最好地适应潜在异步事件的处理?

FreeRTOS不会对应用程序设计器强加任何特定的事件处理策略,但确实提供了允许以简单和可维护的方式实现所选策略的功能。

区分任务的优先级和中断的优先级非常重要:
 任务是一种与运行FreeRTOS的硬件无关的软件功能。任务的优先级由应用程序编写者在软件中分配,软件算法(调度器)决定哪个任务将处于运行状态。
 虽然是用软件编写的,但中断服务例程是一种硬件功能,因为硬件控制着哪个中断服务例程将运行,以及何时运行。
任务仅在没有ISR运行时运行,因此最低优先级的中断将中断最高优先级的任务,任务无法抢先ISR。
FreeRTOS运行的所有架构都能够处理中断,但与中断输入和中断优先级分配相关的细节因架构而异。

从ISR中使用FreeRTOS API

中断安全API

通常需要使用中断服务例程(ISR)中的FreeRTOS API函数提供的功能,但许多FreeRTOS API函数执行的操作在ISR内部无效,其中最值得注意的是将调用API函数的任务置于阻塞状态;如果API函数是从ISR调用的,那么它不是从任务调用的,因此没有可以置于阻塞状态的调用任务。FreeRTOS通过提供一些API函数的两个版本来解决这个问题;一个版本供任务使用,一个版本由ISR使用。用于ISR的函数名称后附了“FromISR”。

注意:切勿从ISR调用名称中没有“FromISR”的FreeRTOS API函数。

使用独立中断安全API的好处

在中断中使用单独的API可以提高任务代码的效率,提高ISR代码的效率并简化中断条目。要了解原因,请考虑另一种解决方案,即提供每个API函数的单一版本,这些函数可以从任务和ISR中调用。如果可以从任务和ISR调用相同版本的API函数,则:

API函数将需要额外的逻辑来确定它们是从任务还是从ISR调用的。额外的逻辑将通过函数引入新的路径,使函数更长、更复杂、更难测试。
 当从任务调用函数时,某些API函数参数将过时,而当从ISR调用函数时其他参数将过时。
 每个FreeRTOS端口都需要提供一种确定执行上下文(任务或ISR)的机制。
 不容易确定执行上下文(任务或ISR)的架构将需要额外的、浪费的、更复杂的使用和非标准的中断条目代码,这些代码允许软件提供执行上下文。

使用独立中断安全API的缺点

拥有两个版本的某些API函数可以提高任务和ISR的效率,但会带来新的问题;有时需要从任务和ISR调用一个不属于FreeRTOS API的函数,但使用FreeRTOS API。
这通常只在集成第三方代码时出现问题,因为这是软件设计不受应用程序编写者控制的唯一一次。如果这确实成为一个问题,那么可以使用以下技术之一来克服这个问题:

1.将中断处理推迟到任务1,因此API函数仅从任务的上下文中调用。
2.如果您使用的是支持中断嵌套的FreeRTOS端口,请使用以“FromISR”结尾的API函数版本,因为该版本可以从任务和ISR调用(相反,不以“FromISR”结尾的API函数不能从ISR调用)。
3.第三方代码通常包括RTOS抽象层,可以实现该层来测试调用函数的上下文(任务或中断),然后调用适合于该上下文的API函数。

xHigherPriorityTaskWoken 参数

本节介绍xHigherPriorityTaskWoken参数的概念。
如果上下文切换是由中断执行的,那么在中断退出时运行的任务可能与在中断进入时正在运行的任务不同——中断将中断一个任务,但返回到另一个任务。
某些FreeRTOS API函数可以将任务从阻止状态移动到就绪状态。
在xQueueSendToBack()等函数中已经看到了这一点,如果有任务处于“已阻塞”状态等待主题队列上的数据可用,则该函数将取消阻塞任务。

如果被FreeRTOS API函数解除阻止的任务的优先级高于处于运行状态的任务的优先权,则根据FreeRTOS调度策略,应该切换到优先级更高的任务。实际切换到更高优先级任务的时间取决于调用API函数的上下文:

如果API函数是从任务调用的
如果在FreeRTOSConfig.h中将configUSE_PREEMPTION设置为1,则在API函数退出之前,在API函数-so内自动切换到更高优先级的任务。

如果API函数是从中断调用的
在中断期间,不会自动切换到更高优先级的任务。相反,设置一个变量来通知应用程序编写者应该执行上下文切换。
中断安全API函数(以“FromISR”结尾的函数)有一个名为pxHigherPriorityTaskWoken的指针参数,用于此目的。

如果要执行上下文切换,那么中断安全API函数会将*pxHigherPriorityTaskWoken设置为pdTRUE。为了能够检测到这种情况的发生,pxHigherPriorityTaskWoken指向的变量在首次使用之前必须初始化为pdFALSE。

如果应用程序编写器选择不向ISR请求上下文切换,则较高优先级的任务将保持在就绪状态,直到下一次调度器运行为止——在最坏的情况下,这将是在下一个滴答tick期间。

FreeRTOS API函数只能将*pxHighPriorityTaskWoken设置为pdTRUE。如果一个ISR调用多个FreeRTOS API函数,那么在每个API函数调用中都可以传递相同的变量作为pxHigherPriorityTaskWoken参数,并且该变量只需要在首次使用之前初始化为pdFALSE。

在API函数的中断安全版本中,上下文切换不会自动发生,原因如下:
1.避免不必要的上下文切换
在任务需要执行任何处理之前,中断可能会执行多次。例如,考虑一个场景,其中任务处理由中断驱动的UART接收的字符串;UART ISR在每次接收到字符时切换到任务是浪费的,因为任务只有在接收到完整字符串后才能执行处理。

2.执行顺序的控制
中断可能偶尔发生,并且发生在不可预测的时间。FreeRTOS专家用户可能希望暂时避免在应用程序的特定点意外切换到不同的任务,尽管这也可以通过使用FreeRTOS调度器锁定机制来实现

3.便携性
这是可以在所有FreeRTOS端口上使用的最简单的机制。

4.效率
针对较小处理器架构的端口只允许在ISR的最后请求上下文切换,而消除这一限制将需要额外的、更复杂的代码。它还允许在同一个ISR内对FreeRTOS API函数进行多个调用,而不会在同一ISR内生成多个上下文切换请求。

5.RTOS滴答中断中的执行
可以将应用程序代码添加到RTOS滴答中断中。在滴答中断内尝试上下文切换的结果取决于使用的FreeRTOS端口。充其量,这将导致对调度器的不必要调用。

pxHigherPriorityTaskWoken参数的使用是可选的。如果不需要,则将pxHigherPriorityTaskWoken设置为NULL。

portYIELD_FROM_ISR()和portEND_SWITCHING_ISR()宏

本节介绍用于从ISR请求上下文切换的宏。

taskYIELD()是一个宏,可以在任务中调用它来请求上下文切换。
portYIELD_FROM_ISR()和portEND_SWITCHING_ISR()都是taskYIELD()的中断安全版本。portYIELD_FROM_ISR()和portEND_SWITCHING_ISR()的使用方式和作用都是一样的。一些FreeRTOS端口只提供这两个宏中的一个。较新的FreeRTOS端口提供这两个宏。本文中的示例使用portYIELD_FROM_ISR()。

portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

中断安全API函数传递的xHigherPriorityTaskWoken参数可以直接用作portYIELD_FROM_ISR()调用中的参数。
如果portYIELD_FROM_ISR()xHigherPriorityTaskWoken参数为pdFALSE(零),则不会请求上下文切换,宏也不会生效。如果portYIELD_FROM_ISR()xHigherPriorityTaskWoken参数不是pdFALSE,则请求上下文切换,处于运行状态的任务可能会发生变化。即使在执行中断时处于运行状态的任务发生了变化,中断也将始终返回到处于运行状态中的任务。

大多数FreeRTOS端口允许在ISR内的任何地方调用portYIELD_FROM_ISR()。一些FreeRTOS端口(主要是用于较小架构的端口)只允许在ISR的最后调用portYIELD_FROM_ISR()。

推迟中断处理

通常认为,保持ISR尽可能短是最佳做法。原因包括:
 即使任务被分配了很高的优先级,它们也只会在硬件没有中断的情况下运行。
 ISR会中断(增加“抖动”)任务的开始时间和执行时间。
 根据FreeRTOS运行的架构,在ISR执行时,可能无法接受任何新的中断,或者至少是新中断的子集。
 应用程序编写者需要考虑任务和ISR同时访问变量、外围设备和内存缓冲区等资源的后果,并加以防范。
 一些FreeRTOS端口允许中断嵌套,但中断嵌套会增加复杂性并降低可预测性。中断时间越短,嵌套的可能性就越小。

中断服务程序必须记录中断的原因,并清除中断。
中断所需的任何其他处理通常都可以在任务中执行,从而允许中断服务例程尽可能快地退出。这被称为“延迟中断处理”,因为中断所需的处理从ISR“延迟”到任务。

将中断处理延迟到任务还允许应用程序编写器相对于应用程序中的其他任务对处理进行优先级排序,并使用所有FreeRTOS API函数。

如果延迟中断处理的任务的优先级高于任何其他任务的优先级,则处理将立即执行,就像处理是在ISR本身中执行的一样。此场景如图48所示,其中任务1是一个正常的应用程序任务,任务2是中断处理被推迟的任务。

在这里插入图片描述
在图48中,中断处理从时间t2开始,实际上在时间t4结束,但ISR中只花费了时间t2和t3之间的时间段。如果没有使用延迟中断处理,那么时间t2和t4之间的整个时间段都将用于ISR。
对于何时最好执行ISR中断所需的所有处理,以及何时最好将部分处理推迟到任务,没有

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值