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 */
