FreeRTOS中断管理--概述

概述

嵌入式实时系统必须采取措施以响应源自环境的事件。例如,到达以太网外围设备的数据包(事件)可能需要传递到TCP / IP堆栈进行处理(操作)。非平凡的系统将不得不处理源自多个来源的事件,所有这些事件都将具有不同的处理开销和响应时间要求。在每种情况下,都必须对最佳事件处理实施策略做出判断:

  1. 应该如何检测事件?通常使用中断,但也可以查询输入。
  2. 使用中断时,应在中断服务程序(ISR)内执行多少处理,而在中断服务程序外进行多少处理?通常希望使每个ISR尽可能短。
  3. 如何将事件传达给主代码(非ISR),以及如何将代码结构化以最佳地处理潜在的异步事件?

FreeRTOS没有在应用程序设计器上强加任何特定的事件处理策略,但是提供了允许以简单且可维护的方式实现所选策略的功能。
区分任务的优先级和中断的优先级很重要:

  1. 任务是与运行FreeRTOS的硬件无关的软件功能。任务的优先级由应用程序编写器在软件中分配,并且软件算法(调度程序)确定哪个任务将处于“运行”状态。
  2. 尽管中断服务程序是用软件编写的,但它是一项硬件功能,因为硬件控制着哪个中断服务程序将运行以及何时运行。任务仅在没有ISR运行时运行,因此优先级最低的中断将中断优先级最高的任务,并且任务无法抢占ISR。

FreeRTOS将在其上运行的所有体系结构都能够处理中断,但是与中断进入和中断优先级分配有关的细节在体系结构之间有所不同。

使用ISR的FreeRTOS API

ISR (API)

通常,有必要使用来自中断服务例程(ISR)的FreeRTOS API函数提供的功能,但是许多FreeRTOS API函数执行的操作在ISR内部无效,其中最引人注目的是将调用的API函数任务置于阻塞状态,如果从ISR调用了API函数,则不会从任务中调用它,因此无法将调用的任务至于阻塞状态(blacking)。FreeRTOS通过提供一些两个版本的API函数来解决此问题。一种用于任务的版本,一种用于ISR的版本。用于ISR的功能的名称后附加了“ FromISR”。

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

使用独立的中断安全(ISR)API

具有用于中断的单独的API,可以使任务代码更高效,ISR代码更高效,并且中断输入更简单。要了解原因,请考虑替代解决方案,该解决方案应该是提供每个API函数的单个版本,而该任务可以从任务和ISR中调用。如果可以从任务和ISR调用相同版本的API函数,则:

  1. API函数将需要其他逻辑来确定是从任务还是从ISR调用它们。附加逻辑将通过功能引入新路径,从而使功能更长,更复杂且更难测试。
  2. 从任务或ISR调用函数时,有些API函数参数可能不需要。
  3. 每个FreeRTOS端口都需要提供一种机制来确定执行上下文(任务或ISR)。
  4. 不容易确定执行上下文(任务或ISR)的体系结构将会造成额外的浪费,使用起来更复杂,以及会使得中断入口代码的不标准,这些代码允许由软件提供执行上下文。
使用独立的中断安全(ISR)API的缺点

具有两个版本的某些API函数可以使任务和ISR更加高效,但会带来一个新问题。有时有必要从任务(或ISR)中调用不属于FreeRTOS API(或ISR API)的函数。
通常,这只是集成第三方代码时的问题,因为这是软件设计不受应用程序编写者控制的唯一时间。如果确实成为问题,则可以使用以下一种技术来解决该问题:

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

