Skip to content

Commit a816e93

Browse files
committed
STM32 LOWPOWERTIMER : introduce LPTIM feature
STM32L0, L4, F7 and few F4 chip are supporting LPTIM feature. We propose to allow user to use LPTIM for MBED LowPowerTimer API instead of using RTC wakeup timers. By default, all targets that are supporting this feature have been configured.
1 parent a5f1426 commit a816e93

File tree

5 files changed

+350
-15
lines changed

5 files changed

+350
-15
lines changed

targets/TARGET_STM/lp_ticker.c

Lines changed: 255 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,264 @@
2727
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828
*******************************************************************************
2929
*/
30-
#include "device.h"
3130

3231
#if DEVICE_LOWPOWERTIMER
3332

3433
#include "rtc_api_hal.h"
3534

35+
#if MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM
36+
37+
LPTIM_HandleTypeDef LptimHandle;
38+
39+
volatile uint32_t lp_SlaveCounter = 0;
40+
volatile uint32_t lp_oc_int_part = 0;
41+
volatile uint16_t lp_TickPeriod_us;
42+
volatile uint8_t lp_Fired = 0;
43+
44+
static void LPTIM1_IRQHandler(void);
45+
static void (*irq_handler)(void);
46+
47+
48+
void lp_ticker_init(void)
49+
{
50+
/* Check if LPTIM is already configured */
51+
#if (TARGET_STM32L0)
52+
if (READ_BIT(RCC->APB1ENR, RCC_APB1ENR_LPTIM1EN) != RESET) {
53+
return;
54+
}
55+
#else
56+
if (__HAL_RCC_LPTIM1_IS_CLK_ENABLED()) {
57+
return;
58+
}
59+
#endif
60+
61+
RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct = {0};
62+
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
63+
64+
#if MBED_CONF_TARGET_LSE_AVAILABLE
65+
66+
/* Enable LSE clock */
67+
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
68+
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
69+
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
70+
71+
/* Select the LSE clock as LPTIM peripheral clock */
72+
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
73+
#if (TARGET_STM32L0)
74+
RCC_PeriphCLKInitStruct.LptimClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
75+
#else
76+
RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
77+
#endif
78+
79+
#else /* MBED_CONF_TARGET_LSE_AVAILABLE */
80+
81+
/* Enable LSI clock */
82+
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
83+
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
84+
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
85+
86+
/* Select the LSI clock as LPTIM peripheral clock */
87+
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
88+
#if (TARGET_STM32L0)
89+
RCC_PeriphCLKInitStruct.LptimClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
90+
#else
91+
RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
92+
#endif
93+
94+
#endif /* MBED_CONF_TARGET_LSE_AVAILABLE */
95+
96+
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
97+
error("HAL_RCC_OscConfig ERROR\n");
98+
return;
99+
}
100+
101+
if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) {
102+
error("HAL_RCCEx_PeriphCLKConfig ERROR\n");
103+
return;
104+
}
105+
106+
__HAL_RCC_LPTIM1_CLK_ENABLE();
107+
__HAL_RCC_LPTIM1_FORCE_RESET();
108+
__HAL_RCC_LPTIM1_RELEASE_RESET();
109+
110+
/* Initialize the LPTIM peripheral */
111+
LptimHandle.Instance = LPTIM1;
112+
LptimHandle.State = HAL_LPTIM_STATE_RESET;
113+
LptimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
114+
115+
/* Prescaler impact:
116+
tick period = Prescaler division factor / LPTIM clock
117+
Example with LPTIM clock = 32768 Hz LSE
118+
Prescaler = LPTIM_PRESCALER_DIV1 => lp_TickPeriod_us = 31us => 2s with 16b timer
119+
Prescaler = LPTIM_PRESCALER_DIV2 => lp_TickPeriod_us = 61us => 4s with 16b timer
120+
Prescaler = LPTIM_PRESCALER_DIV4 => lp_TickPeriod_us = 122us => 8s with 16b timer
121+
Prescaler = LPTIM_PRESCALER_DIV8 => lp_TickPeriod_us = 244us => 16s with 16b timer
122+
Prescaler = LPTIM_PRESCALER_DIV16 => lp_TickPeriod_us = 488us => 32s with 16b timer
123+
Prescaler = LPTIM_PRESCALER_DIV32 => lp_TickPeriod_us = 976us => 64s with 16b timer
124+
Prescaler = LPTIM_PRESCALER_DIV64 => lp_TickPeriod_us = 1.9ms => 128s with 16b timer
125+
Prescaler = LPTIM_PRESCALER_DIV128 => lp_TickPeriod_us = 3.9ms => 256s with 16b timer
126+
*/
127+
LptimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV2;
128+
lp_TickPeriod_us = 2 * 1000000 / RTC_CLOCK;
129+
130+
LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
131+
LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
132+
LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
133+
LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
134+
#if (TARGET_STM32L4)
135+
LptimHandle.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO;
136+
LptimHandle.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO;
137+
#endif /* TARGET_STM32L4 */
138+
139+
if (HAL_LPTIM_Init(&LptimHandle) != HAL_OK) {
140+
error("HAL_LPTIM_Init ERROR\n");
141+
return;
142+
}
143+
144+
NVIC_SetVector(LPTIM1_IRQn, (uint32_t)LPTIM1_IRQHandler);
145+
NVIC_EnableIRQ(LPTIM1_IRQn);
146+
147+
#if !(TARGET_STM32L4)
148+
/* EXTI lines are not configured by default */
149+
__HAL_LPTIM_WAKEUPTIMER_EXTI_ENABLE_IT();
150+
__HAL_LPTIM_WAKEUPTIMER_EXTI_ENABLE_RISING_EDGE();
151+
#endif
152+
153+
__HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_ARRM);
154+
__HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_CMPM);
155+
__HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_CMPOK);
156+
HAL_LPTIM_Counter_Start(&LptimHandle, 0xFFFF);
157+
}
158+
159+
static void LPTIM1_IRQHandler(void)
160+
{
161+
LptimHandle.Instance = LPTIM1;
162+
163+
if (lp_Fired) {
164+
lp_Fired = 0;
165+
if (irq_handler) {
166+
irq_handler();
167+
}
168+
}
169+
170+
/* Compare match interrupt */
171+
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPM) != RESET) {
172+
if (__HAL_LPTIM_GET_IT_SOURCE(&LptimHandle, LPTIM_IT_CMPM) != RESET) {
173+
/* Clear Compare match flag */
174+
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
175+
176+
if (lp_oc_int_part > 0) {
177+
lp_oc_int_part--;
178+
} else {
179+
if (irq_handler) {
180+
irq_handler();
181+
}
182+
}
183+
}
184+
}
185+
186+
/* Compare write interrupt */
187+
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK) != RESET) {
188+
if (__HAL_LPTIM_GET_IT_SOURCE(&LptimHandle, LPTIM_IT_CMPOK) != RESET) {
189+
/* Clear Compare write flag */
190+
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK);
191+
}
192+
}
193+
194+
/* Autoreload match interrupt */
195+
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_ARRM) != RESET) {
196+
if (__HAL_LPTIM_GET_IT_SOURCE(&LptimHandle, LPTIM_IT_ARRM) != RESET) {
197+
/* Clear Autoreload match flag */
198+
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_ARRM);
199+
lp_SlaveCounter++;
200+
}
201+
}
202+
203+
#if !(TARGET_STM32L4)
204+
__HAL_LPTIM_WAKEUPTIMER_EXTI_CLEAR_FLAG();
205+
#endif
206+
}
207+
208+
209+
uint32_t lp_ticker_read_TickCounter(void)
210+
{
211+
uint16_t cntH_old, cntH, cntL;
212+
213+
LptimHandle.Instance = LPTIM1;
214+
215+
/* same algo as us_ticker_read in us_ticker_16b.c */
216+
do {
217+
cntH_old = lp_SlaveCounter;
218+
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_ARRM) == SET) {
219+
cntH_old += 1;
220+
}
221+
cntL = LPTIM1->CNT;
222+
cntH = lp_SlaveCounter;
223+
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_ARRM) == SET) {
224+
cntH += 1;
225+
}
226+
} while (cntH_old != cntH);
227+
uint32_t lp_time = (uint32_t)(cntH << 16 | cntL);
228+
return lp_time;
229+
}
230+
231+
uint32_t lp_ticker_read(void)
232+
{
233+
lp_ticker_init();
234+
return lp_ticker_read_TickCounter() * (uint32_t)lp_TickPeriod_us;
235+
}
236+
237+
void lp_ticker_set_interrupt(timestamp_t timestamp)
238+
{
239+
// Disable IRQs
240+
core_util_critical_section_enter();
241+
242+
uint32_t timestamp_TickCounter = timestamp / (uint32_t)lp_TickPeriod_us;
243+
244+
LptimHandle.Instance = LPTIM1;
245+
irq_handler = (void (*)(void))lp_ticker_irq_handler;
246+
247+
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK);
248+
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
249+
__HAL_LPTIM_COMPARE_SET(&LptimHandle, timestamp_TickCounter & 0xFFFF);
250+
251+
/* CMPOK is set by hardware to inform application that the APB bus write operation to the LPTIM_CMP register has been successfully completed */
252+
while (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK) == RESET) {
253+
}
254+
255+
/* same algo as us_ticker_set_interrupt in us_ticker_16b.c */
256+
uint32_t current_time_TickCounter = lp_ticker_read_TickCounter();
257+
uint32_t delta = timestamp_TickCounter - current_time_TickCounter;
258+
lp_oc_int_part = (delta - 1) >> 16;
259+
if ( ((delta - 1) & 0xFFFF) >= 0x8000 &&
260+
__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPM) == SET ) {
261+
++lp_oc_int_part;
262+
}
263+
264+
// Enable IRQs
265+
core_util_critical_section_exit();
266+
}
267+
268+
void lp_ticker_fire_interrupt(void)
269+
{
270+
lp_Fired = 1;
271+
NVIC_SetPendingIRQ(LPTIM1_IRQn);
272+
}
273+
274+
void lp_ticker_disable_interrupt(void)
275+
{
276+
LptimHandle.Instance = LPTIM1;
277+
__HAL_LPTIM_DISABLE_IT(&LptimHandle, LPTIM_IT_CMPM);
278+
}
279+
280+
void lp_ticker_clear_interrupt(void)
281+
{
282+
LptimHandle.Instance = LPTIM1;
283+
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
284+
}
285+
286+
#else /* MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */
287+
36288
void lp_ticker_init(void)
37289
{
38290
rtc_init();
@@ -74,4 +326,6 @@ void lp_ticker_clear_interrupt(void)
74326
NVIC_ClearPendingIRQ(RTC_WKUP_IRQn);
75327
}
76328

