diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index 9507e0c59c8..ebdb78fb269 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -1600,7 +1600,6 @@ endif # SAMV7_TC3 config SAMV7_ONESHOT bool "TC one-shot wrapper" - depends on SAMV7_FREERUN default n if !SCHED_TICKLESS default y if SCHED_TICKLESS ---help--- diff --git a/arch/arm/src/samv7/Make.defs b/arch/arm/src/samv7/Make.defs index fbd88a6e7f4..66c51a9acb9 100644 --- a/arch/arm/src/samv7/Make.defs +++ b/arch/arm/src/samv7/Make.defs @@ -181,7 +181,7 @@ endif ifeq ($(CONFIG_SAMV7_HAVE_TC),y) CHIP_CSRCS += sam_tc.c ifeq ($(CONFIG_SAMV7_ONESHOT),y) -CHIP_CSRCS += sam_oneshot.c +CHIP_CSRCS += sam_oneshot.c sam_oneshot_lowerhalf.c endif ifeq ($(CONFIG_SAMV7_FREERUN),y) CHIP_CSRCS += sam_freerun.c diff --git a/arch/arm/src/samv7/sam_freerun.c b/arch/arm/src/samv7/sam_freerun.c index b3fbfbf6dfc..4db95112182 100644 --- a/arch/arm/src/samv7/sam_freerun.c +++ b/arch/arm/src/samv7/sam_freerun.c @@ -61,7 +61,7 @@ #include "sam_freerun.h" -#ifdef CONFIG_SAMV7_ONESHOT +#ifdef CONFIG_SAMV7_FREERUN /**************************************************************************** * Private Functions @@ -319,4 +319,4 @@ int sam_freerun_uninitialize(struct sam_freerun_s *freerun) return OK; } -#endif /* CONFIG_SAMV7_ONESHOT */ +#endif /* CONFIG_SAMV7_FREERUN */ diff --git a/arch/arm/src/samv7/sam_oneshot.c b/arch/arm/src/samv7/sam_oneshot.c index 4ee2467a61e..bc9c23b515e 100644 --- a/arch/arm/src/samv7/sam_oneshot.c +++ b/arch/arm/src/samv7/sam_oneshot.c @@ -64,22 +64,6 @@ #ifdef CONFIG_SAMV7_ONESHOT -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -129,7 +113,9 @@ static void sam_oneshot_handler(TC_HANDLE tch, void *arg, uint32_t sr) oneshot->handler = NULL; oneshot_arg = (void *)oneshot->arg; oneshot->arg = NULL; +#ifdef CONFIG_SAMV7_FREERUN oneshot->start_count = 0; +#endif oneshot_handler(oneshot_arg); } @@ -230,7 +216,10 @@ int sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan, oneshot->running = false; oneshot->handler = NULL; oneshot->arg = NULL; +#ifdef CONFIG_SAMV7_FREERUN oneshot->start_count = 0; +#endif + return OK; } @@ -254,8 +243,10 @@ int sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan, * ****************************************************************************/ -int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freerun, - oneshot_handler_t handler, void *arg, const struct timespec *ts) +int sam_oneshot_start(struct sam_oneshot_s *oneshot, + struct sam_freerun_s *freerun, + oneshot_handler_t handler, void *arg, + const struct timespec *ts) { uint64_t usec; uint64_t regval; @@ -285,7 +276,8 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer usec = (uint64_t)ts->tv_sec * USEC_PER_SEC + (uint64_t)(ts->tv_nsec / NSEC_PER_USEC); - /* Get the timer counter frequency and determine the number of counts need to achieve the requested delay. + /* Get the timer counter frequency and determine the number of counts + * needed to achieve the requested delay. * * frequency = ticks / second * ticks = seconds * frequency @@ -312,6 +304,7 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer sam_tc_start(oneshot->tch); +#ifdef CONFIG_SAMV7_FREERUN /* The function sam_tc_start() starts the timer/counter by setting the * bits TC_CCR_CLKEN and TC_CCR_SWTRG in the channel control register. * The first one enables the timer/counter the latter performs an @@ -325,12 +318,16 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer * the counter value of the freerun timer/counter is stored at each start * of the oneshot timer/counter. * - * The function up_timer_gettime() could also be used for this but it takes - * too long. If up_timer_gettime() is called within this function the problem - * vanishes at least if compiled with no optimisation. + * The function up_timer_gettime() could also be used for this but it + * takes too long. If up_timer_gettime() is called within this function + * the problem vanishes at least if compiled with no optimisation. */ - oneshot->start_count = sam_tc_getcounter(freerun->tch); + if (freerun != NULL) + { + oneshot->start_count = sam_tc_getcounter(freerun->tch); + } +#endif /* Enable interrupts. We should get the callback when the interrupt * occurs. @@ -347,8 +344,8 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer * Description: * Cancel the oneshot timer and return the time remaining on the timer. * - * NOTE: This function may execute at a high rate with no timer running (as - * when pre-emption is enabled and disabled). + * NOTE: This function may execute at a high rate with no timer running + * (as when pre-emption is enabled and disabled). * * Input Parameters: * oneshot Caller allocated instance of the oneshot state structure. This @@ -366,8 +363,8 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer * ****************************************************************************/ -int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freerun, - struct timespec *ts) +int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, + struct sam_freerun_s *freerun, struct timespec *ts) { irqstate_t flags; uint64_t usec; @@ -408,16 +405,19 @@ int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct sam_freerun_s *free count = sam_tc_getcounter(oneshot->tch); rc = sam_tc_getregister(oneshot->tch, TC_REGC); +#ifdef CONFIG_SAMV7_FREERUN /* In the case the timer/counter was canceled very short after its start, * the counter register can hold the wrong value (the value of the last * run). To prevent this the counter value is set to zero if not at * least on tick passed since the start of the timer/counter. */ - if (count > 0 && sam_tc_getcounter(freerun->tch) == oneshot->start_count) + if (count > 0 && freerun != NULL && + sam_tc_getcounter(freerun->tch) == oneshot->start_count) { count = 0; } +#endif /* Now we can disable the interrupt and stop the timer. */ @@ -510,13 +510,11 @@ int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct sam_freerun_s *free * ****************************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec) { DEBUGASSERT(oneshot && usec); *usec = (0xffffull * USEC_PER_SEC) / (uint64_t)sam_tc_divfreq(oneshot->tch); return OK; } -#endif #endif /* CONFIG_SAMV7_ONESHOT */ diff --git a/arch/arm/src/samv7/sam_oneshot.h b/arch/arm/src/samv7/sam_oneshot.h index 6c4e42337f1..276698c7dda 100644 --- a/arch/arm/src/samv7/sam_oneshot.h +++ b/arch/arm/src/samv7/sam_oneshot.h @@ -46,7 +46,6 @@ #include #include "sam_tc.h" -#include "sam_freerun.h" #ifdef CONFIG_SAMV7_ONESHOT @@ -83,11 +82,13 @@ struct sam_oneshot_s volatile oneshot_handler_t handler; /* Oneshot expiration callback */ volatile void *arg; /* The argument that will accompany * the callback */ +#ifdef CONFIG_SAMV7_FREERUN volatile uint32_t start_count; /* Stores the value of the freerun counter, * at each start of the onshot timer. Is neccesary * to find out if the onshot counter was updated * correctly at the time of the call to * sam_oneshot_cancel or not. */ +#endif }; /**************************************************************************** @@ -149,9 +150,7 @@ int sam_oneshot_initialize(struct sam_oneshot_s *oneshot, int chan, * ****************************************************************************/ -#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec); -#endif /**************************************************************************** * Name: sam_oneshot_start @@ -165,7 +164,8 @@ int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec); * sam_oneshot_initialize(); * freerun Caller allocated instance of the freerun state structure. This * structure must have been previously initialized via a call to - * sam_freerun_initialize(); + * sam_freerun_initialize(). May be NULL if there is no matching + * free-running timer. * handler The function to call when when the oneshot timer expires. * arg An opaque argument that will accompany the callback. * ts Provides the duration of the one shot timer. @@ -176,8 +176,11 @@ int sam_oneshot_max_delay(struct sam_oneshot_s *oneshot, uint64_t *usec); * ****************************************************************************/ -int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freerun, - oneshot_handler_t handler, void *arg, const struct timespec *ts); +struct sam_freerun_s; +int sam_oneshot_start(struct sam_oneshot_s *oneshot, + struct sam_freerun_s *freerun, + oneshot_handler_t handler, void *arg, + const struct timespec *ts); /**************************************************************************** * Name: sam_oneshot_cancel @@ -194,7 +197,8 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer * sam_oneshot_initialize(); * freerun Caller allocated instance of the freerun state structure. This * structure must have been previously initialized via a call to - * sam_freerun_initialize(); + * sam_freerun_initialize(). May be NULL if there is no matching + * free-running timer. * ts The location in which to return the time remaining on the * oneshot timer. A time of zero is returned if the timer is * not running. @@ -206,8 +210,9 @@ int sam_oneshot_start(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freer * ****************************************************************************/ -int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, struct sam_freerun_s *freerun, - struct timespec *ts); +struct sam_freerun_s; +int sam_oneshot_cancel(struct sam_oneshot_s *oneshot, + struct sam_freerun_s *freerun, struct timespec *ts); #undef EXTERN #ifdef __cplusplus diff --git a/arch/arm/src/samv7/sam_oneshot_lowerhalf.c b/arch/arm/src/samv7/sam_oneshot_lowerhalf.c new file mode 100644 index 00000000000..e980f4c18d3 --- /dev/null +++ b/arch/arm/src/samv7/sam_oneshot_lowerhalf.c @@ -0,0 +1,334 @@ +/**************************************************************************** + * arch/arm/src/sam/sam_oneshot_lowerhalf.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Authors: 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 "sam_oneshot.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of the oneshot timer lower-half driver */ + +struct sam_oneshot_lowerhalf_s +{ + /* This is the part of the lower half driver that is visible to the upper- + * half client of the driver. This must be the first thing in this + * structure so that pointers to struct oneshot_lowerhalf_s are cast + * compatible to struct sam_oneshot_lowerhalf_s and vice versa. + */ + + struct oneshot_lowerhalf_s lh; /* Common lower-half driver fields */ + + /* Private lower half data follows */ + + struct sam_oneshot_s oneshot; /* SAMV7-specific oneshot state */ + oneshot_callback_t callback; /* internal handler that receives callback */ + FAR void *arg; /* Argument that is passed to the handler */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void sam_oneshot_handler(void *arg); + +static int sam_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR uint64_t *usec); +static int sam_start(FAR struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, FAR void *arg, + FAR const struct timespec *ts); +static int sam_cancel(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Lower half operations */ + +static const struct oneshot_operations_s g_oneshot_ops = +{ + .max_delay = sam_max_delay, + .start = sam_start, + .cancel = sam_cancel, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_oneshot_handler + * + * Description: + * Timer expiration handler + * + * Input Parameters: + * arg - Should be the same argument provided when sam_oneshot_start() + * was called. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sam_oneshot_handler(void *arg) +{ + FAR struct sam_oneshot_lowerhalf_s *priv = + (FAR struct sam_oneshot_lowerhalf_s *)arg; + oneshot_callback_t callback; + FAR void *cbarg; + + DEBUGASSERT(priv != NULL); + + /* Perhaps the callback was nullified in a race condition with + * sam_cancel? + */ + + if (priv->callback) + { + /* Sample and nullify BEFORE executing callback (in case the callback + * restarts the oneshot). + */ + + callback = priv->callback; + cbarg = priv->arg; + priv->callback = NULL; + priv->arg = NULL; + + /* Then perform the callback */ + + callback(&priv->lh, cbarg); + } +} + +/**************************************************************************** + * Name: sam_max_delay + * + * Description: + * Determine the maximum delay of the one-shot timer (in microseconds) + * + * Input Parameters: + * lower An instance of the lower-half oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * usec The user-provided location in which to return the maxumum delay + * in microseconds. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +static int sam_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR uint64_t *usec) +{ + FAR struct sam_oneshot_lowerhalf_s *priv = + (FAR struct sam_oneshot_lowerhalf_s *)lower; + + DEBUGASSERT(priv != NULL); + return sam_oneshot_max_delay(&priv->oneshot, usec); +} + +/**************************************************************************** + * Name: sam_start + * + * Description: + * Start the oneshot timer + * + * Input Parameters: + * lower An instance of the lower-half oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * handler The function to call when when the oneshot timer expires. + * arg An opaque argument that will accompany the callback. + * ts Provides the duration of the one shot timer. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +static int sam_start(FAR struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, FAR void *arg, + FAR const struct timespec *ts) +{ + FAR struct sam_oneshot_lowerhalf_s *priv = + (FAR struct sam_oneshot_lowerhalf_s *)lower; + irqstate_t flags; + int ret; + + DEBUGASSERT(priv != NULL); + + /* Save the callback information and start the timer */ + + flags = enter_critical_section(); + priv->callback = callback; + priv->arg = arg; + ret = sam_oneshot_start(&priv->oneshot, NULL, + sam_oneshot_handler, priv, ts); + leave_critical_section(flags); + + if (ret < 0) + { + tmrerr("ERROR: sam_oneshot_start failed: %d\n", flags); + } + + return ret; +} + +/**************************************************************************** + * Name: sam_cancel + * + * Description: + * Cancel the oneshot timer and return the time remaining on the timer. + * + * NOTE: This function may execute at a high rate with no timer running (as + * when pre-emption is enabled and disabled). + * + * Input Parameters: + * lower Caller allocated instance of the oneshot state structure. This + * structure must have been previously initialized via a call to + * oneshot_initialize(); + * ts The location in which to return the time remaining on the + * oneshot timer. A time of zero is returned if the timer is + * not running. + * + * Returned Value: + * Zero (OK) is returned on success. A call to up_timer_cancel() when + * the timer is not active should also return success; a negated errno + * value is returned on any failure. + * + ****************************************************************************/ + +static int sam_cancel(FAR struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts) +{ + FAR struct sam_oneshot_lowerhalf_s *priv = + (FAR struct sam_oneshot_lowerhalf_s *)lower; + irqstate_t flags; + int ret; + + DEBUGASSERT(priv != NULL); + + /* Cancel the timer */ + + flags = enter_critical_section(); + ret = sam_oneshot_cancel(&priv->oneshot, NULL, ts); + priv->callback = NULL; + priv->arg = NULL; + leave_critical_section(flags); + + if (ret < 0) + { + tmrerr("ERROR: sam_oneshot_cancel failed: %d\n", flags); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: oneshot_initialize + * + * Description: + * Initialize the oneshot timer and return a oneshot lower half driver + * instance. + * + * Input Parameters: + * chan Timer counter channel to be used. + * resolution The required resolution of the timer in units of + * microseconds. NOTE that the range is restricted to the + * range of uint16_t (excluding zero). + * + * Returned Value: + * On success, a non-NULL instance of the oneshot lower-half driver is + * returned. NULL is return on any failure. + * + ****************************************************************************/ + +FAR struct oneshot_lowerhalf_s *oneshot_initialize(int chan, + uint16_t resolution) +{ + FAR struct sam_oneshot_lowerhalf_s *priv; + int ret; + + /* Allocate an instance of the lower half driver */ + + priv = (FAR struct sam_oneshot_lowerhalf_s *) + kmm_zalloc(sizeof(struct sam_oneshot_lowerhalf_s)); + + if (priv == NULL) + { + tmrerr("ERROR: Failed to initialized state structure\n"); + return NULL; + } + + /* Initialize the lower-half driver structure */ + + priv->lh.ops = &g_oneshot_ops; + + /* Initialize the contained SAM oneshot timer */ + + ret = sam_oneshot_initialize(&priv->oneshot, chan, resolution); + if (ret < 0) + { + tmrerr("ERROR: Failed to initialized state structure\n"); + kmm_free(priv); + return NULL; + } + + return &priv->lh; +} \ No newline at end of file