Skip to content

Commit 6700776

Browse files
authored
Merge pull request #5749 from jeromecoutant/PR_LPT_LPTIM
STM32 LOWPOWERTIMER : introduce LPTIM feature
2 parents 940614c + a816e93 commit 6700776

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)