Tiva Timer: Revert the previous change. Thre is a better way to handler timerout interrupts.

Removed setting of the initial timer interval load value (or, rather, it is always set to zero for a free-running timer).  Also, do not unconditional enable the timer out interrupt.  The timerout interrupt is not not enabled until tiva_timer32_setinterval() is called.
This commit is contained in:
Gregory Nutt 2015-01-14 07:33:59 -06:00
parent db59dd2208
commit 11eec5f5d8
3 changed files with 214 additions and 164 deletions

View File

@ -203,28 +203,7 @@ struct tiva_timer32config_s
* callback.
*/
/* Mode-specific parameters */
union
{
#ifdef CONFIG_TIVA_TIMER32_PERIODIC
/* 32-bit programmable one-shot or periodic timer */
struct
{
uint32_t interval; /* Value for interval load register */
} periodic;
#endif
#ifdef CONFIG_TIVA_TIMER32_RTC
/* 32-bit RTC with external 32.768-KHz input */
struct
{
/* No special configuration settings */
} rtc;
#endif
} u;
/* Mode-specific parameters may follow */
};
#endif
@ -256,47 +235,7 @@ struct tiva_timer16config_s
* callback.
*/
/* Mode-specific parameters */
union
{
#ifdef CONFIG_TIVA_TIMER16_PERIODIC
/* 16-bit programmable one-shot or periodic timer */
struct
{
uint8_t prescaler; /* Prescaler-1: 0-255 corresponding to 1-256 */
uint16_t interval; /* Value for interval load register */
} periodic;
#endif
#ifdef CONFIG_TIVA_TIMER32_EDGECOUNT
/* 16-bit input edge-count capture mode w/8-bit prescaler */
struct
{
/* TODO: To be provided */
} count;
#endif
#ifdef CONFIG_TIVA_TIMER32_TIMECAP
/* 16-bit input time capture mode w/8-bit prescaler */
struct
{
/* TODO: To be provided */
} time;
#endif
#ifdef CONFIG_TIVA_TIMER32_PWM
/* 16-bit PWM output mode w/8-bit prescaler */
struct
{
/* TODO: To be provided */
} pwm;
#endif
} u;
/* Mode-specific parameters may follow */
};
#endif
@ -582,6 +521,12 @@ uint32_t tiva_timer16_counter(TIMER_HANDLE handle, int tmndx);
* 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.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
* interval - The value to write to the timer interval load register
@ -602,6 +547,12 @@ void tiva_timer32_setinterval(TIMER_HANDLE handle, uint32_t interval);
* 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.
*
* Input Parameters:
* handle - The handle value returned by tiva_gptm_configure()
* interval - The value to write to the timer interval load register
@ -886,14 +837,17 @@ static inline void tiva_gptm0_synchronize(uint32_t sync)
* Bind the configuration timer to a timer lower half instance and
* register the timer drivers at 'devpath'
*
* NOTE: Only 32-bit periodic timers are supported.
* NOTES:
* 1. Only 32-bit periodic timers are supported.
* 2. Timeout interrupts are disabled until tiva_timer32_setinterval() is
* called.
* 3. Match interrupts are disabled until tiva_timer32_relmatch() is
* called.
*
* Input Parameters:
* devpath - The full path to the timer device. This should be of the form
* /dev/timer0
* devpath - The full path to the timer device. This should be of the
* form /dev/timer0
* gptm - General purpose timer number
* timeout - Timeout interval in microseconds. Set to a non-zero value
* to enable timeout interrupts
* altlck - True: Use alternate clock source.
*
* Returned Values:
@ -903,8 +857,7 @@ static inline void tiva_gptm0_synchronize(uint32_t sync)
****************************************************************************/
#ifdef CONFIG_TIMER
int tiva_timer_register(FAR const char *devpath, int gptm, uint32_t timeout,
bool altclk);
int tiva_timer_register(FAR const char *devpath, int gptm, bool altclk);
#endif
#endif /* __ARCH_ARM_SRC_TIVA_TIVA_TIMER_H */

View File

