This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit add99fead3605c366cc57b88b385b0bb07d72359
Author: Gustavo Henrique Nihei <[email protected]>
AuthorDate: Wed Feb 23 14:42:49 2022 -0300

    xtensa/esp32s3: Add support for Oneshot timer
    
    Signed-off-by: Gustavo Henrique Nihei <[email protected]>
---
 arch/xtensa/src/esp32s3/Kconfig                    |  16 +-
 arch/xtensa/src/esp32s3/Make.defs                  |   7 +
 arch/xtensa/src/esp32s3/esp32s3_oneshot.c          | 467 +++++++++++++++++++++
 arch/xtensa/src/esp32s3/esp32s3_oneshot.h          | 212 ++++++++++
 .../xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c | 370 ++++++++++++++++
 5 files changed, 1070 insertions(+), 2 deletions(-)

diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index e875786..e0bb068 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -388,7 +388,7 @@ config ESP32S3_RWDT
 
 endmenu # ESP32-S3 Peripheral Selection
 
-menu "UART configuration"
+menu "UART Configuration"
        depends on ESP32S3_UART
 
 if ESP32S3_UART0
@@ -469,7 +469,19 @@ config ESP32S3_UART2_CTSPIN
 
 endif # ESP32S3_UART2
 
-endmenu # UART configuration
+endmenu # UART Configuration
+
+menu "Timer/Counter Configuration"
+       depends on ESP32S3_TIMER
+
+config ESP32S3_ONESHOT
+       bool "One-shot wrapper"
+       default n
+       ---help---
+               Enable a wrapper around the low level timer/counter functions to
+               support one-shot timer.
+
+endmenu # Timer/Counter Configuration
 
 menu "Application Image Configuration"
 
diff --git a/arch/xtensa/src/esp32s3/Make.defs 
b/arch/xtensa/src/esp32s3/Make.defs
index f645ec1..339edfe 100644
--- a/arch/xtensa/src/esp32s3/Make.defs
+++ b/arch/xtensa/src/esp32s3/Make.defs
@@ -83,3 +83,10 @@ endif
 ifeq ($(CONFIG_WATCHDOG),y)
 CHIP_CSRCS += esp32s3_wdt_lowerhalf.c
 endif
