/* * Copyright (C) 2016 Leon George * * 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 details. */ /** * @ingroup cpu_cc26x0 * @{ * * @file * @brief Low-level timer driver implementation for the CC26x0 * * @author Leon M. George * * @} */ #include #include #include "cpu.h" #include "periph_conf.h" #include "periph/timer.h" /** * @brief Allocate memory for the interrupt context */ static timer_isr_ctx_t ctx[TIMER_NUMOF]; /** * @brief Get the GPT register base for a timer * * @param[in] tim index of the timer * * @return base address */ static inline gpt_reg_t *dev(tim_t tim) { return timer_config[tim].dev; } int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg) { /* make sure given timer is valid */ if (tim >= TIMER_NUMOF) { return -1; } /* enable the times clock */ PRCM->GPTCLKGR |= (1 << timer_config[tim].num); PRCM->CLKLOADCTL = CLKLOADCTL_LOAD; while (!(PRCM->CLKLOADCTL & CLKLOADCTL_LOADDONE)) {} /* disable (and reset) timer */ dev(tim)->CTL = 0; /* save context */ ctx[tim].cb = cb; ctx[tim].arg = arg; /* configure timer to 16-bit, periodic, up-counting */ dev(tim)->CFG = GPT_CFG_16T; dev(tim)->TAMR = (GPT_TXMR_TXMR_PERIODIC | GPT_TXMR_TXCDIR_UP | GPT_TXMR_TXMIE); /* set the timer speed */ dev(tim)->TAPR = (RCOSC48M_FREQ / freq) - 1; /* enable global timer interrupt and start the timer */ timer_irq_enable(tim); dev(tim)->CTL = GPT_CTL_TAEN; return 0; } int timer_set(tim_t tim, int channel, unsigned int timeout) { return timer_set_absolute(tim, channel, timer_read(tim) + timeout); } int timer_set_absolute(tim_t tim, int channel, unsigned int value) { if (channel != 0) { return -1; } dev(tim)->TAMATCHR = value; dev(tim)->IMR |= GPT_IMR_TAMIM; return 0; } int timer_clear(tim_t tim, int channel) { if (channel != 0) { return -1; } dev(tim)->IMR &= ~(GPT_IMR_TAMIM); return 0; } unsigned int timer_read(tim_t tim) { return dev(tim)->TAV & 0xFFFF; } void timer_stop(tim_t tim) { dev(tim)->CTL = 0; } void timer_start(tim_t tim) { dev(tim)->CTL = GPT_CTL_TAEN; } void timer_irq_enable(tim_t tim) { NVIC_EnableIRQ(GPTIMER_0A_IRQN + (2 * timer_config[tim].num)); } void timer_irq_disable(tim_t tim) { NVIC_DisableIRQ(GPTIMER_0A_IRQN + (2 * timer_config[tim].num)); } /** * @brief handle interrupt for a timer * * @param[in] tim index of the timer */ static inline void isr_handler(tim_t tim) { uint32_t mis = dev(tim)->MIS; dev(tim)->ICLR = mis; if (mis & GPT_IMR_TAMIM) { dev(tim)->IMR &= ~GPT_IMR_TAMIM; ctx[tim].cb(ctx[tim].arg, 0); } cortexm_isr_end(); } #ifdef TIMER_0_ISR void TIMER_0_ISR(void) { isr_handler(0); } #endif #ifdef TIMER_1_ISR void TIMER_1_ISR(void) { isr_handler(1); } #endif #ifdef TIMER_2_ISR void TIMER_2_ISR(void) { isr_handler(2); } #endif #ifdef TIMER_3_ISR void TIMER_3_ISR(void) { isr_handler(3); } #endif