From b8fa89fba70ea4ed894d3ef073df4a6744fe9366 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Fri, 17 Oct 2014 14:58:37 +0200 Subject: [PATCH] cpu/nrf51822: fixed timers - changed TIMER_0 to be a 24-bit timer -> see Nordic PAN #32 - cleaned up timer initialization code - added check if an interrupt channel was active --- cpu/nrf51822/include/hwtimer_cpu.h | 6 +-- cpu/nrf51822/periph/timer.c | 78 +++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/cpu/nrf51822/include/hwtimer_cpu.h b/cpu/nrf51822/include/hwtimer_cpu.h index 9b555a008670..1d9ace6df7de 100644 --- a/cpu/nrf51822/include/hwtimer_cpu.h +++ b/cpu/nrf51822/include/hwtimer_cpu.h @@ -9,10 +9,10 @@ /** * @ingroup cpu_nrf51822 * @{ - * + * * @file hwtimer_cpu.h * @brief CPU specific hwtimer configuration options - * + * * @author Hauke Petersen */ @@ -26,7 +26,7 @@ #define HWTIMER_MAXTIMERS 3 /**< the CPU implementation supports 3 HW timers */ #define HWTIMER_SPEED 1000000 /**< the HW timer runs with 1MHz */ -#define HWTIMER_MAXTICKS (0xFFFFFFFF) /**< 32-bit timer */ +#define HWTIMER_MAXTICKS (0xFFFFFF) /**< 24-bit timer -> see PAN note */ /** @} */ diff --git a/cpu/nrf51822/periph/timer.c b/cpu/nrf51822/periph/timer.c index 94716544c15f..044abbe34a95 100644 --- a/cpu/nrf51822/periph/timer.c +++ b/cpu/nrf51822/periph/timer.c @@ -32,8 +32,21 @@ #include "nrf51.h" #include "nrf51_bitfields.h" +/** + * @name Flags to mark active channels + * @{ + */ +#define TIMER_CH0 0x01 +#define TIMER_CH1 0x02 +#define TIMER_CH2 0x04 +/** @} */ + +/** + * @brief struct for keeping track of a timer's state + */ typedef struct { void (*cb)(int); + uint8_t flags; } timer_conf_t; /** @@ -44,13 +57,13 @@ static timer_conf_t timer_config[TIMER_NUMOF]; int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) { NRF_TIMER_Type *timer; + uint32_t bitmode; switch (dev) { #if TIMER_0_EN case TIMER_0: timer = TIMER_0_DEV; - timer->POWER = 1; - timer->BITMODE = TIMER_0_BITMODE; + bitmode = TIMER_0_BITMODE; NVIC_SetPriority(TIMER_0_IRQ, TIMER_IRQ_PRIO); NVIC_EnableIRQ(TIMER_0_IRQ); break; @@ -58,8 +71,7 @@ int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) #if TIMER_1_EN case TIMER_1: timer = TIMER_1_DEV; - timer->POWER = 1; - timer->BITMODE = TIEMR_1_BITMODE; + bitmode = TIMER_1_BITMODE; NVIC_SetPriority(TIMER_1_IRQ, TIMER_IRQ_PRIO); NVIC_EnableIRQ(TIMER_1_IRQ); break; @@ -67,8 +79,7 @@ int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) #if TIMER_2_EN case TIMER_2: timer = TIMER_2_DEV; - timer->POWER = 1; - timer->BITMODE = TIMER_2_BITMODE; + bitmode = TIMER_2_BITMODE; NVIC_SetPriority(TIMER_2_IRQ, TIMER_IRQ_PRIO); NVIC_EnableIRQ(TIMER_2_IRQ); break; @@ -79,12 +90,17 @@ int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) /* save callback */ timer_config[dev].cb = callback; - + timer_config[dev].flags = 0; + /* power on timer */ + timer->POWER = 1; + /* stop and reset timer for configuration */ timer->TASKS_STOP = 1; - + timer->TASKS_CLEAR = 1; + timer->SHORTS = 0; + /* define mode and counter width */ timer->MODE = TIMER_MODE_MODE_Timer; /* set the timer in Timer Mode. */ - timer->TASKS_CLEAR = 1; /* clear the task first to be usable for later. */ - + timer->BITMODE = bitmode; + /* set prescaler, only some preconfigured values possible for now */ switch (ticks_per_us) { case 1: timer->PRESCALER = 4; @@ -104,13 +120,6 @@ int timer_init(tim_t dev, unsigned int ticks_per_us, void (*callback)(int)) default: return -1; } - - /* clear all compare channels */ - timer->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos); - timer->SHORTS = (TIMER_SHORTS_COMPARE1_CLEAR_Enabled << TIMER_SHORTS_COMPARE1_CLEAR_Pos); - timer->SHORTS = (TIMER_SHORTS_COMPARE2_CLEAR_Enabled << TIMER_SHORTS_COMPARE2_CLEAR_Pos); - timer->SHORTS = (TIMER_SHORTS_COMPARE3_CLEAR_Enabled << TIMER_SHORTS_COMPARE3_CLEAR_Pos); - /* start the timer */ timer->TASKS_START = 1; @@ -126,22 +135,26 @@ int timer_set(tim_t dev, int channel, unsigned int timeout) int timer_set_absolute(tim_t dev, int channel, unsigned int value) { volatile NRF_TIMER_Type * timer; + uint8_t *flags; /* get timer base register address */ switch (dev) { #if TIMER_0_EN case TIMER_0: timer = TIMER_0_DEV; + flags = &(timer_config[TIMER_0].flags); break; #endif #if TIMER_1_EN case TIMER_1: timer = TIMER_1_DEV; + flags = &(timer_config[TIMER_1].flags); break; #endif #if TIMER_2_EN case TIMER_2: timer = TIMER_2_DEV; + flags = &(timer_config[TIMER_2].flags); break; #endif case TIMER_UNDEFINED: @@ -151,14 +164,17 @@ int timer_set_absolute(tim_t dev, int channel, unsigned int value) switch (channel) { case 0: timer->CC[0] = value; + *flags = (*flags) | TIMER_CH0; timer->INTENSET |= TIMER_INTENSET_COMPARE0_Msk; break; case 1: timer->CC[1] = value; + *flags = (*flags) | TIMER_CH1; timer->INTENSET |= TIMER_INTENSET_COMPARE1_Msk; break; case 2: timer->CC[2] = value; + *flags = (*flags) | TIMER_CH2; timer->INTENSET |= TIMER_INTENSET_COMPARE2_Msk; break; default: @@ -171,21 +187,25 @@ int timer_set_absolute(tim_t dev, int channel, unsigned int value) int timer_clear(tim_t dev, int channel) { NRF_TIMER_Type *timer; + uint8_t *flags; switch (dev) { #if TIMER_0_EN case TIMER_0: timer = TIMER_0_DEV; + flags = &(timer_config[TIMER_0].flags); break; #endif #if TIMER_1_EN case TIMER_1: timer = TIMER_1_DEV; + flags = &(timer_config[TIMER_1].flags); break; #endif #if TIMER_2_EN case TIMER_2: timer = TIMER_2_DEV; + flags = &(timer_config[TIMER_2].flags); break; #endif case TIMER_UNDEFINED: @@ -195,12 +215,15 @@ int timer_clear(tim_t dev, int channel) /* set timeout value */ switch (channel) { case 0: + *flags = (*flags) & ~TIMER_CH0; timer->INTENCLR = TIMER_INTENCLR_COMPARE0_Msk; break; case 1: + *flags = (*flags) & ~TIMER_CH0; timer->INTENCLR = TIMER_INTENCLR_COMPARE1_Msk; break; case 2: + *flags = (*flags) & ~TIMER_CH0; timer->INTENCLR = TIMER_INTENCLR_COMPARE2_Msk; break; default: @@ -354,8 +377,11 @@ void TIMER_0_ISR(void) for(int i = 0; i < TIMER_0_CHANNELS; i++){ if(TIMER_0_DEV->EVENTS_COMPARE[i] == 1){ TIMER_0_DEV->EVENTS_COMPARE[i] = 0; - TIMER_0_DEV->INTENCLR = (1 << (16 + i)); - timer_config[TIMER_0].cb(i); + if (timer_config[TIMER_0].flags & (1 << i)) { + timer_config[TIMER_0].flags &= ~(1 << i); + TIMER_0_DEV->INTENCLR = (1 << (16 + i)); + timer_config[TIMER_0].cb(i); + } } } if (sched_context_switch_request) { @@ -370,8 +396,11 @@ void TIMER_1_ISR(void) for(int i = 0; i < TIMER_1_CHANNELS; i++){ if(TIMER_1_DEV->EVENTS_COMPARE[i] == 1){ TIMER_1_DEV->EVENTS_COMPARE[i] = 0; - TIMER_1_DEV->INTENCLR = (1 << (16 + i)); - timer_config[TIMER_1].cb(i); + if (timer_config[TIMER_1].flags & (1 << i)) { + timer_config[TIMER_1].flags &= ~(1 << i); + TIMER_1_DEV->INTENCLR = (1 << (16 + i)); + timer_config[TIMER_1].cb(i); + } } } if (sched_context_switch_request) { @@ -386,8 +415,11 @@ void TIMER_2_ISR(void) for(int i = 0; i < TIMER_2_CHANNELS; i++){ if(TIMER_2_DEV->EVENTS_COMPARE[i] == 1){ TIMER_2_DEV->EVENTS_COMPARE[i] = 0; - TIMER_2_DEV->INTENCLR = (1 << (16 + i)); - timer_config[TIMER_2].cb(i); + if (timer_config[TIMER_2].flags & (1 << i)) { + timer_config[TIMER_2].flags &= ~(1 << i); + TIMER_2_DEV->INTENCLR = (1 << (16 + i)); + timer_config[TIMER_2].cb(i); + } } } if (sched_context_switch_request) {