下载 FreeRTOS
 

出色的 RTOS & 嵌入式软件

内核
最新资讯
简化任何设备的身份验证云连接。
利用 CoAP 设计节能型云连接 IoT 解决方案。
11.0.0 版 FreeRTOS 内核简介:
FreeRTOS 路线图和代码贡献流程。
使用 FreeRTOS 实现 OPC-UA over TSN。

在 ARM Cortex-M Core 上运行 RTOS

[另请参阅调试 Cortex 硬故障异常]。


注意: 此页面上有关中断嵌套的信息适用于 使用 Cortex-M3、Cortex-M4、Cortex-M4F、Cortex-M7、Cortex-M33 和 Cortex-M23 时, 不适用于 Cortex-M23 与不包含 BASEPRI 寄存器的 Cortex-M0 或 Cortex-M0+ 核心。


简介

数以千计的应用程序在 ARM Cortex-M 核心上运行 FreeRTOS。 但很少有用户 针对 RTOS 和 ARM Cortex CPU 核心这一组合请求技术支持。 大多数出现的问题 都是中断优先级设置不正确 导致的。 这可能是意料之中的, 因为尽管 ARM Cortex-M 核心使用的中断模型非常强大, 但对于那些习惯了常规中断优先级方案的工程师来说,这种模型有些笨拙和 有悖直觉。 本页旨在描述 ARM Cortex-M 的中断优先级机制,以及如何 与 RTOS 内核一起使用。

请记住,虽然 ARM Cortex-M3 核心强加的优先级方案似乎比较复杂, 但是每个官方 FreeRTOS 移植都配有一个正确配置的演示应用程序, 可作为参考。 此外, FreeRTOS V7.5.0 还引入了 额外的 configASSERT() 调用,专门用于捕获配置错误的 ARM Cortex-M 中断控制器 (NVIC)。 在开发时,请您务必对 configASSERT() 进行定义。


可用的优先级

Cortex-M 硬件详情

首先要知道的是,可用优先级的总数是 由实现定义的,换言之,是由使用 ARM Cortex-M 核心的微控制器制造商 所定义的。 因此, 并非所有 ARM Cortex-M 微控制器都提供相同数量的唯一 中断优先级。

ARM Cortex-M 架构自身允许最多 256 个不同的优先级(最多有 8 个 优先级位,因此从 0 到 0xff 的优先级都是可能的),但绝大多数使用 ARM Cortex-M 核心的微控制器 仅允许使用其中一部分。 例如, TI Stellaris Cortex-M3 和 ARM Cortex-M4 微控制器实现 3 个优先级位, 提供 了 8 个唯一的优先级值。 另一个例子是,NXP LPC17xx ARM Cortex-M3 微控制器 实现 5 个优先位, 提供了 32 个唯一的优先级值。

如果您的项目包含 CMSIS 库头文件,请检查 __NVIC_PRIO_BITS 定义 来查看可用的优先级位数。

使用 RTOS 时的相关性

RTOS 的中断嵌套方案将可用的中断优先级分为 两组:一组将被 RTOS 临界区屏蔽,另一组 永远不会被 RTOS 临界区屏蔽,因此始终处于启用状态。 两个组之间的边界由 FreeRTOSConfig.h 中的 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置 定义。 此设置的最佳值将取决于 微控制器中实现的优先级位数量。


抢占优先级和子优先级

Cortex-M 硬件详情

8 位优先级寄存器分为两个部分:抢占优先级和 子优先级。 分配给每个部分的位数是可配置的。 抢占优先级 定义了一个中断是否可以抢占另一个正在执行的 中断。 当两个抢占优先级相同的中断同时发生时, 子优先级决定首先执行哪个中断。

使用 RTOS 时的相关性

建议将所有优先级位都指定为抢占优先级位, 不保留任何优先级位作为子优先级位。 任何其他配置都会 使 configMAX_SYSCALL_interrupt_PRIORITY 设置与 分配给各个外设中断之间的直接关系复杂化。

大多数系统的默认配置都是所需要的, STM32 驱动器库除外。 如果您使用 STM32 和 STM32 驱动器库, 请通过 调用 NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ) 来确保所有优先级位都被指定为抢占优先级位,这一步需要 在启动 RTOS 前完成。


数值优先级值与逻辑优先级设置之间的反转关系

Cortex-M 硬件详情

还要知道,在 ARM Cortex-M 核心中,优先级的数值越小, 则中断的逻辑优先级越高。 例如,一个 数值优先级被分配为 2 的中断的逻辑优先级高于一个 数值优先级被分配为 5 的中断。 换句话说,优先级为 2 的中断的优先级高于 优先级为 5 的中断,虽然数字 2 比数字 5 要小。 为了更清楚地 说明这一点: 一个数值优先级为 2 的中断可以中断(嵌套) 一个数值优先级为 5 的中断;但数值优先级为 5 的中断不能 中断数值优先级为 2 的中断。

这是 ARM Cortex-M 中断优先级机制中最有悖直觉之处, 因为这与大多数未使用 ARM Cortex-M3 的微控制器架构相反。

使用 RTOS 时的相关性