329+
#endif /* MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */
330+
77331
#endif /* DEVICE_LOWPOWERTIMER */

targets/TARGET_STM/rtc_api.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,14 @@
3131
#if DEVICE_RTC
3232

3333
#include "rtc_api_hal.h"
34-
#include "mbed_error.h"
3534
#include "mbed_mktime.h"
3635

3736
static RTC_HandleTypeDef RtcHandle;
3837

39-
#if DEVICE_LOWPOWERTIMER
38+
#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM
4039
static void (*irq_handler)(void);
4140
static void RTC_IRQHandler(void);
42-
#endif
41+
#endif /* DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */
4342

4443
void rtc_init(void)
4544
{
@@ -55,7 +54,7 @@ void rtc_init(void)
5554
}
5655

5756
#if MBED_CONF_TARGET_LSE_AVAILABLE
58-
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE;
57+
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
5958
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
6059
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
6160
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
@@ -78,7 +77,7 @@ void rtc_init(void)
7877
__HAL_RCC_BACKUPRESET_RELEASE();
7978

8079
// Enable LSI clock
81-
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE;
80+
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
8281
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
8382
RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
8483
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
@@ -108,7 +107,7 @@ void rtc_init(void)
108107
RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;
109108

110109
/* PREDIV_A : 7-bit asynchronous prescaler */
111-
#if DEVICE_LOWPOWERTIMER
110+
#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM
112111
/* PREDIV_A is set to a small value to improve the SubSeconds resolution */
113112
/* with a 32768Hz clock, PREDIV_A=7 gives a precision of 244us */
114113
RtcHandle.Init.AsynchPrediv = 7;
@@ -297,7 +296,7 @@ void rtc_synchronize(void)
297296
}
298297
}
299298

