wfi进入之前没有清除basepri, 导致中断优先级不够,wfi 退不出来

  • BASEPRI 屏蔽 = 完全不唤醒 :WFI 的唤醒条件是「中断优先级高于当前执行优先级 且 高于 BASEPRI 阈值」。只要中断优先级数值 ≥ BASEPRI 值(5 ≥ 2),既不唤醒也不执行 ISR,CPU 就一直停在 WFI。
  • PRIMASK 置位 = 会唤醒但暂不执行 :ARM 明确规定,用 CPSID i(__disable_irq())关中断时,只要来的是"若 PRIMASK 未置位就能抢占"的中断,处理器仍会退出 WFI,只是不进 ISR、保持 pending,等开中断后再响应。

这也是为什么"关总中断反而能唤醒、进临界区反而醒不来"。FreeRTOS 的 taskENTER_CRITICAL() 走的是 BASEPRI 路线,不是 PRIMASK。

另外 AC7843x 的 VLPS 定义是"CPU 进入深度休眠,支持部分模块中断唤醒"------唤醒仍然经过 NVIC 中断路径,所以必然受 BASEPRI/PRIMASK 约束,不存在"绕过 NVIC 的独立引脚唤醒通路"这一侥幸。

一句话定性

现象(优先级数值 5 不唤醒、改成 <2 就能唤醒)几乎可以直接锁定为:进入 VLPS 执行 WFI 时,BASEPRI 仍被 FreeRTOS 临界区设置为阈值 2(0x20),优先级 5(0x50)的 GPIO 中断处于"被屏蔽"状态,而 ARMv7-M 中被 BASEPRI 屏蔽的中断是唤醒不了 WFI 的------不是 GPIO 配置问题,也不是边沿没检测到(示波器已经证明了边沿存在)。

先厘清两个容易混的机制

  • BASEPRI 屏蔽 = 完全不唤醒 :WFI 的唤醒条件是「中断优先级高于当前执行优先级 且 高于 BASEPRI 阈值」。只要中断优先级数值 ≥ BASEPRI 值(5 ≥ 2),既不唤醒也不执行 ISR,CPU 就一直停在 WFI。
  • PRIMASK 置位 = 会唤醒但暂不执行 :ARM 明确规定,用 CPSID i(__disable_irq())关中断时,只要来的是"若 PRIMASK 未置位就能抢占"的中断,处理器仍会退出 WFI,只是不进 ISR、保持 pending,等开中断后再响应。

这也是为什么"关总中断反而能唤醒、进临界区反而醒不来"。FreeRTOS 的 taskENTER_CRITICAL() 走的是 BASEPRI 路线,不是 PRIMASK。

另外 AC7843x 的 VLPS 定义是"CPU 进入深度休眠,支持部分模块中断唤醒"------唤醒仍然经过 NVIC 中断路径,所以必然受 BASEPRI/PRIMASK 约束,不存在"绕过 NVIC 的独立引脚唤醒通路"这一侥幸。

可能造成该问题的原因(按可能性排序)

1. 带 BASEPRI 进入 WFI(最可能)

在 taskENTER_CRITICAL() / portENTER_CRITICAL() / portSET_INTERRUPT_MASK() 未退出、BASEPRI 仍为 0x20 的情况下调用了进 VLPS 的函数并 WFI。优先级 5 ≥ 阈值 2 → 不唤醒;改成 1 或 0 → 解除屏蔽 → 正常唤醒。现象完全吻合。

2. Tickless Idle 路径里 BASEPRI 未清零

vPortSuppressTicksAndSleep() 默认实现用 portDISABLE_INTERRUPTS()(BASEPRI,而非 PRIMASK)后在临界区内 __WFI();你自己实现 configPRE_SLEEP_PROCESSING() / configPRE_SLEEP_PROCESSING() 进 VLPS 时,如果没在这个宏里把 BASEPRI 清 0,唤醒源同样被屏蔽。

3. BASEPRI 残留

  • 在 ISR 里调用进低功耗代码,用了 taskENTER_CRITICAL_FROM_ISR() 但保存/恢复的 BASEPRI 值错误;
  • uxCriticalNesting 计数异常,退出临界区时没有把 BASEPRI 写成 0;
  • 应用层或 SDK 的 PMU_EnterVLPS() 一类函数内部自己 __set_BASEPRI() / 关中断且退出后不恢复。

4. 优先级分组不是"全抢占位"

FreeRTOS 要求 AIRCR.PRIGROUP 配成 4 位全部为抢占优先级(等价 NVIC_PRIORITYGROUP_4)。若存在子优先级位,BASEPRI 只比较 group priority 部分,5 与 2 的屏蔽判定会跟你的设计意图对不上。

5. 优先级位数 / 移位不匹配

configPRIO_BITS 与实际 __NVIC_PRIO_BITS 不一致,或把"未移位的 2"直接当 configMAX_SYSCALL_INTERRUPT_PRIORITY 写进 BASEPRI(0x02 的高 4 位为 0,等于不屏蔽;真正表示阈值 2 的是 0x20)。重复移位则会把阈值抬到异常范围。

6. 实际是"唤醒了又睡回去"

CPU 退出过 WFI(如 PRIMASK 场景),但中断未被执行、唤醒标志未置位,主循环判断"无事发生"又进了 VLPS,从外部看像没醒。需要区分这两种情况。

7. 次要但需排除

  • SCR.SLEEPONEXIT=1(ISR 返回立即再睡)或 SLEEPDEEP/VLPS 请求位配错;
  • 进 VLPS 前中断标志清理顺序错误(应先清 NVIC pending 再清外设标志,顺序反了会丢边沿,但通常表现为"进不去"或"立即退出");
  • 改优先级时改到的 IRQn 与实际引脚所属中断线不是一个(多引脚共用 IRQ);
  • WFI 前后缺 __DSB(); __ISB();,屏障缺失导致时序竞态。
相关推荐
Navigator_Z3 小时前
LeetCode //C - 1286. Iterator for Combination
c语言·算法·leetcode
奋斗的阿狸_19865 小时前
ESP32-S3 + ES7210 四通道麦克风录音上传方案
c语言·开发语言·fpga开发
2401_862880826 小时前
iMX6ULL 驱动工程搭建 + LED 灯驱动
c语言·驱动开发·嵌入式硬件
ACP广源盛139246256736 小时前
Type‑C 扩展坞方案选型笔记|国产 DP1.4 转 HDMI2.0 桥接芯片 GSV2201S @ACP评估
c语言·开发语言·笔记·硬件架构·硬件工程·国产芯片
沐欣工作室_lvyiyi6 小时前
超市智能货架系统设计与实现(论文+源码)
c语言·单片机·课程设计·电子信息工程毕业设计·黑龙江工商学院·广州工商学院·成都工业学院
C++ 老炮儿的技术栈7 小时前
static的作用
c语言·c++·人工智能·单片机·c
小小龙学IT8 小时前
Go 语言 cgo 与 C/C++ 互操作深度解析:从 fwlib 直连到工业数采网关实战系列
c语言·c++·golang
老王爱玩车10 小时前
动态内存管理
c语言·开发语言·学习·面试
Logic10110 小时前
C语言/数据结构数位DP题解:平滑排列数字统计——区间内相邻位差不超过K的数字个数
c语言·数据结构·动态规划·时间复杂度·数位dp·算法题·前导零处理