更改 NVIC 中当前中断的优先级
Changing priority of current interrupt in NVIC
我有一个难题。我正在使用的部件(NXP KL27、Cortex-M0+)在其 I2C 外设中有一个勘误表,因此在接收期间没有流量控制。因此,它需要是一个高优先级中断。我还使用了一个 UART,由于其异步性质,其接收没有流量控制。因此,它需要是一个高优先级的中断。
循环优先
I2C 中断需要比 UART 中断具有更高的优先级,否则传入字节在读取之前可能会在移位寄存器中被删除。它确实不应该以这种方式工作,但这是勘误表,因此它需要更高的优先级。
UART 中断需要比 I2C 中断具有更高的优先级,因为要关闭 I2C 事务,驱动程序(来自 NXP 的 KSDK)需要设置标志并等待状态位。在此等待期间,UART 上的传入字符可能会溢出非 FIFO 移位寄存器。
在尝试解决 UART 问题时,我发现了这种循环依赖。最初的问题是字符从 UART 接收中消失,并且设置了溢出标志。交换优先级时,UART 坚如磐石,从不漏掉一个字符,但 I2C 事务最终因超限而停滞。
可能的解决方案
我提出的解决方案涉及动态更改中断优先级。当 I2C 驱动程序关闭事务时,它不会接收,这意味着导致字节不受控制地流入的勘误不是问题。我想在此期间降低 NVIC 中的 I2C 中断优先级,以便 UART 能够优先于它,从而使 UART 满意(并且不会丢失任何字符)。
问题
我无法从 ARM 中找到任何说明在执行中断时更改中断优先级是否会立即生效,或者当前中断的优先级是否在开始执行时被锁存的信息。我希望有人可以根据他们对架构的深入了解或经验来确定更改优先级是否会立即生效。
其他可能的解决方案
还有许多其他可能的解决方案以及它们不受欢迎的原因。重构 I2C 驱动程序以处理进程上下文中的循环而不是中断上下文将是深入挖掘供应商代码并影响调用它的应用程序代码的一项重大工作。对这些外设中的任何一个使用 DMA 都会占用大量可用的 DMA 通道,并导致为每个事务设置 DMA 的开销(并且还会影响调用驱动程序的应用程序代码)。
我对其他解决方案持开放态度,但犹豫是否要走任何导致供应商代码发生重大变化的道路。
测试
我有一个想法来测试 NVIC 在这方面的工作原理,但我想我会先在这里检查一下。如果我进行实验,我将 post 对结果进行后续回答。
在架构上,这似乎是不可预测的(更改当前活动异常的优先级)。似乎没有适当的逻辑来强制执行更一致的行为(即您关心的注册逻辑显然不存在于 M0/M0+ 中)。
这意味着,如果您测试变通办法的有效性,它可能会起作用 - 并且在您的受限场景中它可能有效。但是,不能保证相同的代码可以在 M3 上运行,或者它在所有场景中都能可靠地运行(例如与调试的任何交互)。您甚至可能会观察到一些完全不可预测的极端情况行为,但区域受限
这在 ARM v6-M ARM 的 B1.5.4 节中指定为不可预测。
对于 v7-M(B1.5.4,异常优先级和抢占)
This definition of execution priority means that an exception handler
can be executing at a priority that is higher than the priority of the
corresponding exception. In particular, if a handler reduces the
priority of its corresponding exception, the execution priority falls
only to the priority of the highest-priority preempted exception.
Therefore, reducing the priority of the current exception never
permits:
A preempted exception to preempt the current exception handler.
Inversion of the priority of preempted exceptions.
v7-M 方面阐明了一些复杂的场景,如果您尝试使用您已确定对 M0+ 部分有用的不可预测的行为,则必须避免这些场景。
实验
我今天编写了一个快速实验,以在我的 Cortex M0+ 特定变体上测试此行为。我将其保留为未被接受的答案,我相信@Sean Houlihane 的答案是最正确的(即它是不可预测的)。我仍然想测试行为并在我使用它的特定情况下报告。
实验是在一块FRDM-KL43Z板上进行的。它有一个红色 LED、一个绿色 LED 和两个按钮。应用程序执行了 GPIO 和中断的一些设置,然后陷入无限循环。
按钮 1:按钮 1 的中断处理程序已初始化为中等优先级 (0x80)。在按钮 1 的每个下降沿,它都会挂起中断。此中断将切换绿色 LED 的状态。
按钮 2:按钮 2 的中断处理程序已初始化为中等优先级 (0x80),但会在执行过程中更改。按钮 2 中断处理程序将 运行 一个持续大约 8 秒的循环(两个阶段,每四个阶段),无限期地重复。它会打开红色 LED 并将其自身的优先级降低到按钮 1 的优先级以下。四秒后,它将关闭红色 LED 并将其自身的优先级增加到按钮 1 的优先级之上。四秒后它将重复。
预期结果
如果假设成立,当红色LED亮起时,按下按钮1将切换绿色LED,当红色LED熄灭时,按下按钮1将无效,直到红色LED熄灭.在永远循环的按钮 2 中断具有较低优先级之前,按钮 1 中断不会执行。
结果
这是无聊的部分。我在上一节中预期的一切都发生了。
结论
对于实验设置(NXP KL43Z Cortex M0+),更改当前正在执行的中断的中断优先级在中断运行ning时生效。因此,我在繁忙等待期间降低优先级并在之后恢复它的棘手解决方法应该可以满足我的需要。
编辑:
后来的结果
虽然实验成功,但在实施针对原始问题的解决方法后,问题开始出现。 UART 和 I2C 处理程序之间的交互相对一致,但第三个外设在其中断处理程序中开始出现非常奇怪的行为。注意UNPREDICTABLE的警告。
一个替代解决方案可能是将处理的后半部分推迟到另一个优先级较低的中断。一个很好的候选者是 PendSV 中断(如果尚未使用),它可以(仅)由软件触发。
更详细的解释,参见 to a similar question and this answer关于PendSV的一般介绍。
我有一个难题。我正在使用的部件(NXP KL27、Cortex-M0+)在其 I2C 外设中有一个勘误表,因此在接收期间没有流量控制。因此,它需要是一个高优先级中断。我还使用了一个 UART,由于其异步性质,其接收没有流量控制。因此,它需要是一个高优先级的中断。
循环优先
I2C 中断需要比 UART 中断具有更高的优先级,否则传入字节在读取之前可能会在移位寄存器中被删除。它确实不应该以这种方式工作,但这是勘误表,因此它需要更高的优先级。
UART 中断需要比 I2C 中断具有更高的优先级,因为要关闭 I2C 事务,驱动程序(来自 NXP 的 KSDK)需要设置标志并等待状态位。在此等待期间,UART 上的传入字符可能会溢出非 FIFO 移位寄存器。
在尝试解决 UART 问题时,我发现了这种循环依赖。最初的问题是字符从 UART 接收中消失,并且设置了溢出标志。交换优先级时,UART 坚如磐石,从不漏掉一个字符,但 I2C 事务最终因超限而停滞。
可能的解决方案
我提出的解决方案涉及动态更改中断优先级。当 I2C 驱动程序关闭事务时,它不会接收,这意味着导致字节不受控制地流入的勘误不是问题。我想在此期间降低 NVIC 中的 I2C 中断优先级,以便 UART 能够优先于它,从而使 UART 满意(并且不会丢失任何字符)。
问题
我无法从 ARM 中找到任何说明在执行中断时更改中断优先级是否会立即生效,或者当前中断的优先级是否在开始执行时被锁存的信息。我希望有人可以根据他们对架构的深入了解或经验来确定更改优先级是否会立即生效。
其他可能的解决方案
还有许多其他可能的解决方案以及它们不受欢迎的原因。重构 I2C 驱动程序以处理进程上下文中的循环而不是中断上下文将是深入挖掘供应商代码并影响调用它的应用程序代码的一项重大工作。对这些外设中的任何一个使用 DMA 都会占用大量可用的 DMA 通道,并导致为每个事务设置 DMA 的开销(并且还会影响调用驱动程序的应用程序代码)。
我对其他解决方案持开放态度,但犹豫是否要走任何导致供应商代码发生重大变化的道路。
测试
我有一个想法来测试 NVIC 在这方面的工作原理,但我想我会先在这里检查一下。如果我进行实验,我将 post 对结果进行后续回答。
在架构上,这似乎是不可预测的(更改当前活动异常的优先级)。似乎没有适当的逻辑来强制执行更一致的行为(即您关心的注册逻辑显然不存在于 M0/M0+ 中)。
这意味着,如果您测试变通办法的有效性,它可能会起作用 - 并且在您的受限场景中它可能有效。但是,不能保证相同的代码可以在 M3 上运行,或者它在所有场景中都能可靠地运行(例如与调试的任何交互)。您甚至可能会观察到一些完全不可预测的极端情况行为,但区域受限
这在 ARM v6-M ARM 的 B1.5.4 节中指定为不可预测。
对于 v7-M(B1.5.4,异常优先级和抢占)
This definition of execution priority means that an exception handler can be executing at a priority that is higher than the priority of the corresponding exception. In particular, if a handler reduces the priority of its corresponding exception, the execution priority falls only to the priority of the highest-priority preempted exception. Therefore, reducing the priority of the current exception never permits:
A preempted exception to preempt the current exception handler.
Inversion of the priority of preempted exceptions.
v7-M 方面阐明了一些复杂的场景,如果您尝试使用您已确定对 M0+ 部分有用的不可预测的行为,则必须避免这些场景。
实验
我今天编写了一个快速实验,以在我的 Cortex M0+ 特定变体上测试此行为。我将其保留为未被接受的答案,我相信@Sean Houlihane 的答案是最正确的(即它是不可预测的)。我仍然想测试行为并在我使用它的特定情况下报告。
实验是在一块FRDM-KL43Z板上进行的。它有一个红色 LED、一个绿色 LED 和两个按钮。应用程序执行了 GPIO 和中断的一些设置,然后陷入无限循环。
按钮 1:按钮 1 的中断处理程序已初始化为中等优先级 (0x80)。在按钮 1 的每个下降沿,它都会挂起中断。此中断将切换绿色 LED 的状态。
按钮 2:按钮 2 的中断处理程序已初始化为中等优先级 (0x80),但会在执行过程中更改。按钮 2 中断处理程序将 运行 一个持续大约 8 秒的循环(两个阶段,每四个阶段),无限期地重复。它会打开红色 LED 并将其自身的优先级降低到按钮 1 的优先级以下。四秒后,它将关闭红色 LED 并将其自身的优先级增加到按钮 1 的优先级之上。四秒后它将重复。
预期结果
如果假设成立,当红色LED亮起时,按下按钮1将切换绿色LED,当红色LED熄灭时,按下按钮1将无效,直到红色LED熄灭.在永远循环的按钮 2 中断具有较低优先级之前,按钮 1 中断不会执行。
结果
这是无聊的部分。我在上一节中预期的一切都发生了。
结论
对于实验设置(NXP KL43Z Cortex M0+),更改当前正在执行的中断的中断优先级在中断运行ning时生效。因此,我在繁忙等待期间降低优先级并在之后恢复它的棘手解决方法应该可以满足我的需要。
编辑: 后来的结果
虽然实验成功,但在实施针对原始问题的解决方法后,问题开始出现。 UART 和 I2C 处理程序之间的交互相对一致,但第三个外设在其中断处理程序中开始出现非常奇怪的行为。注意UNPREDICTABLE的警告。
一个替代解决方案可能是将处理的后半部分推迟到另一个优先级较低的中断。一个很好的候选者是 PendSV 中断(如果尚未使用),它可以(仅)由软件触发。
更详细的解释,参见