You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gu...@apache.org on 2021/09/22 12:48:05 UTC

[incubator-nuttx] branch master updated: xtensa/esp32-s2: Adds freerun timer wrapper

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

gustavonihei 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 2cd4f4a  xtensa/esp32-s2: Adds freerun timer wrapper
2cd4f4a is described below

commit 2cd4f4af792aafbd4344b4637ce04fe4585c2523
Author: Sara Souza <sa...@espressif.com>
AuthorDate: Fri Sep 17 19:13:51 2021 -0300

    xtensa/esp32-s2: Adds freerun timer wrapper
---
 arch/xtensa/src/esp32s2/Kconfig           |   7 +
 arch/xtensa/src/esp32s2/Make.defs         |   4 +
 arch/xtensa/src/esp32s2/esp32s2_freerun.c | 353 ++++++++++++++++++++++++++++++
 arch/xtensa/src/esp32s2/esp32s2_freerun.h | 145 ++++++++++++
 4 files changed, 509 insertions(+)

diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index e4ccd9a..d92ab48 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -855,6 +855,13 @@ config ESP32S2_ONESHOT
 		Enable a wrapper around the low level timer/counter functions to
 		support one-shot timer.
 
+config ESP32S2_FREERUN
+	bool "Freerun timer wrapper"
+	default n
+	---help---
+		Enable a wrapper around the low level timer/counter functions to
+		support freerun timer.
+
 endmenu # Timer/counter Configuration
 endif # ESP32S2_TIMER
 
diff --git a/arch/xtensa/src/esp32s2/Make.defs b/arch/xtensa/src/esp32s2/Make.defs
index 218adbb..7fbe1c1 100644
--- a/arch/xtensa/src/esp32s2/Make.defs
+++ b/arch/xtensa/src/esp32s2/Make.defs
@@ -81,3 +81,7 @@ ifeq ($(CONFIG_TIMER),y)
 CHIP_CSRCS += esp32s2_tim_lowerhalf.c
 endif
 endif