300-
#if DEVICE_LOWPOWERTIMER
299+
#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM
301300

302301
static void RTC_IRQHandler(void)
303302
{
@@ -345,7 +344,7 @@ void rtc_set_wake_up_timer(uint32_t delta)
345344
NVIC_EnableIRQ(RTC_WKUP_IRQn);
346345

347346
RtcHandle.Instance = RTC;
348-
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 0xFFFF & WakeUpCounter, WakeUpClock[DivIndex-1]) != HAL_OK) {
347+
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 0xFFFF & WakeUpCounter, WakeUpClock[DivIndex - 1]) != HAL_OK) {
349348
error("rtc_set_wake_up_timer init error (%d)\n", DivIndex);
350349
}
351350
}
@@ -356,6 +355,6 @@ void rtc_deactivate_wake_up_timer(void)
356355
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
357356
}
358357

359-
#endif /* DEVICE_LOWPOWERTIMER */
358+
#endif /* DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */
360359

361360
#endif /* DEVICE_RTC */

targets/TARGET_STM/rtc_api_hal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
#include "rtc_api.h"
3636
#include "ticker_api.h"
3737
#include "lp_ticker_api.h"
38+
#include "us_ticker_api.h"
39+
#include "hal_tick.h"
40+
#include "mbed_critical.h"
41+
#include "mbed_error.h"
42+
#include "mbed_debug.h"
3843

3944
#ifdef __cplusplus
4045
extern "C" {

targets/TARGET_STM/sleep.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,8 @@
2929
*/
3030
#if DEVICE_SLEEP
3131

32-
#include "cmsis.h"
33-
#include "us_ticker_api.h"
3432
#include "sleep_api.h"
3533
#include "rtc_api_hal.h"
36-
#include "hal_tick.h"
37-
#include "mbed_critical.h"
3834

3935
extern void HAL_SuspendTick(void);
4036
extern void HAL_ResumeTick(void);

0 commit comments

Comments
 (0)