文章目录
-
-
- [1. 外设时钟](#1. 外设时钟)
- [2. 系统电压配置](#2. 系统电压配置)
- [3. SMP配置](#3. SMP配置)
- [4. 进低功耗流程](#4. 进低功耗流程)
-
1. 外设时钟
c
/**
* @brief Peripherals Common Clock Configuration
* @retval None
*/
void PeriphCommonClock_Config(void)
{
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SMPS|RCC_PERIPHCLK_RFWAKEUP;
PeriphClkInitStruct.RFWakeUpClockSelection = RCC_RFWKPCLKSOURCE_LSE;
PeriphClkInitStruct.SmpsClockSelection = RCC_SMPSCLKSOURCE_HSE;
PeriphClkInitStruct.SmpsDivSelection = RCC_SMPSCLKDIV_RANGE0;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN Smps */
// 指定本次要配置的两类外设时钟:SMPS(内置开关电源控制器)时钟 + RFWAKEUP(射频唤醒模块)时钟
// 配置射频唤醒模块的时钟源:选择LSE(低速外部晶振,默认32.768kHz,低功耗下仍可稳定运行,适配BLE低功耗唤醒需求)
// 配置SMPS开关电源的时钟源:选择HSE(高速外部晶振,默认32MHz,精度高稳定性好,保障供电控制的准确性)
// 配置SMPS时钟分频系数:选择RANGE0(对应分频比为1,即SMPS时钟直接等于HSE输入频率,无分频)
/* USER CODE END Smps */
}
2. 系统电压配置
c
static void SystemPower_Config(void)
{
/**
* Select HSI as system clock source after Wake Up from Stop mode
* 功能:配置MCU从Stop低功耗模式唤醒后的系统时钟源
* 设置Stop模式唤醒后使用HSI(高速内部时钟)作为系统时钟,不需要等待外部晶振起振,可大幅降低唤醒耗时,适合低功耗快速响应场景
*/
LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
/* Initialize low power manager */
UTIL_LPM_Init();
/* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */
/* 在启动CPU2(Cortex-M0+ 射频核心)前,先配置CPU2的初始电源模式为SHUTDOWN关机模式,未启动时保持最低功耗,避免额外耗电 */
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
// 编译宏判断:仅当工程配置中启用了USB外设功能时,才编译执行以下USB电源配置代码
#if (CFG_USB_INTERFACE_ENABLE != 0)
/**
* Enable USB power
*/
HAL_PWREx_EnableVddUSB();
#endif /* CFG_USB_INTERFACE_ENABLE != 0 */
return;
}
3. SMP配置
c
void Init_Smps(void)
{
#if (CFG_USE_SMPS != 0)
/**
* Configure and enable SMPS
*
* The SMPS configuration is not yet supported by CubeMx
* when SMPS output voltage is set to 1.4V, the RF output power is limited to 3.7dBm
* the SMPS output voltage shall be increased for higher RF output power
* 配置SMPS启动阶段的最大限流值为80mA。SMPS启动瞬间需要较大电流给后端储能电容充电,
80mA是兼顾启动速度和过流保护的常用配置,可覆盖BLE射频发射峰值电流(20~50mA)的需求,避免启动过流损坏电源模块。
* 设置SMPS稳定工作时的输出电压为1.4V。该电压是给MCU内核、内存、外设逻辑、BLE射频模块供电的核心电压,1.4V是STM32WB主频运行在64MHz、BLE正常收发的标准配置,相比更高电压(如1.5V)可降低10%左右的运行功耗。
* 使能SMPS电源模块,配置生效后SMPS将替代默认的内部LDO为核心域供电,大幅降低运行和休眠状态下的功耗。
*/
LL_PWR_SMPS_SetStartupCurrent(LL_PWR_SMPS_STARTUP_CURRENT_80MA);
LL_PWR_SMPS_SetOutputVoltageLevel(LL_PWR_SMPS_OUTPUT_VOLTAGE_1V40);
LL_PWR_SMPS_Enable();
#endif /* CFG_USE_SMPS != 0 */
return;
}
4. 进低功耗流程
c
while (1)
{
/* USER CODE END WHILE */
MX_APPE_Process();
/* USER CODE BEGIN 3 */
}
c
void MX_APPE_Process(void)
{
/* USER CODE BEGIN MX_APPE_Process_1 */
/* USER CODE END MX_APPE_Process_1 */
UTIL_SEQ_Run(UTIL_SEQ_DEFAULT);
/* USER CODE BEGIN MX_APPE_Process_2 */
/* USER CODE END MX_APPE_Process_2 */
}
c
UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( );
local_taskset = TaskSet;
local_evtset = EvtSet;
local_taskmask = TaskMask;
if ((local_taskset & local_taskmask & SuperMask) == 0U)
{
if ((local_evtset & EvtWaited)== 0U)
{
UTIL_SEQ_Idle( );
}
}
UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( );
c
void UTIL_SEQ_Idle(void)
{
#if (CFG_LPM_SUPPORTED == 1)
UTIL_LPM_EnterLowPower();
#endif /* CFG_LPM_SUPPORTED == 1 */
return;
}
关于官方定义的这个低功耗管理逻辑
官方的逻辑是反向思维
如果不是什么就什么
而不是
如果是什么就什么
c
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
*/
UTIL_PowerDriver.EnterStopMode( );
UTIL_PowerDriver.ExitStopMode( );
}
else
{
/**
* OFF mode is required
*/
UTIL_PowerDriver.EnterOffMode( );
UTIL_PowerDriver.ExitOffMode( );
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( );
}


这两个标志是低功耗模式控制标志位。初始为0
//停止模式不使能标志-不置位
StopModeDisable = UTIL_LPM_NO_BIT_SET; //0
//关机模式不使能标志-不置位
OffModeDisable = UTIL_LPM_NO_BIT_SET; //0
初始化为0
c
void UTIL_LPM_Init( void )
{
//停止模式不使能标志-不置位
StopModeDisable = UTIL_LPM_NO_BIT_SET; //0
//关机模式不使能标志-不置位
OffModeDisable = UTIL_LPM_NO_BIT_SET; //0
UTIL_LPM_INIT_CRITICAL_SECTION( );
}
c
typedef enum
{
CFG_LPM_APP, // APP 0
CFG_LPM_APP_BLE, // BLE 1
/* USER CODE BEGIN CFG_LPM_Id_t */
/* USER CODE END CFG_LPM_Id_t */
} CFG_LPM_Id_t;
typedef enum
{
UTIL_LPM_ENABLE=0,
UTIL_LPM_DISABLE,
} UTIL_LPM_State_t;
跟着初始化一步步走
c
void MX_APPE_Init(void)
{
/* USER CODE END APPE_Init_1 */
appe_Tl_Init(); /* Initialize all transport layers */
}
下一级
static void appe_Tl_Init(void)
{
shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf);
return;
}
下一级
static void APPE_SysUserEvtRx(void * pPayload)
{
APP_DBG_MSG(">>== SHCI_SUB_EVT_CODE_READY\n\r");
APPE_SysEvtReadyProcessing(pPayload);
}
下一级
static void APPE_SysEvtReadyProcessing(void * pPayload)
{
APP_BLE_Init();
UTIL_LPM_SetOffMode(1U << CFG_LPM_APP, UTIL_LPM_ENABLE);
}
APP_BLE_Init里面
void APP_BLE_Init(void)
{
/**
* Do not allow standby in the application
*/
UTIL_LPM_SetOffMode(1 << CFG_LPM_APP_BLE, UTIL_LPM_DISABLE);
}
c
先执行
/**
* Do not allow standby in the application
*/
UTIL_LPM_SetOffMode(1 << CFG_LPM_APP_BLE, UTIL_LPM_DISABLE);
* 1<<1 = 2
* OffModeDisable |= 2;
* OffModeDisable = 2;
后执行
UTIL_LPM_SetOffMode(1U << CFG_LPM_APP, UTIL_LPM_ENABLE);
* 1<<0 = 1
* OffModeDisable &= ~1;
* OffModeDisable &= 0;
* OffModeDisable = 2 & 0 = 2;
* OffModeDisable = 2;
这两个执行完毕 结果OffModeDisable = 2;
c
置位逻辑
void UTIL_LPM_SetOffMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state )
{
UTIL_LPM_ENTER_CRITICAL_SECTION( );
switch(state)
{
case UTIL_LPM_DISABLE:
{
OffModeDisable |= lpm_id_bm;
break;
}
case UTIL_LPM_ENABLE:
{
OffModeDisable &= ( ~lpm_id_bm );
break;
}
default :
{
break;
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION( );
}
两个全局标志都是位掩码,每1bit对应一个业务/外设模块的低功耗禁用申请:
StopModeDisable:值为UTIL_LPM_NO_BIT_SET(也就是0)=
所有模块都允许进入Stop及更低功耗模式;非0=至少有1个模块禁止进入Stop模式
OffModeDisable:值为0=所有模块都允许进入Off最低功耗模式;非0=至少有1个模块禁止进入Off模式
c
此时
StopModeDisable = 0;
OffModeDisable = 2;
void UTIL_LPM_EnterLowPower( void )
{
// 进临界区:关中断,防止低功耗切换过程被中断打断出现逻辑异常
UTIL_LPM_ENTER_CRITICAL_SECTION_ELP( );
//【只要有任何一个模块申请了"不让进Stop模式"】 → 那就只能进最浅的Sleep模式
//如果StopModeDisable是0 → :【所有模块都同意可以进Stop模式】
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
{
//【只要有任何一个模块申请了"不让进Off模式"】 → 那就进中等深度的Stop模式
//如果OffModeDisable也是0 → :【所有模块都同意可以进Off模式】
if( OffModeDisable != UTIL_LPM_NO_BIT_SET )
{
/**
* At least one user disallows Off Mode
* STOP mode is required
*/
UTIL_PowerDriver.EnterStopMode( );
UTIL_PowerDriver.ExitStopMode( );
}
else
{
/**
* OFF mode is required
*/
UTIL_PowerDriver.EnterOffMode( );
UTIL_PowerDriver.ExitOffMode( );
}
}
UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( );
}