From 8126651009315ed0d71aa44ba403b1a91e511fe6 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 25 Dec 2019 18:48:38 +0100 Subject: [PATCH 1/2] cpu/lpc2387: timer: implement timer_set() We can achieve greater accuracy for the relative timer_set() if we don't use the generic implementation. Use the same approach as used by atmega_common to trigger interrupts for too small offsets. tests/periph_timer_short_relative_set should now succeed for all intervals. --- cpu/lpc23xx/include/periph_cpu.h | 5 +++++ cpu/lpc23xx/periph/timer.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/cpu/lpc23xx/include/periph_cpu.h b/cpu/lpc23xx/include/periph_cpu.h index b70270ca73..d29ba35c31 100644 --- a/cpu/lpc23xx/include/periph_cpu.h +++ b/cpu/lpc23xx/include/periph_cpu.h @@ -128,6 +128,11 @@ typedef struct { */ #define TIMER_CHANNEL_NUMOF (4U) +/** + * @brief Prevent shared timer functions from being used + */ +#define PERIPH_TIMER_PROVIDES_SET + /** * @brief Declare needed generic SPI functions * @{ diff --git a/cpu/lpc23xx/periph/timer.c b/cpu/lpc23xx/periph/timer.c index f1d3e20a40..3cda55753b 100644 --- a/cpu/lpc23xx/periph/timer.c +++ b/cpu/lpc23xx/periph/timer.c @@ -21,6 +21,7 @@ #include #include +#include "irq.h" #include "periph_conf.h" #include "periph_cpu.h" #include "periph/timer.h" @@ -167,6 +168,37 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value) dev->MR[channel] = value; /* Match Interrupt */ dev->MCR |= (1 << (channel * 3)); + + return 0; +} + +int timer_set(tim_t tim, int channel, unsigned int timeout) +{ + if (((unsigned) tim >= TIMER_NUMOF) || ((unsigned) channel >= TIMER_CHANNEL_NUMOF)) { + return -1; + } + + /* Interrupt will only be generated on increment, + so a 0 timeout is not possible */ + if (timeout == 0) { + timeout = 1; + } + + lpc23xx_timer_t *dev = get_dev(tim); + + unsigned state = irq_disable(); + dev->TCR = 0; + + unsigned absolute = timeout + dev->TC; + unsigned mask = 1 << (channel * 3); + + dev->MR[channel] = absolute; + dev->MCR |= mask; + set_oneshot(tim, channel); + + dev->TCR = 1; + irq_restore(state); + return 0; } From 178167621b706e150463cb8a6bbb1e094d90704b Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 14 Aug 2020 14:48:15 +0200 Subject: [PATCH 2/2] cpu/lpc2387: timer: use bitarithm_test_and_clear() --- cpu/lpc23xx/periph/timer.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cpu/lpc23xx/periph/timer.c b/cpu/lpc23xx/periph/timer.c index 3cda55753b..750f551e23 100644 --- a/cpu/lpc23xx/periph/timer.c +++ b/cpu/lpc23xx/periph/timer.c @@ -258,13 +258,6 @@ void timer_stop(tim_t tim) static inline void chan_handler(lpc23xx_timer_t *dev, unsigned tim_num, unsigned chan_num) { - const uint32_t mask = (1 << chan_num); - - if ((dev->IR & mask) == 0) { - return; - } - - dev->IR |= mask; if (is_oneshot(tim_num, chan_num)) { dev->MCR &= ~(1 << (chan_num * 3)); } @@ -274,8 +267,15 @@ static inline void chan_handler(lpc23xx_timer_t *dev, unsigned tim_num, unsigned static inline void isr_handler(lpc23xx_timer_t *dev, int tim_num) { - for (unsigned i = 0; i < TIMER_CHANNEL_NUMOF; ++i) { - chan_handler(dev, tim_num, i); + uint32_t state = dev->IR; + uint8_t chan = 0; + + /* clear interrupt flags */ + dev->IR = state; + + while (state) { + state = bitarithm_test_and_clear(state, &chan); + chan_handler(dev, tim_num, chan); } /* we must not forget to acknowledge the handling of the interrupt */