1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

Merge pull request #14391 from benpicco/cpu/stm32-timer_periodic

cpu/stm32: implement periph_timer_periodic
This commit is contained in:
Marian Buschsieweke 2020-08-10 07:58:27 +02:00 committed by GitHub
commit 7d9aed7f66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 129 additions and 10 deletions

View File

@ -13,6 +13,7 @@ config CPU_STM32
select HAS_PERIPH_GPIO
select HAS_PERIPH_GPIO_IRQ
select HAS_PUF_SRAM
select HAS_PERIPH_TIMER_PERIODIC
select HAS_PERIPH_UART_MODECFG
select HAS_PERIPH_UART_NONBLOCKING
select HAS_PERIPH_WDT

View File

@ -5,6 +5,7 @@ FEATURES_PROVIDED += cpu_stm32$(CPU_FAM)
FEATURES_PROVIDED += periph_cpuid
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += puf_sram
FEATURES_PROVIDED += periph_timer_periodic
FEATURES_PROVIDED += periph_uart_modecfg
FEATURES_PROVIDED += periph_uart_nonblocking
FEATURES_PROVIDED += periph_wdt

View File

@ -36,6 +36,57 @@ static inline TIM_TypeDef *dev(tim_t tim)
return timer_config[tim].dev;
}
#ifdef MODULE_PERIPH_TIMER_PERIODIC
/**
* @brief Helper macro to get channel bit in timer/channel bitmap
*/
#define CHAN_BIT(tim, chan) (1 << chan) << (TIMER_CHANNEL_NUMOF * (tim & 1))
/**
* @brief Bitmap for compare channel disable after match
*/
static uint8_t _oneshot[(TIMER_NUMOF+1)/2];
/**
* @brief Clear interrupt enable after the interrupt has fired
*/
static inline void set_oneshot(tim_t tim, int chan)
{
_oneshot[tim >> 1] |= CHAN_BIT(tim, chan);
}
/**
* @brief Enable interrupt with every wrap-around of the timer
*/
static inline void clear_oneshot(tim_t tim, int chan)
{
_oneshot[tim >> 1] &= ~CHAN_BIT(tim, chan);
}
static inline bool is_oneshot(tim_t tim, int chan)
{
return _oneshot[tim >> 1] & CHAN_BIT(tim, chan);
}
#else /* !MODULE_PERIPH_TIMER_PERIODIC */
static inline void set_oneshot(tim_t tim, int chan)
{
(void)tim;
(void)chan;
}
static inline bool is_oneshot(tim_t tim, int chan)
{
(void)tim;
(void)chan;
return true;
}
#endif /* MODULE_PERIPH_TIMER_PERIODIC */
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
{
/* check if device is valid */
@ -74,13 +125,53 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
return -1;
}
set_oneshot(tim, channel);
TIM_CHAN(tim, channel) = (value & timer_config[tim].max);
dev(tim)->SR &= ~(TIM_SR_CC1IF << channel);
#ifdef MODULE_PERIPH_TIMER_PERIODIC
if (dev(tim)->ARR == TIM_CHAN(tim, channel)) {
dev(tim)->ARR = timer_config[tim].max;
}
#endif
dev(tim)->DIER |= (TIM_DIER_CC1IE << channel);
return 0;
}
#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) {
return -1;
}
clear_oneshot(tim, channel);
if (flags & TIM_FLAG_RESET_ON_SET) {
/* setting COUNT gives us an interrupt on all channels */
unsigned state = irq_disable();
dev(tim)->CNT = 0;
/* wait for the interrupt & clear it */
while(dev(tim)->SR == 0) {}
dev(tim)->SR = 0;
irq_restore(state);
}
TIM_CHAN(tim, channel) = value;
dev(tim)->DIER |= (TIM_DIER_CC1IE << channel);
if (flags & TIM_FLAG_RESET_ON_MATCH) {
dev(tim)->ARR = value;
}
return 0;
}
#endif /* MODULE_PERIPH_TIMER_PERIODIC */
int timer_clear(tim_t tim, int channel)
{
if (channel >= (int)TIMER_CHANNEL_NUMOF) {
@ -88,6 +179,13 @@ int timer_clear(tim_t tim, int channel)
}
dev(tim)->DIER &= ~(TIM_DIER_CC1IE << channel);
#ifdef MODULE_PERIPH_TIMER_PERIODIC
if (dev(tim)->ARR == TIM_CHAN(tim, channel)) {
dev(tim)->ARR = timer_config[tim].max;
}
#endif
return 0;
}
@ -108,13 +206,30 @@ void timer_stop(tim_t tim)
static inline void irq_handler(tim_t tim)
{
uint32_t status = (dev(tim)->SR & dev(tim)->DIER);
uint32_t top = dev(tim)->ARR;
uint32_t status = dev(tim)->SR & dev(tim)->DIER;
dev(tim)->SR = 0;
for (unsigned int i = 0; i < TIMER_CHANNEL_NUMOF; i++) {
if (status & (TIM_SR_CC1IF << i)) {
dev(tim)->DIER &= ~(TIM_DIER_CC1IE << i);
isr_ctx[tim].cb(isr_ctx[tim].arg, i);
for (unsigned int i = 0; status; i++) {
uint32_t msk = TIM_SR_CC1IF << i;
/* check if interrupt flag is set */
if ((status & msk) == 0) {
continue;
}
status &= ~msk;
/* interrupt flag gets set for all channels > ARR */
if (TIM_CHAN(tim, i) > top) {
continue;
}
/* disable Interrupt */
if (is_oneshot(tim, i)) {
dev(tim)->DIER &= ~msk;
}
isr_ctx[tim].cb(isr_ctx[tim].arg, i);
}
cortexm_isr_end();
}

View File

@ -4,4 +4,6 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
nucleo-f031k6 \
stm32f030f4-demo \
#

View File

@ -38,7 +38,7 @@
* provides a configuration for it.
*/
#define TIMER_CYCL XTIMER_DEV
#define CYCLE_MS 100UL
#define CYCLE_MS 25UL
#define CYCLES_MAX 10
static unsigned count[TIMER_CHANNEL_NUMOF];

View File

@ -16,9 +16,9 @@ def testfunc(child):
start = time.time()
child.expect_exact('TEST SUCCEEDED')
end = time.time()
# test should run 10 cycles with 100ms each
assert (end - start) > 1
assert (end - start) < 1.5
# test should run 10 cycles with 25ms each
assert (end - start) > 0.25
assert (end - start) < 0.35
if __name__ == "__main__":