You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2021/03/12 12:02:03 UTC

[GitHub] [incubator-nuttx] gustavonihei commented on a change in pull request #3040: riscv/esp32c3: Add ESP32-C3 WLAN netcard driver

gustavonihei commented on a change in pull request #3040:
URL: https://github.com/apache/incubator-nuttx/pull/3040#discussion_r593122074



##########
File path: arch/risc-v/src/esp32c3/esp32c3_rt_timer.c
##########
@@ -0,0 +1,678 @@
+/****************************************************************************
+ * arch/risc-v/src/esp32c3/esp32c3_rt_timer.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this args 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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/kthread.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+
+#include "hardware/esp32c3_soc.h"
+#include "esp32c3_tim.h"
+#include "esp32c3_rt_timer.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_HPWORKPRIORITY
+#  if CONFIG_ESP32C3_RT_TIMER_TASK_PRIORITY >= CONFIG_SCHED_HPWORKPRIORITY
+#    error "RT timer priority should be smaller that high-prio workqueue"
+#  endif
+#endif
+
+#define RT_TIMER_TASK_NAME        CONFIG_ESP32C3_RT_TIMER_TASK_NAME
+#define RT_TIMER_TASK_PRIORITY    CONFIG_ESP32C3_RT_TIMER_TASK_PRIORITY
+#define RT_TIMER_TASK_STACK_SIZE  CONFIG_ESP32C3_RT_TIMER_TASK_STACK_SIZE
+
+#define ESP32C3_TIMER_PRESCALER     (APB_CLK_FREQ / (1000 * 1000))
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static int s_pid;
+
+static sem_t s_toutsem;
+
+static struct list_node s_runlist;
+static struct list_node s_toutlist;
+
+static struct esp32c3_tim_dev_s *s_esp32c3_tim_dev;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: start_rt_timer
+ *
+ * Description:
+ *   Start timer by inserting it into running list and reset hardware timer
+ *   alarm value if this timer in head of list.
+ *
+ * Input Parameters:
+ *   timer - RT timer pointer
+ *   timeout - Timeout value
+ *   repeat  - If the timer run repeat
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void start_rt_timer(FAR struct rt_timer_s *timer,
+                           uint64_t timeout,
+                           bool repeat)
+{
+  irqstate_t flags;
+  struct rt_timer_s *p;
+  bool inserted = false;
+  uint64_t counter;
+  struct esp32c3_tim_dev_s *tim = s_esp32c3_tim_dev;
+
+  flags = enter_critical_section();
+
+  /* Only idle timer can be started */
+
+  if (timer->state == RT_TIMER_IDLE)
+    {
+      /* Calculate the timer's alarm value */
+
+      ESP32C3_TIM_GETCTR(tim, &counter);
+      timer->timeout = timeout;
+      timer->alarm = timer->timeout + counter;
+
+      if (repeat)
+        {
+          timer->flags |= RT_TIMER_REPEAT;
+        }
+      else
+        {
+          timer->flags &= ~RT_TIMER_REPEAT;
+        }
+
+      /** Scan timer list and insert the new timer into previous
+       *  node of timer whose alarm value is larger than new one
+       */
+
+      list_for_every_entry(&s_runlist, p, struct rt_timer_s, list)
+        {
+          if (p->alarm > timer->alarm)
+            {
+              list_add_before(&p->list, &timer->list);
+              inserted = true;
+              break;
+            }
+        }
+
+      /* If not find a larger one, insert new timer into tail of list */
+
+      if (!inserted)
+        {
+          list_add_tail(&s_runlist, &timer->list);
+        }
+
+      timer->state = RT_TIMER_READY;
+
+      /* If this timer is in head of list */
+
+      if (timer == container_of(s_runlist.next, struct rt_timer_s, list))
+        {
+          /* Reset hardware timer alarm */
+
+          ESP32C3_TIM_SETALRVL(tim, timer->alarm);
+          ESP32C3_TIM_SETALRM(tim, true);
+        }
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: stop_rt_timer
+ *
+ * Description:
+ *   Stop timer by removing it from running list and reset hardware timer
+ *   alarm value if this timer is in head of list.
+ *
+ * Input Parameters:
+ *   timer - RT timer pointer
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void stop_rt_timer(FAR struct rt_timer_s *timer)
+{
+  irqstate_t flags;
+  bool ishead;
+  struct rt_timer_s *next_timer;
+  uint64_t alarm;
+  struct esp32c3_tim_dev_s *tim = s_esp32c3_tim_dev;
+
+  flags = enter_critical_section();
+
+  /**
+   * Function "start" can set timer to be repeat, and function "stop"
+   * should remove this feature although it is not in ready state.
+   */
+
+  timer->flags &= ~RT_TIMER_REPEAT;
+
+  /* Only ready timer can be stopped */
+
+  if (timer->state == RT_TIMER_READY)
+    {
+      /* Check if timer is in head of list */
+
+      if (timer == container_of(s_runlist.next, struct rt_timer_s, list))
+        {
+          ishead = true;
+        }
+      else
+        {
+          ishead = false;
+        }
+
+      list_delete(&timer->list);
+      timer->state = RT_TIMER_IDLE;
+
+      /* If timer is in in head of list */
+
+      if (ishead)
+        {
+          /* If list is not empty */
+
+          if (!list_is_empty(&s_runlist))
+            {
+              /* Reset hardware timer alarm value to be next timer's */
+
+              next_timer = container_of(s_runlist.next,
+                                        struct rt_timer_s,
+                                        list);
+              alarm = next_timer->alarm;
+
+              ESP32C3_TIM_SETALRVL(tim, alarm);
+              ESP32C3_TIM_SETALRM(tim, true);
+            }
+        }
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: delete_rt_timer
+ *
+ * Description:
+ *   Delete timer by removing it from list, then set the timer's state
+ *   to be "RT_TIMER_DELETE", inserting into work list to let rt-timer
+ *   thread to delete it and free resource.
+ *
+ * Input Parameters:
+ *   timer - RT timer pointer
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void delete_rt_timer(FAR struct rt_timer_s *timer)
+{
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (timer->state == RT_TIMER_READY)
+    {
+      stop_rt_timer(timer);
+    }
+  else if (timer->state == RT_TIMER_TIMEOUT)
+    {
+      list_delete(&timer->list);
+    }
+  else if (timer->state == RT_TIMER_DELETE)
+    {
+      goto exit;
+    }
+
+  list_add_after(&s_toutlist, &timer->list);
+  timer->state = RT_TIMER_DELETE;
+
+exit:
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: rt_timer_thread
+ *
+ * Description:
+ *   RT timer working thread, it wait for a timeout semaphore, scan
+ *   the timeout list and process all timers in this list.
+ *
+ * Input Parameters:
+ *   argc - Not used
+ *   argv - Not used
+ *
+ * Returned Value:
+ *   0.
+ *
+ ****************************************************************************/
+
+static int rt_timer_thread(int argc, FAR char *argv[])
+{
+  int ret;
+  irqstate_t flags;
+  struct rt_timer_s *timer;
+  enum rt_timer_state_e raw_state;
+
+  while (1)
+    {
+      /* Waiting for timers timeout */
+
+      ret = nxsem_wait(&s_toutsem);
+      if (ret)
+        {
+          tmrerr("ERROR: Wait s_toutsem error=%d\n", ret);
+          assert(0);
+        }
+
+      /* Enter critical to check global timer timeout list */
+
+      flags = enter_critical_section();
+
+      /* Process all timers in list */
+
+      while (!list_is_empty(&s_toutlist))
+        {
+          /* Get first timer in list */
+
+          timer = container_of(s_toutlist.next, struct rt_timer_s, list);
+
+          /* Cache the raw state to decide how to deal with this timer */
+
+          raw_state = timer->state;
+
+          /* Delete timer from list */
+
+          list_delete(&timer->list);
+
+          /* Set timer's state to be let it to able to restart by user */
+
+          timer->state = RT_TIMER_IDLE;
+
+          /* Leave from critical to start to call "callback" function */
+
+          leave_critical_section(flags);
+
+          if (raw_state == RT_TIMER_TIMEOUT)
+            {
+              timer->callback(timer->arg);
+            }
+          else if (raw_state == RT_TIMER_DELETE)
+            {
+              kmm_free(timer);
+            }
+
+          /* Enter critical for next scanning list */
+
+          flags = enter_critical_section();
+
+          if (raw_state == RT_TIMER_TIMEOUT)
+            {
+              /* Check if timer is repeat */
+
+              if (timer->flags & RT_TIMER_REPEAT)
+                {
+                  start_rt_timer(timer, timer->timeout, true);
+                }
+            }
+        }
+
+      leave_critical_section(flags);
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rt_timer_isr
+ *
+ * Description:
+ *   Hardware timer interrupt service function.
+ *
+ * Input Parameters:
+ *   irq     - Not used
+ *   context - Not used
+ *   arg     - Not used
+ *
+ * Returned Value:
+ *   0.
+ *
+ ****************************************************************************/
+
+static int rt_timer_isr(int irq, void *context, void *arg)
+{
+  irqstate_t flags;
+  struct rt_timer_s *timer;
+  uint64_t alarm;
+  uint64_t counter;
+  struct esp32c3_tim_dev_s *tim = s_esp32c3_tim_dev;
+
+  /* Clear interrupt register status */
+
+  ESP32C3_TIM_ACKINT(tim);
+
+  /* Wake up thread to process timeout timers */
+
+  nxsem_post(&s_toutsem);
+
+  flags = enter_critical_section();
+
+  /* Check if there is timer running */
+
+  if (!list_is_empty(&s_runlist))
+    {
+      /**
+       * When stop/delete timer, in the same time the hardware timer
+       * interrupt triggers, function "stop/delete" remove the timer
+       * from running list, so the 1st timer is not which triggers.
+       */
+
+      timer = container_of(s_runlist.next, struct rt_timer_s, list);
+      ESP32C3_TIM_GETCTR(tim, &counter);
+      if (timer->alarm <= counter)
+        {
+          /**
+           * Remove first timer in running list and add it into
+           * timeout list.
+           *
+           * Set the timer's state to be RT_TIMER_TIMEOUT to avoid
+           * other operation.
+           */
+
+          list_delete(&timer->list);
+          timer->state = RT_TIMER_TIMEOUT;
+          list_add_after(&s_toutlist, &timer->list);
+
+          /* Check if thers is timer running */
+
+          if (!list_is_empty(&s_runlist))
+            {
+              /* Reset hardware timer alarm with next timer's alarm value */
+
+              timer = container_of(s_runlist.next, struct rt_timer_s, list);
+              alarm = timer->alarm;
+
+              ESP32C3_TIM_SETALRVL(tim, alarm);
+              ESP32C3_TIM_SETALRM(tim, true);
+            }
+        }
+    }
+
+  leave_critical_section(flags);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rt_timer_create
+ *
+ * Description:
+ *   Create RT timer by into timer creation arguments
+ *
+ * Input Parameters:
+ *   args         - Input RT timer creation arguments
+ *   timer_handle - Output RT timer handle pointer
+ *
+ * Returned Value:
+ *   0 is returned on success. Otherwise, a negated errno value is returned.
+ *
+ ****************************************************************************/
+
+int rt_timer_create(FAR const struct rt_timer_args_s *args,
+                    FAR struct rt_timer_s **timer_handle)
+{
+  struct rt_timer_s *timer;
+
+  timer = (struct rt_timer_s *)kmm_malloc(sizeof(*timer));
+  if (!timer)
+    {
+      tmrerr("ERROR: Failed to allocate %d bytes\n", sizeof(*timer));
+      return -ENOMEM;
+    }
+
+  timer->callback = args->callback;
+  timer->arg      = args->arg;
+  timer->flags    = RT_TIMER_NOFLAGS;
+  timer->state    = RT_TIMER_IDLE;
+  list_initialize(&timer->list);
+
+  *timer_handle = timer;
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: rt_timer_start
+ *
+ * Description:
+ *   Start RT timer.
+ *
+ * Input Parameters:
+ *   timer   - RT timer pointer
+ *   timeout - Timeout value
+ *   repeat  - If the timer run repeat
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void rt_timer_start(FAR struct rt_timer_s *timer,
+                    uint64_t timeout,
+                    bool repeat)
+{
+  stop_rt_timer(timer);
+
+  start_rt_timer(timer, timeout, repeat);
+}
+
+/****************************************************************************
+ * Name: rt_timer_stop
+ *
+ * Description:
+ *   Stop RT timer.
+ *
+ * Input Parameters:
+ *   timer - RT timer pointer
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void rt_timer_stop(FAR struct rt_timer_s *timer)
+{
+  stop_rt_timer(timer);
+}
+
+/****************************************************************************
+ * Name: rt_timer_delete
+ *
+ * Description:
+ *   Stop and deleta RT timer.

Review comment:
       ```suggestion
    *   Stop and delete RT timer.
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org