Skip to content

Commit c6c532c

Browse files
committed
NUCLEO_WB55RG: Rework Clock and sleep support
- move hw_conf.h file to targets/TARGET_STM/TARGET_STM32WB directory as this is used also out of BLE feature. - create a dedicated hal_deepsleep function as the behavior in WB is a lot different from other existing STM32 targets - update clock tree configuration to directly clock the entire tree @ 32MHz out of HSE. This is needed as we want to let the M0 core running without any change on M0-side of clocks when M4 enters /exits deep sleep.
1 parent 4cf4fca commit c6c532c

File tree

6 files changed

+241
-70
lines changed

6 files changed

+241
-70
lines changed

targets/TARGET_STM/TARGET_STM32WB/TARGET_STM32WB55xG/TARGET_NUCLEO_WB55RG/system_clock.c

Lines changed: 31 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,23 @@
1717
/**
1818
* This file configures the system clock as follows:
1919
*-----------------------------------------------------------------------------
20-
* System clock source | 1- USE_PLL_HSE_EXTC (external 8 MHz clock)
20+
* System clock source | 1- USE_PLL_HSE_EXTC (external 32 MHz clock)
2121
* | 2- USE_PLL_HSE_XTAL (external 8 MHz xtal)
2222
* | 3- USE_PLL_HSI (internal 16 MHz)
2323
* | 4- USE_PLL_MSI (internal 100kHz to 48 MHz)
2424
*-----------------------------------------------------------------------------
25-
* SYSCLK(MHz) | 64
26-
* AHBCLK (MHz) | 64
27-
* APB1CLK (MHz) | 64
28-
* APB2CLK (MHz) | 64
25+
* SYSCLK(MHz) | 32
26+
* AHBCLK (MHz) | 32
27+
* APB1CLK (MHz) | 32
28+
* APB2CLK (MHz) | 32
2929
* USB capable | NO // todo
3030
*-----------------------------------------------------------------------------
3131
**/
3232

3333
#include "stm32wbxx.h"
3434
#include "mbed_error.h"
35+
#include "stm32wbxx_ll_hsem.h"
36+
#include "hw_conf.h" /* Common BLE file where BLE shared resources are defined */
3537

3638
// Clock source is selected with CLOCK_SOURCE in json config
3739
#define USE_PLL_HSE_EXTC 0x8 // Use external clock (not available)
@@ -65,6 +67,7 @@ void Configure_RF_Clock_Sources(void);
6567

6668
void SetSysClock(void)
6769
{
70+
while( LL_HSEM_1StepLock( HSEM, CFG_HW_RCC_SEMID ) );
6871
#if ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC)
6972
/* 1- Try to start with HSE and external clock */
7073
if (SetSysClock_PLL_HSE(1) == 0)
@@ -99,6 +102,7 @@ void SetSysClock(void)
99102
#if DEBUG_MCO == 1
100103
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1); // 64 MHz
101104
#endif
105+
LL_HSEM_ReleaseLock( HSEM, CFG_HW_RCC_SEMID, 0 );
102106
}
103107

104108
#if (((CLOCK_SOURCE) & USE_PLL_HSE_XTAL) || ((CLOCK_SOURCE) & USE_PLL_HSE_EXTC))
@@ -107,64 +111,31 @@ void SetSysClock(void)
107111
/******************************************************************************/
108112
uint8_t SetSysClock_PLL_HSE(uint8_t bypass)
109113
{
110-
// System is fully clocked @ 32MHz from HSE
111-
//return 1;
114+
LL_RCC_HSE_Enable();
112115

113-
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
114-
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
115-
116-
#if MBED_CONF_TARGET_LSE_AVAILABLE
117-
// Enable LSE Oscillator to automatically calibrate the MSI clock
118-
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
119-
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // No PLL update
120-
RCC_OscInitStruct.LSEState = RCC_LSE_ON; // External 32.768 kHz clock on OSC_IN/OSC_OUT
121-
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
122-
return 0; // FAIL
123-
}
124-
125-
/* Enable the CSS interrupt in case LSE signal is corrupted or not present */
126-
HAL_RCCEx_DisableLSECSS();
127-
#endif /* MBED_CONF_TARGET_LSE_AVAILABLE */
128-
129-
130-
// HSE has been turned on during system init
131-
// Enable HSE oscillator and activate PLL with HSE as source
132-
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
133-
if (bypass == 0) {
134-
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // External 8 MHz xtal on OSC_IN/OSC_OUT
135-
} else {
136-
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS; // External 32 MHz clock on OSC_IN
137-
}
138-
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // 32 MHz
139-
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
140-
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV8; // 4 MHz
141-
RCC_OscInitStruct.PLL.PLLN = 32; // 128 MHz
142-
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; // 64 MHz // RCC_SYSCLKSOURCE_PLLCLK
143-
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV5;
144-
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV4;
145-
146-
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
147-
return 0; // FAIL
148-
}
149-
150-
// Select PLL as system clock source and configure the clocks dividers
151-
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_HCLK2 | RCC_CLOCKTYPE_HCLK4 | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
152-
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 64 MHz
153-
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 64 MHz
154-
RCC_ClkInitStruct.AHBCLK2Divider = RCC_SYSCLK_DIV2; // 32 MHz
155-
RCC_ClkInitStruct.AHBCLK4Divider = RCC_SYSCLK_DIV1; // 64 MHz
156-
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; // 64 MHz
157-
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 64 MHz
116+
/**
117+
* Switch to HSE as Sys clok source
118+
* All Peripehrals (HCLK, HCLK2, HCLK4, PCLK1, PCLK2) will be clocked
119+
* @ 32MHZ. This is not optimal but a stable setting for enter and exit
120+
* deep sleep mode (STOP mode).
121+
*
122+
*/
123+
while(!LL_RCC_HSE_IsReady());
124+
LL_RCC_SetSysClkSource( LL_RCC_SYS_CLKSOURCE_HSE );
125+
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
158126

