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/05/04 18:22:34 UTC

[incubator-nuttx] branch master updated: risc-v/esp32-c3: Adds freerun 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 b01ddef  risc-v/esp32-c3: Adds freerun wrapper
b01ddef is described below

commit b01ddef61b70453ca4e98922492247e90fb48707
Author: Sara Souza <sa...@espressif.com>
AuthorDate: Thu Apr 22 17:28:20 2021 -0300

    risc-v/esp32-c3: Adds freerun wrapper
---
 arch/risc-v/src/esp32c3/Kconfig                |   7 +
 arch/risc-v/src/esp32c3/Make.defs              |   4 +
 arch/risc-v/src/esp32c3/esp32c3_freerun.c      | 354 +++++++++++++++++++++++++
 arch/risc-v/src/esp32c3/esp32c3_freerun.h      | 145 ++++++++++
 arch/risc-v/src/esp32c3/esp32c3_tim.c          |  30 ++-
 arch/risc-v/src/esp32c3/esp32c3_tim.h          |   2 +
 arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h |   2 +-
 7 files changed, 542 insertions(+), 2 deletions(-)

diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig
index 8115c55..72e5090 100644
--- a/arch/risc-v/src/esp32c3/Kconfig
+++ b/arch/risc-v/src/esp32c3/Kconfig
@@ -403,6 +403,13 @@ config ESP32C3_ONESHOT
 		Enable a wrapper around the low level timer/counter functions to
 		support one-shot timer.
 
+config ESP32C3_FREERUN
+	bool "TIM 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
 endif # ESP32C3_TIMER
 
diff --git a/arch/risc-v/src/esp32c3/Make.defs b/arch/risc-v/src/esp32c3/Make.defs
index 30d217f..7c333a7 100644
--- a/arch/risc-v/src/esp32c3/Make.defs
+++ b/arch/risc-v/src/esp32c3/Make.defs
@@ -100,6 +100,10 @@ ifeq ($(CONFIG_ESP32C3_RT_TIMER),y)
 CHIP_CSRCS += esp32c3_rt_timer.c
 endif
 
+ifeq ($(CONFIG_ESP32C3_FREERUN),y)
+CHIP_CSRCS += esp32c3_freerun.c
+endif
+
 ifeq ($(CONFIG_ESP32C3_DISABLE_STDC_ATOMIC),)
 CHIP_CSRCS += esp32c3_std_atomic.c
 endif
