Modified for BG96
Fork of mbed-dev by
Diff: targets/TARGET_STM/sleep.c
- Revision:
- 186:707f6e361f3e
- Parent:
- 181:57724642e740
- Child:
- 187:0387e8f68319
diff -r 08ed48f1de7f -r 707f6e361f3e targets/TARGET_STM/sleep.c --- a/targets/TARGET_STM/sleep.c Thu Apr 19 17:12:19 2018 +0100 +++ b/targets/TARGET_STM/sleep.c Fri Jun 22 16:45:37 2018 +0100 @@ -1,6 +1,6 @@ /* mbed Microcontroller Library ******************************************************************************* - * Copyright (c) 2016, STMicroelectronics + * Copyright (c) 2018, STMicroelectronics * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,22 +30,115 @@ #if DEVICE_SLEEP #include "sleep_api.h" -#include "rtc_api_hal.h" +#include "us_ticker_api.h" +#include "hal_tick.h" +#include "mbed_critical.h" +#include "mbed_error.h" + +extern void rtc_synchronize(void); + +/* 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; +} + +// On L4 platforms we've seen unstable PLL CLK configuraiton +// when DEEP SLEEP exits just few µs after being entered +// So we need to force MSI usage before setting clocks again +static void ForceClockOutofDeepSleep(void) +{ + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + uint32_t pFLatency = 0; + + /* Enable Power Control clock */ + __HAL_RCC_PWR_CLK_ENABLE(); + +#ifdef PWR_FLAG_VOS + /* Poll VOSF bit of in PWR_CSR. Wait until it is reset to 0 */ + //while (__HAL_PWR_GET_FLAG(PWR_FLAG_VOS) != RESET) {}; +#endif + + /* Get the Oscillators configuration according to the internal RCC registers */ + HAL_RCC_GetOscConfig(&RCC_OscInitStruct); + +#if (TARGET_STM32L4 || TARGET_STM32L1) /* MSI used for L4 */ + /**Initializes the CPU, AHB and APB busses clocks + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; + RCC_OscInitStruct.MSIState = RCC_MSI_ON; + RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; + RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_4; // Intermediate freq, 1MHz range + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + error("clock issue\r\n"); + } -extern void HAL_SuspendTick(void); -extern void HAL_ResumeTick(void); + /* Get the Clocks configuration according to the internal RCC registers */ + HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency); + + // Select HSI ss system clock source as a first step +#ifdef RCC_CLOCKTYPE_PCLK2 + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK + | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; +#else + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK + | RCC_CLOCKTYPE_PCLK1); +#endif + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK) { + error("clock issue\r\n"); + } +#else /* HSI used on others */ + /**Initializes the CPU, AHB and APB busses clocks + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = 16; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { + error("clock issue"); + } + + /* Get the Clocks configuration according to the internal RCC registers */ + HAL_RCC_GetClockConfig(&RCC_ClkInitStruct, &pFLatency); + + /**Initializes the CPU, AHB and APB busses clocks + */ +#ifdef RCC_CLOCKTYPE_PCLK2 + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; +#else + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1); +#endif + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, pFLatency) != HAL_OK) { + error("clock issue"); + } +#endif // TARGET_STM32L4 +} void hal_sleep(void) { // Disable IRQs core_util_critical_section_enter(); - // Stop HAL tick to avoid to exit sleep in 1ms - HAL_SuspendTick(); // Request to enter SLEEP mode HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI); - // Restart HAL tick - HAL_ResumeTick(); // Enable IRQs core_util_critical_section_exit(); @@ -56,8 +149,6 @@ // Disable IRQs core_util_critical_section_enter(); - // Stop HAL tick - HAL_SuspendTick(); uint32_t EnterTimeUS = us_ticker_read(); // Request to enter STOP mode with regulator in low power mode @@ -83,16 +174,18 @@ #else /* TARGET_STM32L4 */ HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); #endif /* TARGET_STM32L4 */ - - // Restart HAL tick - HAL_ResumeTick(); - - // Enable IRQs - core_util_critical_section_exit(); + // Verify Clock Out of Deep Sleep + ForceClockOutofDeepSleep(); // After wake-up from STOP reconfigure the PLL SetSysClock(); + /* 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); + TIM_HandleTypeDef TimMasterHandle; TimMasterHandle.Instance = TIM_MST; __HAL_TIM_SET_COUNTER(&TimMasterHandle, EnterTimeUS); @@ -107,6 +200,8 @@ rtc_synchronize(); } #endif + // Enable IRQs + core_util_critical_section_exit(); } #endif