Tiva Timer: Completes implementation of the timer driver lower half

This commit is contained in:
Gregory Nutt 2015-01-13 10:06:40 -06:00
parent 1bd74b4dcc
commit ffa34aa5db
3 changed files with 202 additions and 34 deletions

View File

@ -183,14 +183,13 @@ typedef FAR void *TIMER_HANDLE;
*
* Input Parameters:
* handle - The same value as returned by tiva_gptm_configure()
* config - The same value provided as as an input to tiva_gptm_configure()
* arg - The same value provided in struct tiva_timer32config_s
* status - The value of the GPTM masked status register that caused the
* interrupt
*/
struct tiva_gptm32config_s;
typedef void (*timer32_handler_t)(TIMER_HANDLE handle,
const struct tiva_gptm32config_s *config,
typedef void (*timer32_handler_t)(TIMER_HANDLE handle, void *arg,
uint32_t status);
/* This structure describes the configuration of one 32-bit timer */
@ -200,6 +199,9 @@ struct tiva_timer32config_s
uint8_t flags; /* See TIMER_FLAG_* definitions */
timer32_handler_t handler; /* Non-NULL: Interrupts will be enabled
* and forwarded to this function */
void *arg; /* Argument that accompanies the handler
* callback.
*/
/* Mode-specific parameters */
@ -231,7 +233,7 @@ struct tiva_timer32config_s
*
* Input Parameters:
* handle - The same value as returned by tiva_gptm_configure()
* config - The same value provided as as an input to tiva_gptm_configure()
* arg - The same value provided in struct tiva_timer16config_s
* status - The value of the GPTM masked status register that caused the
* interrupt.
* tmndx - Either TIMER16A or TIMER16B. This may be useful in the
@ -239,8 +241,7 @@ struct tiva_timer32config_s
*/
struct tiva_gptm16config_s;
typedef void (*timer16_handler_t)(TIMER_HANDLE handle,
const struct tiva_gptm16config_s *config,
typedef void (*timer16_handler_t)(TIMER_HANDLE handle, void *arg,
uint32_t status, int tmndx);
/* This structure describes the configuration of one 16-bit timer A/B */
@ -251,6 +252,9 @@ struct tiva_timer16config_s
uint8_t flags; /* See TIMER_FLAG_* definitions */
timer16_handler_t handler; /* Non-NULL: Interrupts will be enabled
* and forwarded to this function */
void *arg; /* Argument that accompanies the handler
* callback.
*/
/* Mode-specific parameters */
@ -615,6 +619,44 @@ void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx)
# define tiva_timer16b_setinterval(h,l) tiva_timer16_setinterval(h,l,TIMER16B)
#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);
#endif
/****************************************************************************
* Name: tiva_timer16_remaining
*
* Description:
* Get the time remaining before a one-shot or periodic 16-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_TIMER16_PERIODIC
/* To be provided */
#endif
/****************************************************************************
* Name: tiva_timer32_absmatch
*

View File

@ -536,7 +536,7 @@ static int tiva_timer32_interrupt(struct tiva_gptmstate_s *priv)
DEBUGASSERT(timer32->handler);
if (timer32->handler)
{
timer32->handler((TIMER_HANDLE)priv, config32, status);
timer32->handler((TIMER_HANDLE)priv, timer32->arg, status);
}
}
@ -662,7 +662,7 @@ static int tiva_timer16_interrupt(struct tiva_gptmstate_s *priv, int tmndx)
DEBUGASSERT(timer16->handler);
if (timer16->handler)
{
timer16->handler((TIMER_HANDLE)priv, config16, status, tmndx);
timer16->handler((TIMER_HANDLE)priv, timer16->arg, status, tmndx);
}
}
@ -2588,6 +2588,113 @@ void tiva_timer16_setinterval(TIMER_HANDLE handle, uint16_t interval, int tmndx)
}
#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 >= 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
/****************************************************************************
* Name: tiva_rtc_setalarm
*

View File

@ -76,7 +76,7 @@ struct tiva_lowerhalf_s
uint32_t clkin; /* Input clock frequency */
uint32_t timeout; /* The current timeout value (us) */
uint32_t clkticks; /* Actual clock ticks for current interval */
uint32_t adjustment; /* Time lost due to clock resolution truncation (us) */
uint32_t adjustment; /* Time lost due to truncation (us) */
bool started; /* True: Timer has been started */
};
@ -90,8 +90,7 @@ static uint32_t tiva_ticks2usec(struct tiva_lowerhalf_s *priv, uint32_t ticks);
/* Interrupt handling *******************************************************/
static void tiva_handler(TIMER_HANDLE handle,
const struct tiva_gptm32config_s *config, uint32_t status);
static void tiva_handler(TIMER_HANDLE handle, void *arg, uint32_t status);
/* "Lower half" driver methods **********************************************/
@ -195,16 +194,16 @@ static uint32_t tiva_ticks2usec(struct tiva_lowerhalf_s *priv, uint32_t ticks)
*
****************************************************************************/
static void tiva_handler(TIMER_HANDLE handle,
const struct tiva_gptm32config_s *config,
uint32_t status)
static void tiva_handler(TIMER_HANDLE handle, void *arg, uint32_t status)
{
struct tiva_lowerhalf_s *priv;
struct tiva_lowerhalf_s *priv = (struct tiva_lowerhalf_s *)arg;
timvdbg("Entry\n");
timvdbg("Entry: status=%08x\n", status);
DEBUGASSERT(arg && status);
/* Check if the timeout interrupt is pending */
#warning Missing logic
if ((status & TIMER_INT_TATO) != 0)
{
uint32_t timeout;
@ -219,7 +218,12 @@ static void tiva_handler(TIMER_HANDLE handle,
/* Set next interval interval. TODO: make sure the interval is not
* so soon it will be missed!
*/
#warning Missing logic
#if 0 /* Too much in this context */
tiva_timer32_setinterval(priv->handle, priv->clkticks);
#else
tiva_gptm_putreg(priv->handle, TIVA_TIMER_TAILR_OFFSET, priv->clkticks);
#endif
/* Calculate the next adjustment */
@ -327,7 +331,7 @@ static int tiva_getstatus(struct timer_lowerhalf_s *lower,
struct timer_status_s *status)
{
struct tiva_lowerhalf_s *priv = (struct tiva_lowerhalf_s *)lower;
uint32_t elapsed;
uint32_t remaining;
timvdbg("Entry\n");
DEBUGASSERT(priv);
@ -349,14 +353,14 @@ static int tiva_getstatus(struct timer_lowerhalf_s *lower,
status->timeout = priv->timeout;
/* Get the time remaining until the timer expires (in microseconds) */
/* Get the time remaining until the timer expires (in microseconds). */
//elapsed = ;
status->timeleft = ((uint64_t)priv->timeout * elapsed) / (priv->clkticks + 1); /* TODO - check on this +1 */
remaining = tiva_timer32_remaining(priv->handle);
status->timeleft = tiva_ticks2usec(priv, remaining);
timvdbg(" flags : %08x\n", status->flags);
timvdbg(" timeout : %d\n", status->timeout);
timvdbg(" timeleft : %d\n", status->timeleft);
timvdbg(" timeout : %d\n", status->timeout);
timvdbg(" timeleft : %d\n", status->timeleft);
return OK;
}
@ -519,7 +523,8 @@ int tiva_timer_register(const char *devpath, int gptm, uint32_t timeout,
{
struct tiva_lowerhalf_s *priv;
struct tiva_gptm32config_s *config;
void *rethandle;
void *drvr;
int ret;
DEBUGASSERT(devpath);
timvdbg("Entry: devpath=%s\n", devpath);
@ -537,7 +542,6 @@ int tiva_timer_register(const char *devpath, int gptm, uint32_t timeout,
priv->ops = &g_timer_ops;
priv->clkin = altclk ? ALTCLK_FREQUENCY : SYSCLK_FREQUENCY;
priv->timeout = timeout;
config = &priv->config;
config->cmn.gptm = gptm;
@ -545,15 +549,26 @@ int tiva_timer_register(const char *devpath, int gptm, uint32_t timeout,
config->cmn.alternate = altclk;
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 */
ret = tiva_settimeout((struct timer_lowerhalf_s *)priv, timeout);
if (ret < 0)
{
timdbg("ERROR: Failed to set initial timeout\n");
goto errout_with_alloc;
}
/* Create the timer handle */
priv->handle = tiva_gptm_configure((const struct tiva_gptmconfig_s *)&priv->config);
if (!priv->handle)
{
timdbg("ERROR: Failed to create timer handle\n");
return -EINVAL;
ret = -EINVAL;
goto errout_with_alloc;
}
/* Register the timer driver as /dev/timerX. The returned value from
@ -561,23 +576,27 @@ int tiva_timer_register(const char *devpath, int gptm, uint32_t timeout,
* REVISIT: The returned handle is discard here.
*/
rethandle = timer_register(devpath, (struct timer_lowerhalf_s *)priv);
if (!rethandle)
drvr = timer_register(devpath, (struct timer_lowerhalf_s *)priv);
if (!drvr)
{
/* Free the allocated state structure */
kmm_free(priv);
/* The actual cause of the failure may have been a failure to allocate
* perhaps a failure to register the timer driver (such as if the
* 'depath' were not unique). We know here but we return EEXIST to
* indicate the failure (implying the non-unique devpath).
*/
return -EEXIST;
ret = -EEXIST;
goto errout_with_timer;
}
return OK;
errout_with_timer:
tiva_gptm_release(priv->handle); /* Free timer resources */
errout_with_alloc:
kmm_free(priv); /* Free the allocated state structure */
return ret; /* Return the error indication */
}
#endif /* CONFIG_TIMER && CONFIG_TIVA_TIMER */