@ -855,6 +855,9 @@ static int tiva_oneshot_periodic_mode32(struct tiva_gptmstate_s *priv,
* 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 */
@ -884,26 +887,6 @@ static int tiva_oneshot_periodic_mode32(struct tiva_gptmstate_s *priv,
*/
#warning Missing Logic
/* Enable one-shot/periodic interrupts Enable interrupts only if an
* non-NULL interrupt handler.
*/
if (timer->handler)
{
/* Select the interrupt mask that will enable the timer interrupt.
* Any non-zero value of imr indicates that interrupts are expected.
*/
priv->imr = TIMER_INT_TATO;
/* Clearing the TACINTD bit allows the time-out interrupt to be
* generated as normal
*/
/* REVISIT: When will interrupts be enabled? */
regval &= ~TIMER_TnMR_TnCINTD;
}
/* Enable count down? */
if (TIMER_ISCOUNTUP(timer))
@ -950,25 +933,12 @@ static int tiva_oneshot_periodic_mode32(struct tiva_gptmstate_s *priv,
* 15:0 of the GPTM Timer B Interval Load (GPTMTBILR) register.
* Writes to GPTMTBILR are ignored.
*
* 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"
* 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().
*/
regval = timer->u.periodic.interval;
tiva_putreg(priv, TIVA_TIMER_TAILR_OFFSET, regval);
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
@ -1090,6 +1060,9 @@ static int tiva_oneshot_periodic_mode16(struct tiva_gptmstate_s *priv,
* 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 */
@ -1119,26 +1092,6 @@ static int tiva_oneshot_periodic_mode16(struct tiva_gptmstate_s *priv,
*/
#warning Missing Logic
/* Enable one-shot/periodic interrupts? Enable interrupts only if an
* interrupt handler was provided.
*/
if (timer->handler)
{
/* Select the interrupt mask that will enable the timer interrupt.
* Any non-zero value of 'imr' indicates that interrupts are expected.
*/
priv->imr |= tmndx ? TIMER_INT_TBTO : TIMER_INT_TATO;
/* Clearing the TnCINTD bit allows the time-out interrupt to be
* generated as normal
*/
/* REVISIT: When will interrupts be enabled? */
regval &= ~TIMER_TnMR_TnCINTD;
}
/* Enable count down? */
if (TIMER_ISCOUNTUP(timer))
@ -1178,34 +1131,19 @@ static int tiva_oneshot_periodic_mode16(struct tiva_gptmstate_s *priv,
*/
#warning Missing Logic
/* Set the input clock pre-scaler value */
regoffset = tmndx ? TIVA_TIMER_TBPR_OFFSET : TIVA_TIMER_TAPR_OFFSET;
tiva_putreg(priv, regoffset, (uint32_t)timer->u.periodic.prescaler);
/* 5. Load the start value into the GPTM Timer n Interval Load Register
* (GPTMTnILR).
*
* 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"
* 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().
*/
regval = (uint32_t)timer->u.periodic.interval;
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, regval);
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
@ -2324,6 +2262,12 @@ uint32_t tiva_timer16_counter(TIMER_HANDLE handle, int tmndx)
* 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
@ -2353,13 +2297,80 @@ uint32_t tiva_timer16_counter(TIMER_HANDLE handle, int tmndx)
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 moder;
uintptr_t loadr;
uintptr_t imrr;
uint32_t modev1;
uint32_t modev2;
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;
moder = base + TIVA_TIMER_TAMR_OFFSET;
imrr = base + TIVA_TIMER_IMR_OFFSET;
/* Make the following atomic */
flags = irqsave();
/* Set the new timeout interval */
tiva_putreg(priv, TIVA_TIMER_TAILR_OFFSET, interval);
putreg32(interval, loadr);
/* Enable/disable timeout interrupts */
if (toints)
{
/* 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);
/* 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)
{
lldbg("%08x->%08x\n", moder, modev1);
lldbg("%08x<-%08x\n", moder, modev2);
lldbg("%08x<-%08x\n", imrr, priv->imr);
}
#endif
}
#endif
@ -2370,6 +2381,12 @@ void tiva_timer32_setinterval(TIMER_HANDLE handle, uint32_t interval)
* 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
@ -2400,15 +2417,93 @@ void tiva_timer32_setinterval(TIMER_HANDLE handle, uint32_t interval)
void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx)
{
struct tiva_gptmstate_s *priv = (struct tiva_gptmstate_s *)handle;
unsigned int regoffset;
const struct tiva_gptm16config_s *config;
const struct tiva_timer16config_s *timer;
irqstate_t flags;
uintptr_t base;
uintptr_t moder;
uintptr_t loadr;
uintptr_t imrr;
uint32_t intbit;
uint32_t modev1;
uint32_t modev2;
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;
moder = base + TIVA_TIMER_TBMR_OFFSET;
}
else
{
intbit = TIMER_INT_TATO;
loadr = base + TIVA_TIMER_TAILR_OFFSET;
moder = base + TIVA_TIMER_TAMR_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 */
regoffset = tmndx ? TIVA_TIMER_TBILR_OFFSET : TIVA_TIMER_TAILR_OFFSET;
tiva_putreg(priv, regoffet, interval);
putreg32(interval, loadr);
/* Enable/disable timeout interrupts */
if (toints)
{
/* 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);
/* 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)
{
lldbg("%08x->%08x\n", moder, modev1);
lldbg("%08x<-%08x\n", moder, modev2);
lldbg("%08x<-%08x\n", imrr, priv->imr);
}
#endif
}
#endif
@ -2495,7 +2590,7 @@ uint32_t tiva_timer32_remaining(TIMER_HANDLE handle)
* REVISIT: Or the difference +1?
*/
DEBUGASSERT(interval >= counter);
DEBUGASSERT(interval == 0 || interval >= counter);
remaining = interval - counter;
}
else
@ -2897,3 +2992,4 @@ void tiva_timer16_relmatch(TIMER_HANDLE handle, uint32_t relmatch, int tmndx)
#endif
}
#endif

View File

@ -398,7 +398,7 @@ static int tiva_getstatus(struct timer_lowerhalf_s *lower,
/* Get the time remaining until the timer expires (in microseconds). */
remaining = tiva_timer32_remaining(priv->handle);
status->timeleft = tiva_ticks2usec(priv, remaining);
status->timeleft = tiva_ticks2usec(priv, remaining);
timvdbg(" flags : %08x\n", status->flags);
timvdbg(" timeout : %d\n", status->timeout);
@ -531,14 +531,17 @@ static int tiva_ioctl(struct timer_lowerhalf_s *lower, int cmd,
* Bind the configuration timer to a timer lower half instance and
* register the timer drivers at 'devpath'
*
* NOTE: Only 32-bit periodic timers are supported.
* NOTES:
* 1. Only 32-bit periodic timers are supported.
* 2. Timeout interrupts are disabled until tiva_timer32_setinterval() is
* called.
* 3. Match interrupts are disabled until tiva_timer32_relmatch() is
* called.
*
* Input Parameters:
* devpath - The full path to the timer device. This should be of the form
* /dev/timer0
* devpath - The full path to the timer device. This should be of the
* form /dev/timer0
* gptm - General purpose timer number
* timeout - Timeout interval in microseconds. Set to a non-zero value
* to enable timeout interrupts
* altlck - True: Use alternate clock source.
*
* Returned Values:
@ -547,8 +550,7 @@ static int tiva_ioctl(struct timer_lowerhalf_s *lower, int cmd,
*
****************************************************************************/
int tiva_timer_register(const char *devpath, int gptm, uint32_t timeout,
bool altclk)
int tiva_timer_register(FAR const char *devpath, int gptm, bool altclk)
{
struct tiva_lowerhalf_s *priv;
struct tiva_gptm32config_s *config;
@ -579,11 +581,10 @@ int tiva_timer_register(const char *devpath, int gptm, uint32_t timeout,
config->config.flags = TIMER_FLAG_COUNTUP;
config->config.handler = tiva_handler;
config->config.arg = priv;
config->config.u.periodic.interval = tiva_usec2ticks(priv, timeout);
/* Set the initial timer interval */
tiva_timeout(priv, timeout);
tiva_timeout(priv, 0);
/* Create the timer handle */