Cortex M0 +(SAMD21)未执行待处理中断

时间:2016-06-22 04:47:56

标签: assembly arduino embedded cortex-m isr

当我尝试将微控制器置于休眠状态然后将其唤醒时,我发现了这个问题,这是一个中断驱动的应用程序。我注意到我的代码没有从我的“睡眠”之后的代码行中恢复。指令。

当我在使用调试器单步执行代码时手动触发中断时,它会在跳转到ISR之前需要多个步骤(有时为2,有时为50,具体取决于代码)。

在尝试调试此问题时,我编写了一段非常简单的代码来展示问题:

#include <Arduino.h>
// Setup and Loop declared in Arduino core
void configInterrupt(void);
volatile uint32_t debug = 0;
uint32_t int_count = 0;

void EIC_Handler(void){
  int_count++;
  EIC->INTFLAG.reg = 1 << 0;
}

void configInterrupt(void){
  NVIC_DisableIRQ(EIC_IRQn);
  NVIC_ClearPendingIRQ(EIC_IRQn);
  NVIC_SetPriority(EIC_IRQn, 0);
  NVIC_EnableIRQ(EIC_IRQn);
  GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC));
  EIC->WAKEUP.reg |= (1 << 0);
  EIC->CONFIG[0].reg |= 0x2;                    // falling edge
  pinConfig(16,INPUT,UP);                   // pin 16 as input with pullup 
  PORT->Group[0].PINCFG[16].bit.PMUXEN = 1; // enable peripheral muxing
  PORT->Group[0].PMUX[8].bit.PMUXE = 0x0;       // function A (EIC) = 0x0
  EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << 0);
  EIC->CTRL.bit.ENABLE = 1;
}

void setup() {
  configInterrupt();                            
}

void loop() {
  for(int i = 0 ; i < 100 ; i++) debug++;   // volatile so that the compiler doesn't touch

  String debugstring = "";

  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  __DSB();
  __WFI();
}

我正在使用外部中断进行调试,我使用跳线触发自己,这样我就知道应该何时触发它。我注意到的是,当我调试代码并逐步执行它时,如果我手动触发外部中断,那么它不会立即跳转到ISR。中断变为等待&#39;在NVIC中,例外条目不会在代码后面执行。

我已经阅读了很多关于SAMD21数据表中的中断和异常,Cortex M0 +通用用户指南和ARM体系结构手册。据推测,Cortex M系列具有低延迟中断,没有指令开销,因此看起来代码应该在触发中断后相对快速地跳转到ISR。

我已经多次阅读了Cortex M0 +通用指南的2.3.6以及ARM体系结构手册的B1.3.2,它们都非常详细地介绍了异常输入。 SAMD21数据表似乎没有太多低级信息。

我试图找出问题并找出设备行为中的任何模式,并且我注意到了一些事情。

它只在特定的代码行跳转到ISR。例如,在上面的代码中,如果在&#39; loop()&#39;开始时触发外部中断。它会在到达字符串声明时跳转到ISR,无论“#”中有多少次迭代。环。如果我将字符串声明移到&#39;上面。然后它会立即跳转到ISR(在2或3个调试步骤之后)。

我已尝试插入延迟,NOP和ISB,这些延迟不会影响所需的时间或使其立即跳转。 当我通过NVIC中的ISPR寄存器在软件中设置挂起中断时,会出现同样的问题。 我已经跟踪了Atmel Studio中的基本FLASH内存,并发现&#34; stack&#34;处理器的当前状态&#39;被推,也不会立即改变。它只会在我到达ISR中的第一行代码时发生变化。

我注意到的其他代码与String声明类似,导致代码跳转到ISR的是Wire库的endTransmission函数,SD卡库中的一些函数,Arduino延迟函数

这是否与我首先使用调试器干扰/不干扰中断的事实有关?在调试器出来之前,我确定问题已经发生了。编辑:通过Cortex M0 +技术参考手册和ARMv6手册阅读我找到了一个名为DHCSR的寄存器,它允许调试器屏蔽中断,但我无法解决如何访问这些寄存器的问题。

主要问题:除了PRIMASK和全局/个人使能寄存器位之外,还有什么可能阻止执行待处理中断?

编辑:遗漏了一条重要的信息,虽然我在Atmel Studio工作但该项目使用的是Arduino核心。

编辑:我注意到在手动触发中断后,在我的下一个调试步骤中,它在NVIC-&gt; ISPR寄存器中变为待处理状态。这让我相信中断在某处被掩盖了(我已经检查了PRIMASK,全局启用和个人启用到目前为止没有运气)。

1 个答案:

答案 0 :(得分:0)

String debugstring = "";是这个东西实际上是C ++的线索。 因此,您必须将IRQ处理程序声明为纯C函数:

extern "C" {
void EIC_Handler(void);
}
void EIC_Handler(void){
  int_count++;
  EIC->INTFLAG.reg = 1 << 0;
}

否则函数是C ++,它不能作为IRQ处理程序,因为链接器无法识别它。