本文主要用于记录STM32单片机功耗异常的分析过程,直接看 分析原因 部分可以快速知道问题原因和解决方法。
各场景的功耗见下表:
模式 | 常规工作模式 | Standby模式(正常) | Standby模式(异常) |
---|---|---|---|
功耗 | 9mA | 2uA | 0.7mA |
拿了几块功耗正常的板子,对开发与测试的场景进行了多次测试验证,发现了以下规律:
测试场景编号 | 开发环境 | 编译器 | 烧录器 | Standby功耗 |
---|---|---|---|---|
TD1 | Eclipse (Oxygen-4.73) | Arm-GCC | J-Link | 偶发性异常 |
TD2 | Keil-MDK (v5.23) | MDK默认编译器 | J-Link | 正常 |
TD3 | Keil-MDK (v5.23) | MDK默认编译器 | ST-Link | 正常 |
测试场景编号 | 生产烧录环境 | 烧录器 | 烧录器驱动 | Standby功耗 |
---|---|---|---|---|
TP1 | STM32 ST-Link Utility (v3.7.0) | ST-Link | v4.4.0 | 全部异常 |
TP2 | SEGGER J-Flash (v5.00) | J-Link | v6.10 | 正常 |
本步骤结论:特定场景的软件下载方式,会触发这个异常。
补充说明:在这一步时,怀疑烧录软件配置选项有问题,于是把烧录上位机所有的选项都改了一遍,但是没有效果。
之前测试的是整个板子的功耗,需要在这一步定位是板上的哪个器件引起的功耗异常。
因为在烧录后会引起这个故障,所以MCU的嫌疑最大。于是,用一块只贴有MCU及其外围器件的板子(MCU核心板)再次进行了Step-1的几项测试。测得MCU自身的功耗与Step-1测的板功耗结果很接近。看来,板子功耗异常是MCU引起的。
使用功耗正常、功耗异常的两块MCU核心板进行对比测试,用示波器量了MCU所有管脚的状态。发现在进入Standby状态后,异常功耗MCU的SWDIO-Pin为高电平,正常的为低电平。
查看ST Reference manual(RM0091),MCU进入Standby状态,PA13(SWDIO-Pin)是高阻态。
那么,Standby状态下SWIO-Pin输出为高电平应该是个异常状态。
是因为没有固定这个脚电平?
于是,做了两个验证:
结果这两种方式都没有效果。可以认定,SWDIO的高电平,与管脚电平未固定没有关系,是SWDIO自身输出(或内部上拉到)高电平。
本步骤结论:板子功耗异常是MCU引起的,此时MCU的SWDIO脚会异常输出(或内部上拉到)高电平。
继续在MCU核心板上测试,尝试恢复Standby功耗异常的MCU,试了以下几种方法:
恢复方式 | SWDIO状态 | Standby功耗 |
---|---|---|
唤醒信号给到Wakeup Pin (Wakeup event) | 高电平 | 未恢复 |
拉低Reset Pin到GND1秒 (System Reset) | 高电平 | 未恢复 |
使用Step-1中的5种方式重新烧录程序 (Download) | 高电平 | 未恢复 |
断开板子电源后重新上电 (Power-on Reset) | 低电平 | 恢复 |
本步骤结论:只有Power-on reset才能恢复功耗异常。
这一步的思路是 单片机状态的差异,往往会体现在它的寄存器值上。
经过前几步的分析,得到了一些结论:
以上这些结论指向MCU的调试功能。于是,将排查重点放到调试相关的寄存器上。
查看ST Reference manual(RM0091)对DBG寄存器的描述(下图),发现:
查看ST Reference manual(RM0091)对该位的描述(下图)。DBG_STANDBY位为1时,进入Standby模式,HCLK不会停止,而是转换为内部RC电路(内部低速晶振)作为时钟源继续运行。所以就会在异常的Standby状态下处于 比正常工作模式低,比常规standby模式高的功耗。
又拿了个standby模式下功耗正常的MCU核心板测了下,它的DBG_STANDBY位为0。看来很可能是这个原因。
在代码中增加主动将DBG_STANDBY清0的动作,放在进入Standby之前。
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_DBGMCUEN);
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY);
补充说明:这里需要注意,因为DBG也是外设的一种,操作DBG寄存器前要使能其外设时钟。
将这个程序使用Step-1中的几种方式烧录到MCU中,Standby功耗都正常。
本步骤结论:DBG_STANDBY位在烧录时被Debugger配置为1,使得MCU进入Standby功耗异常。
通过以上几个步骤的排查,再结合Step-1的测试,发现与烧录上位机STM32 ST-Link Utility的设置有关。
其中有一项配置“Enable debug in low power mode”,如果勾选了。再连接MCU,点击“connect”后,会将MCU的DBG_STANDBY位写1,且在烧录完成、断开连接后不会清除。
又进行了4项测试:
测试编号 | MCU核心板类型 | 是否勾选Enable debug in low power mode | Standby功耗 |
---|---|---|---|
1 | 功耗正常 | 勾选 | 异常 |
2 | 功耗正常 | 不勾选 | 正常 |
3 | 功耗异常 |
勾选 | 异常 |
4 | 功耗异常 |
勾选 | 异常 |
结论:
参考ST Reference manual(RM0091), 如果MCU进入Standby功耗异常,以下三种方式可以恢复:
下面是STM32进入Standby模式的常规代码
void Bsp_Enter_Standby(void)
{
/* Enable Wakeup1 pin(PA0) */
PWR->CSR |= PWR_CSR_EWUP1;
/* STM32F0 MCU enters standby mode*/
PWR->CR |= PWR_CR_CWUF; /* Clear up wake up flag */
PWR->CR |= PWR_CR_CSBF; /* Clear standby flag */
PWR->CR |= PWR_CR_PDDS; /* Select standby mode */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__WFI(); /* Wait for interrupt */
/* Then MCU will enter standby mode. After the MCU wakes up, it will run from
* Reset_Handler */
}
下面是添加关闭DBG_STANDBY的代码
void Bsp_Enter_Standby(void)
{
/* Enable Wakeup1 pin(PA0) */
PWR->CSR |= PWR_CSR_EWUP1;
#if (!defined(DEBUG) || !defined(USE_DBG_STANDBY))
/* Disable DBG_STANDBY. Prevent DBG_STANDBY from being enabled by debugger when
* downloading programs, causing standby mode power consumption to be too high */
SET_BIT(RCC->APB2ENR, RCC_APB2ENR_DBGMCUEN);
CLEAR_BIT(DBGMCU->CR, DBGMCU_CR_DBG_STANDBY);
#endif
/* STM32F0 MCU enters standby mode*/
PWR->CR |= PWR_CR_CWUF; /* Clear up wake up flag */
PWR->CR |= PWR_CR_CSBF; /* Clear standby flag */
PWR->CR |= PWR_CR_PDDS; /* Select standby mode */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__WFI(); /* Wait for interrupt */
/* Then MCU will enter standby mode. After the MCU wakes up, it will run from
* Reset_Handler */
}