+
+ifeq ($(CONFIG_ESP32S2_FREERUN),y)
+CHIP_CSRCS += esp32s2_freerun.c
+endif
diff --git a/arch/xtensa/src/esp32s2/esp32s2_freerun.c b/arch/xtensa/src/esp32s2/esp32s2_freerun.c
new file mode 100644
index 0000000..bce3ab0
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/esp32s2_freerun.c
@@ -0,0 +1,353 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_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 <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+
+#include "esp32s2_freerun.h"
+#include "esp32s2_clockconfig.h"
+#include "esp32s2_gpio.h"
+
+#ifdef CONFIG_ESP32S2_FREERUN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX_TIMERS 4
+#define MAX_US_RESOLUTION 819 /* MAX_US = (PREmax * USEC_PER_SEC) / CLKmin */ 
+#define TIMER_WIDTH 64
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_freerun_handler
+ *
+ * Description:
+ *   Timer interrupt callback.  When the freerun timer counter overflows,
+ *   this interrupt will occur.  It will just increment an overflow counter.
+ *
+ * Input Parameters:
+ *   irq              - IRQ associated to that interrupt.
+ *   arg              - An opaque argument provided when the interrupt
+ *                      was registered.
+ *
+ * Returned Value:
+ *   OK
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static int esp32s2_freerun_handler(int irq, void *context, void *arg)
+{
+  struct esp32s2_freerun_s *freerun = (struct esp32s2_freerun_s *) arg;
+
+  DEBUGASSERT(freerun != NULL);
+
+  freerun->overflow++;
+  ESP32S2_TIM_SETALRM(freerun->tch, true); /* Re-enables the alarm */
+  ESP32S2_TIM_ACKINT(freerun->tch);        /* Clear the Interrupt */
+  return OK;
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_freerun_initialize
+ *
+ * Description:
+ *   Initialize the freerun timer wrapper.
+ *
+ * Input Parameters:
+ *   freerun          - A pointer to an 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 esp32s2_freerun_initialize(struct esp32s2_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-C3 prescaler doesn't support.
+   * max resolution = (max prescaler * USEC_PER_SEC) / esp32s2_clk_apb_freq()
+   */
+
+  DEBUGASSERT(resolution <= MAX_US_RESOLUTION);
+
+  freerun->tch = esp32s2_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.
+       */
+
+      ESP32S2_TIM_STOP(freerun->tch);
+
+      /* Configure clock source */
+
+      ESP32S2_TIM_CLK_SRC(freerun->tch, ESP32S2_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 */
+
+      ESP32S2_TIM_SETPRE(freerun->tch, pre);
+
+      /* Configure TIMER mode */
+
+      ESP32S2_TIM_SETMODE(freerun->tch, ESP32S2_TIM_MODE_UP);
+
+      /* Clear TIMER counter value */
+
+      ESP32S2_TIM_CLEAR(freerun->tch);
+
+      /* Set the maximum timeout */
+
+      ESP32S2_TIM_SETALRVL(freerun->tch, freerun->max_timeout);
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+
+      /* Set the interrupt */
+
+      freerun->overflow = 0;
+
+      /* Enable autoreload */
+
+      ESP32S2_TIM_SETARLD(freerun->tch, true);
+
+      /* Enable TIMER alarm */
+
+      ESP32S2_TIM_SETALRM(freerun->tch, true);
+
+      /* Clear Interrupt Bits Status */
+
+      ESP32S2_TIM_ACKINT(freerun->tch);
+
+      /* Register the handler */
+
+        {
+          irqstate_t flags = enter_critical_section();
+          ret = ESP32S2_TIM_SETISR(freerun->tch, esp32s2_freerun_handler,
+                                   freerun);
+          leave_critical_section(flags);
+        }
+
+      if (ret == OK)
+        {
+          ESP32S2_TIM_ENABLEINT(freerun->tch);
+        }
+
+#endif
+      /* Finally, start the TIMER */
+
+      ESP32S2_TIM_START(freerun->tch);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32s2_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
+ *                      esp32s2_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 esp32s2_freerun_counter(struct esp32s2_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);
+
+  /* Temporarily disable the overflow counter. */
+
+  flags    = enter_critical_section();
+
+  overflow = freerun->overflow;
+  ESP32S2_TIM_GETCTR(freerun->tch, &counter);
+  pending  = ESP32S2_TIM_CHECKINT(freerun->tch);
+  ESP32S2_TIM_GETCTR(freerun->tch, &verify);
+
+  /* If an interrupt was pending before we re-enabled interrupts,
+   * then the overflow needs to be incremented.
+   */
+
+  if (pending)
+    {
+      ESP32S2_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: esp32s2_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
+ *                      esp32s2_freerun_initialize();
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s2_freerun_uninitialize(struct esp32s2_freerun_s *freerun)
+{
+  int ret;
+  DEBUGASSERT(freerun != NULL);
+  DEBUGASSERT(freerun->tch != NULL);
+
+  /* Stop timer */
+
+  ESP32S2_TIM_STOP(freerun->tch);
+
+  /* Disable timer interrupt */
+
+  ESP32S2_TIM_DISABLEINT(freerun->tch);
+
+  /* Detach handler */
+
+  ret = ESP32S2_TIM_SETISR(freerun->tch, NULL, NULL);
+
+  /* Free the timer */
+
+  esp32s2_tim_deinit(freerun->tch);
+  freerun->tch = NULL;
+
+  return ret;
+}
+
+#endif /* CONFIG_ESP32S2_FREERUN */
diff --git a/arch/xtensa/src/esp32s2/esp32s2_freerun.h b/arch/xtensa/src/esp32s2/esp32s2_freerun.h
new file mode 100644
index 0000000..f61b42e
--- /dev/null
+++ b/arch/xtensa/src/esp32s2/esp32s2_freerun.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * arch/xtensa/src/esp32s2/esp32s2_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_ESP32S2_FREERUN_H
+#define __ARCH_XTENSA_SRC_ESP32S2_FREERUN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include "esp32s2_tim.h"
+
+#ifdef CONFIG_ESP32S2_FREERUN
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The freerun client must allocate an instance of this structure and called
+ * esp32s2_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 esp32s2_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 esp32s2_tim_dev_s *tch;     /* Handle returned by esp32s2_tim_init() */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s2_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 esp32s2_freerun_initialize(struct esp32s2_freerun_s *freerun,
+                               int chan, uint16_t resolution);
+
+/****************************************************************************
+ * Name: esp32s2_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
+ *                      esp32s2_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 esp32s2_freerun_counter(struct esp32s2_freerun_s *freerun,
+                            struct timespec *ts);
+
+/****************************************************************************
+ * Name: esp32s2_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
+ *                      esp32s2_freerun_initialize();
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32s2_freerun_uninitialize(struct esp32s2_freerun_s *freerun);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_ESP32S2_FREERUN */
+#endif /* __ARCH_XTENSA_SRC_ESP32S2_FREERUN_H */