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


The following commit(s) were added to refs/heads/master by this push:
     new 16030f7  xtensa/esp32s3: Add support for Free-running Timer
16030f7 is described below

commit 16030f713ee83a680dbd0f0114acc00b7c34b4b6
Author: Gustavo Henrique Nihei <[email protected]>
AuthorDate: Wed Mar 2 11:11:19 2022 -0300

    xtensa/esp32s3: Add support for Free-running Timer
    
    Signed-off-by: Gustavo Henrique Nihei <[email protected]>
---
 arch/xtensa/src/esp32s3/Kconfig           |   7 +
 arch/xtensa/src/esp32s3/Make.defs         |   4 +
 arch/xtensa/src/esp32s3/esp32s3_freerun.c | 365 ++++++++++++++++++++++++++++++
 arch/xtensa/src/esp32s3/esp32s3_freerun.h | 145 ++++++++++++
 4 files changed, 521 insertions(+)

diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index 33edeac..3bcabf0 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -481,6 +481,13 @@ config ESP32S3_ONESHOT
                Enable a wrapper around the low level timer/counter functions to
                support one-shot timer.
 
+config ESP32S3_FREERUN
+       bool "Free-running wrapper"
+       default n
+       ---help---
+               Enable a wrapper around the low level timer/counter functions to
+               support a free-running timer.
+
 endmenu # Timer/Counter Configuration
 
 config ESP32S3_TICKLESS
diff --git a/arch/xtensa/src/esp32s3/Make.defs 
b/arch/xtensa/src/esp32s3/Make.defs
index 5c33b35..202ac2e 100644
--- a/arch/xtensa/src/esp32s3/Make.defs
+++ b/arch/xtensa/src/esp32s3/Make.defs
@@ -96,3 +96,7 @@ ifeq ($(CONFIG_ONESHOT),y)
 CHIP_CSRCS += esp32s3_oneshot_lowerhalf.c
 endif
 endif
