From c05984b341ef41b8bc40f93d7fc5acf90e2eee81 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Sun, 19 Apr 2020 00:32:50 +0200 Subject: [PATCH] cpu/sam0_common: timer: don't ignore frequency in timer_init() Now that we can query the GCLK frequency at run-time, there is no need to implicitely hard-code the timer frequency in the config struct anymore. --- cpu/sam0_common/periph/timer.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/cpu/sam0_common/periph/timer.c b/cpu/sam0_common/periph/timer.c index fbd3e249da..775360c3a6 100644 --- a/cpu/sam0_common/periph/timer.c +++ b/cpu/sam0_common/periph/timer.c @@ -71,19 +71,43 @@ static inline void _irq_enable(tim_t tim) NVIC_EnableIRQ(timer_config[tim].irq); } +static uint8_t _get_prescaler(unsigned long freq_out, unsigned long freq_in) +{ + uint8_t scale = 0; + while (freq_in > freq_out) { + freq_in >>= 1; + + /* after DIV16 the prescaler gets more coarse */ + if (++scale > TC_CTRLA_PRESCALER_DIV16_Val) { + freq_in >>= 1; + } + } + + /* fail if output frequency can't be derived from input frequency */ + assert(freq_in == freq_out); + + return scale; +} + /** * @brief Setup the given timer */ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg) { - (void) freq; const tc32_conf_t *cfg = &timer_config[tim]; + uint8_t scale = _get_prescaler(freq, sam0_gclk_freq(cfg->gclk_src)); /* make sure given device is valid */ if (tim >= TIMER_NUMOF) { return -1; } + /* make sure the prescaler is withing range */ + if (scale > TC_CTRLA_PRESCALER_DIV1024_Val) { + DEBUG("[timer %d] scale %d is out of range\n", tim, scale); + return -1; + } + /* make sure the timer is not running */ timer_stop(tim); @@ -104,7 +128,7 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg) #ifdef TC_CTRLA_WAVEGEN_NFRQ | TC_CTRLA_WAVEGEN_NFRQ #endif - | cfg->prescaler + | TC_CTRLA_PRESCALER(scale) | TC_CTRLA_PRESCSYNC_RESYNC; #ifdef TC_WAVE_WAVEGEN_NFRQ