From 1bb93021df3231ae73fdca13e6b34d5621883991 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 11 Aug 2016 14:07:43 -0600 Subject: [PATCH] STM32: Add a experimental oneshot, lower-half driver for STM32 --- arch/arm/src/stm32/stm32_oneshot_lowerhalf.c | 325 +++++++++++++++++++ include/nuttx/timers/oneshot.h | 21 +- 2 files changed, 338 insertions(+), 8 deletions(-) create mode 100644 arch/arm/src/stm32/stm32_oneshot_lowerhalf.c diff --git a/arch/arm/src/stm32/stm32_oneshot_lowerhalf.c b/arch/arm/src/stm32/stm32_oneshot_lowerhalf.c new file mode 100644 index 00000000000..7a6f65352cd --- /dev/null +++ b/arch/arm/src/stm32/stm32_oneshot_lowerhalf.c @@ -0,0 +1,325 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32_waste.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 "stm32_oneshot.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of the oneshot timer lower-half driver */ + +struct stm32_oneshot_lowerhalf_s +{ + /* This is the part of the lower half driver that is visible to the upper- + * half client of the driver. + */ + + struct stm32_oneshot_lowerhalf_s lh; + + /* Private lower half data follows */ + + struct stm32_oneshot_s oneshot; /* STM32-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 stm32_oneshot_handler(void *arg); + +static int stm32_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR uint64_t *usec); +static int stm32_start(FAR struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, FAR void *arg, + FAR const struct timespec *ts); +static int stm32_cancel(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 = stm32_max_delay, + .start = stm32_start, + .cancel = stm32_cancel, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_oneshot_handler + * + * Description: + * Timer expiration handler + * + * Input Parameters: + * arg - Should be the same argument provided when stm32_oneshot_start() + * was called. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_oneshot_handler(void *arg) +{ + FAR struct stm32_oneshot_lowerhalf_s *priv = + (FAR struct stm32_oneshot_lowerhalf_s *)lower; + oneshot_handler_t callback; + FAR void *arg; + + DEBUGASSERT(priv != NULL); + + /* Perhaps the callback was nullified in a race condition with + * stm32_cancel? + */ + + if (priv->callback) + { + /* Sample and nullify BEFORE executing callback (in case the callback + * restarts the oneshot). + */ + + callback = priv->callback; + arg = priv->arg; + priv->callback = NULL; + priv->arg = NULL; + + /* Then perform the callback */ + + callback(&priv->lh, arg); + } +} + +/**************************************************************************** + * Name: stm32_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 stm32_max_delay(FAR struct oneshot_lowerhalf_s *lower, + FAR uint64_t *usec) +{ + FAR struct stm32_oneshot_lowerhalf_s *priv = + (FAR struct stm32_oneshot_lowerhalf_s *)lower; + + DEBUGASSERT(priv != NULL); + return stm32_oneshot_max_delay(&priv->oneshot, usec); +} + +/**************************************************************************** + * Name: stm32_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 stm32_start(FAR struct oneshot_lowerhalf_s *lower, + oneshot_callback_t callback, FAR void *arg, + FAR const struct timespec *ts) +{ + FAR struct stm32_oneshot_lowerhalf_s *priv = + (FAR struct stm32_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 = stm32_oneshot_start(&priv->lh, stm32_oneshot_handler, + priv, ts); + leave_critical_section(flags); + + if (ret < 0) + { + tmrerr("ERROR: stm32_oneshot_start failed: %d\n", flags); + } + + return ret; +} + +/**************************************************************************** + * Name: stm32_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 stm32_cancel(struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); +{ + FAR struct stm32_oneshot_lowerhalf_s *priv = + (FAR struct stm32_oneshot_lowerhalf_s *)lower; + irqstate_t flags; + int ret; + + DEBUGASSERT(priv != NULL); + + /* Cancel the timer */ + + flags = enter_critical_section(); + ret = stm32_oneshot_cancel(&priv->oneshot, ts); + priv->callback = NULL; + priv->arg = NULL; + leave_critical_section(flags); + + if (ret < 0) + { + tmrerr("ERROR: stm32_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 stm32_oneshot_lowerhalf_s *priv; + int ret; + + /* Allocate an instance of the lower half driver */ + + priv = (FAR struct stm32_oneshot_lowerhalf_s *) + kmm_zalloc(sizeof(struct stm32_oneshot_lowerhalf_s)); + + if (priv == NULL) + { + tmrerr("ERROR: Failed to initialized state structure\n"); + return NULL; + } + + ret = stm32_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 diff --git a/include/nuttx/timers/oneshot.h b/include/nuttx/timers/oneshot.h index 8b5e22207a4..b4e17a05900 100644 --- a/include/nuttx/timers/oneshot.h +++ b/include/nuttx/timers/oneshot.h @@ -131,23 +131,27 @@ * arg - The opaque argument provided when the interrupt was registered */ -typedef void (*oneshot_callback_t)(FAR struct oneshot_dev_s *lower, - void *arg); +struct oneshot_lowerhalf_s; +typedef void (*oneshot_callback_t)(FAR struct oneshot_lowerhalf_s *lower, + FAR void *arg); /* The one short operations supported by the lower half driver */ +struct timespec; struct oneshot_operations_s { - CODE int (*max_delay)(FAR struct oneshot_s *lower, uint64_t *usec); - CODE int (*start)(FAR struct oneshot_dev_s *lower, + CODE int (*max_delay)(FAR struct oneshot_lowerhalf_s *lower, + FAR uint64_t *usec); + CODE int (*start)(FAR struct oneshot_lowerhalf_s *lower, oneshot_callback_t callback, FAR void *arg, FAR const struct timespec *ts); - CODE int (*cancel)(struct oneshot_dev_s *lower, FAR struct timespec *ts); + CODE int (*cancel)(struct oneshot_lowerhalf_s *lower, + FAR struct timespec *ts); }; -/* This structure describes the state of the oneshot timer driver */ +/* This structure describes the state of the oneshot timer lower-half driver */ -struct oneshot_dev_s +struct oneshot_lowerhalf_s { /* This is the part of the lower half driver that is visible to the upper- * half client of the driver. @@ -194,7 +198,8 @@ extern "C" * ****************************************************************************/ -FAR struct oneshot_dev_s *oneshot_initialize(int chan, uint16_t resolution); +FAR struct oneshot_lowerhalf_s *oneshot_initialize(int chan, + uint16_t resolution); #undef EXTERN #ifdef __cplusplus