+
+ifeq ($(CONFIG_ESP32S3_FREERUN),y)
+CHIP_CSRCS += esp32s3_freerun.c
+endif
diff --git a/arch/xtensa/src/esp32s3/esp32s3_freerun.c 
b/arch/xtensa/src/esp32s3/esp32s3_freerun.c
new file mode 100644
index 0000000..73d6776
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_freerun.c
@@ -0,0 +1,365 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_freerun.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 <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+
+#include "esp32s3_freerun.h"
+#include "esp32s3_clockconfig.h"
+#include "esp32s3_gpio.h"
+
+#ifdef CONFIG_ESP32S3_FREERUN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX_TIMERS          2
+
+/* Definition for maximum resolution value in microseconds.
+ * Calculated according to the following algorithm:
+ *   (PREmax * USEC_PER_SEC) / CLKmin
+ * where:
+ *   PREmax == 65536, maximum supported divider in HW
+ *   CLKmin == 80 MHz, lowest clock frequency (from APB)
+ */
+
+#define MAX_US_RESOLUTION   819
+
+#define TIMER_WIDTH         54  /* ESP32-S3 timer has 54-bit counter */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: freerun_handler
+ *
+ * Description:
+ *   Timer interrupt callback. When the freerun timer counter overflows,
+ *   this interrupt will occur. We will just increment an overflow counter.
+ *
+ * Input Parameters:
+ *   irq           - CPU interrupt index.
+ *   context       - Context data from the ISR.
+ *   arg           - Opaque pointer to the internal driver state structure.
+ *
+ * Returned Value:
+ *   OK
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static int freerun_handler(int irq, void *context, void *arg)
+{
+  struct esp32s3_freerun_s *freerun = (struct esp32s3_freerun_s *) arg;
+
+  DEBUGASSERT(freerun != NULL);
+
+  freerun->overflow++;
+
+  ESP32S3_TIM_SETALRM(freerun->tch, true); /* Re-enables the alarm */
+  ESP32S3_TIM_ACKINT(freerun->tch);        /* Clear the Interrupt */
+
+  return OK;
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_freerun_initialize
+ *
+ * Description:
+ *   Initialize the freerun timer wrapper.
+ *
+ * Input Parameters:
+ *   freerun    - Caller allocated instance of the freerun 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_freerun_initialize(struct esp32s3_freerun_s *freerun, int chan,
+                               uint16_t resolution)
+{
+  uint16_t pre;
+  int ret = OK;
+
+  tmrinfo("chan=%d resolution=%d usecs\n", chan, resolution);
+
+  DEBUGASSERT(freerun != NULL);
+  DEBUGASSERT(chan >= 0);
+  DEBUGASSERT(chan < MAX_TIMERS);
+  DEBUGASSERT(resolution > 0);
+
+  /* We can't have a resolution bigger than this.
+   * The ESP32-S3 prescaler doesn't support.
+   * max resolution = (max prescaler * USEC_PER_SEC) / esp_clk_apb_freq()
+   */
+
+  DEBUGASSERT(resolution <= MAX_US_RESOLUTION);
+
+  freerun->tch = esp32s3_tim_init(chan);
+  if (freerun->tch == NULL)
+    {
+      tmrerr("ERROR: Failed to allocate TIM %d\n", chan);
+      ret = -EBUSY;
+    }
+  else
+    {
+      /* Initialize the remaining fields in the state structure. */
+
+      freerun->chan        = chan;
+      freerun->resolution  = resolution;
+      freerun->max_timeout = (UINT64_C(1) << (TIMER_WIDTH - 1));
+
+      /* Ensure timer is disabled.
+       * Change the prescaler divider with the timer enabled can lead to
+       * unpredictable results.
+       */
+
+      ESP32S3_TIM_STOP(freerun->tch);
+
+      /* Configure clock source */
+
+      ESP32S3_TIM_CLK_SRC(freerun->tch, ESP32S3_TIM_APB_CLK);
+
+      /* Calculate the suitable prescaler for a period for the requested
+       * resolution.
+       */
+
+      pre = esp_clk_apb_freq() * resolution / USEC_PER_SEC;
+
+      tmrinfo("pre=%" PRIu16 " clk=%d\n", pre, esp_clk_apb_freq());
+
+      /* Configure TIMER prescaler */
+
+      ESP32S3_TIM_SETPRE(freerun->tch, pre);
+
+      /* Configure TIMER mode */
+
+      ESP32S3_TIM_SETMODE(freerun->tch, ESP32S3_TIM_MODE_UP);
+
+      /* Clear TIMER counter value */
+
+      ESP32S3_TIM_CLEAR(freerun->tch);
+
+      /* Set the maximum timeout */
+
+      ESP32S3_TIM_SETALRVL(freerun->tch, freerun->max_timeout);
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+
+      /* Set the interrupt */
+
+      freerun->overflow = 0;
+
+      /* Enable autoreload */
+
+      ESP32S3_TIM_SETARLD(freerun->tch, true);
+
+      /* Enable TIMER alarm */
+
+      ESP32S3_TIM_SETALRM(freerun->tch, true);
+
+      /* Clear Interrupt Bits Status */
+
+      ESP32S3_TIM_ACKINT(freerun->tch);
+
+      /* Register the handler */
+
+        {
+          irqstate_t flags = enter_critical_section();
+          ret = ESP32S3_TIM_SETISR(freerun->tch, freerun_handler, freerun);
+          leave_critical_section(flags);
+        }
+
+      if (ret == OK)
+        {
+          ESP32S3_TIM_ENABLEINT(freerun->tch);
+        }
+
+#endif
+      /* Finally, start the TIMER */
+
+      ESP32S3_TIM_START(freerun->tch);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s3_freerun_counter
+ *
+ * Description:
+ *   Read the counter register of the free-running timer.
+ *
+ * Input Parameters:
+ *   freerun - Caller allocated instance of the freerun state structure.
+ *             This structure must have been previously initialized via a
+ *             call to esp32s3_freerun_initialize().
+ *   ts      - The location in which to return the time from the
+ *             free-running timer.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+
+int esp32s3_freerun_counter(struct esp32s3_freerun_s *freerun,
+                            struct timespec *ts)
+{
+  uint64_t usec;
+  uint64_t counter;
+  uint64_t verify;
+  uint32_t overflow;
+  uint32_t sec;
+  int pending;
+  irqstate_t flags;
+
+  DEBUGASSERT(freerun != NULL);
+  DEBUGASSERT(ts != NULL);
+  DEBUGASSERT(freerun->tch != NULL);
+
+  /* Temporarily disable the overflow counter. */
+
+  flags    = enter_critical_section();
+
+  overflow = freerun->overflow;
+  ESP32S3_TIM_GETCTR(freerun->tch, &counter);
+  pending  = ESP32S3_TIM_CHECKINT(freerun->tch);
+  ESP32S3_TIM_GETCTR(freerun->tch, &verify);
+
+  /* If an interrupt was pending before we re-enabled interrupts, then the
+   * overflow needs to be incremented.
+   */
+
+  if (pending)
+    {
+      ESP32S3_TIM_ACKINT(freerun->tch);
+
+      /* Increment the overflow count and use the value of the guaranteed to
+       * be AFTER the overflow occurred.
+       */
+
+      overflow++;
+      counter = verify;
+
+      /* Update freerun overflow counter. */
+
+      freerun->overflow = overflow;
+    }
+
+  leave_critical_section(flags);
+
+  tmrinfo("counter=%" PRIu64 " (%" PRIu64 ") overflow=%" PRIu32
+          ", pending=%i\n",
+          counter, verify, overflow, pending);
+
+  usec = (uint64_t)(((overflow * freerun->max_timeout) + counter)
+          * freerun->resolution);
+
+  /* And return the value of the timer */
+
+  sec         = (uint32_t)(usec / USEC_PER_SEC);
+  ts->tv_sec  = sec;
+  ts->tv_nsec = (usec - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
+
+  tmrinfo("   usec=%" PRIu64 " ts=(%lu, %lu)\n",
+          usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+
+  return OK;
+}
+
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Name: esp32s3_freerun_uninitialize
+ *
+ * Description:
+ *   Stop the free-running timer and release all resources that it uses.
+ *
+ * Input Parameters:
+ *   freerun - Caller allocated instance of the freerun state structure.
+ *             This structure must have been previously initialized via a
+ *             call to esp32s3_freerun_initialize().
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_freerun_uninitialize(struct esp32s3_freerun_s *freerun)
+{
+  int ret;
+
+  DEBUGASSERT(freerun != NULL);
+  DEBUGASSERT(freerun->tch != NULL);
+
+  tmrinfo("chan=%d\n", freerun->chan);
+
+  /* Stop timer */
+
+  ESP32S3_TIM_STOP(freerun->tch);
+
+  /* Disable timer interrupt */
+
+  ESP32S3_TIM_DISABLEINT(freerun->tch);
+
+  /* Detach handler */
+
+  ret = ESP32S3_TIM_SETISR(freerun->tch, NULL, NULL);
+
+  /* Free the timer */
+
+  esp32s3_tim_deinit(freerun->tch);
+  freerun->tch = NULL;
+
+  return ret;
+}
+
+#endif /* CONFIG_ESP32S3_FREERUN */
diff --git a/arch/xtensa/src/esp32s3/esp32s3_freerun.h 
b/arch/xtensa/src/esp32s3/esp32s3_freerun.h
new file mode 100644
index 0000000..b2016d5
--- /dev/null
+++ b/arch/xtensa/src/esp32s3/esp32s3_freerun.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s3/esp32s3_freerun.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_ESP32S3_FREERUN_H
+#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_FREERUN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include "esp32s3_tim.h"
+
+#ifdef CONFIG_ESP32S3_FREERUN
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The freerun client must allocate an instance of this structure and called
+ * esp32s3_freerun_initialize() before using the freerun facilities.  The
+ * client should not access the contents of this structure directly since
+ * the contents are subject to change.
+ */
+
+struct esp32s3_freerun_s
+{
+  uint8_t chan;                  /* The timer/counter in use */
+  uint32_t overflow;             /* Timer counter overflow */
+  uint16_t resolution;           /* Timer resolution */
+  uint64_t max_timeout;          /* Maximum timeout to overflow */
+  struct esp32s3_tim_dev_s *tch; /* Handle returned by esp32s3_tim_init() */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_freerun_initialize
+ *
+ * Description:
+ *   Initialize the freerun timer wrapper.
+ *
+ * Input Parameters:
+ *   freerun          - Caller allocated instance of the freerun
+ *                      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_freerun_initialize(struct esp32s3_freerun_s *freerun, int chan,
+                               uint16_t resolution);
+
+/****************************************************************************
+ * Name: esp32s3_freerun_counter
+ *
+ * Description:
+ *   Read the counter register of the free-running timer.
+ *
+ * Input Parameters:
+ *   freerun          - Caller allocated instance of the freerun state
+ *                      structure.  This structure must have been previously
+ *                      initialized via a call to
+ *                      esp32s3_freerun_initialize();
+ *   ts               - The location in which to return the time from the
+ *                      free-running timer.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_freerun_counter(struct esp32s3_freerun_s *freerun,
+                            struct timespec *ts);
+
+/****************************************************************************
+ * Name: esp32s3_freerun_uninitialize
+ *
+ * Description:
+ *   Stop the free-running timer and release all resources that it uses.
+ *
+ * Input Parameters:
+ *   freerun          - Caller allocated instance of the freerun state
+ *                      structure. This structure must have been previously
+ *                      initialized via a call to
+ *                      esp32s3_freerun_initialize();
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_freerun_uninitialize(struct esp32s3_freerun_s *freerun);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_ESP32S3_FREERUN */
+#endif /* __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_FREERUN_H */

Reply via email to