Questions:应用有时会遇到无法正常进入低功耗的问题
具体表现为执行__WFI()命令进入低功耗时,在无唤醒条件的情况下,系统却直接跳过该命令,代码继续向下执行的现象。
Answer:
本文将采用低功耗的Standby模式为例进行分析及说明。
【问题根本原因】:
进入低功耗调用的__WFI()命令实质为“等待中断”,若在执行__WFI()命令时,NVIC中断内已有处于挂起且未被响应的中断的话,代码就会跳过__WFI命令继续向下执行。
此为ARM内核的特性,所有以ARM内核为基础设计的芯片均会存在此现象。
【问题解法】:
在执行__WFI()前,清除NVIC中断内所有处于挂起状态的NVIC pending位。
Analysis:
本文将采用低功耗的Standby模式加上USART1的接收中断为例进行说明分析。
【问题代码段示例】(其中不参与本文说明的代码未贴出):
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE); ///<①开启PWR时钟 nvic_irq_enable(USART1_IRQn, 0, 0); ///<②使能USART1对应的NVIC中断 usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE); ///<③使能USART1接收中断 __disable_irq(); ///<④禁止所有NVIC中断响应 while(usart_flag_get(USART1, USART_RDBF_FLAG) == RESET); ///<⑤等待RDBF标志置位 pwc_standby_mode_enter(); ///<⑥进Standby的命令 while(1); |
【问题逻辑分析】:
在实际运行时,当收到数据后
1) USART1的RDBF标志被置位;
2) 因③的设定, USART1对应的NVIC pending位会跟随RDBF置位;
3) 因②的设定,置位的NVIC pending位会跳转到对应的中断函数执行;
4) 但又因④的设定,代码实际不会跳转到中断函数执行,且NVIC pending位将被一直保持置位状态;
5) 故在⑥执行的时,因存在NVIC pending位处于置位状态,系统会直接跳过⑥内的__WFI();命令而继续向后执行,最终PC会停留到代码最后的while(1)语句。
【问题解法示例】:
为了能正常进入Standby,应用需要在执行__WFI()前清除处于置位状态的NVIC pending位,即在前示例代码的⑤⑥之间添加如下代码:
usart_flag_clear(USART1, USART_RDBF_FLAG); ///<清除USART1的RDBF标志 NVIC_ClearPendingIRQ(USART1_IRQn); ///<清除USART1对应的NVIC pending标志 |
【注意事项】:
A. 本文只针对调用__WFI()进入的低功耗,__WFE()不存在类似问题;
B. 若不使能外设对应的NVIC中断,此时NVIC pending位同样会被置位,不过该置位的NVIC pending位不会对应用产生任何影响;
C. 问题解法中,在清除NVIC pending标志前,一定要先清除对应外设的中断标志,如前述示例中,USART1对应的NVIC pending位会跟随RDBF置位,若不先清除RDBF的话,将无法清除其对应的NVIC pending位;
D. 在非低功耗应用中,同样需要注意本文所述问题,因为置位的NVIC pending位会带来后续中断函数额外多执行一次的现象;
E. 一般带有指令跳转的IAP或其他相关应用会很容易撞到本文所述问题。建议初始设计时要严格注意使用到的外设对应的NVIC pending位的状态。
类型:MCU应用
适用型号:AT32全系列
主功能:NVIC pending位清除,执行__WFI()进低功耗异常
次功能:无