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/nuttx.git

commit 6dcb8270e303012821c120098ebf7b52d2944d17
Author: ouyangxiangzhen <[email protected]>
AuthorDate: Wed Jul 30 10:37:56 2025 +0800

    timers/oneshot: Add new clkdev interfaces.
    
    This commit introduce new clockdevice interfaces for oneshot.
    - It can represent both `timer` and `alarm`.
    - It simplifies the implementation of timer driver. Timer driver do not 
need considering the time conversion between clock count, tick and timespec.
    - It sets timer align to the tick boundary to improve timer accuracy.
    - It can avoid using 64-bit division during timer expiration interrupt, 
improves performance and reduces interrupt latency.
    - It considers almost all multiplication overflow problems in time 
conversion without processing at the driver.
    
    Signed-off-by: ouyangxiangzhen <[email protected]>
---
 drivers/timers/Kconfig         |   2 +-
 include/nuttx/timers/oneshot.h | 242 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 221 insertions(+), 23 deletions(-)

diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig
index 7cc2d4abc1f..62416e868af 100644
--- a/drivers/timers/Kconfig
+++ b/drivers/timers/Kconfig
@@ -124,7 +124,7 @@ config ONESHOT
 if ONESHOT
 
 config ONESHOT_COUNT
-       bool "Oneshot count-based clock device driver"
+       bool
        default n
        ---help---
                This option enables the oneshot implementation to be based on 
the
diff --git a/include/nuttx/timers/oneshot.h b/include/nuttx/timers/oneshot.h
index 877c7acf086..302527588f9 100644
--- a/include/nuttx/timers/oneshot.h
+++ b/include/nuttx/timers/oneshot.h
@@ -96,8 +96,8 @@
  *
  ****************************************************************************/
 
-#define ONESHOT_MAX_DELAY(l,t) (l)->ops->max_delay(l,t)
-#define ONESHOT_TICK_MAX_DELAY(l,t) oneshot_tick_max_delay(l,t)
+#define ONESHOT_MAX_DELAY(l,t) oneshot_max_delay(l,t)
+#define ONESHOT_TICK_MAX_DELAY(l,t)  oneshot_tick_max_delay(l,t)
 
 /****************************************************************************
  * Name: ONESHOT_START
@@ -119,7 +119,7 @@
  *
  ****************************************************************************/
 
-#define ONESHOT_START(l,t) (l)->ops->start(l,t)
+#define ONESHOT_START(l,t) oneshot_start(l,t)
 #define ONESHOT_TICK_START(l,t) oneshot_tick_start(l,t)
 
 /****************************************************************************
@@ -146,7 +146,7 @@
  *
  ****************************************************************************/
 
-#define ONESHOT_CANCEL(l,t) (l)->ops->cancel(l,t)
+#define ONESHOT_CANCEL(l,t) oneshot_cancel(l,t)
 #define ONESHOT_TICK_CANCEL(l,t) oneshot_tick_cancel(l,t)
 
 /****************************************************************************
@@ -168,7 +168,7 @@
  *
  ****************************************************************************/
 
-#define ONESHOT_CURRENT(l,t) (l)->ops->current(l,t)
+#define ONESHOT_CURRENT(l,t) oneshot_current(l,t)
 #define ONESHOT_TICK_CURRENT(l,t) oneshot_tick_current(l,t)
 
 /****************************************************************************
@@ -266,43 +266,205 @@ extern "C"
  * Inline Functions
  ****************************************************************************/
 
+#ifdef CONFIG_ONESHOT_COUNT
+static inline_function
+void oneshot_count_init(FAR struct oneshot_lowerhalf_s *lower,
+                        uint32_t frequency)
+{
+  DEBUGASSERT(lower && frequency);
+
+  lower->frequency = frequency;
+}
+#endif
+
+static inline_function
+int oneshot_max_delay(FAR struct oneshot_lowerhalf_s *lower,
+                      FAR struct timespec *ts)
+{
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  clkcnt_t max = lower->ops->max_delay(lower);
+  clkcnt_max_timespec(max, lower->frequency, ts);
+#else
+  ret = lower->ops->max_delay(lower, ts);
+#endif
+  return ret;
+}
+
+/****************************************************************************
+ * Name: oneshot_current
+ *
+ * Description:
+ *   Get the current time.
+ *
+ * Input Parameters:
+ *   ops - The oneshot interface.
+ *   lower - The oneshot lowerhalf data.
+ *   ts - The pointer to the current time.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline_function
+int oneshot_current(FAR struct oneshot_lowerhalf_s *lower,
+                    FAR struct timespec *ts)
+{
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  clkcnt_t cnt  = lower->ops->current(lower);
+  uint32_t freq = lower->frequency;
+  uint64_t sec  = clkcnt_cnt2sec(cnt, freq);
+
+  cnt          -= sec * freq;
+  ts->tv_nsec   = clkcnt_delta_cnt2nsec(cnt, freq);
+  ts->tv_sec    = sec;
+#else
+  ret = lower->ops->current(lower, ts);
+#endif
+  return ret;
+}
+
+/****************************************************************************
+ * Name: oneshot_cancel
+ *
+ * Description:
+ *   Cancel the timer
+ *
+ * Input Parameters:
+ *   ops - The oneshot interface.
+ *   ts - The delta time in timespec.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline_function
+int oneshot_cancel(FAR struct oneshot_lowerhalf_s *lower,
+                   FAR struct timespec *ts)
+{
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  lower->ops->cancel(lower);
+  oneshot_current(lower, ts);
+#else
+  ret = lower->ops->cancel(lower, ts);
+#endif
+  return ret;
+}
+
+/****************************************************************************
+ * Name: oneshot_start
+ *
+ * Description:
+ *   Set the relative time in timespec to trigger the clockevent.
+ *
+ * Input Parameters:
+ *   ops - The oneshot interface.
+ *   ts - The delta time in timespec.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline_function
+int oneshot_start(FAR struct oneshot_lowerhalf_s *lower,
+                  FAR const struct timespec *ts)
+{
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  clkcnt_t freq = lower->frequency;
+  clkcnt_t cnt  = clkcnt_delta_time2cnt(ts->tv_nsec, freq, NSEC_PER_SEC) +
+                  ts->tv_sec * freq;
+
+  lower->ops->start(lower, cnt);
+#else
+  ret = lower->ops->start(lower, ts);
+#endif
+  return ret;
+}
+
 /* Tick-based compatiable layer for oneshot */
 
 static inline_function
 int oneshot_tick_max_delay(FAR struct oneshot_lowerhalf_s *lower,
                            FAR clock_t *tick)
 {
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  clkcnt_t max = lower->ops->max_delay(lower);
+  *tick = clkcnt_max_tick(max, lower->frequency);
+#else
   struct timespec ts;
 
-  ONESHOT_MAX_DELAY(lower, &ts);
+  ret = lower->ops->max_delay(lower, &ts);
   *tick = clock_time2ticks(&ts);
-
-  return OK;
+#endif
+  return ret;
 }
 
