/**************************************************************************** * arch/arm/src/tiva/tiva_timerlib.c * * Copyright (C) 2015 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name NuttX nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "up_arch.h" #include "chip/tiva_syscontrol.h" #include "chip/tiva_timer.h" #include "tiva_enableclks.h" #include "tiva_enablepwr.h" #include "tiva_periphrdy.h" #include "tiva_timer.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /**************************************************************************** * Private Types ****************************************************************************/ /* This structure retains the fixed, well-known attributes of a GPTM module */ struct tiva_gptmattr_s { uintptr_t base; /* Register base address */ uint16_t irq[2]; /* Timer A/B interrupt numbers */ #ifdef CONFIG_TIVA_TIMER_32BIT xcpt_t handler32; /* Handler for 32-bit timer interrupts */ #endif #ifdef CONFIG_TIVA_TIMER_16BIT xcpt_t handler16[2]; /* Handlers for 16-bit timer A/B interrupts */ #endif }; /* This structure represents the state of a GPTM module */ struct tiva_gptmstate_s { /* Constant timer attributes and configuration */ const struct tiva_gptmattr_s *attr; const struct tiva_gptmconfig_s *config; /* Variable state values */ uint32_t clkin; /* Frequency of the input clock */ uint32_t imr; /* Interrupt mask value. Zero if no interrupts */ #ifdef CONFIG_TIVA_TIMER_REGDEBUG /* Register level debug */ bool wrlast; /* Last was a write */ uintptr_t addrlast; /* Last address */ uint32_t vallast; /* Last value */ int ntimes; /* Number of times */ #endif }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ /* Register Access */ #ifdef CONFIG_TIVA_TIMER_REGDEBUG static bool tiva_timer_checkreg(struct tiva_gptmstate_s *priv, bool wr, uint32_t regval, uintptr_t regaddr); #endif static uint32_t tiva_getreg(struct tiva_gptmstate_s *priv, unsigned int offset); static void tiva_putreg(struct tiva_gptmstate_s *priv, unsigned int offset, uint32_t regval); /* Interrupt handling */ #ifdef CONFIG_TIVA_TIMER_32BIT static int tiva_timer32_interrupt(struct tiva_gptmstate_s *priv); # ifdef CONFIG_TIVA_TIMER0 static int tiva_gptm0_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER1 static int tiva_gptm1_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER2 static int tiva_gptm2_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER3 static int tiva_gptm3_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER4 static int tiva_gptm4_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER5 static int tiva_gptm5_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER6 static int tiva_gptm6_interrupt(int irq, FAR void *context); # endif # ifdef CONFIG_TIVA_TIMER7 static int tiva_gptm7_interrupt(int irq, FAR void *context); #endif #endif /* CONFIG_TIVA_TIMER_32BIT */ #ifdef CONFIG_TIVA_TIMER_16BIT static int tiva_timer16_interrupt(struct tiva_gptmstate_s *priv, int tmndx); #ifdef CONFIG_TIVA_TIMER0 static int tiva_timer0a_interrupt(int irq, FAR void *context); static int tiva_timer0b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER1 static int tiva_timer1a_interrupt(int irq, FAR void *context); static int tiva_timer1b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER2 static int tiva_timer2a_interrupt(int irq, FAR void *context); static int tiva_timer2b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER3 static int tiva_timer3a_interrupt(int irq, FAR void *context); static int tiva_timer3b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER4 static int tiva_timer4a_interrupt(int irq, FAR void *context); static int tiva_timer4b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER5 static int tiva_timer5a_interrupt(int irq, FAR void *context); static int tiva_timer5b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER6 static int tiva_timer6a_interrupt(int irq, FAR void *context); static int tiva_timer6b_interrupt(int irq, FAR void *context); #endif #ifdef CONFIG_TIVA_TIMER7 static int tiva_timer7a_interrupt(int irq, FAR void *context); static int tiva_timer7b_interrupt(int irq, FAR void *context); #endif #endif /* CONFIG_TIVA_TIMER_16BIT */ /* Timer initialization and configuration */ #ifdef CONFIG_TIVA_TIMER32_PERIODIC static int tiva_oneshot_periodic_mode32(struct tiva_gptmstate_s *priv, const struct tiva_timer32config_s *timer); #endif /* CONFIG_TIVA_TIMER32_PERIODIC */ #ifdef CONFIG_TIVA_TIMER16_PERIODIC static int tiva_oneshot_periodic_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); #endif #ifdef CONFIG_TIVA_TIMER32_RTC static int tiva_rtc_mode32(struct tiva_gptmstate_s *priv, const struct tiva_timer32config_s *timer); #endif #ifdef CONFIG_TIVA_TIMER32_EDGECOUNT static int tiva_input_edgecount_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); #endif #ifdef CONFIG_TIVA_TIMER32_TIMECAP static int tiva_input_time_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); #endif #ifdef CONFIG_TIVA_TIMER32_PWM static int tiva_pwm_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); #endif #ifdef CONFIG_TIVA_TIMER_32BIT static int tiva_timer32_configure(struct tiva_gptmstate_s *priv, const struct tiva_timer32config_s *timer); #endif #ifdef CONFIG_TIVA_TIMER_16BIT static int tiva_timer16_configure(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx); #endif /**************************************************************************** * Private Data ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER0 static const struct tiva_gptmattr_s g_gptm0_attr = { .base = TIVA_TIMER0_BASE, .irq = { TIVA_IRQ_TIMER0A, TIVA_IRQ_TIMER0B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm0_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer0a_interrupt, tiva_timer0b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm0_state; #endif #ifdef CONFIG_TIVA_TIMER1 static const struct tiva_gptmattr_s g_gptm1_attr = { .base = TIVA_TIMER1_BASE, .irq = { TIVA_IRQ_TIMER1A, TIVA_IRQ_TIMER1B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm1_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer1a_interrupt, tiva_timer1b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm1_state; #endif #ifdef CONFIG_TIVA_TIMER2 static const struct tiva_gptmattr_s g_gptm2_attr = { .base = TIVA_TIMER2_BASE, .irq = { TIVA_IRQ_TIMER2A, TIVA_IRQ_TIMER2B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm2_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer2a_interrupt, tiva_timer2b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm2_state; #endif #ifdef CONFIG_TIVA_TIMER3 static const struct tiva_gptmattr_s g_gptm3_attr = { .base = TIVA_TIMER3_BASE, .irq = { TIVA_IRQ_TIMER3A, TIVA_IRQ_TIMER3B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm3_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer3a_interrupt, tiva_timer3b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm3_state; #endif #ifdef CONFIG_TIVA_TIMER4 static const struct tiva_gptmattr_s g_gptm4_attr = { .base = TIVA_TIMER4_BASE, .irq = { TIVA_IRQ_TIMER4A, TIVA_IRQ_TIMER4B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm4_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer4a_interrupt, tiva_timer4b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm4_state; #endif #ifdef CONFIG_TIVA_TIMER5 static const struct tiva_gptmattr_s g_gptm5_attr = { .base = TIVA_TIMER5_BASE, .irq = { TIVA_IRQ_TIMER5A, TIVA_IRQ_TIMER5B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm5_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer5a_interrupt, tiva_timer5b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm5_state; #endif #ifdef CONFIG_TIVA_TIMER6 static const struct tiva_gptmattr_s g_gptm6_attr = { .base = TIVA_TIMER6_BASE, .irq = { TIVA_IRQ_TIMER6A, TIVA_IRQ_TIMER6B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm6_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer6a_interrupt, tiva_timer6b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm6_state; #endif #ifdef CONFIG_TIVA_TIMER7 static const struct tiva_gptmattr_s g_gptm7_attr = { .base = TIVA_TIMER7_BASE, .irq = { TIVA_IRQ_TIMER7A, TIVA_IRQ_TIMER7B }, #ifdef CONFIG_TIVA_TIMER_32BIT .handler32 = tiva_gptm7_interrupt, #endif #ifdef CONFIG_TIVA_TIMER_16BIT .handler16 = { tiva_timer7a_interrupt, tiva_timer7b_interrupt }, #endif }; static struct tiva_gptmstate_s g_gptm7_state; #endif /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: tiva_checkreg * * Description: * Check if the current register access is a duplicate of the preceding. * * Input Parameters: * regval - The value to be written * regaddr - The address of the register to write to * * Returned Value: * true: This is the first register access of this type. * flase: This is the same as the preceding register access. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_REGDEBUG static bool tiva_timer_checkreg(struct tiva_gptmstate_s *priv, bool wr, uint32_t regval, uintptr_t regaddr) { if (wr == priv->wrlast && /* Same kind of access? */ regval == priv->vallast && /* Same value? */ regaddr == priv->addrlast) /* Same address? */ { /* Yes, then just keep a count of the number of times we did this. */ priv->ntimes++; return false; } else { /* Did we do the previous operation more than once? */ if (priv->ntimes > 0) { /* Yes... show how many times we did it */ lldbg("...[Repeats %d times]...\n", priv->ntimes); } /* Save information about the new access */ priv->wrlast = wr; priv->vallast = regval; priv->addrlast = regaddr; priv->ntimes = 0; } /* Return true if this is the first time that we have done this operation */ return true; } #endif /**************************************************************************** * Name: tiva_getreg * * Description: * Read one 32-bit GPTM register * ****************************************************************************/ static uint32_t tiva_getreg(struct tiva_gptmstate_s *priv, unsigned int offset) { uintptr_t regaddr = priv->attr->base + offset; uint32_t regval = getreg32(regaddr); #ifdef CONFIG_TIVA_TIMER_REGDEBUG if (tiva_timer_checkreg(priv, false, regval, regaddr)) { lldbg("%08x->%08x\n", regaddr, regval); } #endif return regval; } /**************************************************************************** * Name: tiva_putreg * * Description: * Write one 32-bit GPTM register * ****************************************************************************/ static void tiva_putreg(struct tiva_gptmstate_s *priv, unsigned int offset, uint32_t regval) { uintptr_t regaddr = priv->attr->base + offset; #ifdef CONFIG_TIVA_TIMER_REGDEBUG if (tiva_timer_checkreg(priv, true, regval, regaddr)) { lldbg("%08x<-%08x\n", regaddr, regval); } #endif putreg32(regval, regaddr); } /**************************************************************************** * Name: tiva_modifyreg * * Description: * This function permits atomic of any timer register by its offset into * the timer block. Its primary purpose is to support inline functions * defined in this header file. * ****************************************************************************/ static void tiva_modifyreg(struct tiva_gptmstate_s *priv, unsigned int offset, uint32_t clrbits, uint32_t setbits) { #ifdef CONFIG_TIVA_TIMER_REGDEBUG irqstate_t flags; uint32_t regval; flags = irqsave(); regval = tiva_getreg(priv, offset); regval &= ~clrbits; regval |= setbits; tiva_putreg(priv, offset, regval); irqrestore(flags); #else uintptr_t regaddr = priv->attr->base + offset; modifyreg32(regaddr, clrbits, setbits); #endif } /**************************************************************************** * Name: tiva_timer32_interrupt * * Description: * Common interrupt handler for 32-bit timers * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_32BIT static int tiva_timer32_interrupt(struct tiva_gptmstate_s *priv) { const struct tiva_gptm32config_s *config32; const struct tiva_timer32config_s *timer32; uint32_t status; DEBUGASSERT(priv && priv->attr && priv->config); /* Get the set of pending interrupts from the mask interrupt status * register. */ status = tiva_getreg(priv, TIVA_TIMER_MIS_OFFSET); DEBUGASSERT(status != 0); if (status != 0) { tiva_putreg(priv, TIVA_TIMER_ICR_OFFSET, status); /* If this was a match (or RTC match) interrupt, then disable further * match interrupts. */ if ((status & (TIMER_INT_TAM | TIMER_INT_RTC)) != 0) { status &= ~(TIMER_INT_TAM | TIMER_INT_RTC); tiva_putreg(priv, TIVA_TIMER_IMR_OFFSET, priv->imr); } /* Get the timer configuration from the private state structure */ config32 = (const struct tiva_gptm32config_s *)priv->config; timer32 = &config32->config; /* Forward the interrupt to the handler. There should always be a non- * NULL handler in this case. */ DEBUGASSERT(timer32->handler); if (timer32->handler) { timer32->handler((TIMER_HANDLE)priv, timer32->arg, status); } } return OK; } #endif /**************************************************************************** * Name: tiva_gptmN_interrupt, N=0..7 * * Description: * Individual interrupt handlers for each 32-bit timer * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_32BIT #ifdef CONFIG_TIVA_TIMER0 static int tiva_gptm0_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm0_state); } #endif #ifdef CONFIG_TIVA_TIMER1 static int tiva_gptm1_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm1_state); } #endif #ifdef CONFIG_TIVA_TIMER2 static int tiva_gptm2_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm2_state); } #endif #ifdef CONFIG_TIVA_TIMER3 static int tiva_gptm3_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm3_state); } #endif #ifdef CONFIG_TIVA_TIMER4 static int tiva_gptm4_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm4_state); } #endif #ifdef CONFIG_TIVA_TIMER5 static int tiva_gptm5_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm5_state); } #endif #ifdef CONFIG_TIVA_TIMER6 static int tiva_gptm6_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm6_state); } #endif #ifdef CONFIG_TIVA_TIMER7 static int tiva_gptm7_interrupt(int irq, FAR void *context) { return tiva_timer32_interrupt(&g_gptm7_state); } #endif #endif /**************************************************************************** * Name: tiva_timer16_interrupt * * Description: * Common interrupt handler for 16-bit timers * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT static int tiva_timer16_interrupt(struct tiva_gptmstate_s *priv, int tmndx) { const struct tiva_gptm16config_s *config16; const struct tiva_timer16config_s *timer16; uint32_t intmask; uint32_t status; DEBUGASSERT(priv && priv->attr && priv->config && (unsigned)tmndx < 2); /* Read the masked interrupt status, masking out bits only for this timer. */ intmask = tmndx ? TIMERB_INTS : TIMERA_INTS; status = tiva_getreg(priv, TIVA_TIMER_MIS_OFFSET) & intmask; DEBUGASSERT(status != 0); if (status != 0) { /* Clear all pending interrupts for this timer */ tiva_putreg(priv, TIVA_TIMER_ICR_OFFSET, status); /* If this was a match interrupt, then disable further match * interrupts. */ if ((status & (TIMER_INT_TAM | TIMER_INT_TBM)) != 0) { priv->imr &= ~((TIMER_INT_TAM | TIMER_INT_TBM) & intmask); tiva_putreg(priv, TIVA_TIMER_IMR_OFFSET, priv->imr); } /* Get the timer configuration from the private state structure */ config16 = (const struct tiva_gptm16config_s *)priv->config; timer16 = &config16->config[tmndx]; /* Forward the interrupt to the handler. There should always be a * non-NULL handler in this context. */ DEBUGASSERT(timer16->handler); if (timer16->handler) { timer16->handler((TIMER_HANDLE)priv, timer16->arg, status, tmndx); } } return OK; } #endif /**************************************************************************** * Name: tiva_timerNa_interrupt, tiva_timerNb_interrupt, N=0..7 * * Description: * Individual interrupt handlers for each 16-bit timer * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT #ifdef CONFIG_TIVA_TIMER0 static int tiva_timer0a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm0_state, TIMER16A); } static int tiva_timer0b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm0_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER1 static int tiva_timer1a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm1_state, TIMER16A); } static int tiva_timer1b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm1_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER2 static int tiva_timer2a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm2_state, TIMER16A); } static int tiva_timer2b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm2_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER3 static int tiva_timer3a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm3_state, TIMER16A); } static int tiva_timer3b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm3_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER4 static int tiva_timer4a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm4_state, TIMER16A); } static int tiva_timer4b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm4_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER5 static int tiva_timer5a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm5_state, TIMER16A); } static int tiva_timer5b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm5_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER6 static int tiva_timer6a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm6_state, TIMER16A); } static int tiva_timer6b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm6_state, TIMER16B); } #endif #ifdef CONFIG_TIVA_TIMER7 static int tiva_timer7a_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm7_state, TIMER16A); } static int tiva_timer7b_interrupt(int irq, FAR void *context) { return tiva_timer16_interrupt(&g_gptm7_state, TIMER16B); } #endif #endif /**************************************************************************** * Name: tiva_oneshot_periodic_mode32 * * Description: * Configure a 32-bit timer to operate in one-shot or periodic mode * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_PERIODIC static int tiva_oneshot_periodic_mode32(struct tiva_gptmstate_s *priv, const struct tiva_timer32config_s *timer) { uint32_t regval; /* The GPTM is configured for One-Shot and Periodic modes by the following * sequence: * * 1. Ensure the timer is disabled (the TAEN bit in the GPTMCTL register * is cleared) before making any changes. * * NOTE: The TAEN bit was cleared when the timer was reset prior to * calling this function. * * 2. Write the GPTM Configuration Register (GPTMCFG) to select 32-bit * operation. */ tiva_putreg(priv, TIVA_TIMER_CFG_OFFSET, TIMER_CFG_CFG_32); /* 3. Configure the TAMR field in the GPTM Timer n Mode Register * (GPTMTAMR): * * a. Write a value of 0x1 for One-Shot mode. * b. Write a value of 0x2 for Periodic mode. * * When Timer A and TimerB are concatenated, the GPTMTBMR register is * ignored and GPTMTAMR controls the modes for both Timer A and Timer B */ regval = tiva_getreg(priv, TIVA_TIMER_TAMR_OFFSET); regval &= ~TIMER_TnMR_TnMR_MASK; if (priv->config->mode == TIMER32_MODE_ONESHOT) { regval |= TIMER_TnMR_TnMR_ONESHOT; } else /* if (priv->config->mode == TIMER32_MODE_PERIODIC) */ { regval |= TIMER_TnMR_TnMR_PERIODIC; } tiva_putreg(priv, TIVA_TIMER_TAMR_OFFSET, regval); /* 4. Optionally configure the TASNAPS, TAWOT, TAMINTD, and TACDIR bits in * the GPTMTAMR register to select whether to capture the value of the * free-running timer at time-out, use an external trigger to start * counting, configure an additional trigger or interrupt, and count up * or down. * * TASNAPS - GPTM Timer A Snap-Shot Mode * 0: Snap-shot mode is disabled (default) * 1: If the 32-bit timeris configured in the periodic mode, * the actual free-running, capture or snapshot value of * the timer is loaded at the time-out event/capture or * snapshot event into the concatenated GPTM Timer A * (GPTMTAR) register. * TAWOT - GPTM Timer A Wait-on-Trigger * 0: The 32-bit timer begins counting as soon as it is * enabled (default). * 1: If the 32-bit timer is enabled, it does not begin * counting until it receives a trigger from the timer * in the previous position in the daisy chain. * TAINTD - One-shot/Periodic Interrupt Disable * 0: Time-out interrupt functions as normal. * 1: Time-out interrupt are disabled (default). * TACDIR - GPTM Timer A Count Direction * 0: The timer counts down (default). * 1: The timer counts up. When counting up, the timer * starts from a value of 0. * * NOTE: one-shot/periodic timeout interrupts remain disabled until * tiva_timer32_setinterval is called. */ /* Setup defaults */ regval &= (TIMER_TnMR_TnCDIR | TIMER_TnMR_TnWOT | TIMER_TnMR_TnCDIR); #ifdef CONFIG_ARCH_CHIP_TM4C129 regval |= TIMER_TnMR_TnCINTD; #endif /* Enable snapshot mode? * * In periodic, snap-shot mode (TnMR field is 0x2 and the TnSNAPS bit is * set in the GPTMTnMR register), the value of the timer at the time-out * event is loaded into the GPTMTnR register and the value of the * prescaler is loaded into the GPTMTnPS register. The free-running * counter value is shown in the GPTMTnV register. In this manner, * software can determine the time elapsed from the interrupt assertion * to the ISR entry by examining the snapshot values and the current value * of the free-running timer. Snapshot mode is not available when the * timer is configured in one-shot mode. * * TODO: Not implemented */ #warning Missing Logic /* Enable wait-on-trigger? * * TODO: Not implemented */ #warning Missing Logic /* Enable count down? */ if (TIMER_ISCOUNTUP(timer)) { regval |= TIMER_TnMR_TnCDIR_UP; } tiva_putreg(priv, TIVA_TIMER_TAMR_OFFSET, regval); /* Enable and configure ADC trigger outputs */ if (TIMER_ISADCTIMEOUT(timer) || TIMER_ISADCMATCH(timer)) { #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Enable timeout triggers now (match triggers will be * enabled when the first match value is set). */ if (TIMER_ISADCTIMEOUT(timer)) { tiva_putreg(priv, TIVA_TIMER_ADCEV_OFFSET, TIMER_ADCEV_TATOADCEN); } #endif /* Enable ADC trigger outputs by setting the TAOTE bit in the * control register. */ regval = tiva_getreg(priv, TIVA_TIMER_CTL_OFFSET); regval |= TIMER_CTL_TAOTE; tiva_putreg(priv, TIVA_TIMER_CTL_OFFSET, regval); } /* In addition, if using CCP pins, the TCACT field can be programmed to * configure the compare action. */ #warning Missing Logic /* TODO: Enable and configure uDMA trigger outputs */ /* 5. Load the start value into the GPTM Timer n Interval Load Register * (GPTMTAILR). * * When a GPTM is configured to one of the 32-bit modes, GPTMTAILR * appears as a 32-bit register; the upper 16-bits correspond to bits * 15:0 of the GPTM Timer B Interval Load (GPTMTBILR) register. * Writes to GPTMTBILR are ignored. * * NOTE: The default is a free-running timer. The timer interval * reload register is clear here. It can be set to any value * desired by calling tiva_timer32_setinterval(). */ tiva_putreg(priv, TIVA_TIMER_TAILR_OFFSET, 0); /* Preload the timer counter register by setting the timer value register. * The timer value will be copied to the timer counter register on the * next clock cycle. */ if (TIMER_ISCOUNTUP(timer)) { /* Count up from zero */ tiva_putreg(priv, TIVA_TIMER_TAV_OFFSET, 0); } else { /* Count down from the timer reload value */ tiva_putreg(priv, TIVA_TIMER_TAV_OFFSET, regval); } /* 6. If interrupts are required, set the appropriate bits in the GPTM * Interrupt Mask Register (GPTMIMR). * * NOTE: Interrupts are still disabled at the NVIC. Interrupts will * be enabled at the NVIC after the timer is started. */ tiva_putreg(priv, TIVA_TIMER_IMR_OFFSET, priv->imr); /* 7. Set the TAEN bit in the GPTMCTL register to enable the timer and * start counting. * 8. Poll the GPTMRIS register or wait for the interrupt to be generated * (if enabled). In both cases, the status flags are cleared by writing * a 1 to the appropriate bit of the GPTM Interrupt Clear Register * (GPTMICR). * * NOTE: This timer is not started until tiva_gptm_enable() is called. */ return OK; } #endif /**************************************************************************** * Name: tiva_oneshot_periodic_mode16 * * Description: * Configure 16-bit timer A/B to operate in one-short or periodic mode * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER16_PERIODIC static int tiva_oneshot_periodic_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx) { unsigned int regoffset; uint32_t regval; /* The GPTM is configured for One-Shot and Periodic modes by the following * sequence: * * 1. Ensure the timer is disabled (the TnEN bit in the GPTMCTL register * is cleared) before making any changes. * * NOTE: The TnEN bit was cleared when the timer was reset prior to * calling this function. * * 2. Write the GPTM Configuration Register (GPTMCFG) to select 16-bit * operation. * * NOTE: 16-bit mode of operation was already selected in * tiva_gptm_configure() before this function was called. * * 3. Configure the TnMR field in the GPTM Timer n Mode Register * (GPTMTnMR): * a. Write a value of 0x1 for One-Shot mode. * b. Write a value of 0x2 for Periodic mode. */ regoffset = tmndx ? TIVA_TIMER_TBMR_OFFSET : TIVA_TIMER_TAMR_OFFSET; regval = tiva_getreg(priv, regoffset); regval &= ~TIMER_TnMR_TnMR_MASK; if (timer->mode == TIMER16_MODE_ONESHOT) { regval |= TIMER_TnMR_TnMR_ONESHOT; } else /* if (timer->mode == TIMER16_MODE_PERIODIC) */ { regval |= TIMER_TnMR_TnMR_PERIODIC; } tiva_putreg(priv, regoffset, regval); /* 4. Optionally configure the TnSNAPS, TnWOT, TnMINTD, and TnCDIR bits in * the GPTMTnMR register to select whether to capture the value of the * free-running timer at time-out, use an external trigger to start * counting, configure an additional trigger or interrupt, and count up * or down. In addition, if using CCP pins, the TCACT field can be * programmed to configure the compare action. * * TnSNAPS - GPTM Timer A/B Snap-Shot Mode * 0: Snap-shot mode is disabled (default) * 1: If the 16-bit timer is configured in the periodic mode, * the actual free-running, capture or snapshot value of * the timer is loaded at the time-out event/capture or * snapshot event into the GPTM Timer A/B (GPTMTnR) * register. If the timer prescaler is used, the prescaler * snapshot is loaded into the GPTM Timer A/B (GPTMTnPR). * TnWOT - GPTM Timer A/B Wait-on-Trigger * 0: The 16-bit begins counting as soon as it is enabled (default). * 1: If the 16-bit timer is enabled, it does not begin counting * until it receives a trigger from the timer in the * previous position in the daisy chain. * TnINTD - One-shot/Periodic Interrupt Disable * 0: Time-out interrupt functions as normal. * 1: Time-out interrupt are disabled (default). * TnCDIR - GPTM Timer A/B Count Direction * 0: The timer counts down (default). * 1: The timer counts up. When counting up, the timer * starts from a value of 0. * * NOTE: one-shot/periodic timeout interrupts remain disabled until * tiva_timer32_setinterval is called. */ /* Setup defaults */ regval &= (TIMER_TnMR_TnCDIR | TIMER_TnMR_TnWOT | TIMER_TnMR_TnCDIR); #ifdef CONFIG_ARCH_CHIP_TM4C129 regval |= TIMER_TnMR_TnCINTD; #endif /* Enable snapshot mode? * * In periodic, snap-shot mode (TnMR field is 0x2 and the TnSNAPS bit is * set in the GPTMTnMR register), the value of the timer at the time-out * event is loaded into the GPTMTnR register and the value of the * prescaler is loaded into the GPTMTnPS register. The free-running * counter value is shown in the GPTMTnV register. In this manner, * software can determine the time elapsed from the interrupt assertion * to the ISR entry by examining the snapshot values and the current value * of the free-running timer. Snapshot mode is not available when the * timer is configured in one-shot mode. * * TODO: Not implemented */ #warning Missing Logic /* Enable wait-on-trigger? * * TODO: Not implemented */ #warning Missing Logic /* Enable count down? */ if (TIMER_ISCOUNTUP(timer)) { regval |= TIMER_TnMR_TnCDIR_UP; } tiva_putreg(priv, regoffset, regval); /* Enable and configure ADC trigger outputs */ if (TIMER_ISADCTIMEOUT(timer) || TIMER_ISADCMATCH(timer)) { /* Enable ADC trigger outputs by setting the TnOTE bit in the * control register. */ regval = tiva_getreg(priv, TIVA_TIMER_CTL_OFFSET); regval |= tmndx ? TIMER_CTL_TBOTE : TIMER_CTL_TAOTE; tiva_putreg(priv, TIVA_TIMER_CTL_OFFSET, regval); #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Enable timeout triggers now (match triggers will be * enabled when the first match value is set). */ if (TIMER_ISADCTIMEOUT(timer)) { regval = tmndx ? TIMER_ADCEV_TBTOADCEN : TIMER_ADCEV_TATOADCEN; tiva_putreg(priv, TIVA_TIMER_ADCEV_OFFSET, regval); } #endif /* CONFIG_ARCH_CHIP_TM4C129 */ } /* TODO: Enable and configure uDMA trigger outputs */ /* In addition, if using CCP pins, the TCACT field can be programmed to * configure the compare action. */ #warning Missing Logic /* 5. Load the start value into the GPTM Timer n Interval Load Register * (GPTMTnILR). * * NOTE: The default is a free-running timer. The timer interval * reload and prescale registers are cleared here. They can be set to * any value desired by calling tiva_timer32_setinterval(). */ regoffset = tmndx ? TIVA_TIMER_TBPR_OFFSET : TIVA_TIMER_TAPR_OFFSET; tiva_putreg(priv, regoffset, 0); regoffset = tmndx ? TIVA_TIMER_TBILR_OFFSET : TIVA_TIMER_TAILR_OFFSET; tiva_putreg(priv, regoffset, 0); /* Preload the timer counter register by setting the timer value register. * The timer value will be copied to the timer counter register on the * next clock cycle. */ regoffset = tmndx ? TIVA_TIMER_TBV_OFFSET : TIVA_TIMER_TAV_OFFSET; if (TIMER_ISCOUNTUP(timer)) { /* Count up from zero */ tiva_putreg(priv, regoffset, 0); } else { /* Count down from the timer reload value */ tiva_putreg(priv, regoffset, regval); } /* 6. If interrupts are required, set the appropriate bits in the GPTM * Interrupt Mask Register (GPTMIMR). * * NOTE: Interrupts are still disabled at the NVIC. Interrupts will * be enabled at the NVIC after the timer is started. */ tiva_putreg(priv, TIVA_TIMER_IMR_OFFSET, priv->imr); /* 7. Set the TnEN bit in the GPTMCTL register to enable the timer and * start counting. * 8. Poll the GPTMRIS register or wait for the interrupt to be generated * (if enabled). In both cases, the status flags are cleared by writing * a 1 to the appropriate bit of the GPTM Interrupt Clear Register * (GPTMICR). * * NOTE: This timer is not started until tiva_gptm_enable() is called. */ return OK; } #endif /**************************************************************************** * Name: tiva_rtc_mode32 * * Description: * Configure a 32-bit timer to operate in RTC mode * * The input clock on a CCP0 input is required to be 32.768 KHz in RTC * mode. The clock signal is then divided down to a 1-Hz rate and is * passed along to the input of the counter. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_RTC static int tiva_rtc_mode32(struct tiva_gptmstate_s *priv, const struct tiva_timer32config_s *timer) { uint32_t regval; /* To use the RTC mode, the timer must have a 32.768-KHz input signal on * an even CCP input. To enable the RTC feature, follow these steps: * * 1. Ensure the timer is disabled (the TAEN bit is cleared) before making * any changes. * * NOTE: The TAEN bit was cleared when the timer was reset prior to * calling this function. * * 2. If the timer has been operating in a different mode prior to this, * clear any residual set bits in the GPTM Timer n Mode (GPTMTnMR) * register before reconfiguring. * * NOTE: The TAMR and TBMR registers were cleared when the timer * was reset prior to calling this function. * * 3. Write the GPTM Configuration Register (GPTMCFG) with a to select * the 32-bit RTC mode. */ tiva_putreg(priv, TIVA_TIMER_CFG_OFFSET, TIMER_CFG_CFG_RTC); /* 4. Write the match value to the GPTM Timer n Match Register * (GPTMTnMATCHR). * * NOTE: The match register is not set until tiva_rtc_setalarm() is * called. * * 5. Set/clear the RTCEN and TnSTALL bit in the GPTM Control Register * (GPTMCTL) as needed. * * RTCEN - 1: RTC counting continues while the processor is * halted by the debugger * TASTALL - 1: Timer A freezes counting while the processor is * halted by the debugger. */ regval = tiva_getreg(priv, TIVA_TIMER_CTL_OFFSET); #ifdef CONFIG_DEBUG_SYMBOLS regval |= (TIMER_CTL_RTCEN | TIMER_CTL_TASTALL); #else regval &= ~(TIMER_CTL_RTCEN | TIMER_CTL_TASTALL); #endif tiva_putreg(priv, TIVA_TIMER_CTL_OFFSET, regval); /* 6. If interrupts are required, set the RTCIM bit in the GPTM Interrupt * Mask Register (GPTMIMR). * * NOTE: RTC interrupts are not enabled until tiva_rtc_setalarm() is * called. * * 7. Set the TAEN bit in the GPTMCTL register to enable the timer and * start counting. * * When the timer count equals the value in the GPTMTnMATCHR register, * the GPTM asserts the RTCRIS bit in the GPTMRIS register and continues * counting until Timer A is disabled or a hardware reset. The interrupt * is cleared by writing the RTCCINT bit in the GPTMICR register. Note * that if the GPTMTnILR register is loaded with a new value, the timer * begins counting at this new value and continues until it reaches * 0xFFFF.FFFF, at which point it rolls over. * * NOTE: The RTC timer will not be enabled until tiva_gptm_enable() is * called. */ return OK; } #endif /**************************************************************************** * Name: tiva_input_edgecount_mode16 * * Description: * Configure 16-bit timer A/B to operate in Input Edge-Count mode * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_EDGECOUNT static int tiva_input_edgecount_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx) { /* A timer is configured to Input Edge-Count mode by the following sequence: * * 1. Ensure the timer is disabled (the TnEN bit is cleared) before making * any changes. * * NOTE: The TnEN bit was cleared when the timer was reset prior to * calling this function. * * 2. Write the GPTM Configuration Register (GPTMCFG) to select 16-bit * operation. * * NOTE: 16-bit mode of operation was already selected in * tiva_gptm_configure() before this function was called. * * 3. In the GPTM Timer Mode (GPTMTnMR) register, write the TnCMR field to * 0x0 and the TnMR field to 0x3. */ /* 4. Configure the type of event(s) that the timer captures by writing * the TnEVENT field of the GPTM Control (GPTMCTL) register. */ /* 5. Program registers according to count direction: * * - In down-count mode, the GPTMTnMATCHR and GPTMTnPMR registers are * configured so that the difference between the value in the GPTMTnILR * and GPTMTnPR registers and the GPTMTnMATCHR and GPTMTnPMR registers * equals the number of edge events that must be counted. * * - In up-count mode, the timer counts from 0x0 to the value in the * GPTMTnMATCHR and GPTMTnPMR registers. Note that when executing an * up-count, the value of the GPTMTnPR and GPTMTnILR must be greater * than the value of GPTMTnPMR and GPTMTnMATCHR. */ /* 6. If interrupts are required, set the CnMIM bit in the GPTM Interrupt * Mask (GPTMIMR) register. */ #warning Missing Logic /* 7. Set the TnEN bit in the GPTMCTL register to enable the timer and * begin waiting for edge events. * 8. Poll the CnMRIS bit in the GPTMRIS register or wait for the * interrupt to be generated (if enabled). In both cases, the status * flags are cleared by writing a 1 to the CnMCINT bit of the GPTM * Interrupt Clear (GPTMICR) register. * * When counting down in Input Edge-Count Mode, the timer stops after the * programmed number of edge events has been detected. To re-enable the * timer, ensure that the TnEN bit is cleared and repeat steps 4 through 8. * * NOTE: This timer is not started until tiva_gptm_enable() is called. */ return -ENOSYS; } #endif /**************************************************************************** * Name: tiva_input_time_mode16 * * Description: * Configure 16-bit timer A/B to operate in Input Time mode * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_TIMECAP static int tiva_input_time_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx) { /* A timer is configured to Input Edge Time mode by the following sequence: * * 1. Ensure the timer is disabled (the TnEN bit is cleared) before making * any changes. * * NOTE: The TnEN bit was cleared when the timer was reset prior to * calling this function. * * 2. Write the GPTM Configuration Register (GPTMCFG) to select 16-bit * operation. * * NOTE: 16-bit mode of operation was already selected in * tiva_gptm_configure() before this function was called. * * 3. In the GPTM Timer Mode (GPTMTnMR) register, write the TnCMR field to * 0x1 and the TnMR field to 0x3 and select a count direction by * programming the TnCDIR bit. */ /* 4. Configure the type of event that the timer captures by writing the * TnEVENT field of the GPTM Control (GPTMCTL) register. */ /* 5. If a prescaler is to be used, write the prescale value to the GPTM * Timer n Prescale Register (GPTMTnPR). */ /* 6. Load the timer start value into the GPTM Timer n Interval Load * (GPTMTnILR) register. * * REVISIT: When the ALTCLK bit is set in the GPTMCC register to enable * using the alternate clock source, the synchronization imposes * restrictions on the starting count value (down-count), terminal value * (up-count) and the match value. This restriction applies to all modes * of operation. Each event must be spaced by 4 Timer (ALTCLK) clock * periods + 2 system clock periods. If some events do not meet this * requirement, then it is possible that the timer block may need to be * reset for correct functionality to be restored. * * Example: ALTCLK= TPIOSC = 62.5ns (16Mhz Trimmed) * Thclk = 1us (1Mhz) * 4*62.5ns + 2*1us = 2.25us 2.25us/62.5ns = 36 or 0x23 * * The minimum values for the periodic or one-shot with a match * interrupt enabled are: GPTMTAMATCHR = 0x23 GPTMTAILR = 0x46" */ /* 7. If interrupts are required, set the CnEIM bit in the GPTM Interrupt * Mask (GPTMIMR) register. */ #warning Missing Logic /* 8. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable the * timer and start counting. * 9. Poll the CnERIS bit in the GPTMRIS register or wait for the interrupt * to be generated (if enabled). In both cases, the status flags are * cleared by writing a 1 to the CnECINT bit of the GPTM Interrupt * Clear (GPTMICR) register. The time at which the event happened can * be obtained by reading the GPTM Timer n (GPTMTnR) register. * * In Input Edge Timing mode, the timer continues running after an edge * event has been detected, but the timer interval can be changed at any * time by writing the GPTMTnILR register and clearing the TnILD bit in * the GPTMTnMR register. The change takes effect at the next cycle after * the write. * * NOTE: This timer is not started until tiva_gptm_enable() is called. */ return -ENOSYS; } #endif /**************************************************************************** * Name: tiva_pwm_mode16 * * Description: * Configure 16-bit timer A/B to operate in PWM mode * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_PWM static int tiva_pwm_mode16(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx) { /* A timer is configured to PWM mode using the following sequence: * * 1. Ensure the timer is disabled (the TnEN bit is cleared) before making * any changes. * * NOTE: The TnEN bit was cleared when the timer was reset prior to * calling this function. * * 2. Write the GPTM Configuration Register (GPTMCFG) to select 16-bit * operation. * * NOTE: 16-bit mode of operation was already selected in * tiva_gptm_configure() before this function was called. * * 3. In the GPTM Timer Mode (GPTMTnMR) register, set the TnAMS bit to * 0x1, the TnCMR bit to 0x0, and the TnMR field to 0x2. */ /* 4. Configure the output state of the PWM signal (whether or not it is * inverted) in the TnPWML field of the GPTM Control (GPTMCTL) register. */ /* 5. If a prescaler is to be used, write the prescale value to the GPTM * Timer n Prescale Register (GPTMTnPR). */ /* 6. If PWM interrupts are used, configure the interrupt condition in the * TnEVENT field in the GPTMCTL register and enable the interrupts by * setting the TnPWMIE bit in the GPTMTnMR register. Note that edge * detect interrupt behavior is reversed when the PWM output is * inverted. */ /* 7. Load the timer start value into the GPTM Timer n Interval Load * (GPTMTnILR) register. * * REVISIT: When the ALTCLK bit is set in the GPTMCC register to enable * using the alternate clock source, the synchronization imposes * restrictions on the starting count value (down-count), terminal value * (up-count) and the match value. This restriction applies to all modes * of operation. Each event must be spaced by 4 Timer (ALTCLK) clock * periods + 2 system clock periods. If some events do not meet this * requirement, then it is possible that the timer block may need to be * reset for correct functionality to be restored. * * Example: ALTCLK= TPIOSC = 62.5ns (16Mhz Trimmed) * Thclk = 1us (1Mhz) * 4*62.5ns + 2*1us = 2.25us 2.25us/62.5ns = 36 or 0x23 * * The minimum values for the periodic or one-shot with a match * interrupt enabled are: GPTMTAMATCHR = 0x23 GPTMTAILR = 0x46" */ /* 8. Load the GPTM Timer n Match (GPTMTnMATCHR) register with the match * value. */ #warning Missing Logic /* 9. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable * the timer and begin generation of the output PWM signal. * * In PWM Time mode, the timer continues running after the PWM signal has * been generated. The PWM period can be adjusted at any time by writing * the GPTMTnILR register, and the change takes effect at the next cycle * after the write. * * NOTE: This timer is not started until tiva_gptm_enable() is called. */ return -ENOSYS; } #endif /**************************************************************************** * Name: tiva_timer32_configure * * Description: * Configure the 32-bit timer to operate in the provided mode. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_32BIT static int tiva_timer32_configure(struct tiva_gptmstate_s *priv, const struct tiva_timer32config_s *timer) { switch (priv->config->mode) { #ifdef CONFIG_TIVA_TIMER32_PERIODIC case TIMER32_MODE_ONESHOT: /* 32-bit programmable one-shot timer */ case TIMER32_MODE_PERIODIC: /* 32-bit programmable periodic timer */ return tiva_oneshot_periodic_mode32(priv, timer); #endif /* CONFIG_TIVA_TIMER32_PERIODIC */ #ifdef CONFIG_TIVA_TIMER32_RTC case TIMER32_MODE_RTC: /* 32-bit RTC with external 32.768-KHz * input */ return tiva_rtc_mode32(priv, timer); #endif default: return -EINVAL; } } #endif /**************************************************************************** * Name: tiva_timer16_configure * * Description: * Configure 16-bit timer A or B to operate in the provided mode. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT static int tiva_timer16_configure(struct tiva_gptmstate_s *priv, const struct tiva_timer16config_s *timer, int tmndx) { /* Configure the timer per the selected mode */ switch (timer->mode) { case TIMER16_MODE_NONE: return OK; #ifdef CONFIG_TIVA_TIMER16_PERIODIC case TIMER16_MODE_ONESHOT: /* 16-bit programmable one-shot timer */ case TIMER16_MODE_PERIODIC: /* 16-bit programmable periodic timer */ return tiva_oneshot_periodic_mode16(priv, timer, tmndx); #endif #ifdef CONFIG_TIVA_TIMER32_EDGECOUNT case TIMER16_MODE_COUNT_CAPTURE: /* 16-bit input-edge count-capture * mode w/8-bit prescaler */ return tiva_input_edgecount_mode16(priv, timer, tmndx); #endif #ifdef CONFIG_TIVA_TIMER32_TIMECAP case TIMER16_MODE_TIME_CAPTURE: /* 16-bit input-edge time-capture * mode w/8-bit prescaler */ return tiva_input_time_mode16(priv, timer, tmndx); #endif #ifdef CONFIG_TIVA_TIMER32_PWM case TIMER16_MODE_PWM: /* 16-bit PWM output mode w/8-bit * prescaler */ return tiva_pwm_mode16(priv, timer, tmndx); #endif default: return -EINVAL; } } #endif /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: tiva_gptm_configure * * Description: * Configure a general purpose timer module to operate in the provided * modes. * * Input Parameters: * gptm - Describes the configure of the GPTM timer resources * * Returned Value: * On success, a non-NULL handle is returned that can be used with the * other timer interfaces. NULL is returned on any failure to initialize * the timer. * ****************************************************************************/ TIMER_HANDLE tiva_gptm_configure(const struct tiva_gptmconfig_s *config) { const struct tiva_gptmattr_s *attr; struct tiva_gptmstate_s *priv; uint32_t regval; int ret; DEBUGASSERT(config); /* Select the GPTM module. */ switch (config->gptm) { #ifdef CONFIG_TIVA_TIMER0 case 0: /* Enable GPTM0 clocking and power */ attr = &g_gptm0_attr; priv = &g_gptm0_state; break; #endif #ifdef CONFIG_TIVA_TIMER1 case 1: attr = &g_gptm1_attr; priv = &g_gptm1_state; break; #endif #ifdef CONFIG_TIVA_TIMER2 case 2: attr = &g_gptm2_attr; priv = &g_gptm2_state; break; #endif #ifdef CONFIG_TIVA_TIMER3 case 3: attr = &g_gptm3_attr; priv = &g_gptm3_state; break; #endif #ifdef CONFIG_TIVA_TIMER4 case 4: attr = &g_gptm4_attr; priv = &g_gptm4_state; break; #endif #ifdef CONFIG_TIVA_TIMER5 case 5: attr = &g_gptm5_attr; priv = &g_gptm5_state; break; #endif #ifdef CONFIG_TIVA_TIMER6 case 6: attr = &g_gptm6_attr; priv = &g_gptm6_state; break; #endif #ifdef CONFIG_TIVA_TIMER7 case 7: attr = &g_gptm7_attr; priv = &g_gptm7_state; break; #endif default: return (TIMER_HANDLE)NULL; } /* Initialize the state structure */ memset(priv, 0, sizeof(struct tiva_gptmstate_s)); priv->attr = attr; priv->config = config; /* Disable and detach all interrupt handlers */ up_disable_irq(attr->irq[TIMER16A]); up_disable_irq(attr->irq[TIMER16B]); (void)irq_detach(attr->irq[TIMER16A]); (void)irq_detach(attr->irq[TIMER16B]); /* Enable power and clocking to the GPTM module * * - Enable Power (TM4C129 family only): Applies power (only) to the GPTM * module. This is not an essential step since enabling clocking * will also apply power. The only significance is that the GPTM state * will be retained if the GPTM clocking is subsequently disabled. * - Enable Clocking (All families): Applies both power and clocking to * the GPTM module, bringing it a fully functional state. */ tiva_gptm_enableclk(config->gptm); tiva_gptm_enablepwr(config->gptm); /* Wait for the gptm to become ready before modifying its registers */ while (!tiva_gpio_periphrdy(config->gptm)); /* Reset the timer to be certain that it is in the disabled state */ regval = getreg32(TIVA_SYSCON_SRTIMER); regval |= SYSCON_SRTIMER(config->gptm); putreg32(regval, TIVA_SYSCON_SRTIMER); regval &= ~SYSCON_SRTIMER(config->gptm); putreg32(regval, TIVA_SYSCON_SRTIMER); /* Wait for the reset to complete */ while (!tiva_emac_periphrdy()); up_udelay(250); /* Select the alternate timer clock source is so requested. The general * purpose timer has the capability of being clocked by either the system * clock or an alternate clock source. By setting the ALTCLK bit in the * GPTM Clock Configuration (GPTMCC) register, software can selects an * alternate clock source as programmed in the Alternate Clock * Configuration (ALTCLKCFG) register in the System Control Module. The * alternate clock source options available are PIOSC, RTCOSC and LFIOSC. * * NOTE: The actual alternate clock source selection is a global property * and cannot be configure on a timer-by-timer basis here. That selection * must be done by common logic earlier in the initialization sequence. * * NOTE: Both the frequency of the SysClk (SYSCLK_FREQUENCY) and of the * alternate clock (ALTCLK_FREQUENCY) must be provided in the board.h * header file. */ if (config->alternate) { #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Enable the alternate clock source */ regval = tiva_getreg(priv, TIVA_TIMER_CC_OFFSET); regval |= TIMER_CC_ALTCLK; tiva_putreg(priv, TIVA_TIMER_CC_OFFSET, regval); /* Remember the frequency of the input clock */ priv->clkin = ALTCLK_FREQUENCY; #else timvdbg("tiva_gptm_configure: Error: alternate clock only available on TM4C129 devices\n"); return (TIMER_HANDLE)NULL; #endif /* CONFIG_ARCH_CHIP_TM4C129 */ } else { /* Remember the frequency of the input clock */ priv->clkin = SYSCLK_FREQUENCY; } /* Then [re-]configure the timer into the new configuration */ if (config->mode != TIMER16_MODE) { #ifdef CONFIG_TIVA_TIMER_32BIT const struct tiva_gptm32config_s *config32 = (const struct tiva_gptm32config_s *)config; /* Attach the 32-bit timer interrupt handler (but do not yet enable * the interrupt). */ ret = irq_attach(attr->irq[TIMER32], attr->handler32); if (ret == OK) { /* Configure the 32-bit timer */ ret = tiva_timer32_configure(priv, &config32->config); } #else return (TIMER_HANDLE)NULL; #endif } else { #ifdef CONFIG_TIVA_TIMER_16BIT const struct tiva_gptm16config_s *config16 = (const struct tiva_gptm16config_s *)config; /* Attach the 16-bit timer interrupt handlers (but do not yet enable * the interrupts). */ ret = irq_attach(attr->irq[TIMER16A], attr->handler16[TIMER16A]); if (ret == OK) { ret = irq_attach(attr->irq[TIMER16B], attr->handler16[TIMER16B]); } if (ret == OK) { /* Write the GPTM Configuration Register (GPTMCFG) to select 16- * bit operation. */ tiva_putreg(priv, TIVA_TIMER_CFG_OFFSET, TIMER_CFG_CFG_16); /* Configure 16-bit timer A */ ret = tiva_timer16_configure(priv, &config16->config[TIMER16A], TIMER16A); } /* Configure 16-bit timer B */ if (ret == OK) { ret = tiva_timer16_configure(priv, &config16->config[TIMER16B], TIMER16B); } #else return (TIMER_HANDLE)NULL; #endif } /* Return the timer handler if successfully configured */ return ret < 0 ? (TIMER_HANDLE)NULL : (TIMER_HANDLE)priv; } /**************************************************************************** * Name: tiva_gptm_release * * Description: * Release resources held by the timer instance. After this function is * called, the timer handle is invalid and must not be used further. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * * Returned Value: * None. * ****************************************************************************/ void tiva_gptm_release(TIMER_HANDLE handle) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_gptmconfig_s *config; const struct tiva_gptmattr_s *attr; uint32_t regval; DEBUGASSERT(priv && priv->attr && priv->config); config = priv->config; attr = priv->attr; /* Disable and detach interrupt handlers */ up_disable_irq(attr->irq[TIMER16A]); up_disable_irq(attr->irq[TIMER16B]); (void)irq_detach(attr->irq[TIMER16A]); (void)irq_detach(attr->irq[TIMER16B]); /* Reset the time to be certain that it is in the disabled state */ regval = getreg32(TIVA_SYSCON_SRTIMER); regval |= SYSCON_SRTIMER(config->gptm); putreg32(regval, TIVA_SYSCON_SRTIMER); regval &= ~SYSCON_SRTIMER(config->gptm); putreg32(regval, TIVA_SYSCON_SRTIMER); /* Wait for the reset to complete */ while (!tiva_emac_periphrdy()); up_udelay(250); /* Disable power and clocking to the GPTM module */ tiva_gptm_disableclk(config->gptm); tiva_gptm_disablepwr(config->gptm); /* Un-initialize the state structure */ memset(priv, 0, sizeof(struct tiva_gptmstate_s)); } /**************************************************************************** * Name: tiva_gptm_putreg * * Description: * This function permits setting of any timer register by its offset into * the timer block. Its primary purpose is to support inline functions * defined in this header file. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * offset - The offset to the timer register to be written * value - The value to write to the timer register * * Returned Value: * None. * ****************************************************************************/ void tiva_gptm_putreg(TIMER_HANDLE handle, unsigned int offset, uint32_t value) { DEBUGASSERT(handle); tiva_putreg((struct tiva_gptmstate_s *)handle, offset, value); } /**************************************************************************** * Name: tiva_gptm_getreg * * Description: * This function permits reading of any timer register by its offset into * the timer block. Its primary purpose is to support inline functions * defined in this header file. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * offset - The offset to the timer register to be written * * Returned Value: * The 32-bit value read at the provided offset into the timer register base * address. * ****************************************************************************/ uint32_t tiva_gptm_getreg(TIMER_HANDLE handle, unsigned int offset) { DEBUGASSERT(handle); return tiva_getreg((struct tiva_gptmstate_s *)handle, offset); } /**************************************************************************** * Name: tiva_gptm_modifyreg * * Description: * This function permits atomic of any timer register by its offset into * the timer block. Its primary purpose is to support inline functions * defined in this header file. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * offset - The offset to the timer register to be written * clrbits - The collection of bits to be cleared in the register * setbits - The collection of bits to be set in the register * * Returned Value: * None. * ****************************************************************************/ void tiva_gptm_modifyreg(TIMER_HANDLE handle, unsigned int offset, uint32_t clrbits, uint32_t setbits) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; DEBUGASSERT(priv && priv->attr); tiva_modifyreg(priv, offset, clrbits, setbits); } /**************************************************************************** * Name: tiva_timer32_start * * Description: * After tiva_gptm_configure() has been called to configure a 32-bit timer, * this function must be called to start the timer(s). * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_32BIT void tiva_timer32_start(TIMER_HANDLE handle) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; DEBUGASSERT(priv && priv->attr); /* Set the TAEN bit in the GPTMCTL register to enable the 32-bit timer and * start counting */ tiva_modifyreg(priv, TIVA_TIMER_CTL_OFFSET, 0, TIMER_CTL_TAEN); /* Enable interrupts at the NVIC if interrupts are expected */ if (priv->imr) { up_enable_irq(priv->attr->irq[TIMER32]); } } #endif /**************************************************************************** * Name: tiva_timer16_start * * Description: * After tiva_gptm_configure() has been called to configure 16-bit timer(s), * this function must be called to start one 16-bit timer. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT void tiva_timer16_start(TIMER_HANDLE handle, int tmndx) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; uint32_t setbits; uint32_t intmask; DEBUGASSERT(priv && priv->attr && (unsigned)tmndx < 2); /* Set the TnEN bit in the GPTMCTL register to enable the 16-bit timer and * start counting */ setbits = tmndx ? TIMER_CTL_TBEN : TIMER_CTL_TAEN; tiva_modifyreg(priv, TIVA_TIMER_CTL_OFFSET, 0, setbits); /* Enable interrupts at the NVIC if interrupts are expected */ intmask = tmndx ? TIMERB_INTS : TIMERA_INTS; if ((priv->imr & intmask) != 0) { up_enable_irq(priv->attr->irq[tmndx]); } } #endif /**************************************************************************** * Name: tiva_timer32_stop * * Description: * After tiva_timer32_start() has been called to start a 32-bit timer, * this function may be called to stop the timer. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_32BIT void tiva_timer32_stop(TIMER_HANDLE handle) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; DEBUGASSERT(priv && priv->attr); /* Disable interrupts at the NVIC */ up_disable_irq(priv->attr->irq[TIMER32]); /* Clear the TAEN bit in the GPTMCTL register to disable the 16-bit timer */ tiva_modifyreg(priv, TIVA_TIMER_CTL_OFFSET, TIMER_CTL_TAEN, 0); } #endif /**************************************************************************** * Name: tiva_timer16_stop * * Description: * After tiva_timer32_start() has been called to start a 16-bit timer, * this function may be called to stop the timer. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT void tiva_timer16_stop(TIMER_HANDLE handle, int tmndx) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; uint32_t clrbits; DEBUGASSERT(priv && priv->attr && (unsigned)tmndx < 2); /* Disable interrupts at the NVIC */ up_disable_irq(priv->attr->irq[tmndx]); /* Clear the TnEN bit in the GPTMCTL register to disable the 16-bit timer */ clrbits = tmndx ? TIMER_CTL_TBEN : TIMER_CTL_TAEN; tiva_gptm_modifyreg(handle, TIVA_TIMER_CTL_OFFSET, clrbits, 0); } #endif /**************************************************************************** * Name: tiva_timer16_counter * * Description: * Return the current 24-bit counter value of the 16-bit timer. * * The timer 24-bit value is the 16-bit counter value AND the 8-bit * prescaler value. From the caller's point of view the match value is * the 24-bit timer at the timer input clock frequency. * * When counting down in periodic modes, the prescaler contains the * least-significant bits of the count. When counting up, the prescaler * holds the most-significant bits of the count. But the caller is * protected from this complexity. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer * * Returned Value: * The current 24-bit counter value. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT uint32_t tiva_timer16_counter(TIMER_HANDLE handle, int tmndx) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_gptm16config_s *gptm; const struct tiva_timer16config_s *config; irqstate_t flags; uintptr_t base; uintptr_t timerr; uintptr_t prescr; uint32_t timerv; uint32_t prescv; uint32_t checkv; uint32_t counter; DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode == TIMER16_MODE && (unsigned)tmndx < 2); /* Get settings common to both 16-bit timers */ gptm = (const struct tiva_gptm16config_s *)priv->config; base = priv->attr->base; /* Get settings unique to one of the 16-bit timers */ if (tmndx) { /* Get the Timer B configuration */ config = &gptm->config[TIMER16B]; /* Get Timer B register addresses */ timerr = base + TIVA_TIMER_TBR_OFFSET; prescr = base + TIVA_TIMER_TBPR_OFFSET; } else { /* Get the Timer A configuration */ config = &gptm->config[TIMER16A]; /* Get Timer A register addresses */ timerr = base + TIVA_TIMER_TAR_OFFSET; prescr = base + TIVA_TIMER_TAPR_OFFSET; } /* Are we counting up or down? */ if (TIMER_ISCOUNTUP(config)) { /* We are counting up. The prescaler holds the most-significant bits of * the count. Sample these registers until we are assured that there * is no roll-over from the counter to the prescaler register. */ do { flags = irqsave(); checkv = getreg32(prescr); timerv = getreg32(timerr); prescv = getreg32(prescr); irqrestore(flags); } while (checkv != prescv); /* Then form the 32-bit counter value with the prescaler as the most * significant 8-bits. */ counter = (prescv & 0xff) << 16 | (timerv & 0xffff); } else { /* We are counting down. The prescaler contains the least-significant * bits of the count. Sample these registers until we are assured that * there is no roll-over from the counter to the counter register. */ do { flags = irqsave(); checkv = getreg32(timerr); prescv = getreg32(prescr); timerv = getreg32(timerr); irqrestore(flags); } while (checkv != timerv); /* Then form the 32-bit counter value with the counter as the most * significant 8-bits. */ counter = (timerv & 0xffff) << 8 | (prescv & 0xff); } /* Return the counter value */ return counter; } #endif /**************************************************************************** * Name: tiva_timer32_setinterval * * Description: * This function may be called at any time to change the timer interval * load value of a 32-bit timer. * * It the timer is configured as a 32-bit one-shot or periodic timer, then * then function will also enable timeout interrupts. * * NOTE: As of this writing, there is no interface to disable the timeout * interrupts once they have been enabled. * * REVISIT: When the ALTCLK bit is set in the GPTMCC register to enable * using the alternate clock source, the synchronization imposes * restrictions on the starting count value (down-count), terminal value * (up-count) and the match value. This restriction applies to all modes * of operation. Each event must be spaced by 4 Timer (ALTCLK) clock * periods + 2 system clock periods. If some events do not meet this * requirement, then it is possible that the timer block may need to be * reset for correct functionality to be restored. * * Example: ALTCLK= TPIOSC = 62.5ns (16Mhz Trimmed) * Thclk = 1us (1Mhz) * 4*62.5ns + 2*1us = 2.25us 2.25us/62.5ns = 36 or 0x23 * * The minimum values for the periodic or one-shot with a match * interrupt enabled are: GPTMTAMATCHR = 0x23 GPTMTAILR = 0x46" * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * interval - The value to write to the timer interval load register * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_32BIT void tiva_timer32_setinterval(TIMER_HANDLE handle, uint32_t interval) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_gptm32config_s *config; const struct tiva_timer32config_s *timer; irqstate_t flags; uintptr_t base; uintptr_t loadr; uintptr_t imrr; #ifdef CONFIG_ARCH_CHIP_TM4C129 uintptr_t moder; uint32_t modev1; uint32_t modev2; #endif /* CONFIG_ARCH_CHIP_TM4C129 */ bool toints; DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode != TIMER16_MODE); config = (const struct tiva_gptm32config_s *)priv->config; timer = &config->config; /* Do we need to enable timeout interrupts? Interrupts are only enabled * if (1) the user has provided a handler, and (2) the timer timer is * configure as a one-short or periodic timer. */ base = priv->attr->base; toints = false; if (timer->handler && (config->cmn.mode == TIMER32_MODE_ONESHOT || config->cmn.mode == TIMER32_MODE_PERIODIC)) { toints = true; } loadr = base + TIVA_TIMER_TAILR_OFFSET; imrr = base + TIVA_TIMER_IMR_OFFSET; /* Make the following atomic */ flags = irqsave(); /* Set the new timeout interval */ putreg32(interval, loadr); /* Enable/disable timeout interrupts */ if (toints) { #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Clearing the TACINTD bit allows the time-out interrupt to be * generated as normal */ moder = base + TIVA_TIMER_TAMR_OFFSET; modev1 = getreg32(moder); modev2 = modev1 & ~TIMER_TnMR_TnCINTD; putreg32(modev2, moder); #endif /* CONFIG_ARCH_CHIP_TM4C129 */ /* Set the new interrupt mask */ priv->imr |= TIMER_INT_TATO; putreg32(priv->imr, imrr); } irqrestore(flags); #ifdef CONFIG_TIVA_TIMER_REGDEBUG /* Generate low-level debug output outside of the critical section */ lldbg("%08x<-%08x\n", loadr, interval); if (toints) { # ifdef CONFIG_ARCH_CHIP_TM4C129 lldbg("%08x->%08x\n", moder, modev1); lldbg("%08x<-%08x\n", moder, modev2); # endif /* CONFIG_ARCH_CHIP_TM4C129 */ lldbg("%08x<-%08x\n", imrr, priv->imr); } #endif } #endif /**************************************************************************** * Name: tiva_timer16_setinterval * * Description: * This function may be called at any time to change the timer interval * load value of a 16-bit timer. * * It the timer is configured as a 16-bit one-shot or periodic timer, then * then function will also enable timeout interrupts. * * NOTE: As of this writing, there is no interface to disable the timeout * interrupts once they have been enabled. * * REVISIT: When the ALTCLK bit is set in the GPTMCC register to enable * using the alternate clock source, the synchronization imposes * restrictions on the starting count value (down-count), terminal value * (up-count) and the match value. This restriction applies to all modes * of operation. Each event must be spaced by 4 Timer (ALTCLK) clock * periods + 2 system clock periods. If some events do not meet this * requirement, then it is possible that the timer block may need to be * reset for correct functionality to be restored. * * Example: ALTCLK= TPIOSC = 62.5ns (16Mhz Trimmed) * Thclk = 1us (1Mhz) * 4*62.5ns + 2*1us = 2.25us 2.25us/62.5ns = 36 or 0x23 * * The minimum values for the periodic or one-shot with a match * interrupt enabled are: GPTMTAMATCHR = 0x23 GPTMTAILR = 0x46" * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * interval - The value to write to the timer interval load register * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER_16BIT void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_gptm16config_s *config; const struct tiva_timer16config_s *timer; irqstate_t flags; uintptr_t base; uintptr_t loadr; uintptr_t imrr; #ifdef CONFIG_ARCH_CHIP_TM4C129 uintptr_t moder; uint32_t modev1; uint32_t modev2; #endif /* CONFIG_ARCH_CHIP_TM4C129 */ uint32_t intbit; bool toints; DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode != TIMER16_MODE); config = (const struct tiva_gptm16config_s *)priv->config; timer = &config->config[tmndx]; /* Pre-calculate as much as possible outside of the critical section */ base = priv->attr->base; if (tmndx) { intbit = TIMER_INT_TBTO; loadr = base + TIVA_TIMER_TBILR_OFFSET; } else { intbit = TIMER_INT_TATO; loadr = base + TIVA_TIMER_TAILR_OFFSET; } imrr = base + TIVA_TIMER_IMR_OFFSET; /* Do we need to enable timeout interrupts? Interrupts are only enabled * if (1) the user has provided a handler, and (2) the timer timer is * configure as a one-short or periodic timer. */ toints = false; if (timer->handler && (config->cmn.mode == TIMER16_MODE_ONESHOT || config->cmn.mode == TIMER16_MODE_PERIODIC)) { toints = true; } /* Make the following atomic */ flags = irqsave(); /* Set the new timeout interval */ putreg32(interval, loadr); /* Enable/disable timeout interrupts */ if (toints) { #ifdef CONFIG_ARCH_CHIP_TM4C129 if (tmndx) { moder = base + TIVA_TIMER_TBMR_OFFSET; } else { moder = base + TIVA_TIMER_TAMR_OFFSET; } /* Clearing the TACINTD bit allows the time-out interrupt to be * generated as normal */ modev1 = getreg32(moder); modev2 = modev1 & ~TIMER_TnMR_TnCINTD; putreg32(modev2, moder); #endif /* CONFIG_ARCH_CHIP_TM4C129 */ /* Set the new interrupt mask */ priv->imr |= intbit; putreg32(priv->imr, imrr); } irqrestore(flags); #ifdef CONFIG_TIVA_TIMER_REGDEBUG /* Generate low-level debug output outside of the critical section */ lldbg("%08x<-%08x\n", loadr, interval); if (toints) { #ifdef CONFIG_ARCH_CHIP_TM4C129 lldbg("%08x->%08x\n", moder, modev1); lldbg("%08x<-%08x\n", moder, modev2); #endif lldbg("%08x<-%08x\n", imrr, priv->imr); } #endif } #endif /**************************************************************************** * Name: tiva_timer32_remaining * * Description: * Get the time remaining before a one-shot or periodic 32-bit timer * expires. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure(). * * Returned Value: * Time remaining until the next timeout interrupt. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_PERIODIC uint32_t tiva_timer32_remaining(TIMER_HANDLE handle) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_gptm32config_s *config; irqstate_t flags; uint32_t counter; uint32_t status; uint32_t interval; uint32_t remaining; timvdbg("Entry\n"); DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode != TIMER16_MODE); config = (const struct tiva_gptm32config_s *)priv->config; DEBUGASSERT(config->cmn.mode == TIMER32_MODE_ONESHOT || config->cmn.mode == TIMER32_MODE_PERIODIC); /* These values can be modified if a timer interrupt were to occur. Best * to do this is a critical section. */ flags = irqsave(); /* Get the time remaining until the timer expires (in clock ticks). * Since we have selected a count-up timer timer and the interval will * expire when the count-up timer equals the timeout value, the * difference between the current count value and the timeout is the * time remaining. * * There is a race condition here. What if the timer expires and * counter rolls over between the time that we disabled interrupts * above and the time that we read the counter below? */ counter = tiva_getreg(priv, TIVA_TIMER_TAR_OFFSET); /* If the timer rolled over, there would be a pending timer interrupt. In * that case, the time remaining time is zero. */ status = tiva_getreg(priv, TIVA_TIMER_MIS_OFFSET); if ((status & TIMER_INT_TATO) != 0) { remaining = 0; } else { /* Is this a count-up or a count-down timer? */ if (TIMER_ISCOUNTUP(&config->config)) { /* Counting up.. When the timer is counting up and it reaches the * timeout event (the value in the GPTMTAILR, the timer reloads * with zero. * * Get the current timer interval value */ interval = tiva_getreg(priv, TIVA_TIMER_TAILR_OFFSET); /* The time remaining is the current interval reload value minus * the above sampled counter value. * * REVISIT: Or the difference +1? */ DEBUGASSERT(interval == 0 || interval >= counter); remaining = interval - counter; } else { /* Counting down: When the timer is counting down and it reaches * the timeout event (0x0), the timer reloads its start value * from the GPTMTAILR register on the next cycle. * * The time remaining it then just the the value of the counter * register. * * REVISIT: Or the counter value +1? */ remaining = counter; } } irqrestore(flags); return remaining; } #endif /* CONFIG_TIVA_TIMER32_PERIODIC */ /**************************************************************************** * Name: tiva_rtc_setalarm * * Description: * Setup to receive an interrupt when the RTC counter equals a match time * value. This function sets the match register to the current timer * counter register value PLUS the relative value provided. The relative * value then is an offset in seconds from the current time. * * NOTE: Use of this function is only meaningful for a a 32-bit RTC time. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * delay - A relative time in the future (seconds) * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_RTC void tiva_rtc_setalarm(TIMER_HANDLE handle, uint32_t delay) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_timer32config_s *config; irqstate_t flags; uintptr_t base; uint32_t counter; uint32_t match; #ifdef CONFIG_ARCH_CHIP_TM4C129 uint32_t adcev; uint32_t adcbits; #endif DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode == TIMER32_MODE_RTC); /* Update the saved IMR if an interrupt will be needed */ config = (const struct tiva_timer32config_s *)priv->config; if (config->handler) { /* Update the saved IMR to enable the RTC match interrupt */ priv->imr |= TIMER_INT_RTC; } /* This must be done without interrupt or context switches to minimize * race conditions with the free-running timer. Note that we also * by-pass the normal register accesses to keep the latency to a * minimum. */ base = priv->attr->base; flags = irqsave(); /* Set the match register to the current value of the timer counter plus * the provided relative delay value. */ counter = getreg32(base + TIVA_TIMER_TAR_OFFSET); match = counter + delay; putreg32(match, base + TIVA_TIMER_TAMATCHR_OFFSET); #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Enable ADC trigger (if selected). NOTE the TAOTE bit was already * selected in the GPTMCTL register when the timer was configured. */ adcev = getreg32(base + TIVA_TIMER_ADCEV_OFFSET); adcbits = TIMER_ISADCRTCM(config) ? TIMER_ADCEV_RTCADCEN : 0; putreg32(adcev | adcbits, base + TIVA_TIMER_ADCEV_OFFSET); #endif /* CONFIG_ARCH_CHIP_TM4C129 */ /* TODO: Set uDMA trigger in the same manner */ /* Enable interrupts as necessary */ putreg32(priv->imr, base + TIVA_TIMER_IMR_OFFSET); irqrestore(flags); #ifdef CONFIG_TIVA_TIMER_REGDEBUG /* Generate low-level debug output outside of the critical section */ lldbg("%08x->%08x\n", base + TIVA_TIMER_TAR_OFFSET, counter); lldbg("%08x<-%08x\n", base + TIVA_TIMER_TAMATCHR_OFFSET, match); #ifdef CONFIG_ARCH_CHIP_TM4C129 lldbg("%08x->%08x\n", base + TIVA_TIMER_ADCEV_OFFSET, adcev); lldbg("%08x<-%08x\n", base + TIVA_TIMER_ADCEV_OFFSET, adcev | adcbits); #endif /* CONFIG_ARCH_CHIP_TM4C129 */ lldbg("%08x<-%08x\n", base + TIVA_TIMER_IMR_OFFSET, priv->imr); #endif } #endif /**************************************************************************** * Name: tiva_timer32_relmatch * * Description: * This function may be called at any time to change the timer interval * match value of a 32-bit timer. This function sets the match register * to the current timer counter register value PLUS the relative value * provided. The relative value then is some the offset to some timer * counter value in the future. * * If an interrupt handler is provided, then the match interrupt will also * be enabled. A single match interrupt will be generated; further match * interrupts will be disabled. * * NOTE: Use of this function is only meaningful for a free-runnning, * periodic timer. * * WARNING: For free-running timers, the relative match value should be * sufficiently far in the future to avoid race conditions. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * relmatch - The value to write to the timer match register * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER32_PERIODIC void tiva_timer32_relmatch(TIMER_HANDLE handle, uint32_t relmatch) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_timer32config_s *config; uintptr_t base; irqstate_t flags; uint32_t counter; uint32_t match; #ifdef CONFIG_ARCH_CHIP_TM4C129 uint32_t adcev; uint32_t adcbits; #endif DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode != TIMER16_MODE); /* Update the saved IMR if an interrupt will be needed */ config = (const struct tiva_timer32config_s *)priv->config; if (config->handler) { /* Enable the match interrupt */ priv->imr |= TIMER_INT_TAM; } /* This must be done without interrupt or context switches to minimize * race conditions with the free-running timer. Note that we also * by-pass the normal register accesses to keep the latency to a * minimum. */ base = priv->attr->base; flags = irqsave(); /* Set the match register to the current value of the timer counter plus * the provided relative match value. * * NOTE that the prescale match is not used with the 32-bit timer. */ counter = getreg32(base + TIVA_TIMER_TAR_OFFSET); match = counter + relmatch; putreg32(match, base + TIVA_TIMER_TAMATCHR_OFFSET); #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Enable ADC trigger (if selected). NOTE the TAOTE bit was already * selected in the GPTMCTL register when the timer was configured. */ adcev = getreg32(base + TIVA_TIMER_ADCEV_OFFSET); adcbits = TIMER_ISADCMATCH(config) ? TIMER_ADCEV_CAMADCEN : 0; putreg32(adcev | adcbits, base + TIVA_TIMER_ADCEV_OFFSET); #endif /* CONFIG_ARCH_CHIP_TM4C129 */ /* Enable interrupts as necessary */ putreg32(priv->imr, base + TIVA_TIMER_IMR_OFFSET); irqrestore(flags); #ifdef CONFIG_TIVA_TIMER_REGDEBUG /* Generate low-level debug output outside of the critical section */ lldbg("%08x->%08x\n", base + TIVA_TIMER_TAR_OFFSET, counter); lldbg("%08x<-%08x\n", base + TIVA_TIMER_TAMATCHR_OFFSET, match); #ifdef CONFIG_ARCH_CHIP_TM4C129 lldbg("%08x->%08x\n", base + TIVA_TIMER_ADCEV_OFFSET, adcev); lldbg("%08x<-%08x\n", base + TIVA_TIMER_ADCEV_OFFSET, adcev | adcbits); #endif /* CONFIG_ARCH_CHIP_TM4C129 */ lldbg("%08x<-%08x\n", base + TIVA_TIMER_IMR_OFFSET, priv->imr); #endif /* CONFIG_TIVA_TIMER_REGDEBUG */ } #endif /* CONFIG_TIVA_TIMER32_PERIODIC */ /**************************************************************************** * Name: tiva_timer16_relmatch * * Description: * This function may be called at any time to change the timer interval * match value of a 16-bit timer. This function sets the match register * to the current timer counter register value PLUS the relative value * provided. The relative value then is some the offset to some timer * counter value in the future. * * If an interrupt handler is provided, then the match interrupt will also * be enabled. A single match interrupt will be generated; further match * interrupts will be disabled. * * NOTE: Use of this function is only meaningful for a free-runnning, * periodic timer. * * NOTE: The relmatch input is a really a 24-bit value; it is the 16-bit * match counter match value AND the 8-bit prescaler match value. From * the caller's point of view the match value is the 24-bit time to match * driven at the timer input clock frequency. * * When counting down in periodic modes, the prescaler contains the * least-significant bits of the count. When counting up, the prescaler * holds the most-significant bits of the count. But the caller is * protected from this complexity. * * WARNING: For free-running timers, the relative match value should be * sufficiently far in the future to avoid race conditions. * * Input Parameters: * handle - The handle value returned by tiva_gptm_configure() * relmatch - The value to write to the timer match register * tmndx - Either TIMER16A or TIMER16B to select the 16-bit timer * * Returned Value: * None. * ****************************************************************************/ #ifdef CONFIG_TIVA_TIMER16_PERIODIC void tiva_timer16_relmatch(TIMER_HANDLE handle, uint32_t relmatch, int tmndx) { struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle; const struct tiva_gptm16config_s *gptm; const struct tiva_timer16config_s *config; irqstate_t flags; uintptr_t base; uintptr_t timerr; uintptr_t prescr; uintptr_t matchr; uintptr_t prematchr; uintptr_t imr; #ifdef CONFIG_ARCH_CHIP_TM4C129 uintptr_t adcevr; uint32_t adcevv; uint32_t adcbits; #endif uint32_t timerv; uint32_t prescv; uint32_t matchv; uint32_t prematchv; uint32_t counter; bool countup; DEBUGASSERT(priv && priv->attr && priv->config && priv->config->mode == TIMER16_MODE && (unsigned)tmndx < 2); /* Pre-calculate as much as possible before entering the critical section */ gptm = (const struct tiva_gptm16config_s *)priv->config; base = priv->attr->base; if (tmndx) { /* Update the saved IMR if an interrupt will be needed */ config = &gptm->config[TIMER16B]; if (config->handler) { /* Enable the Timer B match interrupt */ priv->imr |= TIMER_INT_TBM; } /* Get Timer B register addresses */ timerr = base + TIVA_TIMER_TBR_OFFSET; prescr = base + TIVA_TIMER_TBPR_OFFSET; matchr = base + TIVA_TIMER_TBMATCHR_OFFSET; prematchr = base + TIVA_TIMER_TBPMR_OFFSET; #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Do we need to enable ADC trigger on the match? */ adcbits = TIMER_ISADCMATCH(config) ? TIMER_ADCEV_CBMADCEN : 0; #endif /* CONFIG_ARCH_CHIP_TM4C129 */ } else { /* Update the saved IMR if an interrupt will be needed */ config = &gptm->config[TIMER16A]; if (config->handler) { /* Enable the Timer A match interrupt */ priv->imr |= TIMER_INT_TAM; } /* Get Timer A register addresses */ timerr = base + TIVA_TIMER_TAR_OFFSET; prescr = base + TIVA_TIMER_TAPR_OFFSET; matchr = base + TIVA_TIMER_TAMATCHR_OFFSET; prematchr = base + TIVA_TIMER_TAPMR_OFFSET; #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Do we need to enable ADC trigger on the match? */ adcbits = TIMER_ISADCMATCH(config) ? TIMER_ADCEV_CAMADCEN : 0; #endif /* CONFIG_ARCH_CHIP_TM4C129 */ } #ifdef CONFIG_ARCH_CHIP_TM4C129 adcevr = base + TIVA_TIMER_ADCEV_OFFSET; #endif /* CONFIG_ARCH_CHIP_TM4C129 */ imr = base + TIVA_TIMER_IMR_OFFSET; countup = TIMER_ISCOUNTUP(config); /* This must be done without interrupt or context switches to minimize * race conditions with the free-running timer. Note that we also * by-pass the normal register accesses to keep the latency to a * minimum. */ flags = irqsave(); timerv = getreg32(timerr) & 0xffff; prescv = getreg32(prescr) & 0xff; /* Are we counting up or down? */ if (countup) { /* When counting up in one-shot or periodic modes, the prescaler * acts as a timer extension and holds the most-significant bits * of the count */ counter = prescv << 16 | timerv; counter += relmatch; matchv = counter & 0xffff; prematchv = (counter >> 8) & 0xff; } else { /* When counting down in one-shot or periodic modes, the prescaler * acts as a true prescaler and contains the least-significant bits * of the count. */ counter = timerv << 8 | prescv; counter += relmatch; matchv = (counter >> 8) & 0xffff; prematchv = counter & 0xff; } /* Set the match and prescacle match registers */ putreg32(matchv, matchr); putreg32(prematchv, prematchr); #ifdef CONFIG_ARCH_CHIP_TM4C129 /* Enable ADC trigger (if selected). NOTE the TnOTE bit was already * selected in the GPTMCTL register when the timer was configured. */ adcevv = getreg32(adcevr); putreg32(adcevv | adcbits, adcevr); #endif /* Enable interrupts as necessary */ putreg32(priv->imr, imr); irqrestore(flags); #ifdef CONFIG_TIVA_TIMER_REGDEBUG /* Generate low-level debug output outside of the critical section */ lldbg("%08x->%08x\n", timerr, timerv); lldbg("%08x->%08x\n", prescr, prescv); lldbg("%08x<-%08x\n", matchr, matchv); lldbg("%08x<-%08x\n", prematchr, prematchv); #ifdef CONFIG_ARCH_CHIP_TM4C129 lldbg("%08x->%08x\n", adcevr, adcevv); lldbg("%08x<-%08x\n", adcevr, adcevv | adcbits); #endif lldbg("%08x<-%08x\n", imr, priv->imr); #endif } #endif