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 6b71f53b3c30abb58ec238d3f44c6a9238348d7c
Author: Max Kriegleder <[email protected]>
AuthorDate: Sat Oct 24 19:02:49 2026 +0200

    arch/arm/nrf52: Count a pending RTC overflow when reading the time.
    
    The time is periods * 512 s plus the COUNTER. An overflow is counted in
    'periods' by the RTC interrupt, so a time read with interrupts disabled
    between the COUNTER wrapping and that interrupt running came out 512 s
    early: up_timer_gettime() from a critical section or a higher-priority
    handler, and rtc_prepare_alarm() from up_alarm_start(). up_alarm_cancel()
    also read the COUNTER inside its critical section but converted it after
    leaving it, so the interrupt could count the overflow in between and the
    time came out 512 s late.
    
    Read the time in one place, rtc_now(), always with interrupts disabled.
    While the overflow has not been counted its OVRFLW event is still set;
    a COUNTER in its lower half was then read after the overflow, and one in
    its upper half before it.
    
    Checked on the host against a modelled COUNTER and OVRFLW event: read
    just after an overflow whose interrupt has not run, the time was 512 s
    behind before and is right now; reads before the overflow and after its
    interrupt are unchanged.
    
    Assisted-by: Claude:claude-opus-5-5
    Signed-off-by: Max Kriegleder <[email protected]>
---
 arch/arm/src/nrf52/nrf52_tickless_rtc.c | 36 ++++++++++++++++++++-------------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/arch/arm/src/nrf52/nrf52_tickless_rtc.c 
b/arch/arm/src/nrf52/nrf52_tickless_rtc.c
index e716a30cf8d..91a750ac4bc 100644
--- a/arch/arm/src/nrf52/nrf52_tickless_rtc.c
+++ b/arch/arm/src/nrf52/nrf52_tickless_rtc.c
@@ -104,15 +104,31 @@ struct nrf52_tickless_dev_s g_tickless_dev;
  * Private Functions
  ****************************************************************************/
 
-static inline void rtc_counter_to_ts(uint32_t counter, struct timespec *now)
+/* Read the COUNTER and the absolute time it stands for.  Called with
+ * interrupts disabled, so an overflow may not have been counted in
+ * 'periods' yet: its OVRFLW event is then still set.  A COUNTER in its
+ * lower half was read after that overflow, one in its upper half before.
+ */
+
+static uint32_t rtc_now(struct timespec *now)
 {
+  const uint32_t rtc_base = NRF52_RTC_GETBASE(g_tickless_dev.rtc);
+  uint32_t periods = g_tickless_dev.periods;
+  uint32_t counter;
   uint32_t usec;
 
+  counter = NRF52_RTC_GETCOUNTER_REG(rtc_base);
+  if (getreg32(rtc_base + NRF52_RTC_EVENTS_OVRFLW_OFFSET) != 0 &&
+      counter <= RTC_COUNTER_MASK / 2)
+    {
+      periods++;
+    }
+
   usec = COUNTER_TO_USEC(counter);
-  now->tv_sec  = usec / USEC_PER_SEC;
+  now->tv_sec  = usec / USEC_PER_SEC + periods * NRF52_RTC_PERIOD;
   now->tv_nsec = (usec % USEC_PER_SEC) * NSEC_PER_USEC;
 
-  now->tv_sec += g_tickless_dev.periods * NRF52_RTC_PERIOD;
+  return counter;
 }
 
 /* Convert a time shorter than one RTC period to counts, rounding up so
@@ -138,8 +154,7 @@ static void rtc_prepare_alarm(void)
 
   /* Time left until the alarm, zero if it has passed */
 
-  counter = NRF52_RTC_GETCOUNTER_REG(rtc_base);
-  rtc_counter_to_ts(counter, &now);
+  counter = rtc_now(&now);
   clock_timespec_subtract(&g_tickless_dev.alarm, &now, &delta);
 
   /* An alarm further away is prepared again on a later overflow */
@@ -257,21 +272,18 @@ static int rtc_handler(int irq, void *context, void *arg)
 
 int up_alarm_cancel(struct timespec *ts)
 {
-  uint32_t counter;
   irqstate_t flags;
 
   flags = enter_critical_section();
 
   NRF52_RTC_DISABLEINT(g_tickless_dev.rtc, NRF52_RTC_EVT_COMPARE0);
-  NRF52_RTC_GETCOUNTER(g_tickless_dev.rtc, &counter);
+  rtc_now(ts);
 
   NRF52_RTC_ACKINT(g_tickless_dev.rtc, NRF52_RTC_EVT_COMPARE0);
   g_tickless_dev.alarm_set = false;
 
   leave_critical_section(flags);
 
-  rtc_counter_to_ts(counter, ts);
-
   return OK;
 }
 
@@ -303,14 +315,10 @@ int up_alarm_start(const struct timespec *ts)
 
 int up_timer_gettime(struct timespec *ts)
 {
-  uint32_t counter;
   irqstate_t flags;
 
   flags = enter_critical_section();
-
-  NRF52_RTC_GETCOUNTER(g_tickless_dev.rtc, &counter);
-  rtc_counter_to_ts(counter, ts);
-
+  rtc_now(ts);
   leave_critical_section(flags);
 
   return OK;

Reply via email to