在中断中禁用中断是一种很好的嵌入式编程实践吗?

Is it a good embedded programming practice to disable an interrupt in an interrupt?

我想在 ARM Cortex-M3 处理器(带有 NVIC)中实现一些东西。我对嵌入式系统的了解有限,但我知道,ISR 例程应该尽可能简单。

现在我遇到了以下问题:我有一个中断例程,它在收到 CAN 消息时调用。在一种情况下,我必须使用 CAN 消息计算一些耗时的任务,该任务不能被另一个 CAN 消息中断,但在此操作期间可以处理其他中断。我的想法如下:

  1. 收到CAN消息,ISR开始,做一些简单的工作(例如设置标志)
  2. 在 CAN ISR 例程中禁用 CAN 中断。还将 CAN 消息保存到全局变量中,以便在主循环中可以访问它。
  3. 在主循环中,执行耗时任务。
  4. 完成此任务后,再次启用 CAN 中断处理。

这是一个好(或不完全坏)的主意还是我应该换一种方式来做?

an ISR routine should be as simple as possible.

完全正确。

有一个 Linux 内核概念称为 下半部分 。即尽可能保持 ISR 简单。其余的中断处理操作推迟到以后。

有很多方法可以实现下半部分,例如 task-let、work-queues 等

建议阅读以下链接
http://www.makelinux.net/ldd3/chp-10-sect-4
http://www.ibm.com/developerworks/library/l-tasklets/

长时间禁用中断可能会导致中断丢失(显然会丢失一些数据)。设置中断标志后,创建一个延迟工作并从中断上下文中出来。

禁用所有 (CAN) 中断通常不是一个好主意。似乎您想要保护自己免受第二次到达的相同消息的影响,在您完成第一次服务之前。

在那种情况下,您应该利用 ISR 本身 non-interruptable。您可以使用 bool 变量创建一个简单的信号量,并且由于设置它的中断是 non-interruptable,您甚至不必担心对该布尔值的原子访问。 C-like pseudo-code 罐头处理程序:

typedef struct
{
  bool busy;
  can_msg_t msg;
} special_msg_t;

// must be volatile, to prevent optimizer-related bugs:
volatile static special_msg_t special = { false, {0} };

interrupt void can_isr (void)
{
  // non-interruptable ISR, no other interrupt can fire

  if(id==SPECIAL && !special.busy)
  {
    special.busy = true;
    // right here you can open up for more interrupts if you want
    memcpy(&special.msg, &new_msg, size);
  }
}

result_t do_things_with_special (void) // called from main loop
{
  if(!special.busy) 
    return error; // no new message received, no can do

  // do things with the message

  special.busy = false; // flag that processing is done
  return ok;
}