From e6d18af3ad2c69a625fd5aca7f078ccfbcd80d96 Mon Sep 17 00:00:00 2001 From: Jue Date: Thu, 27 Oct 2022 23:50:07 +0200 Subject: [PATCH 1/2] cpu/efm32/timer_series2: fix timer_start() interaction with pm_layered The timer hasn't been enabled yet, if the STATUS isn't RUNNING, yet ... --- cpu/efm32/periph/timer_series2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpu/efm32/periph/timer_series2.c b/cpu/efm32/periph/timer_series2.c index 59b32742943d..ee5772af1387 100644 --- a/cpu/efm32/periph/timer_series2.c +++ b/cpu/efm32/periph/timer_series2.c @@ -255,7 +255,7 @@ static inline void _letimer_start(tim_t dev) { LETIMER_TypeDef *tim = timer_config[dev].dev; - if (tim->STATUS & LETIMER_STATUS_RUNNING) { + if (!(tim->STATUS & LETIMER_STATUS_RUNNING)) { pm_block(LETIMER_PM_BLOCKER); } @@ -266,7 +266,7 @@ static inline void _timer_start(tim_t dev) { TIMER_TypeDef *tim = timer_config[dev].dev; - if (tim->STATUS & TIMER_STATUS_RUNNING) { + if (!(tim->STATUS & TIMER_STATUS_RUNNING)) { pm_block(TIMER_PM_BLOCKER); } From 54e915e40d7e701f36778a2ef75da6b5b41fa1dc Mon Sep 17 00:00:00 2001 From: Jue Date: Thu, 27 Oct 2022 23:48:08 +0200 Subject: [PATCH 2/2] cpu/efm32/timer_series2: sync STATUS register Make sure the STATUS register has been synced between the different clock domains. Especially the LETIMER needs some time to update the STATUS register after it has been enabled. If the LETIMER is started and stopped with just a short delay, pm_layered gets confused because the timer seems to be inactive ... --- cpu/efm32/periph/timer_series2.c | 34 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/cpu/efm32/periph/timer_series2.c b/cpu/efm32/periph/timer_series2.c index ee5772af1387..87aa91c57cb4 100644 --- a/cpu/efm32/periph/timer_series2.c +++ b/cpu/efm32/periph/timer_series2.c @@ -224,26 +224,44 @@ unsigned int timer_read(tim_t dev) return _is_letimer(dev) ? _letimer_read(dev) : _timer_read(dev); } +static inline bool _letimer_is_running(LETIMER_TypeDef *tim) +{ + /* make sure registers are up-to-date and + * we can rely on the STATS register */ + LETIMER_SyncWait(tim); + + return tim->STATUS & LETIMER_STATUS_RUNNING; +} + +static inline bool _timer_is_running(TIMER_TypeDef *tim) +{ + /* make sure registers are up-to-date and + * we can rely on the STATS register */ + TIMER_SyncWait(tim); + + return tim->STATUS & TIMER_STATUS_RUNNING; +} + static inline void _letimer_stop(tim_t dev) { LETIMER_TypeDef *tim = timer_config[dev].dev; - if (tim->STATUS & LETIMER_STATUS_RUNNING) { + if (_letimer_is_running(tim)) { pm_unblock(LETIMER_PM_BLOCKER); } - LETIMER_Enable(timer_config[dev].dev, false); + LETIMER_Enable(tim, false); } static inline void _timer_stop(tim_t dev) { TIMER_TypeDef *tim = timer_config[dev].dev; - if (tim->STATUS & TIMER_STATUS_RUNNING) { + if (_timer_is_running(tim)) { pm_unblock(TIMER_PM_BLOCKER); } - TIMER_Enable(timer_config[dev].dev, false); + TIMER_Enable(tim, false); } void timer_stop(tim_t dev) @@ -255,22 +273,22 @@ static inline void _letimer_start(tim_t dev) { LETIMER_TypeDef *tim = timer_config[dev].dev; - if (!(tim->STATUS & LETIMER_STATUS_RUNNING)) { + if (!_letimer_is_running(tim)) { pm_block(LETIMER_PM_BLOCKER); } - LETIMER_Enable(timer_config[dev].dev, true); + LETIMER_Enable(tim, true); } static inline void _timer_start(tim_t dev) { TIMER_TypeDef *tim = timer_config[dev].dev; - if (!(tim->STATUS & TIMER_STATUS_RUNNING)) { + if (!_timer_is_running(tim)) { pm_block(TIMER_PM_BLOCKER); } - TIMER_Enable(timer_config[dev].dev, true); + TIMER_Enable(tim, true); } void timer_start(tim_t dev)