低功耗无法进入的问题分析
现象
- 低功耗进入与退出前后加入打印函数.发现进入低功耗后立刻退出低功耗
- 打印代码如下
log_i("in\r\n");
UTIL_PowerDriver.EnterStopMode( );
UTIL_PowerDriver.ExitStopMode( );
log_i("out\r\n");
原因
- 中断标志位挂起未清除导致低功耗进入失败
分析
挂起的中断标志位查找
- 完整的进退低功耗函数如下
#define UTIL_LPM_ENTER_CRITICAL_SECTION_ELP() 扩展到:
uint32_t primask_bit= __get_PRIMASK(); __disable_irq()
#define UTIL_LPM_EXIT_CRITICAL_SECTION_ELP() 扩展到:
__set_PRIMASK(primask_bit)
void UTIL_LPM_EnterLowPower( void )
{
UTIL_LPM_ENTER_CRITICAL_SECTION_ELP( );
if( StopModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Stop Mode
* SLEEP mode is required
*/
UTIL_PowerDriver.EnterSleepMode( );
UTIL_PowerDriver.ExitSleepMode( );
}
else
{
if( OffModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Off Mode
* STOP mode is required
*/
log_i("in\r\n");
UTIL_PowerDriver.EnterStopMode( );
UTIL_PowerDriver.ExitStopMode( );
log_i("out\r\n");
}
else
{
/**
* OFF mode is required
*/
UTIL_PowerDriver.EnterOffMode( );
UTIL_PowerDriver.ExitOffMode( );
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( );
}
- 在进入低功耗函数前,关闭中断(实际为屏蔽中断触发,不响应中断).退出低功耗函数后恢复中断.再进入低功耗到退出低功耗期间不会有任何中断响应
- 调用代码
printf("0X%08lx\r\n", SCB->ICSR);
打印中断控制和状态寄存器的值发现为0x400f000.查看数据手册得知,为SYSTICK中断标志位挂起
- 可以判断为SYSTICK中断未处理,导致标志位未清除,无法进入低功耗
SYSTICK中断触发原因
- 在屏蔽中断响应后,没有及时进入低功耗函数,触发了SYSTICK中断.
- 导致中断标志挂起,无法进入低功耗
解决方案
-
进退低功耗函数过程中,尽量减少运行量.防止systick挂起中断,导致进入低功耗失败
-
开关中断函数之间调用较少代码.可以多次开关中断,减少一次开关中间的运行量
-
在中断内打印尽量使用原生的printf,减少调用时间