+/****************************************************************************
+ * Name: oneshot_tick_start
+ *
+ * Description:
+ *   Set the relative time in ticks to trigger the clockevent.
+ *
+ * Input Parameters:
+ *   ops - The oneshot interface.
+ *   tick   - The delta time in ticks.
+
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
 static inline_function
 int oneshot_tick_start(FAR struct oneshot_lowerhalf_s *lower,
-                       clock_t ticks)
+                       clock_t tick)
 {
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  clkcnt_t cnt = clkcnt_tick2cnt(tick, lower->frequency);
+  lower->ops->start(lower, cnt);
+#else
   struct timespec ts;
-  clock_ticks2time(&ts, ticks);
-  return lower->ops->start(lower, &ts);
+  clock_ticks2time(&ts, tick);
+  ret = lower->ops->start(lower, &ts);
+#endif
+  return ret;
 }
 
-static inline_function
-int oneshot_tick_cancel(FAR struct oneshot_lowerhalf_s *lower,
-                        FAR clock_t *tick)
-{
-  struct timespec ts;
-  ONESHOT_CANCEL(lower, &ts);
-  *tick = clock_time2ticks_floor(&ts);
-  return OK;
-}
+/****************************************************************************
+ * Name: oneshot_tick_current
+ *
+ * Description:
+ *   Get the current system tick.
+ *
+ * Input Parameters:
+ *   ops - The oneshot interface.
+ *   lower - The oneshot lowerhalf data.
+ *
+ * Returned Value:
+ *   The current system tick.
+ *
+ ****************************************************************************/
 
 static inline_function
 int oneshot_tick_current(FAR struct oneshot_lowerhalf_s *lower,
                          FAR clock_t *tick)
 {
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  clkcnt_t cnt  = lower->ops->current(lower);
+  uint32_t freq = lower->frequency;
+  uint64_t sec  = clkcnt_cnt2sec(cnt, freq);
+
+  cnt   -= sec * freq;
+  *tick  = sec * TICK_PER_SEC + clkcnt_delta_cnt2tick(cnt, freq);
+#else
   struct timespec ts;
 
   /* Some timer drivers may not have current() function.
@@ -311,9 +473,45 @@ int oneshot_tick_current(FAR struct oneshot_lowerhalf_s 
*lower,
 
   DEBUGASSERT(lower->ops->current);
 
-  ONESHOT_CURRENT(lower, &ts);
+  ret = lower->ops->current(lower, &ts);
+  *tick = clock_time2ticks_floor(&ts);
+#endif
+  return ret;
+}
+
+/****************************************************************************
+ * Name: oneshot_tick_cancel
+ *
+ * Description:
+ *   Cancel the timer.
+ *
+ * Input Parameters:
+ *   ops - The oneshot interface.
+ *   lower - The oneshot lowerhalf data.
+ *
+ * Returned Value:
+ *   The current system tick.
+ *
+ ****************************************************************************/
+
+static inline_function
+int oneshot_tick_cancel(FAR struct oneshot_lowerhalf_s *lower,
+                        FAR clock_t *tick)
+{
+  int ret = OK;
+#ifdef CONFIG_ONESHOT_COUNT
+  lower->ops->cancel(lower);
+  oneshot_tick_current(lower, tick);
+#else
+  struct timespec ts;
+
+  ret = lower->ops->cancel(lower, &ts);
+
+  /* Converting timespec to ticks may overflow. */
+
   *tick = clock_time2ticks_floor(&ts);
-  return OK;
+#endif
+  return ret;
 }
 
 static inline_function

Reply via email to