diff --git a/arch/risc-v/src/esp32c3/esp32c3_freerun.c b/arch/risc-v/src/esp32c3/esp32c3_freerun.c
new file mode 100644
index 0000000..635a249
--- /dev/null
+++ b/arch/risc-v/src/esp32c3/esp32c3_freerun.c
@@ -0,0 +1,354 @@
+/****************************************************************************
+ * arch/risc-v/src/esp32c3/esp32c3_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 "esp32c3_freerun.h"
+#include "esp32c3_clockconfig.h"
+#include "esp32c3_gpio.h"
+
+#ifdef CONFIG_ESP32C3_FREERUN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX_TIMERS 2
+#define MAX_US_RESOLUTION 819
+#define TIMER_WIDTH 54
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32c3_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              - IRQ associated to that interrupt.
+ *   arg              - An opaque argument provided when the interrupt
+ *                      was registered.
+ *
+ * Returned Value:
+ *   OK
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static int esp32c3_freerun_handler(int irq, void *context, void *arg)
+{
+  struct esp32c3_freerun_s *freerun = (struct esp32c3_freerun_s *) arg;
+
+  DEBUGASSERT(freerun != NULL);
+
+  freerun->overflow++;
+  ESP32C3_TIM_SETALRM(freerun->tch, true); /* Re-enables the alarm */
+  ESP32C3_TIM_ACKINT(freerun->tch);        /* Clear the Interrupt */
+  return OK;
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32c3_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 esp32c3_freerun_initialize(struct esp32c3_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) / esp32c3_clk_apb_freq()
+   */
+
+  DEBUGASSERT(resolution <= MAX_US_RESOLUTION);
+
+  freerun->tch = esp32c3_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.
+       */
+
+      ESP32C3_TIM_STOP(freerun->tch);
+
+      /* Configure clock source */
+
+      ESP32C3_TIM_CLK_SRC(freerun->tch, ESP32C3_TIM_APB_CLK);
+
+      /* Calculate the suitable prescaler for a period
+       * for the requested resolution.
+       */
+
+      pre = esp32c3_clk_apb_freq() * resolution / USEC_PER_SEC;
+
+      tmrinfo("pre=% "PRIu16 " clk=%d \n", pre, esp32c3_clk_apb_freq());
+
+      /* Configure TIMER prescaler */
+
+      ESP32C3_TIM_SETPRE(freerun->tch, pre);
+
+      /* Configure TIMER mode */
+
+      ESP32C3_TIM_SETMODE(freerun->tch, ESP32C3_TIM_MODE_UP);
+
+      /* Clear TIMER counter value */
+
+      ESP32C3_TIM_CLEAR(freerun->tch);
+
+      /* Set the maximum timeout */
+
+      ESP32C3_TIM_SETALRVL(freerun->tch, freerun->max_timeout);
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+
+      /* Set the interrupt */
+
+      freerun->overflow = 0;
+
+      /* Enable autoreload */
+
+      ESP32C3_TIM_SETARLD(freerun->tch, true);
+
+      /* Enable TIMER alarm */
+
+      ESP32C3_TIM_SETALRM(freerun->tch, true);
+
+      /* Clear Interrupt Bits Status */
+
+      ESP32C3_TIM_ACKINT(freerun->tch);
+
+      /* Register the handler */
+
+        {
+          irqstate_t flags = enter_critical_section();
+          ret = ESP32C3_TIM_SETISR(freerun->tch, esp32c3_freerun_handler,
+                                   freerun);
+          leave_critical_section(flags);
+        }
+
+      if (ret == OK)
+        {
+          ESP32C3_TIM_ENABLEINT(freerun->tch);
+        }
+
+#endif
+      /* Finally, start the TIMER */
+
+      ESP32C3_TIM_START(freerun->tch);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp32c3_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
+ *                      esp32c3_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 esp32c3_freerun_counter(struct esp32c3_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;
+  ESP32C3_TIM_GETCTR(freerun->tch, &counter);
+  pending  = ESP32C3_TIM_CHECKINT(freerun->tch);
+  ESP32C3_TIM_GETCTR(freerun->tch, &verify);
+
+  /* If an interrupt was pending before we re-enabled interrupts,
+   * then the overflow needs to be incremented.
+   */
+
+  if (pending)
+    {
+      ESP32C3_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: esp32c3_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
+ *                      esp32c3_freerun_initialize();
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32c3_freerun_uninitialize(struct esp32c3_freerun_s *freerun)
+{
+  int ret;
+  DEBUGASSERT(freerun != NULL);
+  DEBUGASSERT(freerun->tch != NULL);
+
+  /* Stop timer */
+
+  ESP32C3_TIM_STOP(freerun->tch);
+
+  /* Disable timer interrupt */
+
+  ESP32C3_TIM_DISABLEINT(freerun->tch);
+
+  /* Detach handler */
+
+  ret = ESP32C3_TIM_SETISR(freerun->tch, NULL, NULL);
+
+  /* Free the timer */
+
+  esp32c3_tim_deinit(freerun->tch);
+  freerun->tch = NULL;
+
+  return ret;
+}
+
+#endif /* CONFIG_ESP32C3_FREERUN */
diff --git a/arch/risc-v/src/esp32c3/esp32c3_freerun.h b/arch/risc-v/src/esp32c3/esp32c3_freerun.h
new file mode 100644
index 0000000..d80da59
--- /dev/null
+++ b/arch/risc-v/src/esp32c3/esp32c3_freerun.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * arch/risc-v/src/esp32c3/esp32c3_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_RISCV_SRC_ESP32C3_FREERUN_H
+#define __ARCH_RISCV_SRC_ESP32C3_FREERUN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <time.h>
+
+#include "esp32c3_tim.h"
+
+#ifdef CONFIG_ESP32C3_FREERUN
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The freerun client must allocate an instance of this structure and called
+ * esp32c3_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 esp32c3_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 */
+  FAR struct esp32c3_tim_dev_s *tch; /* Handle returned by esp32c3_tim_init() */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32c3_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 esp32c3_freerun_initialize(struct esp32c3_freerun_s *freerun, int chan,
+                               uint16_t resolution);
+
+/****************************************************************************
+ * Name: esp32c3_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
+ *                      esp32c3_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 esp32c3_freerun_counter(struct esp32c3_freerun_s *freerun,
+                            struct timespec *ts);
+
+/****************************************************************************
+ * Name: esp32c3_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
+ *                      esp32c3_freerun_initialize();
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned
+ *   on failure.
+ *
+ ****************************************************************************/
+
+int esp32c3_freerun_uninitialize(struct esp32c3_freerun_s *freerun);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_ESP32C3_FREERUN */
+#endif /* __ARCH_RISCV_SRC_ESP32C3_FREERUN_H */
diff --git a/arch/risc-v/src/esp32c3/esp32c3_tim.c b/arch/risc-v/src/esp32c3/esp32c3_tim.c
index 5acb898..db58300 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_tim.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_tim.c
@@ -34,6 +34,7 @@
 
 #include "esp32c3_tim.h"
 #include "esp32c3_irq.h"
+#include "esp32c3_gpio.h"
 
 /****************************************************************************
  * Private Types
@@ -82,6 +83,7 @@ static int esp32c3_tim_setisr(FAR struct esp32c3_tim_dev_s *dev,
 static void esp32c3_tim_enableint(FAR struct esp32c3_tim_dev_s *dev);
 static void esp32c3_tim_disableint(FAR struct esp32c3_tim_dev_s *dev);
 static void esp32c3_tim_ackint(FAR struct esp32c3_tim_dev_s *dev);
+static int  esp32c3_tim_checkint(FAR struct esp32c3_tim_dev_s *dev);
 
 /****************************************************************************
  * Private Data
@@ -107,7 +109,8 @@ struct esp32c3_tim_ops_s esp32c3_tim_ops =
   .setisr        = esp32c3_tim_setisr,
   .enableint     = esp32c3_tim_enableint,
   .disableint    = esp32c3_tim_disableint,
-  .ackint        = esp32c3_tim_ackint
+  .ackint        = esp32c3_tim_ackint,
+  .checkint      = esp32c3_tim_checkint
 };
 
 #ifdef CONFIG_ESP32C3_TIMER0
@@ -655,6 +658,31 @@ static void esp32c3_tim_ackint(FAR struct esp32c3_tim_dev_s *dev)
 }
 
 /****************************************************************************
+ * Name: esp32c3_tim_checkint
+ *
+ * Description:
+ *   Check the interrupt status bit.
+ *
+ * Parameters:
+ *   dev           - Pointer to the timer driver struct.
+ *
+ * Returned Values:
+ *  Return 1 in case of an interrupt is triggered, otherwise 0.
+ *
+ ****************************************************************************/
+
+static int esp32c3_tim_checkint(FAR struct esp32c3_tim_dev_s *dev)
+{
+  struct esp32c3_tim_priv_s *priv = (struct esp32c3_tim_priv_s *)dev;
+  uint32_t reg_value;
+
+  DEBUGASSERT(dev != NULL);
+
+  reg_value = getreg32(TIMG_INT_ST_TIMERS_REG(priv->id));
+  return ((reg_value & TIMG_T0_INT_ST_V) >> TIMG_T0_INT_ST_S);
+}
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/
 
diff --git a/arch/risc-v/src/esp32c3/esp32c3_tim.h b/arch/risc-v/src/esp32c3/esp32c3_tim.h
index e3a0098..12ad92a 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_tim.h
+++ b/arch/risc-v/src/esp32c3/esp32c3_tim.h
@@ -53,6 +53,7 @@
 #define ESP32C3_TIM_ENABLEINT(d)                     ((d)->ops->enableint(d))
 #define ESP32C3_TIM_DISABLEINT(d)                    ((d)->ops->disableint(d))
 #define ESP32C3_TIM_ACKINT(d)                        ((d)->ops->ackint(d))
+#define ESP32C3_TIM_CHECKINT(d)                      ((d)->ops->checkint(d))
 
 /****************************************************************************
  * Public Types
@@ -126,6 +127,7 @@ struct esp32c3_tim_ops_s
   CODE void (*enableint)(FAR struct esp32c3_tim_dev_s *dev);
   CODE void (*disableint)(FAR struct esp32c3_tim_dev_s *dev);
   CODE void (*ackint)(FAR struct esp32c3_tim_dev_s *dev);
+  CODE int  (*checkint)(FAR struct esp32c3_tim_dev_s *dev);
 };
 
 /****************************************************************************
diff --git a/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h b/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h
index b9846d8..d4d080c 100644
--- a/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h
+++ b/arch/risc-v/src/esp32c3/hardware/esp32c3_tim.h
@@ -72,7 +72,7 @@
 /* Maximum value in the high 22 bits from timer counters */
 
 #define LOW_32_MASK                0xffffffff
-#define LOW_22_MASK                0x3fffff
+#define LOW_22_MASK                0x003fffff
 #define SHIFT_32                   32
 
 #define TIMG_T0CONFIG_REG(i)          (REG_TIMG_BASE(i) + 0x0000)