/* USER CODE BEGIN Header */ /** *************************************************************************************** * File Name : stm32_lpm_if.c * Description : Low layer function to enter/exit low power modes (stop, sleep). *************************************************************************************** * @attention * *

© Copyright (c) 2019 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "stm32_lpm_if.h" #include "stm32_lpm.h" #include "app_conf.h" /* USER CODE BEGIN include */ /* USER CODE END include */ /* Exported variables --------------------------------------------------------*/ const struct UTIL_LPM_Driver_s UTIL_PowerDriver = { PWR_EnterSleepMode, PWR_ExitSleepMode, PWR_EnterStopMode, PWR_ExitStopMode, PWR_EnterOffMode, PWR_ExitOffMode, }; /* Private function prototypes -----------------------------------------------*/ static void Switch_On_HSI( void ); static void EnterLowPower( void ); static void ExitLowPower( void ); /* USER CODE BEGIN Private_Function_Prototypes */ /* USER CODE END Private_Function_Prototypes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN Private_Typedef */ /* USER CODE END Private_Typedef */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN Private_Define */ /* USER CODE END Private_Define */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN Private_Macro */ /* USER CODE END Private_Macro */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Private_Variables */ /* USER CODE END Private_Variables */ /* Functions Definition ------------------------------------------------------*/ /** * @brief Enters Low Power Off Mode * @param none * @retval none */ void PWR_EnterOffMode( void ) { /* USER CODE BEGIN PWR_EnterOffMode_1 */ /* USER CODE END PWR_EnterOffMode_1 */ /** * The systick should be disabled for the same reason than when the device enters stop mode because * at this time, the device may enter either OffMode or StopMode. */ HAL_SuspendTick(); EnterLowPower(); /************************************************************************************ * ENTER OFF MODE ***********************************************************************************/ /* * There is no risk to clear all the WUF here because in the current implementation, this API is called * in critical section. If an interrupt occurs while in that critical section before that point, * the flag is set and will be cleared here but the system will not enter Off Mode * because an interrupt is pending in the NVIC. The ISR will be executed when moving out * of this critical section */ LL_PWR_ClearFlag_WU( ); LL_PWR_SetPowerMode( LL_PWR_MODE_STANDBY ); LL_LPM_EnableDeepSleep( ); /**< Set SLEEPDEEP bit of Cortex System Control Register */ /** * This option is used to ensure that store operations are completed */ #if defined ( __CC_ARM) __force_stores( ); #endif __WFI(); /* USER CODE BEGIN PWR_EnterOffMode_2 */ /* USER CODE END PWR_EnterOffMode_2 */ return; } /** * @brief Exits Low Power Off Mode * @param none * @retval none */ void PWR_ExitOffMode( void ) { /* USER CODE BEGIN PWR_ExitOffMode_1 */ /* USER CODE END PWR_ExitOffMode_1 */ HAL_ResumeTick(); /* USER CODE BEGIN PWR_ExitOffMode_2 */ /* USER CODE END PWR_ExitOffMode_2 */ return; } /** * @brief Enters Low Power Stop Mode * @note ARM exists the function when waking up * @param none * @retval none */ void PWR_EnterStopMode( void ) { /* USER CODE BEGIN PWR_EnterStopMode_1 */ /* USER CODE END PWR_EnterStopMode_1 */ /** * When HAL_DBGMCU_EnableDBGStopMode() is called to keep the debugger active in Stop Mode, * the systick shall be disabled otherwise the cpu may crash when moving out from stop mode * * When in production, the HAL_DBGMCU_EnableDBGStopMode() is not called so that the device can reach best power consumption * However, the systick should be disabled anyway to avoid the case when it is about to expire at the same time the device enters * stop mode ( this will abort the Stop Mode entry ). */ HAL_SuspendTick(); /** * This function is called from CRITICAL SECTION */ EnterLowPower(); /************************************************************************************ * ENTER STOP MODE ***********************************************************************************/ LL_PWR_SetPowerMode( LL_PWR_MODE_STOP2 ); LL_LPM_EnableDeepSleep( ); /**< Set SLEEPDEEP bit of Cortex System Control Register */ /** * This option is used to ensure that store operations are completed */ #if defined ( __CC_ARM) __force_stores( ); #endif __WFI(); /* USER CODE BEGIN PWR_EnterStopMode_2 */ /* USER CODE END PWR_EnterStopMode_2 */ return; } /** * @brief Exits Low Power Stop Mode * @note Enable the pll at 32MHz * @param none * @retval none */ void PWR_ExitStopMode( void ) { /* USER CODE BEGIN PWR_ExitStopMode_1 */ /* USER CODE END PWR_ExitStopMode_1 */ /** * This function is called from CRITICAL SECTION */ ExitLowPower(); HAL_ResumeTick(); /* USER CODE BEGIN PWR_ExitStopMode_2 */ /* USER CODE END PWR_ExitStopMode_2 */ return; } /** * @brief Enters Low Power Sleep Mode * @note ARM exits the function when waking up * @param none * @retval none */ void PWR_EnterSleepMode( void ) { /* USER CODE BEGIN PWR_EnterSleepMode_1 */ /* USER CODE END PWR_EnterSleepMode_1 */ HAL_SuspendTick(); /************************************************************************************ * ENTER SLEEP MODE ***********************************************************************************/ LL_LPM_EnableSleep( ); /**< Clear SLEEPDEEP bit of Cortex System Control Register */ /** * This option is used to ensure that store operations are completed */ #if defined ( __CC_ARM) __force_stores(); #endif __WFI( ); /* USER CODE BEGIN PWR_EnterSleepMode_2 */ /* USER CODE END PWR_EnterSleepMode_2 */ return; } /** * @brief Exits Low Power Sleep Mode * @note ARM exits the function when waking up * @param none * @retval none */ void PWR_ExitSleepMode( void ) { /* USER CODE BEGIN PWR_ExitSleepMode_1 */ /* USER CODE END PWR_ExitSleepMode_1 */ HAL_ResumeTick(); /* USER CODE BEGIN PWR_ExitSleepMode_2 */ /* USER CODE END PWR_ExitSleepMode_2 */ return; } /************************************************************* * * LOCAL FUNCTIONS * *************************************************************/ /** * @brief Setup the system to enter either stop or off mode * @param none * @retval none */ static void EnterLowPower( void ) { /** * This function is called from CRITICAL SECTION */ while( LL_HSEM_1StepLock( HSEM, CFG_HW_RCC_SEMID ) ); if ( ! LL_HSEM_1StepLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID ) ) { if( LL_PWR_IsActiveFlag_C2DS() || LL_PWR_IsActiveFlag_C2SB() ) { /* Release ENTRY_STOP_MODE semaphore */ LL_HSEM_ReleaseLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0 ); /** * The switch on HSI before entering Stop Mode is required on Cut2.0 * It is useless from Cut2.1 */ Switch_On_HSI( ); } } else { /** * The switch on HSI before entering Stop Mode is required on Cut2.0 * It is useless from Cut2.1 */ Switch_On_HSI( ); } /* Release RCC semaphore */ LL_HSEM_ReleaseLock( HSEM, CFG_HW_RCC_SEMID, 0 ); return; } /** * @brief Restore the system to exit stop mode * @param none * @retval none */ static void ExitLowPower( void ) { /* Release ENTRY_STOP_MODE semaphore */ LL_HSEM_ReleaseLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0 ); while( LL_HSEM_1StepLock( HSEM, CFG_HW_RCC_SEMID ) ); if(LL_RCC_GetSysClkSource( ) == LL_RCC_SYS_CLKSOURCE_STATUS_HSI) { /* Restore the clock configuration of the application in this user section */ /* USER CODE BEGIN ExitLowPower_1 */ LL_RCC_HSE_Enable( ); __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1); while(!LL_RCC_HSE_IsReady( )); LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE); while (LL_RCC_GetSysClkSource( ) != LL_RCC_SYS_CLKSOURCE_STATUS_HSE); /* USER CODE END ExitLowPower_1 */ } else { /* If the application is not running on HSE restore the clock configuration in this user section */ /* USER CODE BEGIN ExitLowPower_2 */ /* USER CODE END ExitLowPower_2 */ } /* Release RCC semaphore */ LL_HSEM_ReleaseLock( HSEM, CFG_HW_RCC_SEMID, 0 ); return; } /** * @brief Switch the system clock on HSI * @param none * @retval none */ static void Switch_On_HSI( void ) { LL_RCC_HSI_Enable( ); while(!LL_RCC_HSI_IsReady( )); LL_RCC_SetSysClkSource( LL_RCC_SYS_CLKSOURCE_HSI ); LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI); while (LL_RCC_GetSysClkSource( ) != LL_RCC_SYS_CLKSOURCE_STATUS_HSI); return; } /* USER CODE BEGIN Private_Functions */ /* USER CODE END Private_Functions */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/