我有一些代码需要在特定中断结束时运行。
我不想在中断本身的上下文中执行它,但我也不希望它在线程模式下执行。
我希望以低于高级别中断的优先级运行它,这会优先于线程级别(以及其他一些中断)。
我想我需要使用其他一个中断处理程序。
最好使用哪些以及调用它们的最佳方法是什么?
目前我正在计划只使用中断处理程序来处理一些我没有使用的外设,并通过直接通过NVIC设置位来调用它们,但我希望有更好的,更官方的方式。
谢谢,
答案 0 :(得分:15)
ARM Cortex支持一种非常特殊的异常,称为PendSV。您似乎可以完全使用此异常来完成您的工作。实际上,ARM Cortex的所有抢占式RTOS都使用PendSV来实现上下文切换。
要使其工作,您需要优先考虑PendSV为低电平(将0xFF写入NVIC中的PRI_14寄存器)。您还应该优先考虑PendSV之上的所有IRQ(在NVIC的相应优先级寄存器中写入较低的数字)。当您准备好处理整个消息时,从高优先级ISR触发PendSV:
*((uint32_t volatile *)0xE000ED04) = 0x10000000; // trigger PendSV
然后,ARM Cortex CPU将完成您的ISR以及可能被其抢占的所有其他ISR,并最终将尾随链接到PendSV异常。这是解析消息的代码所在的位置。
请注意,PendSV可能被其他ISR抢占。这一切都很好,但显然需要记住通过关键代码段保护所有共享资源(简单地禁用和启用中断)。在ARM Cortex中,通过执行__asm(“cpsid i”)禁用中断,并通过__asm(“cpsie i”)启用中断。 (大多数C编译器为此提供内置的内部函数或宏。)
答案 1 :(得分:3)
您使用的是RTOS吗?通常,这种类型的事物将通过具有高优先级线程来处理,该线程通过中断来发信号通知。
如果您没有使用RTOS,那么您只需执行一些任务,并且中断启动的工作不会占用太多资源,可能最简单的方法就是在上下文中完成高优先级的工作。中断处理程序如果这些条件不成立,那么实现你所说的将是基本的多任务操作系统本身的开始。这本身就是一个有趣的项目,但是如果你想完成工作,你可能想要考虑一个简单的RTOS。
由于您提到了有关您正在进行的工作的一些细节,因此以下概述了我过去如何处理类似问题:
为了通过UART处理接收到的数据,我在处理一个没有完全支持任务的简单系统时使用了一种方法(即,任务是循环的,我很简单while
loop)是为从UART接收的数据建立共享队列。当UART中断触发时,数据从UART的RDR(接收数据寄存器)读取并放入队列中。以队列指针未被破坏的方式处理这个问题的技巧是小心地使队列指针易变,并确保只有中断处理程序修改尾指针,并且只有“前台”任务才能读取数据关闭队列修改了头部指针。高级概述:
producer(UART中断处理程序):
queue.head
和queue.tail
读入当地人; queue.tail
指针)。如果你已经超过队列缓冲区的末尾,则将其包装到队列缓冲区的开头。local.tail
和local.head
- 如果它们相等,则队列已满,您将不得不做任何适当的错误处理。local.tail
点消费者(前景'任务')
queue.head
和queue.tail
读入当地人; local.head
== local.tail
队列为空;返回让下一个任务做一些工作local.head
local.head
并在必要时包装; queue.head
= local.head
确保queue.head
和queue.tail
为volatile
(或在汇编中写入这些位)以确保没有排序问题。
现在只需确保您的UART接收数据队列足够大,它将保留在前台任务有机会运行之前可以接收的所有字节。前台任务需要将队列中的数据拉入其自己的缓冲区,以构建消息以提供给“消息处理器”任务。
答案 2 :(得分:1)
“更正式的方式”或更常规的方法是使用基于优先级的抢先式多任务调度程序和“延迟中断处理程序”模式。
答案 3 :(得分:1)
您要求的内容在Cortex-M3上非常简单。您需要启用STIR寄存器,以便可以使用软件触发低优先级ISR。当高优先级ISR完成关键任务时,它只会触发低优先级中断并退出。如果没有更重要的事情发生,那么NVIC将尾部链接到低优先级处理程序。
答案 4 :(得分:0)
检查处理器文档。如果您写入通常必须在中断内清除的位,某些处理器将会中断。我目前正在使用SiLabs c8051F344和规格表第9.3.1节:
“软件可以通过将任何中断标志设置为逻辑1来模拟中断。如果标志使能了中断,将产生中断请求,CPU将转向与中断标志相关的ISR地址。“