+
+ifeq ($(CONFIG_ESP32S3_ONESHOT),y)
+CHIP_CSRCS += esp32s3_oneshot.c
+ifeq ($(CONFIG_ONESHOT),y)
+CHIP_CSRCS += esp32s3_oneshot_lowerhalf.c
+endif
+endif
diff --git a/arch/xtensa/src/esp32s3/esp32s3_oneshot.c 
b/arch/xtensa/src/esp32s3/esp32s3_oneshot.c
new file mode 100644
index 0000000..ee2105e
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_oneshot.c
@@ -0,0 +1,467 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_oneshot.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/timers/oneshot.h>
+
+#include "esp32s3_clockconfig.h"
+#include "esp32s3_oneshot.h"
+#include "esp32s3_tim.h"
+#include "hardware/esp32s3_soc.h"
+
+#ifdef CONFIG_ESP32S3_ONESHOT
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX_TIMER_COUNTER (UINT64_C(1) << 53)
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int oneshot_handler(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: oneshot_handler
+ *
+ * Description:
+ *   Oneshot interrupt handler. When any oneshot timer interrupt
+ *   expires, this function will be triggered. It will forward the call to
+ *   the next level up.
+ *
+ * Input Parameters:
+ *   irq     - IRQ associated to that interrupt
+ *   context - Interrupt register state save info
+ *   arg     - A pointer to the argument provided when the interrupt was
+ *             registered.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int oneshot_handler(int irq, void *context, void *arg)
+{
+  int ret = OK;
+  struct esp32s3_oneshot_s *oneshot = (struct esp32s3_oneshot_s *)arg;
+  oneshot_handler_t handler;
+  void *handler_arg;
+
+  DEBUGASSERT(oneshot != NULL);
+  DEBUGASSERT(oneshot->handler != NULL);
+
+  tmrinfo("Oneshot handler triggered\n");
+
+  /* Disable interrupts */
+
+  ESP32S3_TIM_DISABLEINT(oneshot->tim);
+
+  /* Detach handler */
+
+  ret = ESP32S3_TIM_SETISR(oneshot->tim, NULL, NULL);
+
+  /* Clear the Interrupt */
+
+  ESP32S3_TIM_ACKINT(oneshot->tim);
+
+  /* The timer is no longer running */
+
+  oneshot->running = false;
+
+  /* Forward the event, clearing out any vestiges */
+
+  handler          = (oneshot_handler_t)oneshot->handler;
+  oneshot->handler = NULL;
+  handler_arg      = (void *)oneshot->arg;
+  oneshot->arg     = NULL;
+
+  /* Call the callback */
+
+  handler(handler_arg);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_initialize
+ *
+ * Description:
+ *   Initialize the oneshot timer wrapper.
+ *
+ * Input Parameters:
+ *   oneshot    Caller allocated instance of the oneshot state structure.
+ *   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:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_initialize(struct esp32s3_oneshot_s *oneshot,
+                               int chan, uint16_t resolution)
+{
+  int ret = OK;
+
+  tmrinfo("chan=%d resolution=%d usecs\n", chan, resolution);
+
+  DEBUGASSERT(oneshot != NULL);
+  DEBUGASSERT(resolution > 0);
+
+  oneshot->chan = chan;
+
+  oneshot->tim = esp32s3_tim_init(chan);
+  if (oneshot->tim == NULL)
+    {
+      tmrerr("ERROR: Failed to allocate TIM %d\n", chan);
+      ret = -EBUSY;
+    }
+  else
+    {
+      uint16_t pre;
+
+      /* Initialize the remaining fields in the state structure. */
+
+      oneshot->running    = false;
+      oneshot->handler    = NULL;
+      oneshot->arg        = NULL;
+      oneshot->resolution = resolution;
+
+      /* Ensure timer is disabled.
+       * Change the prescaler divider with the timer enabled can lead to
+       * unpredictable results.
+       */
+
+      ESP32S3_TIM_STOP(oneshot->tim);
+
+      ESP32S3_TIM_CLK_SRC(oneshot->tim, ESP32S3_TIM_APB_CLK);
+
+      /* Calculate the suitable prescaler according to the current APB
+       * frequency to generate a period equals to resolution.
+       */
+
+      pre = (esp_clk_apb_freq() * resolution) / USEC_PER_SEC;
+
+      /* Configure TIMER prescaler */
+
+      ESP32S3_TIM_SETPRE(oneshot->tim, pre);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_max_delay
+ *
+ * Description:
+ *   Return the maximum delay supported by the timer.
+ *
+ * Input Parameters:
+ *   oneshot Caller allocated instance of the oneshot state structure. This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_oneshot_initialize();
+ *
+ * Output Parameters:
+ *   usec    The location in which to return the maximum delay in us.
+ *
+ * Returned Value:
+ *   Zero (OK).
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_max_delay(struct esp32s3_oneshot_s *oneshot,
+                              uint64_t *usec)
+{
+  DEBUGASSERT(oneshot != NULL);
+  DEBUGASSERT(usec != NULL);
+
+  /* In theory, Maximum delay (us) = resolution (us) * MAX_TIMER_COUNTER
+   * But if the resolution is bigger than 1 us, the value will not fit
+   * in a uint64_t. So, this function assumes the max delay using a
+   * resolution of 1 us.
+   */
+
+  *usec = MAX_TIMER_COUNTER;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_start
+ *
+ * Description:
+ *   Start the oneshot timer
+ *
+ * Input Parameters:
+ *   oneshot Caller allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_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.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_start(struct esp32s3_oneshot_s *oneshot,
+                          oneshot_handler_t handler, void *arg,
+                          const struct timespec *ts)
+{
+  uint64_t timeout_us;
+  int ret = OK;
+
+  tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
+          handler, arg, (unsigned long)ts->tv_sec,
+          (unsigned long)ts->tv_nsec);
+
+  DEBUGASSERT(oneshot != NULL);
+  DEBUGASSERT(handler != NULL);
+  DEBUGASSERT(ts != NULL);
+
+  if (oneshot->running)
+    {
+      tmrinfo("Oneshot timer already in use. Cancelling it...\n");
+
+      /* If the oneshot timer was already started, cancel it and then
+       * restart.
+       */
+
+      esp32s3_oneshot_cancel(oneshot, NULL);
+    }
+
+  /* Save the new callback and its argument */
+
+  oneshot->handler = handler;
+  oneshot->arg     = arg;
+
+  /* Retrieve the duration from timespec in microsecond */
+
+  timeout_us = (uint64_t)ts->tv_sec * USEC_PER_SEC +
+               (uint64_t)(ts->tv_nsec / NSEC_PER_USEC);
+
+  /* Verify if it is a multiple of the configured resolution.
+   * In case it isn't, warn the user.
+   */
+
+  if ((timeout_us % oneshot->resolution) != 0)
+    {
+      tmrwarn("Warning: The interval is not multiple of the resolution.\n"
+               "Adjust the resolution in your bringup file.\n");
+    }
+
+  /* Set the timer */
+
+  /* Ensure timer is stopped */
+
+  ESP32S3_TIM_STOP(oneshot->tim);
+
+  /* Configure TIMER mode */
+
+  ESP32S3_TIM_SETMODE(oneshot->tim, ESP32S3_TIM_MODE_UP);
+
+  /* Clear TIMER counter value */
+
+  ESP32S3_TIM_CLEAR(oneshot->tim);
+
+  /* Disable autoreload */
+
+  ESP32S3_TIM_SETARLD(oneshot->tim, false);
+
+  /* Set the timeout */
+
+  ESP32S3_TIM_SETALRVL(oneshot->tim, timeout_us / oneshot->resolution);
+
+  /* Enable TIMER alarm */
+
+  ESP32S3_TIM_SETALRM(oneshot->tim, true);
+
+  /* Clear Interrupt Bits Status */
+
+  ESP32S3_TIM_ACKINT(oneshot->tim);
+
+  /* Set the interrupt */
+
+  /* Register the handler that calls the callback */
+
+  ret = ESP32S3_TIM_SETISR(oneshot->tim, oneshot_handler, oneshot);
+  if (ret == OK)
+    {
+      ESP32S3_TIM_ENABLEINT(oneshot->tim);
+
+      /* Finally, start the TIMER */
+
+      ESP32S3_TIM_START(oneshot->tim);
+
+      oneshot->running = true;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_cancel
+ *
+ * Description:
+ *   Cancel the oneshot timer and return the time remaining on the timer.
+ *
+ * Input Parameters:
+ *   oneshot Caller allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_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.  ts may be zero in which case the time remaining
+ *           is not returned.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_cancel(struct esp32s3_oneshot_s *oneshot,
+                           struct timespec *ts)
+{
+  int ret = OK;
+  uint64_t current_us;
+  uint64_t remaining_us;
+  uint64_t timeout_us;
+  uint64_t counter_value;
+  uint64_t alarm_value;
+
+  DEBUGASSERT(oneshot != NULL);
+
+  if (!oneshot->running)
+    {
+      tmrinfo("Trying to cancel a non started oneshot timer.\n");
+      ts->tv_sec  = 0;
+      ts->tv_nsec = 0;
+    }
+  else
+    {
+      /* Stop timer */
+
+      ESP32S3_TIM_STOP(oneshot->tim);
+
+      /* Disable int */
+
+      ESP32S3_TIM_DISABLEINT(oneshot->tim);
+
+      /* Detach handler */
+
+      ret = ESP32S3_TIM_SETISR(oneshot->tim, NULL, NULL);
+
+      if (ts != NULL)
+        {
+          /* Get the current counter value */
+
+          ESP32S3_TIM_GETCTR(oneshot->tim, &counter_value);
+
+          /* Get the current configured timeout */
+
+          ESP32S3_TIM_GETALRVL(oneshot->tim, &alarm_value);
+
+          current_us = counter_value * oneshot->resolution;
+          timeout_us = alarm_value   * oneshot->resolution;
+
+          /* Remaining time (us) = timeout (us) - current (us) */
+
+          remaining_us = timeout_us - current_us;
+          ts->tv_sec   = remaining_us / USEC_PER_SEC;
+          remaining_us = remaining_us - ts->tv_sec * USEC_PER_SEC;
+          ts->tv_nsec  = remaining_us * NSEC_PER_USEC;
+        }
+
+      oneshot->running = false;
+      oneshot->handler = NULL;
+      oneshot->arg     = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_current
+ *
+ * Description:
+ *   Get the current time.
+ *
+ * Input Parameters:
+ *   oneshot Caller allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_oneshot_initialize();
+ *
+ * Output Parameters:
+ *   usec    The location in which to return the current time in us.
+ *
+ * Returned Value:
+ *   Zero (OK).
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_current(struct esp32s3_oneshot_s *oneshot,
+                            uint64_t *usec)
+{
+  /* Get the current counter value */
+
+  ESP32S3_TIM_GETCTR(oneshot->tim, usec);
+
+  *usec = *usec * (uint64_t)oneshot->resolution;
+
+  return OK;
+}
+
+#endif /* CONFIG_ESP32S3_ONESHOT */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_oneshot.h 
b/arch/xtensa/src/esp32s3/esp32s3_oneshot.h
new file mode 100644
index 0000000..a9d3cfa
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_oneshot.h
@@ -0,0 +1,212 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_oneshot.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_ESP32S3_ONESHOT_H
+#define __ARCH_XTENSA_SRC_ESP32S3_ONESHOT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include "esp32s3_tim.h"
+
+#ifdef CONFIG_ESP32S3_ONESHOT
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* ONESHOT */
+
+#define ONESHOT_RESOLUTION_US 1
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This describes the callback function that will be invoked when the oneshot
+ * timer expires.  The oneshot fires, the client will receive:
+ *
+ *   arg - The opaque argument provided when the interrupt was registered
+ */
+
+typedef void (*oneshot_handler_t)(void *arg);
+
+/* The oneshot client must allocate an instance of this structure and call
+ * esp32s3_oneshot_initialize() before using the oneshot facilities.  The
+ * client should not access the contents of this structure directly since
+ * the contents are subject to change.
+ */
+
+struct esp32s3_oneshot_s
+{
+  uint8_t                    chan;       /* The timer/counter in use */
+  volatile bool              running;    /* True: the timer is running */
+  struct esp32s3_tim_dev_s  *tim;        /* Pointer returned by
+                                          * esp32s3_tim_init() */
+  volatile oneshot_handler_t handler;    /* Oneshot expiration callback */
+  volatile void             *arg;        /* The argument that will accompany
+                                          * the callback */
+  uint32_t                   resolution; /* us */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_initialize
+ *
+ * Description:
+ *   Initialize the oneshot timer wrapper.
+ *
+ * Input Parameters:
+ *   oneshot    Allocated instance of the oneshot state structure.
+ *   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:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_initialize(struct esp32s3_oneshot_s *oneshot,
+                               int chan, uint16_t resolution);
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_max_delay
+ *
+ * Description:
+ *   Determine the maximum delay of the one-shot timer (in microseconds).
+ *
+ * Input Parameters:
+ *   oneshot    Allocated instance of the oneshot state structure.
+ *
+ * Output Parameters:
+ *   usec    The location in which to return the maximum delay in us.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_max_delay(struct esp32s3_oneshot_s *oneshot,
+                              uint64_t *usec);
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_start
+ *
+ * Description:
+ *   Start the oneshot timer
+ *
+ * Input Parameters:
+ *   oneshot Allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_oneshot_initialize();
+ *   handler The function to call 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.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_start(struct esp32s3_oneshot_s *oneshot,
+                          oneshot_handler_t handler, void *arg,
+                          const struct timespec *ts);
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_cancel
+ *
+ * Description:
+ *   Cancel the oneshot timer and return the time remaining on the timer.
+ *
+ *
+ * Input Parameters:
+ *   oneshot Allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_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.
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_cancel(struct esp32s3_oneshot_s *oneshot,
+                           struct timespec *ts);
+
+/****************************************************************************
+ * Name: esp32s3_oneshot_current
+ *
+ * Description:
+ *   Get the current time.
+ *
+ * Input Parameters:
+ *   oneshot Caller allocated instance of the oneshot state structure.  This
+ *           structure must have been previously initialized via a call to
+ *           esp32s3_oneshot_initialize();
+ *
+ * Output Parameters:
+ *   usec    The location in which to return the current time in us.
+ *
+ * Returned Value:
+ *   Zero (OK).
+ *
+ ****************************************************************************/
+
+int esp32s3_oneshot_current(struct esp32s3_oneshot_s *oneshot,
+                            uint64_t *usec);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_ESP32S3_ONESHOT */
+#endif /* __ARCH_XTENSA_SRC_ESP32S3_ONESHOT_H */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c 
b/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c
new file mode 100644
index 0000000..215fe9c
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c
@@ -0,0 +1,370 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_oneshot_lowerhalf.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <stdio.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/timers/oneshot.h>
+#include <nuttx/kmalloc.h>
+
+#include "esp32s3_oneshot.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct esp32s3_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
+   * struct so that pointers to struct oneshot_lowerhalf_s are cast
+   * compatible to struct esp32s3_oneshot_lowerhalf_s and vice versa.
+   */
+
+  struct oneshot_lowerhalf_s lh;    /* Lower-half instance */
+  struct esp32s3_oneshot_s oneshot; /* ESP32-S3-specific oneshot state */
+  oneshot_callback_t callback;      /* Upper-half Interrupt callback */
+  void *arg;                        /* Argument passed to handler */
+  uint16_t resolution;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void oneshot_lh_handler(void *arg);
+
+/* "Lower-half" driver methods **********************************************/
+
+static int oneshot_lh_max_delay(struct oneshot_lowerhalf_s *lower,
+                                struct timespec *ts);
+static int oneshot_lh_start(struct oneshot_lowerhalf_s *lower,
+                            oneshot_callback_t callback,
+                            void *arg,
+                            const struct timespec *ts);
+static int oneshot_lh_cancel(struct oneshot_lowerhalf_s *lower,
+                             struct timespec *ts);
+static int oneshot_lh_current(struct oneshot_lowerhalf_s *lower,
+                              struct timespec *ts);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* "Lower-half" driver methods */
+
+static const struct oneshot_operations_s g_esp32s3_timer_ops =
+{
+  .max_delay = oneshot_lh_max_delay,
+  .start     = oneshot_lh_start,
+  .cancel    = oneshot_lh_cancel,
+  .current   = oneshot_lh_current
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: oneshot_lh_handler
+ *
+ * Description:
+ *   Timer expiration handler.
+ *
+ * Input Parameters:
+ *   arg - Should be the same argument provided when esp32s3_oneshot_start()
+ *         was called.
+ *
+ ****************************************************************************/
+
+static void oneshot_lh_handler(void *arg)
+{
+  struct esp32s3_oneshot_lowerhalf_s *priv =
+    (struct esp32s3_oneshot_lowerhalf_s *)arg;
+  oneshot_callback_t callback;
+  FAR void *cb_arg;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->callback != NULL);
+
+  tmrinfo("Oneshot LH handler triggered\n");
+
+  /* Sample and nullify BEFORE executing callback (in case the callback
+   * restarts the oneshot).
+   */
+
+  callback       = priv->callback;
+  cb_arg         = priv->arg;
+  priv->callback = NULL;
+  priv->arg      = NULL;
+
+  /* Then perform the callback */
+
+  callback(&priv->lh, cb_arg);
+}
+
+/****************************************************************************
+ * Name: oneshot_lh_max_delay
+ *
+ * Description:
+ *   Determine the maximum delay of the oneshot 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().
+ *   ts      The location in which to return the maximum delay.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+static int oneshot_lh_max_delay(struct oneshot_lowerhalf_s *lower,
+                                struct timespec *ts)
+{
+  DEBUGASSERT(ts != NULL);
+
+  /* The real maximum delay surpass the limit that timespec can represent.
+   * Even using the better case: a resolution of 1 us.
+   * Therefore, here, set the timespec with the maximum value it represent.
+   */
+
+  ts->tv_sec  = UINT32_MAX;
+  ts->tv_nsec = NSEC_PER_SEC - 1;
+
+  tmrinfo("max sec=%" PRIu32 "\n", ts->tv_sec);
+  tmrinfo("max nsec=%ld\n", ts->tv_nsec);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: oneshot_lh_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().
+ *   callback The function to call when when the oneshot timer expires.
+ *            Inside the handler scope.
+ *   arg      A pointer to the 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 oneshot_lh_start(struct oneshot_lowerhalf_s *lower,
+                            oneshot_callback_t callback,
+                            void *arg,
+                            const struct timespec *ts)
+{
+  struct esp32s3_oneshot_lowerhalf_s *priv =
+    (struct esp32s3_oneshot_lowerhalf_s *)lower;
+  int ret;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(callback != NULL);
+  DEBUGASSERT(ts != NULL);
+
+  /* Save the callback information and start the timer */
+
+  flags          = enter_critical_section();
+  priv->callback = callback;
+  priv->arg      = arg;
+  ret            = esp32s3_oneshot_start(&priv->oneshot, oneshot_lh_handler,
+                                         priv, ts);
+  leave_critical_section(flags);
+
+  if (ret < 0)
+    {
+      tmrerr("Failed to start oneshot timer: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: oneshot_lh_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 oneshot_lh_cancel(struct oneshot_lowerhalf_s *lower,
+                             struct timespec *ts)
+{
+  struct esp32s3_oneshot_lowerhalf_s *priv =
+    (struct esp32s3_oneshot_lowerhalf_s *)lower;
+  irqstate_t flags;
+  int ret;
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Cancel the timer */
+
+  flags          = enter_critical_section();
+  ret            = esp32s3_oneshot_cancel(&priv->oneshot, ts);
+  priv->callback = NULL;
+  priv->arg      = NULL;
+  leave_critical_section(flags);
+
+  if (ret < 0)
+    {
+      tmrerr("Failed to cancel oneshot timer: %d\n", ret);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: oneshot_lh_current
+ *
+ * Description:
+ *  Get the current time.
+ *
+ * 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 current time. A time of zero
+ *           is returned for the initialization moment.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success, a negated errno value is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+static int oneshot_lh_current(struct oneshot_lowerhalf_s *lower,
+                              struct timespec *ts)
+{
+  struct esp32s3_oneshot_lowerhalf_s *priv =
+    (struct esp32s3_oneshot_lowerhalf_s *)lower;
+  uint64_t current_us;
+
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(ts != NULL);
+
+  esp32s3_oneshot_current(&priv->oneshot, &current_us);
+  ts->tv_sec  = current_us / USEC_PER_SEC;
+  current_us  = current_us - ts->tv_sec * USEC_PER_SEC;
+  ts->tv_nsec = current_us * NSEC_PER_USEC;
+
+  return OK;
+}
+
+/****************************************************************************
+ * 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.
+ *
+ ****************************************************************************/
+
+struct oneshot_lowerhalf_s *oneshot_initialize(int chan, uint16_t resolution)
+{
+  struct esp32s3_oneshot_lowerhalf_s *priv;
+  int ret;
+
+  /* Allocate an instance of the lower-half driver */
+
+  priv = (struct esp32s3_oneshot_lowerhalf_s *)kmm_zalloc(
+          sizeof(struct esp32s3_oneshot_lowerhalf_s));
+
+  if (priv == NULL)
+    {
+      tmrerr("Failed to allocate oneshot state structure\n");
+      return NULL;
+    }
+
+  priv->lh.ops     = &g_esp32s3_timer_ops; /* Pointer to the LH operations */
+  priv->callback   = NULL;                 /* No callback yet */
+  priv->arg        = NULL;                 /* No arg yet */
+  priv->resolution = resolution;           /* Configured resolution */
+
+  /* Initialize esp32s3_oneshot_s structure */
+
+  ret = esp32s3_oneshot_initialize(&priv->oneshot, chan, resolution);
+  if (ret < 0)
+    {
+      tmrerr("Failed to initialize oneshot timer driver: %d\n", ret);
+      kmm_free(priv);
+      return NULL;
+    }
+
+  return &priv->lh;
+}

Reply via email to