From 94f9a56125485b38d3c915e89499c21213fc70ca Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 3 Jan 2023 22:35:11 +0100 Subject: [PATCH] cpu/qn908x/periph_timer: Implement timer_set() This fixes test failures in tests/periph_timer_short_relative_set. Note: This differs a bit from the implementation in e.g. nRF5x or STM32 in that it always briefly pauses the timer. The issue is that when running the timer can take a few ticks to actually react to the new compare target. So even if the previously written target is still in the future, the timer may not fire anyway. Pausing the timer while setting and setting the target at least one higher than the current count reliably triggers the IRQ. --- cpu/qn908x/include/periph_cpu.h | 4 ++++ cpu/qn908x/periph/timer.c | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/cpu/qn908x/include/periph_cpu.h b/cpu/qn908x/include/periph_cpu.h index bc5e77963070..e7854b36dd35 100644 --- a/cpu/qn908x/include/periph_cpu.h +++ b/cpu/qn908x/include/periph_cpu.h @@ -335,6 +335,10 @@ typedef uint16_t adc_conf_t; */ #define TIMER_CHANNELS (4) #define TIMER_MAX_VALUE (0xffffffff) +/** + * @brief The nRF5x periph_timer implements timer_set() + */ +#define PERIPH_TIMER_PROVIDES_SET 1 /** @} */ /** diff --git a/cpu/qn908x/periph/timer.c b/cpu/qn908x/periph/timer.c index f80faa584dce..43266d5f4102 100644 --- a/cpu/qn908x/periph/timer.c +++ b/cpu/qn908x/periph/timer.c @@ -112,6 +112,31 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value) return 0; } +int timer_set(tim_t tim, int channel, unsigned int value) +{ + DEBUG("timer_set(%u, %u, %u)\n", tim, channel, value); + if ((tim >= TIMER_NUMOF) || (channel >= TIMER_CHANNELS)) { + return -1; + } + CTIMER_Type* const dev = ctimers[tim]; + + /* no IRQ will be generated on value == 0, so bump it here */ + value = (value != 0) ? value : 1; + + unsigned irq_state = irq_disable(); + + /* briefly pause timer */ + ctimers[tim]->TCR &= ~CTIMER_TCR_CEN_MASK; + /* set absolute timeout based on given value and enable IRQ */ + dev->MR[channel] = dev->TC + value; + dev->MCR |= (CTIMER_MCR_MR0I_MASK << (channel * 3)); + /* and resume timer */ + ctimers[tim]->TCR |= CTIMER_TCR_CEN_MASK; + irq_restore(irq_state); + + return 0; +} + int timer_clear(tim_t tim, int channel) { DEBUG("timer_clear(%u, %d)\n", tim, channel);