From 7c0a4b839000f6839e66631713051896972938a4 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 May 2023 12:55:29 +0200 Subject: [PATCH 1/4] cpu/stm32/periph_timer: Support timers with channels != 4 The assumption that all STM32 timers have exactly four channels no longer holds. E.g. the STM32L4 has the following general purpose timers: - TIM2: 32 bit, 4 channels - TIM15: 16 bit, 2 channels - TIM16: 16 bit, 1 channel Hence, a new field is added to the timer configuration to also contain the number of timer channels. Due to alignment the `struct` previously was padded by 16 bit, so adding another 8 bit field doesn't increase its size. For backward compatibility, a value of `0` is considered as alias for `TIMER_CHANNEL_NUMOF` (or 4), so that the number of timer channels only needs to be set when the timer is different from the typical 4 channel timer. This helps backward compatibility. --- cpu/stm32/include/periph/cpu_timer.h | 4 +++- cpu/stm32/periph/timer.c | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cpu/stm32/include/periph/cpu_timer.h b/cpu/stm32/include/periph/cpu_timer.h index 83ed1c68210e..252be33e7051 100644 --- a/cpu/stm32/include/periph/cpu_timer.h +++ b/cpu/stm32/include/periph/cpu_timer.h @@ -30,7 +30,7 @@ extern "C" { #endif /** - * @brief All STM timers have 4 capture-compare channels + * @brief All STM timers have at most 4 capture-compare channels */ #define TIMER_CHANNEL_NUMOF (4U) @@ -53,6 +53,8 @@ typedef struct { uint32_t rcc_mask; /**< corresponding bit in the RCC register */ uint8_t bus; /**< APBx bus the timer is clock from */ uint8_t irqn; /**< global IRQ channel */ + uint8_t channel_numof; /**< number of channels, 0 is alias for + @ref TIMER_CHANNEL_NUMOF */ } timer_conf_t; #ifdef __cplusplus diff --git a/cpu/stm32/periph/timer.c b/cpu/stm32/periph/timer.c index 92660fa7554f..3ea8fb85e77a 100644 --- a/cpu/stm32/periph/timer.c +++ b/cpu/stm32/periph/timer.c @@ -36,6 +36,21 @@ static inline TIM_TypeDef *dev(tim_t tim) return timer_config[tim].dev; } +/** + * @brief Get the number of channels of the timer device + */ +static unsigned channel_numof(tim_t tim) +{ + if (timer_config[tim].channel_numof) { + return timer_config[tim].channel_numof; + } + + /* backwards compatibility with older periph_conf.h files when all STM32 + * had exactly 4 channels */ + return TIMER_CHANNEL_NUMOF; +} + + #ifdef MODULE_PERIPH_TIMER_PERIODIC /** @@ -121,7 +136,7 @@ int timer_init(tim_t tim, uint32_t freq, timer_cb_t cb, void *arg) int timer_set_absolute(tim_t tim, int channel, unsigned int value) { - if (channel >= (int)TIMER_CHANNEL_NUMOF) { + if ((unsigned)channel >= channel_numof(tim)) { return -1; } @@ -150,7 +165,7 @@ int timer_set(tim_t tim, int channel, unsigned int timeout) { unsigned value = (dev(tim)->CNT + timeout) & timer_config[tim].max; - if (channel >= (int)TIMER_CHANNEL_NUMOF) { + if ((unsigned)channel >= channel_numof(tim)) { return -1; } @@ -188,7 +203,7 @@ int timer_set(tim_t tim, int channel, unsigned int timeout) #ifdef MODULE_PERIPH_TIMER_PERIODIC int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags) { - if (channel >= (int)TIMER_CHANNEL_NUMOF) { + if ((unsigned)channel >= channel_numof(tim)) { return -1; } @@ -227,7 +242,7 @@ int timer_set_periodic(tim_t tim, int channel, unsigned int value, uint8_t flags int timer_clear(tim_t tim, int channel) { - if (channel >= (int)TIMER_CHANNEL_NUMOF) { + if ((unsigned)channel >= channel_numof(tim)) { return -1; } From a6e8e1ff7e7863f0c15f9959b9d910b742e243d4 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 May 2023 13:03:19 +0200 Subject: [PATCH 2/4] boards/common/stm32: Add timer config based on TIM2,15,16 This adds the three general purpose timers on STM32L4 boards in a central place so that STM32L4 boards can just include it. Some other families may also have TIM15 and TIM16 and could use this, but likely some generalization is needed to use this for other families as well. This can be added later on. --- .../include/cfg_timer_tim2_tim15_tim16.h | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 boards/common/stm32/include/cfg_timer_tim2_tim15_tim16.h diff --git a/boards/common/stm32/include/cfg_timer_tim2_tim15_tim16.h b/boards/common/stm32/include/cfg_timer_tim2_tim15_tim16.h new file mode 100644 index 000000000000..2f2ad1e4e8bc --- /dev/null +++ b/boards/common/stm32/include/cfg_timer_tim2_tim15_tim16.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup boards_common_stm32 + * @{ + * + * @file + * @brief Common configuration for STM32 Timer peripheral based on TIM2, + * TIM15, and TIM16 + * + * @author Marian Buschsieweke + */ + +#ifndef CFG_TIMER_TIM2_TIM15_TIM16_H +#define CFG_TIMER_TIM2_TIM15_TIM16_H + +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Please note: This likely needs some generalization for use in STM32 families + * other than L4. */ +/** + * @name Timer configuration + * @{ + */ +static const timer_conf_t timer_config[] = { + { + .dev = TIM2, + .max = 0xffffffff, + .rcc_mask = RCC_APB1ENR1_TIM2EN, + .bus = APB1, + .irqn = TIM2_IRQn + }, + { + .dev = TIM15, + .max = 0x0000ffff, + .rcc_mask = RCC_APB2ENR_TIM15EN, + .bus = APB2, + .irqn = TIM1_BRK_TIM15_IRQn, + .channel_numof = 2, + }, + { + .dev = TIM16, + .max = 0x0000ffff, + .rcc_mask = RCC_APB2ENR_TIM16EN, + .bus = APB2, + .irqn = TIM1_UP_TIM16_IRQn, + .channel_numof = 1, + }, +}; + +#define TIMER_0_ISR isr_tim2 /**< IRQ of timer at idx 0 */ +#define TIMER_1_ISR isr_tim1_brk_tim15 /**< IRQ of timer at idx 1 */ +#define TIMER_2_ISR isr_tim1_up_tim16 /**< IRQ of timer at idx 2 */ + +#define TIMER_NUMOF ARRAY_SIZE(timer_config) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* CFG_TIMER_TIM2_TIM15_TIM16_H */ +/** @} */ From 0051d4148cfe0c187322438fc02e406031d5fc54 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 May 2023 13:05:38 +0200 Subject: [PATCH 3/4] boards/nucleo-l432kc: provide three periph_timer instances --- boards/nucleo-l432kc/include/periph_conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/nucleo-l432kc/include/periph_conf.h b/boards/nucleo-l432kc/include/periph_conf.h index 40fd526183e3..af45e7ac4a1e 100644 --- a/boards/nucleo-l432kc/include/periph_conf.h +++ b/boards/nucleo-l432kc/include/periph_conf.h @@ -30,7 +30,7 @@ #include "clk_conf.h" #include "cfg_i2c1_pb6_pb7.h" #include "cfg_rtt_default.h" -#include "cfg_timer_tim2.h" +#include "cfg_timer_tim2_tim15_tim16.h" #ifdef __cplusplus extern "C" { From 4333ed7094a0fd572ba4d24dca14aa10b4a89792 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 May 2023 14:35:37 +0200 Subject: [PATCH 4/4] sys/xtimer: improve documentation - Add a warning that xtimer is deprecated, so that new code hopefully starts using ztimer - Add a hint that `ztimer_xtimer_compat` can be used even after `xtimer` is gone --- sys/include/xtimer.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sys/include/xtimer.h b/sys/include/xtimer.h index 239659996391..5bc861faa13b 100644 --- a/sys/include/xtimer.h +++ b/sys/include/xtimer.h @@ -8,11 +8,11 @@ */ /** - * @defgroup sys_xtimer Timers - * @ingroup sys - * @brief Provides a high level timer module to register - * timers, get current system time, and let a thread sleep for - * a certain amount of time. + * @defgroup sys_xtimer xtimer high level timer abstraction layer (deprecated) + * @ingroup sys + * @brief Provides a high level timer module to register + * timers, get current system time, and let a thread sleep for + * a certain amount of time. * * The implementation takes one low-level timer and multiplexes it. * @@ -20,6 +20,19 @@ * number of active timers. The reason for this is that multiplexing is * realized by next-first singly linked lists. * + * @warning xtimer has been deprecated in favor of the @ref sys_ztimer + * @note With @ref sys_ztimer_xtimer_compat a compatibility wrapper is + * provided that in the vast majority of cases can function as a + * drop-in replacement. This compatibility wrapper is expected to + * replace `xtimer` in the near future and ensure that code still + * depending on the `xtimer` API continues to function. + * @details Note that at least for long running timers, using + * @ref sys_ztimer instead of the compatibility layer can yield + * lower clock drift and lower power consumption compared to + * using the compatibility layer. For details on how to achieve + * lower clock drift and lower power consumption please consult the + * @ref sys_ztimer documentation. + * * @{ * @file * @brief xtimer interface definitions