2014-12-02 06:50:07 +00:00
/* mbed Microcontroller Library
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2018-03-28 13:00:53 +00:00
* Copyright ( c ) 2018 , STMicroelectronics
2014-12-02 06:50:07 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
# if DEVICE_SLEEP
2017-02-21 16:43:22 +00:00
# include "sleep_api.h"
2018-03-28 13:00:53 +00:00
# include "us_ticker_api.h"
2018-06-20 12:58:57 +00:00
# include "us_ticker_data.h"
2018-03-28 13:00:53 +00:00
# include "mbed_critical.h"
# include "mbed_error.h"
2014-12-02 06:50:07 +00:00
2018-07-04 14:44:00 +00:00
extern void save_timer_ctx ( void ) ;
extern void restore_timer_ctx ( void ) ;
2019-02-08 12:30:10 +00:00
extern void SetSysClock ( void ) ;
2014-12-02 06:50:07 +00:00
2018-04-06 13:18:16 +00:00
/* Wait loop - assuming tick is 1 us */
static void wait_loop ( uint32_t timeout )
{
uint32_t t1 , t2 , elapsed = 0 ;
t1 = us_ticker_read ( ) ;
do {
t2 = us_ticker_read ( ) ;
elapsed = ( t2 > t1 ) ? ( t2 - t1 ) : ( ( uint64_t ) t2 + 0xFFFFFFFF - t1 + 1 ) ;
} while ( elapsed < timeout ) ;
return ;
}
2018-06-18 14:35:42 +00:00
static void ForcePeriphOutofDeepSleep ( void )
2018-04-06 15:03:53 +00:00
{
2018-03-28 13:37:45 +00:00
uint32_t pFLatency = 0 ;
2018-06-18 14:35:42 +00:00
RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 } ;
2018-03-28 13:37:45 +00:00
/* Get the Clocks configuration according to the internal RCC registers */
HAL_RCC_GetClockConfig ( & RCC_ClkInitStruct , & pFLatency ) ;
# ifdef RCC_CLOCKTYPE_PCLK2
2018-06-27 12:21:07 +00:00
RCC_ClkInitStruct . ClockType = ( RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 ) ;
2018-03-28 13:37:45 +00:00
RCC_ClkInitStruct . APB2CLKDivider = RCC_HCLK_DIV1 ;
2018-11-23 17:03:25 +00:00
# else /* RCC_CLOCKTYPE_PCLK2 */
2018-06-27 12:21:07 +00:00
RCC_ClkInitStruct . ClockType = ( RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 ) ;
2018-11-23 17:03:25 +00:00
# endif /* RCC_CLOCKTYPE_PCLK2 */
# if defined (RCC_SYSCLKSOURCE_MSI) /* STM32Lx */
RCC_ClkInitStruct . SYSCLKSource = RCC_SYSCLKSOURCE_MSI ;
# else /* defined RCC_SYSCLKSOURCE_MSI */
2018-03-28 13:37:45 +00:00
RCC_ClkInitStruct . SYSCLKSource = RCC_SYSCLKSOURCE_HSI ;
2018-11-23 17:03:25 +00:00
# endif /* defined RCC_SYSCLKSOURCE_MSI */
RCC_ClkInitStruct . AHBCLKDivider = RCC_SYSCLK_DIV1 ;
RCC_ClkInitStruct . APB1CLKDivider = RCC_HCLK_DIV1 ;
2018-03-28 13:37:45 +00:00
if ( HAL_RCC_ClockConfig ( & RCC_ClkInitStruct , pFLatency ) ! = HAL_OK ) {
2018-11-23 17:03:25 +00:00
error ( " ForcePeriphOutofDeepSleep clock issue \r \n " ) ;
2018-03-28 13:37:45 +00:00
}
}
2018-11-23 17:03:25 +00:00
2018-06-18 14:35:42 +00:00
static void ForceOscOutofDeepSleep ( void )
{
RCC_OscInitTypeDef RCC_OscInitStruct = { 0 } ;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE ( ) ;
/* Get the Oscillators configuration according to the internal RCC registers */
HAL_RCC_GetOscConfig ( & RCC_OscInitStruct ) ;
2018-11-23 17:03:25 +00:00
# if defined (RCC_SYSCLKSOURCE_MSI) /* STM32Lx */
2018-06-18 14:35:42 +00:00
RCC_OscInitStruct . OscillatorType = RCC_OSCILLATORTYPE_MSI ;
RCC_OscInitStruct . MSIState = RCC_MSI_ON ;
RCC_OscInitStruct . MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT ;
2020-01-07 16:58:53 +00:00
# if defined RCC_MSIRANGE_11
RCC_OscInitStruct . MSIClockRange = RCC_MSIRANGE_11 ; // Highest freq, 48MHz range
# else
RCC_OscInitStruct . MSIClockRange = RCC_MSIRANGE_6 ; // 4MHz range
# endif
2018-06-18 14:35:42 +00:00
RCC_OscInitStruct . PLL . PLLState = RCC_PLL_NONE ;
2018-11-23 17:03:25 +00:00
# else /* defined RCC_SYSCLKSOURCE_MSI */
2018-06-18 14:35:42 +00:00
RCC_OscInitStruct . OscillatorType = RCC_OSCILLATORTYPE_HSI ;
RCC_OscInitStruct . HSIState = RCC_HSI_ON ;
RCC_OscInitStruct . HSICalibrationValue = 16 ;
RCC_OscInitStruct . PLL . PLLState = RCC_PLL_NONE ;
2018-11-23 17:03:25 +00:00
# endif /* defined RCC_SYSCLKSOURCE_MSI */
2018-06-18 14:35:42 +00:00
if ( HAL_RCC_OscConfig ( & RCC_OscInitStruct ) ! = HAL_OK ) {
2018-11-23 17:03:25 +00:00
error ( " ForceOscOutofDeepSleep clock issue \r \n " ) ;
2018-06-18 14:35:42 +00:00
}
2019-11-22 15:01:52 +00:00
2018-06-18 14:35:42 +00:00
}
2017-01-18 13:56:36 +00:00
void hal_sleep ( void )
2016-11-23 15:41:32 +00:00
{
2017-07-25 09:30:05 +00:00
// Disable IRQs
core_util_critical_section_enter ( ) ;
2014-12-02 06:50:07 +00:00
// Request to enter SLEEP mode
2019-11-27 13:25:30 +00:00
# if defined(PWR_CR1_LPR)
2018-08-13 07:21:31 +00:00
// State Transitions (see 5.3 Low-power modes, Fig. 13):
// * (opt): Low Power Run (LPR) Mode -> Run Mode
// * Run Mode -> Sleep
// --- Wait for Interrupt --
// * Sleep -> Run Mode
// * (opt): Run Mode -> Low Power Run Mode
// [5.4.1 Power control register 1 (PWR_CR1)]
2018-11-23 17:03:25 +00:00
// LPR: When this bit is set, the regulator is switched from main mode (MR) to low-power mode (LPR).
2019-11-27 13:25:30 +00:00
uint32_t lowPowerMode = LL_PWR_IsEnabledLowPowerRunMode ( ) ;
if ( lowPowerMode ) {
HAL_PWR_EnterSLEEPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_SLEEPENTRY_WFI ) ;
} else {
HAL_PWR_EnterSLEEPMode ( PWR_MAINREGULATOR_ON , PWR_SLEEPENTRY_WFI ) ;
}
# elif defined(PWR_CR_LPDS) || defined(PWR_CR1_LPDS)
uint32_t lowPowerMode = LL_PWR_GetRegulModeDS ( ) ;
2018-08-13 07:21:31 +00:00
if ( lowPowerMode ) {
2018-09-26 06:54:13 +00:00
HAL_PWR_EnterSLEEPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_SLEEPENTRY_WFI ) ;
2018-10-15 08:19:42 +00:00
} else {
HAL_PWR_EnterSLEEPMode ( PWR_MAINREGULATOR_ON , PWR_SLEEPENTRY_WFI ) ;
2018-08-13 07:21:31 +00:00
}
# else
2014-12-02 06:50:07 +00:00
HAL_PWR_EnterSLEEPMode ( PWR_MAINREGULATOR_ON , PWR_SLEEPENTRY_WFI ) ;
2018-08-13 07:21:31 +00:00
# endif
2017-07-25 09:30:05 +00:00
// Enable IRQs
core_util_critical_section_exit ( ) ;
2014-12-02 06:50:07 +00:00
}
2018-08-07 11:42:46 +00:00
extern int serial_is_tx_ongoing ( void ) ;
2018-09-14 12:20:54 +00:00
extern int mbed_sdk_inited ;
2018-08-06 15:57:24 +00:00
2019-02-08 12:30:10 +00:00
/* Most of STM32 targets can have the same generic deep sleep
* function , but a few targets might need very specific sleep
* mode management , so this function is defined as WEAK .
* Check for alternative hal_deepsleep specific implementation
* in targets folders in case of doubt */
__WEAK void hal_deepsleep ( void )
2014-12-02 06:50:07 +00:00
{
2018-08-06 15:57:24 +00:00
/* WORKAROUND:
* MBED serial driver does not handle deepsleep lock
* to prevent entering deepsleep until HW serial FIFO is empty .
* This is tracked in mbed issue 4408.
* For now , we ' re checking all Serial HW FIFO . If any transfer is ongoing
* we ' re not entering deep sleep and returning immediately . */
2018-11-23 17:03:25 +00:00
if ( serial_is_tx_ongoing ( ) ) {
2018-08-06 15:57:24 +00:00
return ;
}
2017-07-25 09:30:05 +00:00
// Disable IRQs
core_util_critical_section_enter ( ) ;
2018-07-04 14:44:00 +00:00
save_timer_ctx ( ) ;
2016-11-23 15:41:32 +00:00
2014-12-02 06:50:07 +00:00
// Request to enter STOP mode with regulator in low power mode
2018-11-23 17:03:25 +00:00
# ifdef PWR_CR1_LPMS_STOP2 /* STM32L4 */
2017-01-31 10:44:41 +00:00
int pwrClockEnabled = __HAL_RCC_PWR_IS_CLK_ENABLED ( ) ;
int lowPowerModeEnabled = PWR - > CR1 & PWR_CR1_LPR ;
2017-11-07 16:50:56 +00:00
2017-02-07 21:24:20 +00:00
if ( ! pwrClockEnabled ) {
2017-01-09 11:21:24 +00:00
__HAL_RCC_PWR_CLK_ENABLE ( ) ;
2017-02-07 21:24:20 +00:00
}
if ( lowPowerModeEnabled ) {
2017-01-09 11:21:24 +00:00
HAL_PWREx_DisableLowPowerRunMode ( ) ;
2017-02-07 21:24:20 +00:00
}
2017-11-07 16:50:56 +00:00
2017-01-31 10:44:41 +00:00
HAL_PWREx_EnterSTOP2Mode ( PWR_STOPENTRY_WFI ) ;
2017-11-07 16:50:56 +00:00
2017-02-07 21:24:20 +00:00
if ( lowPowerModeEnabled ) {
2017-01-31 10:44:41 +00:00
HAL_PWREx_EnableLowPowerRunMode ( ) ;
2017-02-07 21:24:20 +00:00
}
if ( ! pwrClockEnabled ) {
2017-01-09 11:21:24 +00:00
__HAL_RCC_PWR_CLK_DISABLE ( ) ;
2017-02-07 21:24:20 +00:00
}
2019-11-18 17:13:09 +00:00
# elif defined(DUAL_CORE)
int lowPowerModeEnabled = LL_PWR_GetRegulModeDS ( ) ;
# if defined(CORE_CM7)
HAL_PWREx_EnterSTOPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_STOPENTRY_WFI , PWR_D3_DOMAIN ) ;
HAL_PWREx_EnterSTOPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_STOPENTRY_WFI , PWR_D1_DOMAIN ) ;
# elif defined(CORE_CM4)
HAL_PWREx_EnterSTOPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_STOPENTRY_WFI , PWR_D3_DOMAIN ) ;
HAL_PWREx_EnterSTOPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_STOPENTRY_WFI , PWR_D2_DOMAIN ) ;
# else
# error "Wrong Core selection"
# endif /* CORE_CM7 */
if ( lowPowerModeEnabled ) {
LL_PWR_SetRegulModeDS ( lowPowerModeEnabled ) ;
}
2018-11-23 17:03:25 +00:00
# else /* PWR_CR1_LPMS_STOP2 */
2014-12-02 06:50:07 +00:00
HAL_PWR_EnterSTOPMode ( PWR_LOWPOWERREGULATOR_ON , PWR_STOPENTRY_WFI ) ;
2018-11-23 17:03:25 +00:00
# endif /* PWR_CR1_LPMS_STOP2 */
2018-07-04 14:44:00 +00:00
2018-09-14 12:20:54 +00:00
/* Prevent HAL_GetTick() from using ticker_read_us() to read the
* us_ticker timestamp until the us_ticker context is restored . */
mbed_sdk_inited = 0 ;
2019-11-18 17:13:09 +00:00
/* After wake-up from STOP reconfigure the PLL */
# if defined(DUAL_CORE)
2019-11-22 15:01:52 +00:00
/* CFG_HW_STOP_MODE_SEMID is used to protect read access to STOP flag, and this avoid both core to configure clocks if both exit from stop at the same time */
while ( LL_HSEM_1StepLock ( HSEM , CFG_HW_STOP_MODE_SEMID ) ) {
2019-11-18 17:13:09 +00:00
}
2019-11-22 15:01:52 +00:00
/* Clocks need to be reconfigured only if system has been in stop mode */
if ( LL_PWR_CPU_IsActiveFlag_STOP ( ) & & LL_PWR_CPU2_IsActiveFlag_STOP ( ) ) {
/* We've seen unstable PLL CLK configuration when DEEP SLEEP exits just few µs after being entered
* So we need to force clock init out of Deep Sleep .
* This init has been split into 2 separate functions so that the involved structures are not allocated on the stack in parallel .
* This will reduce the maximum stack usage in case on non - optimized / debug compilers settings
*/
while ( LL_HSEM_1StepLock ( HSEM , CFG_HW_RCC_SEMID ) ) {
}
ForceOscOutofDeepSleep ( ) ;
ForcePeriphOutofDeepSleep ( ) ;
2019-11-18 17:13:09 +00:00
SetSysClock ( ) ;
2019-11-22 15:01:52 +00:00
LL_HSEM_ReleaseLock ( HSEM , CFG_HW_RCC_SEMID , HSEM_CR_COREID_CURRENT ) ;
2019-11-18 17:13:09 +00:00
}
2019-11-22 15:01:52 +00:00
# if defined(CORE_CM7)
LL_PWR_ClearFlag_CPU ( ) ;
# elif defined(CORE_CM4)
LL_PWR_ClearFlag_CPU2 ( ) ;
2019-11-18 17:13:09 +00:00
# else
2019-11-22 15:01:52 +00:00
# error "Core not supported"
# endif
LL_HSEM_ReleaseLock ( HSEM , CFG_HW_STOP_MODE_SEMID , HSEM_CR_COREID_CURRENT ) ;
# else
/* We've seen unstable PLL CLK configuration when DEEP SLEEP exits just few µs after being entered
* So we need to force clock init out of Deep Sleep .
* This init has been split into 2 separate functions so that the involved structures are not allocated on the stack in parallel .
* This will reduce the maximum stack usage in case on non - optimized / debug compilers settings
*/
ForceOscOutofDeepSleep ( ) ;
ForcePeriphOutofDeepSleep ( ) ;
2014-12-02 06:50:07 +00:00
SetSysClock ( ) ;
2019-11-18 17:13:09 +00:00
# endif
2016-11-23 15:41:32 +00:00
2018-04-06 13:18:16 +00:00
/* Wait for clock to be stabilized.
* TO DO : a better way of doing this , would be to rely on
* HW Flag . At least this ensures proper operation out of
* deep sleep */
wait_loop ( 500 ) ;
2019-02-08 12:30:10 +00:00
2018-07-04 14:44:00 +00:00
restore_timer_ctx ( ) ;
2017-02-10 16:01:36 +00:00
2018-09-14 12:20:54 +00:00
/* us_ticker context restored, allow HAL_GetTick() to read the us_ticker
* timestamp via ticker_read_us ( ) again . */
mbed_sdk_inited = 1 ;
2018-03-28 13:37:45 +00:00
// Enable IRQs
2018-06-27 12:21:07 +00:00
core_util_critical_section_exit ( ) ;
2014-12-02 06:50:07 +00:00
}
# endif