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

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit ce37a07ec644ab3da9c88e3134b0d7b1888c8767
Author: raiden00pl <[email protected]>
AuthorDate: Thu Oct 29 20:16:03 2026 +0100

    arch/arm/src/common/stm32: Add LPTIM oneshot lower-half.
    
    stm32_lptim_oneshot_initialize() returns a oneshot lower-half on LPTIMn
    running in single mode. The longest delay is 65536 counts of the kernel
    clock (STM32_LPTIMn_CLKIN) divided by 128.
    
    Signed-off-by: raiden00pl <[email protected]>
    Assisted-by: Claude Code
---
 arch/arm/src/common/stm32/CMakeLists.txt           |   3 +
 arch/arm/src/common/stm32/Make.defs                |   3 +
 arch/arm/src/common/stm32/stm32_lptim.h            |   7 +
 .../common/stm32/stm32_lptim_oneshot_lowerhalf.c   | 276 +++++++++++++++++++++
 4 files changed, 289 insertions(+)

diff --git a/arch/arm/src/common/stm32/CMakeLists.txt 
b/arch/arm/src/common/stm32/CMakeLists.txt
index 2453bc75b36..6b4c4b9c85e 100644
--- a/arch/arm/src/common/stm32/CMakeLists.txt
+++ b/arch/arm/src/common/stm32/CMakeLists.txt
@@ -102,6 +102,9 @@ if(CONFIG_STM32_LPTIM)
   if(CONFIG_TIMER)
     list(APPEND SRCS stm32_lptim_lowerhalf.c)
   endif()
+  if(CONFIG_ONESHOT)
+    list(APPEND SRCS stm32_lptim_oneshot_lowerhalf.c)
+  endif()
 endif()
 
 if(CONFIG_STM32_FREERUN)
diff --git a/arch/arm/src/common/stm32/Make.defs 
b/arch/arm/src/common/stm32/Make.defs
index 7c2611b450d..85c6920f419 100644
--- a/arch/arm/src/common/stm32/Make.defs
+++ b/arch/arm/src/common/stm32/Make.defs
@@ -112,6 +112,9 @@ CHIP_CSRCS += stm32_lptim.c
 ifeq ($(CONFIG_TIMER),y)
 CHIP_CSRCS += stm32_lptim_lowerhalf.c
 endif
+ifeq ($(CONFIG_ONESHOT),y)
+CHIP_CSRCS += stm32_lptim_oneshot_lowerhalf.c
+endif
 endif
 ifeq ($(CONFIG_STM32_FREERUN),y)
 CHIP_CSRCS += stm32_freerun.c
diff --git a/arch/arm/src/common/stm32/stm32_lptim.h 
b/arch/arm/src/common/stm32/stm32_lptim.h
index 6f006d4d40d..672c006b2bb 100644
--- a/arch/arm/src/common/stm32/stm32_lptim.h
+++ b/arch/arm/src/common/stm32/stm32_lptim.h
@@ -174,6 +174,13 @@ int stm32_lptim_deinit(struct stm32_lptim_dev_s *dev);
 int stm32_lptim_timer_initialize(const char *devpath, int lptim);
 #endif
 