以 "FromISR" 结尾的 FreeRTOS 函数是中断安全的,但前提是 调用这些函数的中断的逻辑优先级不高于 configMAX_SYSCALL_INTERRUPT_PRIORITY 定义的优先级(configMAX_SYSCALL_INTERRUPT_PRIORITY 在 FreeRTOSConfig.h 头文件中定义)。 因此,对于任何使用一个 RTOS API 函数的中断服务程序, 必须为其手动设置为一个数值优先级, 这个值必须等于或大于 configMAX_SYSCALL_INTERRUPT_PRIORITY 设定 的值。 这确保了中断的逻辑优先级等于或小于 configMAX_SYSCALL_INTRUPT_PRIORITY 设置。

Cortex-M 中断的默认数值优先级为 0。 0 是最高的 优先级。 因此,切勿将使用中断安全 RTOS API 的中断的优先级 保留为其默认值


Cortex-M 内部优先级表示

Cortex-M 硬件详情

ARM Cortex-M 核心将中断优先级值存储在 其 8 位中断优先级寄存器的最高有效位中。 例如,如果 一个 ARM Cortex-M 微控制器仅实现 3 个优先位, 那么这 3 个位分别向上移位为位 5、6 和 7。 位 0 到 位 4 可以取任何值,但为了将来的验证和最大兼容性,应将它们 设置为 1。

ARM Cortex-M 内部表示如下图所示。


Cortex-M 中断优先级寄存器显示实现的位
Cortex-M 优先级寄存器的空间最多可容纳 8 个优先级位。 例如,如果微控制器仅实现 3 个位,则 使用的是 3 个最高有效位。


将值 5 存储在实现 3 个优先级位的 ARM Cortex-M 核心中

上图展示了值 5(二进制 101)是如何存储在 实现 3 个优先位的微控制器的优先级寄存器中的。 该图演示了为什么当 3 个位移到所需位置而其余位设置为 1 时, 值 5 (二进制 0000 0101)也可以被认为 是 191 (二进制 1011 1111)。


将值 5 存储在实现 4 个优先级位的 ARM Cortex-M 核心中

上图展示了值 5(二进制 101)是如何存储在 实现 4 个优先位的微控制器的优先级寄存器中的。 该图演示了为什么当 4 个位移到所需位置而其余位设置为 1 时, 值 5 (二进制 0000 0101)也可以被认为 是 95 (二进制 0101 1111)。


使用 RTOS 时的相关性

如上所述, 使用 RTOS API 中断服务程序的逻辑优先级需要等于或低于 configMAX_SYSCALL_INTRUPT_PRIORITY 的设置(逻辑优先级越低,则优先级数值 越大)。

CMSIS 和各微控制器制造商提供库函数,可用于 设置中断的优先级。 一些库函数要求 在 8 位字节的最低有效位中指定中断优先级, 也有另一些库函数要求要指定的中断优先级已经 移到了 8 位字节的最高有效位中。 查看被调用函数的文档来确定 您需要的是哪一个。如果这里出了错,会导致 意料之外的行为。

configMAX_SYSCALL_INTERRUPT_PRIORITY 和 configKERNEL_INTERRUPT_PRIORITY 位于 FreeRTOSConfig.h 中,需要按照 ARM Cortex-M 核心的要求 为它们指定优先级值,即将优先级位移到 最高有效位。 这就是 为什么 在每个官方 FreeRTOS 演示配套的 FreeRTOSConfig.h 头文件中,应该具有最低的中断优先级的 configKERNEL_interrupt_PRIORITY 被设置为 255(二进制 1111 1111)。 采用上述方式来指定这些值有许多原因: RTOS 内核直接访问 ARM Cortex-M3 硬件 (无需通过任何第三方库函数),RTOS 内核的实现 早于大多数库函数的实现, 并且最早的 ARM Cortex-M3 库面世时也使用了此方案。


临界区

Cortex-M 硬件详情

RTOS 内核使用 ARM Cortex-M 核心的 BASEPRI 寄存器 来实现临界区。 因此,RTOS 内核能够仅屏蔽一部分中断, 从而提供灵活的中断嵌套模型。

BASEPRI 是一个位掩码。 为 BASEPRI 设置为一个值后,它可以屏蔽所有逻辑优先级等于 或低于该值的中断。 因此,无法使用 BASEPRI 来 屏蔽优先级为 0 的中断。

题外话: 可以从中断中安全调用的 FreeRTOS API 函数 使用 BASEPRI 来实现中断安全临界区。 进入临界区时, BASEPRI 的值设置为 configMAX_SYSCALL_interrupt_PRIORITY, 退出临界区时,设置为 0。 我们收到许多故障报告 认为 BASEPRI 应在退出临界区时返回到原始值,而不仅仅是设置为 0, 但是 Cortex-M NVIC 绝不会接受一个优先级低于当前正在执行的中断的优先级的中断, 不管 BASEPRI 设置为多少。 一个总是 将 BASEPRI 设置为 0 的实现执行代码的速度比一个 存储然后恢复 BASEPRI 值的实现更快 (编译器的优化器打开的情况下)。

使用 RTOS 内核时的相关性

RTOS 内核通过将 configMAX_SYSCALL_INTRUPT_PRIORITY 的值 写入 ARM Cortex-M BASEPRI 寄存器来创建临界区。 因为 BASEPRI 无法屏蔽 优先级为 0 的中断(最高的优先级), 所以不得将 configMAX_SYSCALL_INTERRUPT_PRIORITY 设置为 0。



Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.