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

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

commit 4821abc3e76e29884a89b66bd89abf1fb6486652
Author: raiden00pl <[email protected]>
AuthorDate: Sat Oct 10 15:02:34 2026 +0200

    arch/arm/src/common/stm32: limit one-shot delays to the timer width
    
    stm32_oneshot_max_delay() assumed a 32-bit counter and
    stm32_oneshot_start() only checked the period against UINT32_MAX, so on
    a 16-bit timer a longer delay was silently truncated to the low 16 bits
    of the period and the one-shot fired early.
    
    Compute the maximum delay from the timer counter width and return
    -ERANGE from stm32_oneshot_start() when the requested delay does not
    fit.
    
    Signed-off-by: raiden00pl <[email protected]>
    Assisted-by: Claude Code
---
 arch/arm/src/common/stm32/stm32_oneshot.c | 45 ++++++++++++++++++-------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/arch/arm/src/common/stm32/stm32_oneshot.c 
b/arch/arm/src/common/stm32/stm32_oneshot.c
index fa11cb6e246..d1969c0f2d9 100644
--- a/arch/arm/src/common/stm32/stm32_oneshot.c
+++ b/arch/arm/src/common/stm32/stm32_oneshot.c
@@ -226,8 +226,8 @@ int stm32_oneshot_max_delay(struct stm32_oneshot_s 
*oneshot, uint64_t *usec)
 {
   DEBUGASSERT(oneshot != NULL && usec != NULL);
 
-  *usec = (uint64_t)(UINT32_MAX / oneshot->frequency) *
-          (uint64_t)USEC_PER_SEC;
+  *usec = ((((uint64_t)1 << STM32_TIM_GETWIDTH(oneshot->tch)) - 1) *
+           USEC_PER_SEC) / oneshot->frequency;
   return OK;
 }
 
@@ -264,22 +264,6 @@ int stm32_oneshot_start(struct stm32_oneshot_s *oneshot,
   DEBUGASSERT(oneshot && handler && ts);
   DEBUGASSERT(oneshot->tch);
 
-  /* Was the oneshot already running? */
-
-  flags = enter_critical_section();
-  if (oneshot->running)
-    {
-      /* Yes.. then cancel it */
-
-      tmrinfo("Already running... cancelling\n");
-      stm32_oneshot_cancel(oneshot, NULL);
-    }
-
-  /* Save the new handler and its argument */
-
-  oneshot->handler = handler;
-  oneshot->arg     = arg;
-
   /* Express the delay in microseconds */
 
   usec = ts->tv_sec * USEC_PER_SEC +
@@ -296,7 +280,30 @@ int stm32_oneshot_start(struct stm32_oneshot_s *oneshot,
   period = (usec * (uint64_t)oneshot->frequency) / USEC_PER_SEC;
 
   tmrinfo("usec=%llu period=%08llx\n", usec, period);
-  DEBUGASSERT(period <= UINT32_MAX);
+
+  /* The period must fit in the timer counter */
+
+  if (period > ((uint64_t)1 << STM32_TIM_GETWIDTH(oneshot->tch)) - 1)
+    {
+      tmrerr("ERROR: delay too long for the timer\n");
+      return -ERANGE;
+    }
+
+  /* Was the oneshot already running? */
+
+  flags = enter_critical_section();
+  if (oneshot->running)
+    {
+      /* Yes.. then cancel it */
+
+      tmrinfo("Already running... cancelling\n");
+      stm32_oneshot_cancel(oneshot, NULL);
+    }
+
+  /* Save the new handler and its argument */
+
+  oneshot->handler = handler;
+  oneshot->arg     = arg;
 
   /* Set up to receive the callback when the interrupt occurs */
 

Reply via email to