From f0e7d2fc034520cbaee6e3f197e6986664f25bf5 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Mon, 19 Oct 2015 17:23:12 +0200 Subject: [PATCH] cpu/kinetis_common/timer.c: cleanup and fix the pit timer It simplifies the virtual "count up timer" and improves the accuracy a little. The LDVAL for the prescaler should be set as a number of prescaler cycles-1. The virtual up-counter should be corrected in the isr by +1 (See PIT reference manual). This also fixes a bug where the timer is not used by xtimer and up-counter does not overflow. --- cpu/kinetis_common/timer.c | 63 ++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/cpu/kinetis_common/timer.c b/cpu/kinetis_common/timer.c index 0982615e17..99b9a8f05d 100644 --- a/cpu/kinetis_common/timer.c +++ b/cpu/kinetis_common/timer.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2014 PHYTEC Messtechnik GmbH + * Copyright (C) 2015 PHYTEC Messtechnik GmbH * * 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 @@ -40,13 +40,8 @@ typedef struct { void (*cb)(int); } timer_conf_t; -/** Type for virtual count up timer */ -typedef struct { - uint32_t counter32b; - uint32_t diff; -} count_up_timer_t; - -static count_up_timer_t cu_timer[TIMER_NUMOF]; +/* Virtual count up timer */ +static uint32_t cu_timer[TIMER_NUMOF]; /** Timer state memory */ static timer_conf_t config[TIMER_NUMOF]; @@ -65,7 +60,7 @@ inline static void pit_timer_stop(uint8_t ch) inline static void timer_set_prescaler(uint8_t ch, unsigned int ticks_per_us) { TIMER_BASE->CHANNEL[ch].TCTRL = 0x0; - TIMER_BASE->CHANNEL[ch].LDVAL = (TIMER_CLOCK / 1e6) / ticks_per_us; + TIMER_BASE->CHANNEL[ch].LDVAL = (TIMER_CLOCK / 1e6) / ticks_per_us - 1; TIMER_BASE->CHANNEL[ch].TCTRL = (PIT_TCTRL_TEN_MASK); } @@ -78,8 +73,8 @@ inline static void timer_set_counter(uint8_t ch) inline static uint32_t pit_timer_read(tim_t dev, uint8_t ch) { - return cu_timer[dev].counter32b + (TIMER_BASE->CHANNEL[ch].LDVAL - - TIMER_BASE->CHANNEL[ch].CVAL); + return cu_timer[dev] + (TIMER_BASE->CHANNEL[ch].LDVAL + - TIMER_BASE->CHANNEL[ch].CVAL); } inline static void pit_timer_set_max(uint8_t ch) @@ -91,12 +86,11 @@ inline static void pit_timer_set_max(uint8_t ch) int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) { - PIT_Type *timer = TIMER_BASE; - /* enable timer peripheral clock */ TIMER_CLKEN(); - timer->MCR = PIT_MCR_FRZ_MASK; + TIMER_BASE->MCR = 0; + TIMER_BASE->MCR = PIT_MCR_FRZ_MASK; switch (dev) { #if TIMER_0_EN @@ -123,8 +117,7 @@ int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) /* set callback function */ config[dev].cb = callback; - cu_timer[dev].counter32b = 0; - cu_timer[dev].diff = 0; + cu_timer[dev] = 0; /* enable the timer's interrupt */ timer_irq_enable(dev); @@ -144,6 +137,8 @@ int timer_set(tim_t dev, int channel, unsigned int timeout) int timer_set_absolute(tim_t dev, int channel, unsigned int value) { + uint32_t diff = 0; + /* we only support one channel */ if (channel != 0) { return -1; @@ -152,20 +147,20 @@ int timer_set_absolute(tim_t dev, int channel, unsigned int value) #if TIMER_0_EN case TIMER_0: - cu_timer[dev].counter32b = pit_timer_read(dev, TIMER_0_COUNTER_CH); + cu_timer[dev] = pit_timer_read(dev, TIMER_0_COUNTER_CH); pit_timer_stop(TIMER_0_COUNTER_CH); - cu_timer[dev].diff = value - cu_timer[dev].counter32b; - TIMER_BASE->CHANNEL[TIMER_0_COUNTER_CH].LDVAL = cu_timer[dev].diff; + diff = value - cu_timer[dev]; + TIMER_BASE->CHANNEL[TIMER_0_COUNTER_CH].LDVAL = diff; pit_timer_start(TIMER_0_COUNTER_CH); break; #endif #if TIMER_1_EN case TIMER_1: - cu_timer[dev].counter32b = pit_timer_read(dev, TIMER_1_COUNTER_CH); + cu_timer[dev] = pit_timer_read(dev, TIMER_1_COUNTER_CH); pit_timer_stop(TIMER_1_COUNTER_CH); - cu_timer[dev].diff = value - cu_timer[dev].counter32b; - TIMER_BASE->CHANNEL[TIMER_1_COUNTER_CH].LDVAL = cu_timer[dev].diff; + diff = value - cu_timer[dev]; + TIMER_BASE->CHANNEL[TIMER_1_COUNTER_CH].LDVAL = diff; pit_timer_start(TIMER_1_COUNTER_CH); break; #endif @@ -175,8 +170,7 @@ int timer_set_absolute(tim_t dev, int channel, unsigned int value) return -1; } - DEBUG("cntr: %lu, value: %u, diff: %lu\n", - cu_timer[dev].counter32b, value, cu_timer[dev].diff); + DEBUG("cntr: %lu, value: %u, diff: %lu\n", cu_timer[dev], value, diff); return 0; } @@ -191,16 +185,14 @@ int timer_clear(tim_t dev, int channel) #if TIMER_0_EN case TIMER_0: - cu_timer[dev].counter32b = timer_read(dev); - cu_timer[dev].diff = 0; + cu_timer[dev] = timer_read(dev); pit_timer_set_max(TIMER_0_COUNTER_CH); break; #endif #if TIMER_1_EN case TIMER_1: - cu_timer[dev].counter32b = timer_read(dev); - cu_timer[dev].diff = 0; + cu_timer[dev] = timer_read(dev); pit_timer_set_max(TIMER_1_COUNTER_CH); break; #endif @@ -210,8 +202,6 @@ int timer_clear(tim_t dev, int channel) return -1; } - DEBUG("clear\n"); - return 0; } @@ -344,16 +334,15 @@ void timer_reset(tim_t dev) inline static void pit_timer_irq_handler(tim_t dev, uint8_t ch) { - cu_timer[dev].counter32b += TIMER_BASE->CHANNEL[ch].LDVAL; + cu_timer[dev] += TIMER_BASE->CHANNEL[ch].LDVAL + 1; + pit_timer_set_max(ch); + + if (config[dev].cb != NULL) { + config[dev].cb(dev); + } TIMER_BASE->CHANNEL[ch].TFLG = PIT_TFLG_TIF_MASK; - if (cu_timer[dev].diff) { - if (config[dev].cb != NULL) { - config[dev].cb(0); - } - } - if (sched_context_switch_request) { thread_yield(); }