+#ifdef CONFIG_ONESHOT
+/* Get a oneshot timer lower-half on LPTIMn */
+
+struct oneshot_lowerhalf_s;
+struct oneshot_lowerhalf_s *stm32_lptim_oneshot_initialize(int lptim);
+#endif
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/arch/arm/src/common/stm32/stm32_lptim_oneshot_lowerhalf.c 
b/arch/arm/src/common/stm32/stm32_lptim_oneshot_lowerhalf.c
new file mode 100644
index 00000000000..7ece2aafc79
--- /dev/null
+++ b/arch/arm/src/common/stm32/stm32_lptim_oneshot_lowerhalf.c
@@ -0,0 +1,276 @@
+/****************************************************************************
+ * arch/arm/src/common/stm32/stm32_lptim_oneshot_lowerhalf.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/debug.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/timers/oneshot.h>
+
+#include "stm32_lptim.h"
+
+#if defined(CONFIG_ONESHOT) && defined(CONFIG_STM32_LPTIM)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Counts of the 16-bit counter up to the autoreload match in single mode
+ * (ARR)
+ */
+
+#define LPTIM_COUNT_MIN  1
+#define LPTIM_COUNT_MAX  0xffff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_lptim_oneshot_s
+{
+  struct oneshot_lowerhalf_s lh;     /* Must be first */
+  struct stm32_lptim_dev_s  *lptim;  /* LPTIM driver */
+  bool                       running;
+  uint32_t                   fmin;   /* Slowest counter clock */
+  uint32_t                   freq;   /* Counter clock of the delay */
+  uint32_t                   count;  /* Counts of the delay */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int stm32_lptim_os_max_delay(struct oneshot_lowerhalf_s *lower,
+                                    struct timespec *ts);
+static int stm32_lptim_os_start(struct oneshot_lowerhalf_s *lower,
+                                const struct timespec *ts);
+static int stm32_lptim_os_cancel(struct oneshot_lowerhalf_s *lower,
+                                 struct timespec *ts);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct oneshot_operations_s g_lptim_oneshot_ops =
+{
+  .max_delay = stm32_lptim_os_max_delay,
+  .start     = stm32_lptim_os_start,
+  .cancel    = stm32_lptim_os_cancel,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void stm32_lptim_os_halt(struct stm32_lptim_oneshot_s *priv)
+{
+  STM32_LPTIM_ENABLE(priv->lptim, false);
+  STM32_LPTIM_DISABLEINT(priv->lptim, LPTIM_ISR_ARRM);
+  STM32_LPTIM_SETISR(priv->lptim, NULL, NULL, 0);
+  priv->running = false;
+}
+
+static int stm32_lptim_os_handler(int irq, void *context, void *arg)
+{
+  struct stm32_lptim_oneshot_s *priv = arg;
+
+  STM32_LPTIM_ACKINT(priv->lptim, LPTIM_ISR_ARRM);
+  stm32_lptim_os_halt(priv);
+  oneshot_process_callback(&priv->lh);
+  return OK;
+}
+
+static int stm32_lptim_os_max_delay(struct oneshot_lowerhalf_s *lower,
+                                    struct timespec *ts)
+{
+  struct stm32_lptim_oneshot_s *priv = (struct stm32_lptim_oneshot_s *)lower;
+  uint64_t usec = (uint64_t)LPTIM_COUNT_MAX * 1000000 / priv->fmin;
+
+  ts->tv_sec  = usec / 1000000;
+  ts->tv_nsec = (usec % 1000000) * 1000;
+  return OK;
+}
+
+static int stm32_lptim_os_start(struct oneshot_lowerhalf_s *lower,
+                                const struct timespec *ts)
+{
+  struct stm32_lptim_oneshot_s *priv = (struct stm32_lptim_oneshot_s *)lower;
+  irqstate_t flags;
+  uint64_t usec;
+  uint64_t freq;
+  uint64_t count;
+  int ret;
+
+  /* Express the delay in microseconds */
+
+  usec = (uint64_t)ts->tv_sec * 1000000 + ts->tv_nsec / 1000;
+
+  /* The delay must fit in the counter at the slowest counter clock */
+
+  if (usec > (uint64_t)LPTIM_COUNT_MAX * 1000000 / priv->fmin)
+    {
+      tmrerr("ERROR: delay too long for the timer\n");
+      return -ERANGE;
+    }
+
+  flags = enter_critical_section();
+
+  if (priv->running)
+    {
+      stm32_lptim_os_halt(priv);
+    }
+
+  /* The highest counter clock, set by the prescaler, that fits the delay
+   * into the 16-bit counter.
+   */
+
+  freq = usec > 0 ? (uint64_t)LPTIM_COUNT_MAX * 1000000 / usec : UINT32_MAX;
+  if (freq > UINT32_MAX)
+    {
+      freq = UINT32_MAX;
+    }
+
+  ret = STM32_LPTIM_SETCLOCK(priv->lptim, (uint32_t)freq);
+  if (ret <= 0)
+    {
+      leave_critical_section(flags);
+      return ret < 0 ? ret : -EINVAL;
+    }
+
+  count = usec * ret / 1000000;
+  if (count < LPTIM_COUNT_MIN)
+    {
+      count = LPTIM_COUNT_MIN;
+    }
+
+  priv->freq  = ret;
+  priv->count = count;
+
+  STM32_LPTIM_SETISR(priv->lptim, stm32_lptim_os_handler, priv, 0);
+  STM32_LPTIM_ACKINT(priv->lptim, LPTIM_ISR_ARRM);
+  STM32_LPTIM_ENABLEINT(priv->lptim, LPTIM_ISR_ARRM);
+
+  STM32_LPTIM_ENABLE(priv->lptim, true);
+  STM32_LPTIM_SETPERIOD(priv->lptim, count);
+  STM32_LPTIM_START(priv->lptim, STM32_LPTIM_MODE_SINGLE);
+  priv->running = true;
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+static int stm32_lptim_os_cancel(struct oneshot_lowerhalf_s *lower,
+                                 struct timespec *ts)
+{
+  struct stm32_lptim_oneshot_s *priv = (struct stm32_lptim_oneshot_s *)lower;
+  irqstate_t flags;
+  uint64_t usec = 0;
+  uint32_t cnt;
+
+  flags = enter_critical_section();
+
+  if (priv->running)
+    {
+      cnt = STM32_LPTIM_GETCOUNTER(priv->lptim);
+      if (cnt < priv->count)
+        {
+          usec = (uint64_t)(priv->count - cnt) * 1000000 / priv->freq;
+        }
+
+      stm32_lptim_os_halt(priv);
+    }
+
+  leave_critical_section(flags);
+
+  if (ts != NULL)
+    {
+      ts->tv_sec  = usec / 1000000;
+      ts->tv_nsec = (usec % 1000000) * 1000;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_lptim_oneshot_initialize
+ *
+ * Description:
+ *   Initialize LPTIMn as a oneshot timer lower-half.  The counter runs on
+ *   the LPTIM kernel clock, STM32_LPTIMn_CLKIN in board.h.
+ *
+ * Input Parameters:
+ *   lptim - The LPTIM instance number
+ *
+ * Returned Value:
+ *   The oneshot lower-half on success, NULL on failure.
+ *
+ ****************************************************************************/
+
+struct oneshot_lowerhalf_s *stm32_lptim_oneshot_initialize(int lptim)
+{
+  struct stm32_lptim_oneshot_s *priv;
+  int ret;
+
+  priv = kmm_zalloc(sizeof(struct stm32_lptim_oneshot_s));
+  if (priv == NULL)
+    {
+      return NULL;
+    }
+
+  priv->lptim = stm32_lptim_init(lptim);
+  if (priv->lptim == NULL)
+    {
+      kmm_free(priv);
+      return NULL;
+    }
+
+  /* The slowest counter clock gives the longest delay */
+
+  ret = STM32_LPTIM_SETCLOCK(priv->lptim, 1);
+  if (ret <= 0)
+    {
+      tmrerr("ERROR: LPTIM%d kernel clock unknown\n", lptim);
+      stm32_lptim_deinit(priv->lptim);
+      kmm_free(priv);
+      return NULL;
+    }
+
+  priv->fmin   = ret;
+  priv->lh.ops = &g_lptim_oneshot_ops;
+  return &priv->lh;
+}
+
+#endif /* CONFIG_ONESHOT && CONFIG_STM32_LPTIM */

Reply via email to