中断睡眠后,Cortex M0 +在线程模式下返回错误位置

时间:2016-06-21 00:46:19

标签: c atmel cortex-m

我不确定我是否遗漏了一些明显的东西,但是其他任何人都遇到过从ISR返回到某个随机位置的Cortex M0 +(或任何Cortex M系列)的任何问题从睡眠模式唤醒后的线程模式(例如,不返回到WFI指令下面的行)。它似乎在代码中间醒来,比如在for循环的中间或函数的中间。我使用的是ATSAMD218A微控制器,并且一直在使用Atmel Studio 7中的调试器。我试图找出问题并发现以下情况:

  • 只有在设备进入休眠状态时才会发生,当设备在唤醒时被中断,ISR总是返回正确的位置。
  • ISR总是返回代码中的相同(不正确)位置,如果我注释掉该函数或代码段,则它开始返回另一个错误位置
  • 我没有成功插入延迟和NOP来尝试确定它是与时序相关还是与时钟周期相关,但它仍然总是返回到相同(不正确)的位置
  • 我尝试使用直接寄存器访问以及使用Arduino中断库来实现中断。
  • 它在空闲和待机模式(睡眠和深度睡眠)中发生
  • 在调试期间查看汇编指令时,就在ISR退出之前,' bx lr'调用指令,该指令应该分支到链接寄存器。链接寄存器包含一个名为EXC_RETURN的值,表示返回行为,在我的例子中是0xFFFFFFF9(返回到线程模式)。但是,我无法找到它返回到任何地方的实际内存地址。存储器地址不在任何核心寄存器R0-R15中。

我一直在阅读ARMv6架构参考手册以及Cortex M0 +通用用户指南。不太清楚发生了什么,任何调试建议都会非常感激。有没有人更好地理解Cortex M系列的异常处理,并且可以指出我找到线程模式在ISR之后返回的内存地址的正确方向。如果您愿意,我可以提供代码,但即使是一段简单的代码,除了循环计数,睡眠然后唤醒都会造成麻烦。

EDIT 我已在下面添加了相关代码。它是最剥离的版本(*剥离)仍然会导致问题。我还没有包含RTC代码功能(使用DS3231RTC库),因为我相当确定它们没有任何效果。如果你认为我应该上传更多让我知道。

void configInterrupt(void){
  NVIC_DisableIRQ(EIC_IRQn);
  NVIC_ClearPendingIRQ(EIC_IRQn);
  NVIC_SetPriority(EIC_IRQn, 0);
  NVIC_EnableIRQ(EIC_IRQn);

  // Enable GCLK for IEC (External Interrupt Controller)
  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);                     // custom 'pinMode' function
  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 EIC_Handler(void){   
  RTC_FLAG = 1;           // my debug breakpoint is here, at this point the stack has already been pushed and I can see the PC value that will be popped off
  int_count++;
  EIC->INTFLAG.reg = 1 << 0;
}

void setup() {
  configInterrupt();                
  configureRTC();
  RTC_FLAG = 1;
}

void loop() {
  if (RTC_FLAG == 1) {
    RTC_FLAG = 0;
    setNextAlarm();
  }

  for (int i = 0 ; i <= WINDOW-1 ; i++) {
        String data = "";

        rawVal  = 0;     // data gets read from sensor here (stripped)
        data += String(rawVal);   
        data += ",";

        distance = 0;    // distance calculated from rawVal here (stripped)
        data += String(distance);
        data += ",";

        mean = 0;        // mean calculated in a function here (stripped)
        data += String(mean);
        data += ",";

        data += String(int_count);    // ISR returns here 
        // Data gets written to file here (stripped)
}

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

1 个答案:

答案 0 :(得分:0)

我尝试使用Atmel ASF框架实现相同的代码段,查看API设置的寄存器以及顺序。他们通常也会参考勘误表并实施一项工作。

加载低功耗示例项目,它在电源模式之间切换,并按下xplained board按钮。如果它可以在你的主板上的模式之间跳转,你知道它不是那个部分。您可能必须将唤醒引脚移动到与硬件匹配的位置。