159-
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) {
160-
return 0; // FAIL
161-
}
127+
/**
128+
* Set RNG on HSI48
129+
*/
130+
LL_RCC_HSI48_Enable();
131+
while (!LL_RCC_HSI48_IsReady());
132+
LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_HSI48);
162133

163-
// Disable MSI Oscillator
164-
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
165-
RCC_OscInitStruct.MSIState = RCC_MSI_OFF;
166-
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // No PLL update
167-
HAL_RCC_OscConfig(&RCC_OscInitStruct);
134+
/**
135+
* Switch OFF MSI and HSI
136+
*/
137+
LL_RCC_MSI_Disable();
138+
LL_RCC_HSI_Disable();
168139

169140
// Output clock on MCO1 pin(PA8) for debugging purpose
170141
#if DEBUG_MCO == 2
@@ -327,12 +298,5 @@ void Configure_RF_Clock_Sources(void)
327298
*/
328299
LL_RCC_LSI1_Disable();
329300

330-
/**
331-
* Set RNG on HSI48
332-
*/
333-
LL_RCC_HSI48_Enable();
334-
while (!LL_RCC_HSI48_IsReady());
335-
LL_RCC_SetCLK48ClockSource(LL_RCC_CLK48_CLKSOURCE_HSI48);
336-
337301
return;
338302
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/* mbed Microcontroller Library
2+
*******************************************************************************
3+
* Copyright (c) 2019, STMicroelectronics
4+
* All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions are met:
8+
*
9+
* 1. Redistributions of source code must retain the above copyright notice,
10+
* this list of conditions and the following disclaimer.
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
* 3. Neither the name of STMicroelectronics nor the names of its contributors
15+
* may be used to endorse or promote products derived from this software
16+
* without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
*******************************************************************************
29+
*/
30+
#if DEVICE_SLEEP
31+
32+
#include "sleep_api.h"
33+
#include "us_ticker_api.h"
34+
#include "us_ticker_data.h"
35+
#include "mbed_critical.h"
36+
#include "mbed_error.h"
37+
#include "stm32wbxx_ll_hsem.h"
38+
#include "stm32wbxx_ll_cortex.h"
39+
#include "hw_conf.h" /* Common BLE file where BLE shared resources are defined */
40+
41+
extern void save_timer_ctx(void);
42+
extern void restore_timer_ctx(void);
43+
extern int serial_is_tx_ongoing(void);
44+
extern int mbed_sdk_inited;
45+
extern void SetSysClock(void);
46+
47+
static void Switch_On_HSI( void )
48+
{
49+
LL_RCC_HSI_Enable();
50+
while(!LL_RCC_HSI_IsReady());
51+
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
52+
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI);
53+
54+
return;
55+
}
56+
57+
static void LPM_EnterStopMode(void)
58+
{
59+
/**
60+
* This function is called from CRITICAL SECTION
61+
*/
62+
63+
while( LL_HSEM_1StepLock( HSEM, CFG_HW_RCC_SEMID ) );
64+
65+
if ( ! LL_HSEM_1StepLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID ) )
66+
{
67+
if( LL_PWR_IsActiveFlag_C2DS() )
68+
{
69+
/* Release ENTRY_STOP_MODE semaphore */
70+
LL_HSEM_ReleaseLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0 );
71+
72+
Switch_On_HSI();
73+
}
74+
}
75+
else
76+
{
77+
Switch_On_HSI();
78+
}
79+
80+
/* Release RCC semaphore */
81+
LL_HSEM_ReleaseLock( HSEM, CFG_HW_RCC_SEMID, 0 );
82+
83+
return;
84+
}
85+
86+
static void LPM_ExitStopMode(void)
87+
{
88+
/**
89+
* This function is called from CRITICAL SECTION
90+
*/
91+
92+
/* Release ENTRY_STOP_MODE semaphore */
93+
LL_HSEM_ReleaseLock( HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0 );
94+
95+
if( (LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI) || (LL_PWR_IsActiveFlag_C1STOP() != 0) )
96+
{
97+
LL_PWR_ClearFlag_C1STOP_C1STB();
98+
99+
while( LL_HSEM_1StepLock( HSEM, CFG_HW_RCC_SEMID ) );
100+
101+
if(LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
102+
{
103+
LL_RCC_HSE_Enable();
104+
while(!LL_RCC_HSE_IsReady());
105+
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
106+
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE);
107+
}
108+
else
109+
{
110+
/**
111+
* As long as the current application is fine with HSE as system clock source,
112+
* there is nothing to do here
113+
*/
114+
}
115+
116+
/* Release RCC semaphore */
117+
LL_HSEM_ReleaseLock( HSEM, CFG_HW_RCC_SEMID, 0 );
118+
}
119+
120+
return;
121+
}
122+
123+
void HW_LPM_StopMode(void)
124+
{
125+
LL_PWR_SetPowerMode(LL_PWR_MODE_STOP2);
126+
127+
LL_LPM_EnableDeepSleep(); /**< Set SLEEPDEEP bit of Cortex System Control Register */
128+
129+
/**
130+
* This option is used to ensure that store operations are completed
131+
*/
132+
#if defined ( __CC_ARM)
133+
__force_stores();
134+
#endif
135+
136+
__WFI();
137+
138+
return;
139+
}
140+
141+
/* STM32WB has very specific needs to handling STOP mode.
142+
* The target has a cortex-M4 and cortex-M0 and needs to
143+
* handle shared ressources btw both cores.
144+
* Each core can sleep independantly, but the first one that
145+
* wkaes-up needs to restore the clock tree.
146+
*/
147+
void hal_deepsleep(void)
148+
{
149+
/* WORKAROUND:
150+
* MBED serial driver does not handle deepsleep lock
151+
* to prevent entering deepsleep until HW serial FIFO is empty.
152+
* This is tracked in mbed issue 4408.
153+
* For now, we're checking all Serial HW FIFO. If any transfer is ongoing
154+
* we're not entering deep sleep and returning immediately. */
155+
if (serial_is_tx_ongoing()) {
156+
return;
157+
}
158+
159+
// Disable IRQs
160+
core_util_critical_section_enter();
161+
162+
save_timer_ctx();
163+
164+
/* Prevent HAL_GetTick() from using ticker_read_us() to read the
165+
* us_ticker timestamp until the us_ticker context is restored. */
166+
mbed_sdk_inited = 0;
167+
168+
/**
169+
* Enter the STOP mode
170+
*/
171+
LPM_EnterStopMode();
172+
HW_LPM_StopMode();
173+
LPM_ExitStopMode();
174+
175+
/* After wake-up from STOP reconfigure the whole clock tree */
176+
SetSysClock();
177+
178+
restore_timer_ctx();
179+
180+
/* us_ticker context restored, allow HAL_GetTick() to read the us_ticker
181+
* timestamp via ticker_read_us() again. */
182+
mbed_sdk_inited = 1;
183+
184+
// Enable IRQs
185+
core_util_critical_section_exit();
186+
}
187+
188+
189+
#endif