如果上下文切换是由中断执行的,则中断退出时运行的任务可能与进入中断时正在运行的任务不同 。即:中断从一个任务进入中断,而中断退出后可能运行的是另外一个任务。
一些FreeRTOS API函数可以将任务从“已阻止”状态转移到“就绪”状态。
如:xQueueSendToBack()函数,其功能是如果有一个任务处于“阻塞”状态等待在主题队列上的数据可用,它将取消阻塞任务。
如果是FreeRTOS API函数解除了阻塞状态的任务的优先级高于处于“运行”状态的任务的优先级,则根据FreeRTOS调度策略,应切换到更高优先级的任务。实际切换到更高优先级的任务的时间取决于调用API函数的上下文:
1. 从任务中调用API函数
如果在FreeRTOSConfig.h中将configUSE_PREEMPTION设置为1,则切换到更高优先级的任务会自动在API函数内发生-即:在退出API函数之前。在图 43中已经看到了这一点,其中写入计时器命令队列导致在退出写入命令队列的函数之前切换到RTOS守护程序任务。
2.从中断中调用API函数
在中断内不会自动发生切换到更高优先级的任务。而是设置一个变量来通知应用程序编写者应该执行上下文切换。中断安全API函数(以“ FromISR”结尾的函数)具有一个称为pxHigherPriorityTaskWoken的指针参数,用于此目的。
如果应该执行上下文切换,则将设置中断安全API函数 pxHigherPriorityTask置为pdTRUE。为了能够检测到这种情况,在首次使用之前,必须将pxHigherPriorityTaskWoken指向的变量初始化为pdFALSE。
如果应用程序编写者选择不从ISR请求上下文切换,则优先级较高的任务将保持在“就绪”状态,直到调度程序下一次运行为止(最坏的情况是在下一个滴答中断期间)。
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端口。充其量,这将导致对调度程序的不必要的调用。

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

portYIELD_FROM_ISR()和portEND_SWITCHING_ISR()

taskYIELD()是可以在任务中调用以请求上下文切换的宏。portYIELD_FROM_ISR()和portEND_SWITCHING_ISR()都是taskYIELD()的中断安全版本。portYIELD_FROM_ISR()和portEND_SWITCHING_ISR()都以相同的方式使用,并且执行相同的操作。某些FreeRTOS端口仅提供两个宏中的其中一个。较新的FreeRTOS端口提供了两个宏。
portEND_SWITCHING_ISR宏
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
portYIELD_FROM_ISR宏
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尽可能短。原因包括:

  1. 即使为任务分配了很高的优先级,它们也只会在硬件不处理任何中断的情况下运行。
  2. ISR可能会中断(增加“抖动”)任务的开始时间和执行时间。
  3. 根据运行FreeRTOS的体系结构,在执行ISR时,可能无法接受任何新的中断或至少新中断的子集。
  4. 应用程序编写者需要考虑任务和ISR同时访问的资源(例如变量,外围设备和内存缓冲区)的后果并加以防范。
  5. 一些FreeRTOS端口允许中断嵌套,但是中断嵌套会增加复杂性并降低可预测性。中断时间越短,嵌套的可能性就越小。

中断服务程序必须记录中断原因,并清除中断。中断所需的任何其他处理通常都可以在任务中执行,从而允许中断服务例程尽快退出。这称为“延迟中断处理”,因为中断所需的处理是从ISR“延迟”到任务的。
将中断处理推迟到任务,还允许应用程序编写者相对于应用程序中的其他任务优先处理,并使用所有FreeRTOS API函数。
如果延迟中断处理的任务的优先级高于任何其他任务的优先级,则将立即执行该处理,就像该处理已在ISR本身中执行一样。如下图中显示了这种情况,其中任务1是正常的应用程序任务,任务2是将中断处理推迟到的任务。

在这里插入图片描述在上图中,中断处理在时间t2开始,并在时间t4结束之前有效,但是在ISR中仅花费了时间t2和t3之间的时间。如果未使用延迟的中断处理,则时间t2和t4之间的整个时间段将用在ISR中。
对于何时是最佳执行ISR中的中断所必需的所有处理,以及何时最佳地将部分处理推迟到任务,没有绝对的规则。在以下情况下,将处理推迟到任务中最有用:

  1. 中断所需的处理并非易事。例如,如果中断只是存储模数转换的结果,则几乎可以肯定,这最好在ISR内部执行,但是如果转换结果也必须通过软件过滤器传递,则可能是最好在任务中执行过滤器。
  2. 对于中断处理而言,可以很方便的执行在ISR内部无法执行的操作(如写入控制台或分配内存)。
  3. 中断处理不是确定性的,这意味着事先不知道处理将花费多长时间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值