Cortex M0+中断 sleep 后返回线程模式错误位置

标签 c atmel cortex-m

我不确定我是否在这里遗漏了一些明显的东西,但是其他人是否遇到过 Cortex M0+(或任何 Cortex M 系列)在被中断后从 ISR 返回到线程模式中的随机位置的任何问题从 sleep 模式唤醒(例如,不返回到 WFI 指令下方的行)。它似乎在代码中间醒来,就像在 for 循环的中间或函数的中间。我使用的是 ATSAMD218A 微 Controller ,并且一直在使用 Atmel Studio 7 中的调试器。我试图找出问题并注意到以下几点:

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

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

编辑 我在下面添加了相关代码。它是最精简的版本 (*stripped) 仍然会导致问题。我没有包含 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();
}

最佳答案

我会尝试使用 Atmel ASF 框架实现相同的代码段,查看 API 设置的寄存器以及顺序。他们通常还会引用勘误表并实现变通办法。

加载低功耗示例项目,它在功耗模式之间切换,并在按下 xplained 板按钮时唤醒。如果它可以在您的电路板上的模式之间跳跃,您就知道它不是零件。您可能需要将唤醒引脚移动到与您的硬件相匹配的地方。

关于Cortex M0+中断 sleep 后返回线程模式错误位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37933962/

相关文章:

objective-c - Objective C 中 struct ivar 的奇怪内存行为

gcc - 一个人如何颠倒 "int"值的低 8 位的顺序并保持高 8 位不变?

c - 裸机 C 编程中 LED 闪烁 : STM32L476RG Nucleo Board

c - 取消引用该指针给我-46,但我不知道为什么

c - Azure IoT - 重置和清除设备孪生

c - 对 AVR 进行编程以解释 Arduino 旋转编码器模块的输入时出现问题

arm - 为什么 Cortex-M4 在链接描述文件中包含 ARM to Thumb 胶水

assembly - ARM 皮质 M0/M3/M4 :Why PC is always Even number in Thumb State

c - 如何从 C 中的字符串中删除 <it></in> 和 () 内的所有内容?

visual-studio - “The visual Studio component cache is out of date, please restart Visual Studio.”