关于stop模式下RTC唤醒不进入main的问题
项目场景:
STM32L073VZT6在Stop模式下RTC唤醒执行完回调函数后不进入mian循环。
项目场景:stop低功耗裸机设计,RTC秒唤醒执行完被置起的任务后进入stop模式。其中有个任务是使用LPUART的DMA发送,接收用IDLE中断。确定的是发送数据的时间段是在RUN下,接收有一部分已经在stop下(强调一下,IDLE中断无法在Stop下产生,因为项目没有实时性,所以在下一秒唤醒后产生IDLE中断进行数据解析,因此数据会延迟一秒)。特别地在进入睡眠前使能了SLEEPONEXIT位,RTC唤醒执行回调函数时清除该标志位,以进入main循环,其他中断均不清除。
问题描述
RTC唤醒后执行完回调函数偶尔不进入main循环,下一秒恢复正常。项目中使用了SLEEPONEXIT位但RTC唤醒在退出中断回调函数前也确定被清除,功耗曲线持续在约120μA,有点像sleep模式,但整个项目没有sleep设计也没有相关代码块。
睡眠函数部分重要代码如下:
/*LPUART配置在睡眠模式下工作,时钟选择LSE即可,若其他串口也需要在睡眠模式下可以接受数据,则在进入stop前需要使能uartstop模式*/voidEnterStop(void){SCB->SCR|=SCB_SCR_SLEEPONEXIT_Msk;//产生中断执行完回调后继续睡眠,库函数为HAL_PWR_EnableSleepOnExitHAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI);/*若系统时钟使用的是不是MSI,从stop醒来后需要重新配置系统时钟 SysCofig() 或者在进入stop前使用__HAL_RCC_WAKEUPSTOP_CLK_CONFIG宏通过RCC->CFGR 寄存器中的 STOPWUCK 位来选择唤醒后的时钟源*/}若产生中断后除了执行完中断回调需要进入run模式执行复杂任务,则需要在中断函数中清除SCB->SCR的SCB_SCR_SLEEPONEXIT_Msk位,如RTC中断。
SCB->SCR&=SCB_SCR_SLEEPONEXIT_Msk/*或调用库函数HAL_PWR_DisableSleepOnExit()清除*/原因分析:
Sop模式下若有使用DMA进行串口收发,在进入Stop前一定要关闭DMA。这里的关闭不一定要去Deinit或者stop DMA,可以关闭串口CR3寄存器中的DMAT/DMAR状态位。
这里在实际项目中发现一个小问题,HAL库的HAL_UART_Transmit_DMA函数中会监测各状态位的使能情况,若DMAT为失能状态也会使能。
但是实际项目中若在使用DMA发送之前不提前使能DMAT,发送会出现异常(欢迎大佬指点)。
解决方案:
在进入stop前调用Hal库函数HAL_UART_DMAPause()暂停DMAT或DMAR,然后在调用HAL_UART_Transmit_DMA函数前用库函数HAL_UART_DMAResume()恢复传输。
暂停DMA收发和恢复DMA收发的库函数源码会检测DMAR和DMAT,分别进行失能和使能。但是如果直接调用这个库函数进行暂停和恢复也还是会偶尔出现高功耗的情况。最终解决是不使用库函数,因为没有使用DMA的接收,直接对LPUART的CR3寄存器的DMAT位进行寄存器级别的使能与失能。
在HAL_PWR_EnterSTOPMode()函数前增加如下代码:
LPUART1->CR3&=~LPUART_CR3_DMAT