You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM Cortex M0+处理器唤醒后重复休眠,如何恢复正常执行?

Arduino MKR Wifi 1010(Cortex-M0+)休眠唤醒后重复休眠的问题解决

你的问题核心是:调用__WFI()进入休眠后,能被中断唤醒并执行ISR,但ISR返回后设备再次进入休眠,而非继续执行主程序逻辑。结合Cortex-M0+(SAMD21G18)的硬件特性,最常见的原因及解决方法如下:

1. 中断标志位未清除(最可能的原因)

Cortex-M0+的异步唤醒中断触发后,对应外设的中断标志位会被置位。如果ISR中未清除该标志,CPU会持续检测到“未处理的中断”,导致ISR返回后,系统误以为仍有中断等待处理,进而再次触发休眠流程。

针对SAMD21(MKR Wifi 1010的主控芯片),需要在ISR中手动清除对应引脚的中断标志位:

void wakeISR() {
  // 根据唤醒引脚获取对应的PORT组和引脚位
  const PinDescription& pinDesc = g_APinDescription[WAKE_PIN];
  PORT->Group[pinDesc.ulPort].INTFLAG = (1 << pinDesc.ulPin);
}

注意:Arduino的attachInterrupt()默认不会自动清除SAMD21的硬件中断标志位,必须手动操作寄存器完成。

2. 主程序流程逻辑问题

如果你的__WFI()调用被放在一个循环体内,唤醒后主程序会立刻再次执行__WFI(),表现为“重复休眠”。需要确保唤醒后有明确的执行路径,避免立刻回到休眠:

void loop() {
  Serial.println("Entering sleep...");
  Serial.flush();
  
  // 关闭非必要外设降低功耗
  Serial.end();
  
  __WFI(); // 进入休眠,等待中断唤醒
  
  // 唤醒后恢复外设并执行后续逻辑
  Serial.begin(9600);
  Serial.println("Woke up successfully!");
  
  // 添加唤醒后的处理代码,避免立刻再次休眠
  delay(2000);
}

3. 休眠模式与时钟恢复问题

MKR Wifi 1010的STANDBY模式会关闭大部分外设时钟,若唤醒后核心时钟或外设时钟未正确恢复,可能导致程序执行异常,看起来像是“再次休眠”。可以在唤醒后重新初始化需要的外设(如串口、WiFi模块),确保时钟正常运行:

// 唤醒后恢复WiFi模块示例
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
}

4. 排除PRIMASK寄存器干扰

虽然PRIMASK主要用于屏蔽全局中断,但可以在进入休眠前确保其处于允许中断的状态(值为0),避免异常:

__set_PRIMASK(0); // 允许所有中断
__WFI();

完整示例代码

#include <Arduino.h>

#define WAKE_PIN 2 // 用于唤醒的引脚
const char* ssid = "your_ssid";
const char* password = "your_password";

void wakeISR() {
  // 清除中断标志位
  const PinDescription& pinDesc = g_APinDescription[WAKE_PIN];
  PORT->Group[pinDesc.ulPort].INTFLAG = (1 << pinDesc.ulPin);
}

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // 配置唤醒引脚为上拉输入
  pinMode(WAKE_PIN, INPUT_PULLUP);
  // 注册下降沿触发的中断
  attachInterrupt(digitalPinToInterrupt(WAKE_PIN), wakeISR, FALLING);

  // 配置休眠模式为STANDBY(最低功耗模式之一)
  PM->SLEEP.reg = PM_SLEEP_SLEEPMODE_STANDBY;
}

void loop() {
  Serial.println("Preparing to sleep...");
  Serial.flush();

  // 关闭WiFi以降低功耗
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  // 关闭串口
  Serial.end();

  // 确保允许中断,进入休眠
  __set_PRIMASK(0);
  __WFI();

  // 唤醒后恢复外设
  Serial.begin(9600);
  while (!Serial);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWoke up and reconnected to WiFi!");
  delay(3000); // 停留一段时间再进入下一次休眠
}

内容的提问来源于stack exchange,提问作者Caulder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 23:13:14