targets/TARGET_STM/lp_ticker.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ void lp_ticker_init(void)
139139
#endif /* MBED_CONF_TARGET_LPTICKER_LPTIM_CLOCK */
140140

141141
LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
142+
#if defined (LPTIM_ACTIVEEDGE_FALLING)
143+
LptimHandle.Init.Trigger.ActiveEdge = LPTIM_ACTIVEEDGE_FALLING;
144+
#endif
145+
#if defined (LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION)
146+
LptimHandle.Init.Trigger.SampleTime = LPTIM_TRIGSAMPLETIME_DIRECTTRANSITION;
147+
#endif
148+
142149
LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
143150
LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
144151
LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;

targets/TARGET_STM/sleep.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
extern void save_timer_ctx(void);
3939
extern void restore_timer_ctx(void);
40+
extern void SetSysClock(void);
4041

4142
/* Wait loop - assuming tick is 1 us */
4243
static void wait_loop(uint32_t timeout)
@@ -145,7 +146,12 @@ void hal_sleep(void)
145146
extern int serial_is_tx_ongoing(void);
146147
extern int mbed_sdk_inited;
147148

148-
void hal_deepsleep(void)
149+
/* Most of STM32 targets can have the same generic deep sleep
150+
* function, but a few targets might need very specific sleep
151+
* mode management, so this function is defined as WEAK.
152+
* Check for alternative hal_deepsleep specific implementation
153+
* in targets folders in case of doubt */
154+
__WEAK void hal_deepsleep(void)
149155
{
150156
/* WORKAROUND:
151157
* MBED serial driver does not handle deepsleep lock
@@ -207,6 +213,7 @@ void hal_deepsleep(void)
207213
* deep sleep */
208214
wait_loop(500);
209215

216+
210217
restore_timer_ctx();
211218

212219
/* us_ticker context restored, allow HAL_GetTick() to read the us_ticker

0 commit comments

Comments
 (0)