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 8fdc815796b534404b5e56390a853a1274101f0e
Author: raiden00pl <[email protected]>
AuthorDate: Thu Oct 22 16:15:30 2026 +0200

    arch/arm/nrf52,nrf53: time the superframe from the RTC counter
    
    The RTC was restarted from the beacon compare match, so the superframe
    drifted by the interrupt latency, the beacon interval was twice the one
    of the beacon order, the CAP end ignored the superframe order and a
    device synchronized once to any beacon and never again.  Keep a 64-bit
    RTC time base, schedule the beacon TX and the end of the active portion
    from the superframe start, and synchronize a tracking device to every
    beacon of its coordinator from the SHR start (IEEE 802.15.4-2003
    7.5.1.1, 7.5.4.1).
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <[email protected]>
---
 arch/arm/src/nrf52/nrf52_ieee802154.c       |  48 +--
 arch/arm/src/nrf52/nrf52_ieee802154_radio.c |  69 ++++-
 arch/arm/src/nrf52/nrf52_ieee802154_radio.h |  17 +-
 arch/arm/src/nrf52/nrf52_ieee802154_rtc.c   | 451 ++++++++++++++++++++--------
 arch/arm/src/nrf52/nrf52_ieee802154_rtc.h   |  46 ++-
 arch/arm/src/nrf52/nrf52_ieee802154_trace.c |   3 +-
 arch/arm/src/nrf52/nrf52_ieee802154_trace.h |   3 +-
 arch/arm/src/nrf53/Kconfig                  |   5 +
 arch/arm/src/nrf53/nrf53_ieee802154.c       |  48 +--
 arch/arm/src/nrf53/nrf53_ieee802154_radio.c |  69 ++++-
 arch/arm/src/nrf53/nrf53_ieee802154_radio.h |  17 +-
 arch/arm/src/nrf53/nrf53_ieee802154_rtc.c   | 451 ++++++++++++++++++++--------
 arch/arm/src/nrf53/nrf53_ieee802154_rtc.h   |  46 ++-
 arch/arm/src/nrf53/nrf53_ieee802154_trace.c |   3 +-
 arch/arm/src/nrf53/nrf53_ieee802154_trace.h |   3 +-
 15 files changed, 929 insertions(+), 350 deletions(-)

diff --git a/arch/arm/src/nrf52/nrf52_ieee802154.c 
b/arch/arm/src/nrf52/nrf52_ieee802154.c
index 8bc19f07195..3089c5046b0 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154.c
@@ -729,6 +729,7 @@ nrf52_radioi8_beaconstart(struct ieee802154_radio_s *radio,
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
   struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
   irqstate_t                  flags;
+  int                         ret;
 
   if (sfspec->pancoord)
     {
@@ -739,18 +740,22 @@ nrf52_radioi8_beaconstart(struct ieee802154_radio_s 
*radio,
       memcpy(&dev->state.sf, (void *)sfspec,
              sizeof(struct ieee802154_superframespec_s));
 
-      /* Setup beacon transmission, macBSN starts from a random value */
+      /* Configure the superframe timings */
 
-      dev->radio->ops->beacon_setup(dev, beacon->bf_data, beacon->bf_len);
-      dev->radio->state.bsn = rand();
-
-      /* Configure RTC events */
+      ret = dev->rtc->ops->setup(dev, &dev->state.sf);
+      if (ret == OK)
+        {
+          /* Setup beacon transmission, macBSN starts from a random value */
 
-      dev->rtc->ops->setup(dev, &dev->state.sf);
+          dev->radio->ops->beacon_setup(dev, beacon->bf_data,
+                                        beacon->bf_len);
+          dev->radio->state.bsn = rand();
 
-      /* Start RTC */
+          /* The PAN coordinator defines the superframe */
 
-      dev->rtc->ops->start(dev);
+          dev->radio->state.sftrack = false;
+          dev->rtc->ops->start(dev);
+        }
 
       leave_critical_section(flags);
     }
@@ -758,10 +763,10 @@ nrf52_radioi8_beaconstart(struct ieee802154_radio_s 
*radio,
     {
       /* TODO: missing logic for non-PAN coord */
 
-      return -ENOTTY;
+      ret = -ENOTTY;
     }
 
-  return OK;
+  return ret;
 #else
   return -ENOTSUP;
 #endif
@@ -847,6 +852,7 @@ nrf52_radioi8_sfupdate(struct ieee802154_radio_s *radio,
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
   struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
   irqstate_t                  flags;
+  int                         ret = OK;
 
   flags = enter_critical_section();
 
@@ -859,28 +865,32 @@ nrf52_radioi8_sfupdate(struct ieee802154_radio_s *radio,
 
   if (sfspec->beaconorder < 15)
     {
-      /* Need slotted CSMA-CA */
-
-      dev->radio->state.slotted = true;
+      /* Configure the superframe timings */
 
-      /* Configure RTC */
+      ret = dev->rtc->ops->setup(dev, &dev->state.sf);
+      if (ret == OK)
+        {
+          /* Need slotted CSMA-CA */
 
-      dev->rtc->ops->setup(dev, &dev->state.sf);
+          dev->radio->state.slotted = true;
 
-      /* Wait for beacon to sync */
+          /* Sync with the beacons */
 
-      dev->radio->state.wait_for_beacon = true;
+          dev->radio->state.sftrack = true;
+        }
     }
   else
     {
       /* Need un-slotted CSMA-CA */
 
+      dev->rtc->ops->stop(dev);
       dev->radio->state.slotted = false;
+      dev->radio->state.sftrack = false;
     }
 
   leave_critical_section(flags);
 
-  return OK;
+  return ret;
 #else
   return -ENOTSUP;
 #endif
@@ -962,8 +972,10 @@ nrf52_radioi8_register(struct nrf52_radio_board_s *board)
 
   DEBUGASSERT(dev->rtc->ops->setup);
   DEBUGASSERT(dev->rtc->ops->start);
+  DEBUGASSERT(dev->rtc->ops->sync);
   DEBUGASSERT(dev->rtc->ops->stop);
   DEBUGASSERT(dev->rtc->ops->reset);
+  DEBUGASSERT(dev->rtc->ops->elapsed);
 #endif
 
   /* Connect MAC ops */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c 
b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
index 7f269eaa146..a2c88dbb6f9 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
@@ -168,6 +168,9 @@ static void nrf52_radioi8_rx_parse(struct 
nrf52_radioi8_dev_s *dev,
                                    uint8_t *ftype, uint8_t *cmdtype);
 static void nrf52_radioi8_ack_transmit(struct nrf52_radioi8_dev_s *dev);
 static bool nrf52_radioi8_filter(struct nrf52_radioi8_dev_s *dev);
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+static bool nrf52_radioi8_coordbeacon(struct nrf52_radioi8_dev_s *dev);
+#endif
 #if NRF52_GTS_SLOTS > 0
 static void nrf52_radioi8_gts_setup(struct nrf52_radioi8_dev_s *dev,
                                     uint8_t fifo, struct iob_s *frame);
@@ -559,6 +562,52 @@ static bool nrf52_radioi8_filter(struct 
nrf52_radioi8_dev_s *dev)
   return false;
 }
 
+#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
+/****************************************************************************
+ * Name: nrf52_radioi8_coordbeacon
+ *
+ * Description:
+ *   The received frame is a beacon of our coordinator (IEEE 802.15.4-2003
+ *   7.5.4.1).
+ *
+ ****************************************************************************/
+
+static bool nrf52_radioi8_coordbeacon(struct nrf52_radioi8_dev_s *dev)
+{
+  uint8_t *rx = &dev->radio->rxbuf[1];
+  uint8_t  eaddr[IEEE802154_EADDRSIZE];
+  uint8_t  mode;
+  int      i;
+
+  if ((rx[0] & IEEE802154_FRAMECTRL_FTYPE) != IEEE802154_FRAME_BEACON ||
+      !IEEE802154_PANIDCMP(&rx[3], dev->state.addr.panid))
+    {
+      return false;
+    }
+
+  mode = ((rx[1] << 8) & IEEE802154_FRAMECTRL_SADDR) >>
+         IEEE802154_FRAMECTRL_SHIFT_SADDR;
+
+  if (mode == IEEE802154_ADDRMODE_SHORT)
+    {
+      return IEEE802154_SADDRCMP(&rx[5], dev->state.coordaddr.saddr);
+    }
+  else if (mode == IEEE802154_ADDRMODE_EXTENDED)
+    {
+      /* Sent least significant octet first */
+
+      for (i = 0; i < IEEE802154_EADDRSIZE; i++)
+        {
+          eaddr[i] = rx[5 + IEEE802154_EADDRSIZE - 1 - i];
+        }
+
+      return IEEE802154_EADDRCMP(eaddr, dev->state.coordaddr.eaddr);
+    }
+
+  return false;
+}
+#endif
+
 #if NRF52_GTS_SLOTS > 0
 /****************************************************************************
  * Name: nrf52_radioi8_gts_setup
@@ -1892,24 +1941,12 @@ static void nrf52_radioi8_state_rx(struct 
nrf52_radioi8_dev_s *dev)
     }
 
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
-  /* TODO: resync with beacon ? */
+  /* The superframe started with the SHR of the coordinator beacon */
 
-  if (dev->radio->state.wait_for_beacon == true)
+  if (dev->radio->state.sftrack && dev->radio->state.waitack == false &&
+      nrf52_radioi8_coordbeacon(dev))
     {
-      uint16_t *fc = (uint16_t *)&rxbuf[0];
-
-      /* TODO: NOT TESTES, should we check panid here ? */
-
-      if (((*fc & IEEE802154_FRAMECTRL_FTYPE) == IEEE802154_FRAME_BEACON) &&
-          IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC,
-                              &dev->state.addr.panid))
-        {
-          /* Start RTC */
-
-          dev->rtc->ops->start(dev);
-
-          dev->radio->state.wait_for_beacon = false;
-        }
+      dev->rtc->ops->sync(dev, rxbuf[0]);
     }
 #endif
 
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.h 
b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
index 188ae4c2fda..359bfaf43f8 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
@@ -56,6 +56,21 @@
                                        IEEE802154_TURN_AROUND_TIME +    \
                                        10 + 12)
 
+/* RADIO ramp-up time in fast ramp-up mode */
+
+#define NRF52_RADIOI8_RAMPUP_US       (40)
+
+/* Air time of a frame with the given PHR: SHR, PHR and PSDU, 32 us/octet */
+
+#define NRF52_RADIOI8_FRAME_US(phr)   (((phr) + 6) * 2 * IEEE802154_SYMBOL_US)
+
+/* IFS after a frame with the given PHR */
+
+#define NRF52_RADIOI8_IFS_US(phr)                       \
+  (((phr) > IEEE802154_MAX_SIFS_FRAME_SIZE ?            \
+    IEEE802154_LIFS_SYMBOLS : IEEE802154_SIFS_SYMBOLS) * \
+   IEEE802154_SYMBOL_US)
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -112,7 +127,7 @@ struct nrf52_radioi8_radio_data_s
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
   /* Superframe data */
 
-  bool    wait_for_beacon;      /* Device wait for beacon */
+  bool    sftrack;              /* Device tracks the beacons */
   bool    ble;                  /* Batter life extension */
   bool    beacon_pending;       /* A beacon waits for the radio */
   uint8_t bsn;                  /* macBSN, the beacon sequence number */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c 
b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c
index 6cdce657422..c04fe379385 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.c
@@ -44,10 +44,6 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
-#  warning Beacon and superframe support work in progress
-#endif
-
 #ifndef CONFIG_NRF52_RTC0
 #  error CONFIG_NRF52_RTC0 is needed to handle radio timings
 #endif
@@ -56,16 +52,27 @@
 
 #define NRF52_IEEE802154_RTC0   (0)
 
-/* RTC prescaler set to 0, freq = 32.768kHz, resolution = 30.517 us */
+/* RTC prescaler set to 0, freq = 32.768kHz, 1 tick = 15625 / 512 us */
 
 #define NRF52_RTC_PRESCALER     (0)
-#define NRF52_RTC_FREQUENCY     (32768)
+#define NRF52_RTC_TICK_NUM      (15625)
+#define NRF52_RTC_TICK_DEN      (512)
+
+/* 24-bit counter */
 
-#define NRF52_RTC_RESOLUTION_NS (30517)
+#define NRF52_RTC_COUNTER_BITS  (24)
+#define NRF52_RTC_COUNTER_MASK  ((1 << NRF52_RTC_COUNTER_BITS) - 1)
 
-/* 31 * 30.517us = 946.027us */
+/* A compare value closer than 2 ticks to the counter may not match */
 
-#define NRF52_RTC_TIMESLOT_CC   (31)
+#define NRF52_RTC_CC_MARGIN     (2)
+#define NRF52_RTC_CC_MARGIN_US  ((NRF52_RTC_CC_MARGIN * NRF52_RTC_TICK_NUM + \
+                                  NRF52_RTC_TICK_DEN - 1) / NRF52_RTC_TICK_DEN)
+
+/* Superframe events compare channel */
+
+#define NRF52_RTC_CC            (NRF52_RTC_CC0)
+#define NRF52_RTC_EVT           (NRF52_RTC_EVT_COMPARE0)
 
 /****************************************************************************
  * Private Function Prototypes
@@ -76,8 +83,12 @@
 static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev,
                              struct ieee802154_superframespec_s *sfspec);
 static int nrf52_radioi8_rtc_start(struct nrf52_radioi8_dev_s *dev);
+static int nrf52_radioi8_rtc_sync(struct nrf52_radioi8_dev_s *dev,
+                                  uint8_t phr);
 static int nrf52_radioi8_rtc_stop(struct nrf52_radioi8_dev_s *dev);
 static void nrf52_radioi8_rtc_reset(struct nrf52_radioi8_dev_s *dev);
+static bool nrf52_radioi8_rtc_elapsed(struct nrf52_radioi8_dev_s *dev,
+                                      uint32_t *us);
 
 /* Interrupts logic */
 
@@ -92,10 +103,12 @@ static int nrf52_radioi8_isr_rtc(int irq, void *context, 
void *arg);
 
 static struct nrf52_radioi8_rtc_ops_s g_radioi8_rtc_ops =
 {
-  .setup = nrf52_radioi8_rtc,
-  .start = nrf52_radioi8_rtc_start,
-  .stop  = nrf52_radioi8_rtc_stop,
-  .reset = nrf52_radioi8_rtc_reset
+  .setup   = nrf52_radioi8_rtc,
+  .start   = nrf52_radioi8_rtc_start,
+  .sync    = nrf52_radioi8_rtc_sync,
+  .stop    = nrf52_radioi8_rtc_stop,
+  .reset   = nrf52_radioi8_rtc_reset,
+  .elapsed = nrf52_radioi8_rtc_elapsed
 };
 
 /* RTC instance */
@@ -107,69 +120,171 @@ static struct nrf52_radioi8_rtc_s g_radioi8_rtc;
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf52_radioi8_rtc
+ * Name: nrf52_radioi8_rtc_ticks
  *
  * Description:
- *   Configure RTC events according to superframe spec.
+ *   Get the 64-bit RTC counter.  Must be called with the radio locked.
  *
  ****************************************************************************/
 
-static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev,
-                             struct ieee802154_superframespec_s *sfspec)
+static uint64_t nrf52_radioi8_rtc_ticks(struct nrf52_radioi8_rtc_s *rtc)
 {
-  uint32_t   bi     = 0;
-  uint32_t   sd     = 0;
-  uint32_t   cap    = 0;
-  irqstate_t flags;
+  uint32_t ovf = rtc->ovf;
+  uint32_t cnt = 0;
 
-  flags = enter_critical_section();
+  NRF52_RTC_GETCOUNTER(rtc->rtc, &cnt);
+
+  /* Overflow not handled yet */
+
+  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_EVT_OVRFLW))
+    {
+      NRF52_RTC_GETCOUNTER(rtc->rtc, &cnt);
+      ovf += 1;
+    }
+
+  return ((uint64_t)ovf << NRF52_RTC_COUNTER_BITS) | cnt;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_now
+ *
+ * Description:
+ *   Get the current time in us.  Must be called with the radio locked.
+ *
+ ****************************************************************************/
+
+static uint64_t nrf52_radioi8_rtc_now(struct nrf52_radioi8_rtc_s *rtc)
+{
+  return nrf52_radioi8_rtc_ticks(rtc) * NRF52_RTC_TICK_NUM /
+         NRF52_RTC_TICK_DEN;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_alarm
+ *
+ * Description:
+ *   Schedule a superframe event.  The compare value matches on every
+ *   counter wrap, the interrupt handler ignores the matches before the
+ *   event time.  Must be called with the radio locked.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_rtc_alarm(struct nrf52_radioi8_rtc_s *rtc,
+                                    uint8_t evt, uint64_t time)
+{
+  uint64_t ticks = time * NRF52_RTC_TICK_DEN / NRF52_RTC_TICK_NUM;
+  uint64_t now   = nrf52_radioi8_rtc_ticks(rtc);
+
+  if (ticks < now + NRF52_RTC_CC_MARGIN)
+    {
+      ticks = now + NRF52_RTC_CC_MARGIN;
+    }
+
+  rtc->evt      = evt;
+  rtc->evt_time = time;
+
+  NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_EVT);
+  NRF52_RTC_SETCC(rtc->rtc, NRF52_RTC_CC, ticks & NRF52_RTC_COUNTER_MASK);
+  NRF52_RTC_ENABLEEVT(rtc->rtc, NRF52_RTC_EVT);
+  NRF52_RTC_ENABLEINT(rtc->rtc, NRF52_RTC_EVT);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_cancel
+ *
+ * Description:
+ *   Cancel the scheduled superframe event.  Must be called with the radio
+ *   locked.
+ *
+ ****************************************************************************/
 
-  /* Stop RTC and clear the counter */
+static void nrf52_radioi8_rtc_cancel(struct nrf52_radioi8_rtc_s *rtc)
+{
+  NRF52_RTC_DISABLEINT(rtc->rtc, NRF52_RTC_EVT);
+  NRF52_RTC_DISABLEEVT(rtc->rtc, NRF52_RTC_EVT);
+  NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_EVT);
 
-  NRF52_RTC_STOP(dev->rtc->rtc);
-  NRF52_RTC_CLEAR(dev->rtc->rtc);
+  rtc->evt = NRF52_SFEVT_NONE;
+}
 
-  /* Initialize BI counter */
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_next
+ *
+ * Description:
+ *   Schedule the next superframe event after the superframe start.  Must
+ *   be called with the radio locked.
+ *
+ ****************************************************************************/
 
-  bi = ((IEEE802154_BASE_SUPERFRAME_DURATION *
-        (2 << sfspec->beaconorder) *
-         IEEE802154_SYMBOL_US * 1000)  /
-        NRF52_RTC_RESOLUTION_NS);
-  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_BI, bi);
+static void nrf52_radioi8_rtc_next(struct nrf52_radioi8_dev_s *dev)
+{
+  struct nrf52_radioi8_rtc_s *rtc = dev->rtc;
 
-  /* Initialize SD counter */
+  if (rtc->sd < rtc->bi)
+    {
+      nrf52_radioi8_rtc_alarm(rtc, NRF52_SFEVT_SDEND,
+                              rtc->sf_start + rtc->sd);
+    }
+  else
+    {
+      /* No inactive portion, the MAC updates the beacon from now */
 
-  sd = ((IEEE802154_BASE_SUPERFRAME_DURATION *
-         (2 << sfspec->sforder) *
-         IEEE802154_SYMBOL_US * 1000) /
-        NRF52_RTC_RESOLUTION_NS);
-  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_SD, sd);
+      if (work_available(&dev->rtc->inactive_work))
+        {
+          work_queue(HPWORK, &dev->rtc->inactive_work,
+                     nrf52_radioi8_work_inactive, dev, 0);
+        }
 
-  /* Initialize CAP counter */
+      nrf52_radioi8_rtc_alarm(rtc, NRF52_SFEVT_START,
+                              rtc->sf_start + rtc->bi -
+                              NRF52_RADIOI8_RAMPUP_US);
+    }
+}
 
-  cap = ((sfspec->final_capslot *
-          IEEE802154_TIMESLOT_US * 1000) /
-         NRF52_RTC_RESOLUTION_NS);
-  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_CAP, cap);
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc
+ *
+ * Description:
+ *   Configure the superframe timings according to superframe spec.
+ *
+ ****************************************************************************/
 
-  /* Initialize timeslot counter */
+static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s *dev,
+                             struct ieee802154_superframespec_s *sfspec)
+{
+  struct nrf52_radioi8_rtc_s *rtc = dev->rtc;
+  uint32_t                    slot;
+  irqstate_t                  flags;
 
-  dev->rtc->rtc_timeslot = NRF52_RTC_TIMESLOT_CC;
-  NRF52_RTC_SETCC(dev->rtc->rtc, NRF52_RTC_TIMESLOT, dev->rtc->rtc_timeslot);
+  if (sfspec->beaconorder > 14 ||
+      (sfspec->sforder > sfspec->beaconorder && sfspec->sforder != 15))
+    {
+      return -EINVAL;
+    }
 
-  /* Configure interrupts */
+  flags = enter_critical_section();
 
-  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_BI);
-  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_SD);
-  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_CAP);
-  NRF52_RTC_ENABLEINT(dev->rtc->rtc, NRF52_RTC_TIMESLOT);
+  /* BI = aBaseSuperframeDuration * 2^BO, SD = aBaseSuperframeDuration *
+   * 2^SO, the CAP ends with the final CAP slot (IEEE 802.15.4-2003 7.5.1.1)
+   */
 
-  /* Configure events */
+  rtc->bi = (IEEE802154_BASE_SUPERFRAME_DURATION * IEEE802154_SYMBOL_US) <<
+            sfspec->beaconorder;
 
-  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_BI);
-  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_SD);
-  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_CAP);
-  NRF52_RTC_ENABLEEVT(dev->rtc->rtc, NRF52_RTC_TIMESLOT);
+  if (sfspec->sforder == 15)
+    {
+      /* The superframe is not active after the beacon */
+
+      rtc->sd  = 0;
+      rtc->cap = 0;
+    }
+  else
+    {
+      slot     = (IEEE802154_BASE_SLOT_DURATION * IEEE802154_SYMBOL_US) <<
+                 sfspec->sforder;
+      rtc->sd  = slot * IEEE802154_NUM_SUPERFRAME_SLOTS;
+      rtc->cap = slot * (sfspec->final_capslot + 1);
+    }
 
   leave_critical_section(flags);
 
@@ -180,13 +295,54 @@ static int nrf52_radioi8_rtc(struct nrf52_radioi8_dev_s 
*dev,
  * Name: nrf52_radioi8_rtc_start
  *
  * Description:
- *   Start RTC.
+ *   Start transmitting beacons.
  *
  ****************************************************************************/
 
 static int nrf52_radioi8_rtc_start(struct nrf52_radioi8_dev_s *dev)
 {
-  NRF52_RTC_START(dev->rtc->rtc);
+  struct nrf52_radioi8_rtc_s *rtc = dev->rtc;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  rtc->sf_start = nrf52_radioi8_rtc_now(rtc) + NRF52_RTC_CC_MARGIN_US +
+                  NRF52_RADIOI8_RAMPUP_US;
+  rtc->running  = false;
+
+  nrf52_radioi8_rtc_alarm(rtc, NRF52_SFEVT_START,
+                          rtc->sf_start - NRF52_RADIOI8_RAMPUP_US);
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_sync
+ *
+ * Description:
+ *   Synchronize with the beacon just received, the superframe started
+ *   with its SHR.
+ *
+ ****************************************************************************/
+
+static int nrf52_radioi8_rtc_sync(struct nrf52_radioi8_dev_s *dev,
+                                  uint8_t phr)
+{
+  struct nrf52_radioi8_rtc_s *rtc = dev->rtc;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  nrf52_radioi8_trace_put(RADIO_TRACE_SFSYNC, phr);
+
+  rtc->sf_start = nrf52_radioi8_rtc_now(rtc) - NRF52_RADIOI8_FRAME_US(phr);
+  rtc->capstart = NRF52_RADIOI8_FRAME_US(phr) + NRF52_RADIOI8_IFS_US(phr);
+  rtc->running  = true;
+
+  leave_critical_section(flags);
+
   return OK;
 }
 
@@ -194,13 +350,21 @@ static int nrf52_radioi8_rtc_start(struct 
nrf52_radioi8_dev_s *dev)
  * Name: nrf52_radioi8_rtc_stop
  *
  * Description:
- *   Stop RTC.
+ *   Stop the superframe.
  *
  ****************************************************************************/
 
 static int nrf52_radioi8_rtc_stop(struct nrf52_radioi8_dev_s *dev)
 {
-  NRF52_RTC_STOP(dev->rtc->rtc);
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  nrf52_radioi8_rtc_cancel(dev->rtc);
+  dev->rtc->running = false;
+
+  leave_critical_section(flags);
+
   return OK;
 }
 
@@ -208,20 +372,81 @@ static int nrf52_radioi8_rtc_stop(struct 
nrf52_radioi8_dev_s *dev)
  * Name: nrf52_radioi8_rtc_reset
  *
  * Description:
- *   Reset RTC.
+ *   Reset RTC, the counter runs from now on.
  *
  ****************************************************************************/
 
 static void nrf52_radioi8_rtc_reset(struct nrf52_radioi8_dev_s *dev)
 {
+  struct nrf52_radioi8_rtc_s *rtc = dev->rtc;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
   /* Configure RTC - freq = 32.768 kHz */
 
-  NRF52_RTC_STOP(dev->rtc->rtc);
-  NRF52_RTC_SETPRE(dev->rtc->rtc, NRF52_RTC_PRESCALER);
+  nrf52_radioi8_rtc_cancel(rtc);
+  NRF52_RTC_STOP(rtc->rtc);
+  NRF52_RTC_CLEAR(rtc->rtc);
+  NRF52_RTC_SETPRE(rtc->rtc, NRF52_RTC_PRESCALER);
+
+  /* Count overflows */
+
+  NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_EVT_OVRFLW);
+  NRF52_RTC_ENABLEEVT(rtc->rtc, NRF52_RTC_EVT_OVRFLW);
+  NRF52_RTC_ENABLEINT(rtc->rtc, NRF52_RTC_EVT_OVRFLW);
 
   /* Reset data */
 
-  dev->rtc->rtc_timeslot = 0;
+  rtc->ovf      = 0;
+  rtc->sf_start = 0;
+  rtc->running  = false;
+
+  NRF52_RTC_START(rtc->rtc);
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: nrf52_radioi8_rtc_elapsed
+ *
+ * Description:
+ *   Time in us since the superframe start.
+ *
+ ****************************************************************************/
+
+static bool nrf52_radioi8_rtc_elapsed(struct nrf52_radioi8_dev_s *dev,
+                                      uint32_t *us)
+{
+  struct nrf52_radioi8_rtc_s *rtc = dev->rtc;
+  uint64_t                    now;
+  irqstate_t                  flags;
+  bool                        ret = false;
+
+  flags = enter_critical_section();
+
+  if (rtc->running)
+    {
+      now = nrf52_radioi8_rtc_now(rtc);
+      if (now < rtc->sf_start)
+        {
+          *us = 0;
+        }
+      else if (now - rtc->sf_start > UINT32_MAX)
+        {
+          *us = UINT32_MAX;
+        }
+      else
+        {
+          *us = now - rtc->sf_start;
+        }
+
+      ret = true;
+    }
+
+  leave_critical_section(flags);
+
+  return ret;
 }
 
 /****************************************************************************
@@ -256,94 +481,72 @@ static int nrf52_radioi8_isr_rtc(int irq, void *context, 
void *arg)
   struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
   struct nrf52_radioi8_rtc_s *rtc = NULL;
   irqstate_t                  flags;
+  uint8_t                     evt;
 
   DEBUGASSERT(dev != NULL);
   rtc = dev->rtc;
 
   flags = enter_critical_section();
 
-  /* End of CAP */
-
-  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_CAP))
+  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_EVT_OVRFLW))
     {
-      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCCAP, 0);
-
-      /* TODO */
-
-      /* Clear event */
-
-      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_CAP);
+      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_EVT_OVRFLW);
+      rtc->ovf += 1;
     }
 
-  /* End of active portion */
-
-  else if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_SD))
+  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_EVT))
     {
-      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCSD, 0);
-
-      /* Schedule work */
+      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_EVT);
 
-      DEBUGASSERT(work_available(&dev->rtc->inactive_work));
-      work_queue(HPWORK, &dev->rtc->inactive_work,
-                 nrf52_radioi8_work_inactive, dev, 0);
+      /* A match before the event time is a counter wrap */
 
-      /* Reset timeslot */
-
-      rtc->rtc_timeslot = NRF52_RTC_TIMESLOT_CC;
-
-      /* Clear event */
-
-      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_SD);
-    }
-
-  /* Beacon interval */
-
-  else if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_BI))
-    {
-      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCBI, 0);
-
-      /* Transmit beacon if we are not endpoint */
-
-      if (dev->state.devmode != NRF52_DEVMODE_ENDPOINT)
+      evt = rtc->evt;
+      if (evt == NRF52_SFEVT_NONE ||
+          nrf52_radioi8_rtc_ticks(rtc) <
+          rtc->evt_time * NRF52_RTC_TICK_DEN / NRF52_RTC_TICK_NUM)
         {
-          /* Transmit data from beaconbuf */
-
-          dev->radio->ops->beacon_tx(dev);
+          goto out;
         }
 
-      /* Clear event */
+      rtc->evt = NRF52_SFEVT_NONE;
 
-      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_BI);
+      /* Superframe start */
 
-      /* Next cycle */
+      if (evt == NRF52_SFEVT_START)
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCBI, 0);
 
-      NRF52_RTC_TRGOVRFLW(rtc->rtc);
+          rtc->sf_start = rtc->evt_time + NRF52_RADIOI8_RAMPUP_US;
+          rtc->capstart = NRF52_RADIOI8_FRAME_US(dev->radio->beaconbuf[0]) +
+                          NRF52_RADIOI8_IFS_US(dev->radio->beaconbuf[0]);
+          rtc->running  = true;
 
-      /* TODO: resync with beacon ? */
-    }
-
-  /* Timeslot in active portion */
+          /* Transmit data from beaconbuf */
 
-  if (NRF52_RTC_CHECKINT(rtc->rtc, NRF52_RTC_TIMESLOT))
-    {
-      nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCTIMESLOT, 0);
+          dev->radio->ops->beacon_tx(dev);
 
-      /* TODO: how to sync transmission with timeslot ?
-       *       do we need count every timeslot here ?
-       *       or wait for the timeslot we are interested in ?
-       *       or just use txdelay ?
-       */
+          nrf52_radioi8_rtc_next(dev);
+        }
 
-      /* Update timeslot */
+      /* End of active portion */
 
-      rtc->rtc_timeslot += NRF52_RTC_TIMESLOT_CC;
-      NRF52_RTC_SETCC(rtc->rtc, NRF52_RTC_TIMESLOT, rtc->rtc_timeslot);
+      else if (evt == NRF52_SFEVT_SDEND)
+        {
+          nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_RTCSD, 0);
 
-      /* Clear event */
+          if (work_available(&dev->rtc->inactive_work))
+            {
+              work_queue(HPWORK, &dev->rtc->inactive_work,
+                         nrf52_radioi8_work_inactive, dev, 0);
+            }
 
-      NRF52_RTC_ACKINT(rtc->rtc, NRF52_RTC_TIMESLOT);
+          nrf52_radioi8_rtc_alarm(rtc, NRF52_SFEVT_START,
+                                  rtc->sf_start + rtc->bi -
+                                  NRF52_RADIOI8_RAMPUP_US);
+        }
     }
 
+out:
   leave_critical_section(flags);
 
   return OK;
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h 
b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
index 21767c9e02e..ef01eb96152 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_rtc.h
@@ -29,6 +29,11 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <nuttx/wqueue.h>
+
 #include "nrf52_rtc.h"
 
 /****************************************************************************
@@ -39,18 +44,18 @@
  * Public Types
  ****************************************************************************/
 
-/* RTC events */
+/* Superframe events */
 
-enum nrf52_ieee802154_rtc_e
+enum nrf52_ieee802154_sfevt_e
 {
-  NRF52_RTC_BI       = 0,       /* Beacon Interval interval (BI) */
-  NRF52_RTC_TIMESLOT = 1,       /* Time slot */
-  NRF52_RTC_CAP      = 2,       /* Contention Access Period (CAP) */
-  NRF52_RTC_SD       = 3        /* Super Frame Duration (SD) */
+  NRF52_SFEVT_NONE  = 0,        /* No event scheduled */
+  NRF52_SFEVT_START = 1,        /* Superframe start, beacon TX */
+  NRF52_SFEVT_SDEND = 2         /* End of the active portion */
 };
 
 /* Forward reference */
 
+struct ieee802154_superframespec_s;
 struct nrf52_radioi8_rtc_s;
 struct nrf52_radioi8_dev_s;
 
@@ -58,22 +63,30 @@ struct nrf52_radioi8_dev_s;
 
 struct nrf52_radioi8_rtc_ops_s
 {
-  /* Configure RTC events according to superframe spec */
+  /* Configure the superframe timings according to superframe spec */
 
   int (*setup)(struct nrf52_radioi8_dev_s *dev,
                struct ieee802154_superframespec_s *sfspec);
 
-  /* Start RTC */
+  /* Start transmitting beacons */
 
   int (*start)(struct nrf52_radioi8_dev_s *dev);
 
-  /* Stop RTC */
+  /* A beacon with the given PHR was just received */
+
+  int (*sync)(struct nrf52_radioi8_dev_s *dev, uint8_t phr);
+
+  /* Stop the superframe */
 
   int (*stop)(struct nrf52_radioi8_dev_s *dev);
 
   /* Reset RTC */
 
   void (*reset)(struct nrf52_radioi8_dev_s *dev);
+
+  /* Time in us since the superframe start, false if not synchronized */
+
+  bool (*elapsed)(struct nrf52_radioi8_dev_s *dev, uint32_t *us);
 };
 
 /* RTC interface */
@@ -88,15 +101,24 @@ struct nrf52_radioi8_rtc_s
 
   struct nrf52_radioi8_rtc_ops_s *ops;
 
-#ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
   /* For deferring inactive state work to the work queue */
 
   struct work_s inactive_work;
 
+  /* Superframe timings in us */
+
+  uint64_t sf_start;            /* Start of the current superframe */
+  uint64_t evt_time;            /* Time of the scheduled event */
+  uint32_t bi;                  /* Beacon interval */
+  uint32_t sd;                  /* Superframe duration */
+  uint32_t cap;                 /* End of the CAP */
+  uint32_t capstart;            /* Start of the CAP, after the beacon IFS */
+
   /* RTC state */
 
-  uint32_t rtc_timeslot;
-#endif
+  uint32_t ovf;                 /* Counter overflows */
+  uint8_t  evt;                 /* Scheduled event */
+  bool     running;             /* Superframe timing valid */
 };
 
 /****************************************************************************
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_trace.c 
b/arch/arm/src/nrf52/nrf52_ieee802154_trace.c
index 0ce5f1e0582..e58a01fa4d7 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_trace.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_trace.c
@@ -57,8 +57,6 @@ static const char *g_radio_trace_str[] =
   "TIM IRQ: TIM WAIT ACK",
   "TIM IRQ: TIM CSMA DELAY",
   "RTC IRQ: RTC SD",
-  "RTC IRQ: RTC CAP",
-  "RTC IRQ: RTC TIMESLOT",
   "RTC IRQ: RTC BI",
 
   "WORK: RX",
@@ -78,6 +76,7 @@ static const char *g_radio_trace_str[] =
   "NOACK",
   "DROPFRAME",
   "TXTRYAGAIN",
+  "SFSYNC",
 };
 
 /* Trace data */
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_trace.h 
b/arch/arm/src/nrf52/nrf52_ieee802154_trace.h
index a675eab6d51..b2be03d9e3b 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_trace.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_trace.h
@@ -68,8 +68,6 @@ enum radio_trace_type_e
   RADIO_TRACE_IRQ_TIMWAITACK,
   RADIO_TRACE_IRQ_TIMCSMADELAY,
   RADIO_TRACE_IRQ_RTCSD,
-  RADIO_TRACE_IRQ_RTCCAP,
-  RADIO_TRACE_IRQ_RTCTIMESLOT,
   RADIO_TRACE_IRQ_RTCBI,
 
   /* Works */
@@ -93,6 +91,7 @@ enum radio_trace_type_e
   RADIO_TRACE_NOACK,
   RADIO_TRACE_DROPFRAME,
   RADIO_TRACE_TXRETRY,
+  RADIO_TRACE_SFSYNC,
 };
 
 /****************************************************************************
diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig
index 670a231c067..30d55acb3eb 100644
--- a/arch/arm/src/nrf53/Kconfig
+++ b/arch/arm/src/nrf53/Kconfig
@@ -718,6 +718,11 @@ config NRF53_RADIO_IEEE802154_SUPERFRAME
        default n
        select NRF53_RTC0
        select NRF53_USE_LFCLK
+       ---help---
+               The superframe timing runs from the LFCLK.  With the LFXO source
+               (NRF53_LFCLK_XTAL) the application core must configure the
+               oscillator (NRF53_OSCILLATOR_LFXO), otherwise the network core
+               waits for the LFCLK forever at boot.
 
 config NRF53_RADIO_IEEE802154_GTS_SLOTS
        int "RADIO IEEE802.15.4 GTS slots"
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154.c 
b/arch/arm/src/nrf53/nrf53_ieee802154.c
index 3ecca0ba9bc..a6b40e32034 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154.c
+++ b/arch/arm/src/nrf53/nrf53_ieee802154.c
@@ -729,6 +729,7 @@ nrf53_radioi8_beaconstart(struct ieee802154_radio_s *radio,
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
   struct nrf53_radioi8_dev_s *dev = (struct nrf53_radioi8_dev_s *)radio;
   irqstate_t                  flags;
+  int                         ret;
 
   if (sfspec->pancoord)
     {
@@ -739,18 +740,22 @@ nrf53_radioi8_beaconstart(struct ieee802154_radio_s 
*radio,
       memcpy(&dev->state.sf, (void *)sfspec,
              sizeof(struct ieee802154_superframespec_s));
 
-      /* Setup beacon transmission, macBSN starts from a random value */
+      /* Configure the superframe timings */
 
-      dev->radio->ops->beacon_setup(dev, beacon->bf_data, beacon->bf_len);
-      dev->radio->state.bsn = rand();
-
-      /* Configure RTC events */
+      ret = dev->rtc->ops->setup(dev, &dev->state.sf);
+      if (ret == OK)
+        {
+          /* Setup beacon transmission, macBSN starts from a random value */
 
-      dev->rtc->ops->setup(dev, &dev->state.sf);
+          dev->radio->ops->beacon_setup(dev, beacon->bf_data,
+                                        beacon->bf_len);
+          dev->radio->state.bsn = rand();
 
-      /* Start RTC */
+          /* The PAN coordinator defines the superframe */
 
-      dev->rtc->ops->start(dev);
+          dev->radio->state.sftrack = false;
+          dev->rtc->ops->start(dev);
+        }
 
       leave_critical_section(flags);
     }
@@ -758,10 +763,10 @@ nrf53_radioi8_beaconstart(struct ieee802154_radio_s 
*radio,
     {
       /* TODO: missing logic for non-PAN coord */
 
-      return -ENOTTY;
+      ret = -ENOTTY;
     }
 
-  return OK;
+  return ret;
 #else
   return -ENOTSUP;
 #endif
@@ -847,6 +852,7 @@ nrf53_radioi8_sfupdate(struct ieee802154_radio_s *radio,
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
   struct nrf53_radioi8_dev_s *dev = (struct nrf53_radioi8_dev_s *)radio;
   irqstate_t                  flags;
+  int                         ret = OK;
 
   flags = enter_critical_section();
 
@@ -859,28 +865,32 @@ nrf53_radioi8_sfupdate(struct ieee802154_radio_s *radio,
 
   if (sfspec->beaconorder < 15)
     {
-      /* Need slotted CSMA-CA */
-
-      dev->radio->state.slotted = true;
+      /* Configure the superframe timings */
 
-      /* Configure RTC */
+      ret = dev->rtc->ops->setup(dev, &dev->state.sf);
+      if (ret == OK)
+        {
+          /* Need slotted CSMA-CA */
 
-      dev->rtc->ops->setup(dev, &dev->state.sf);
+          dev->radio->state.slotted = true;
 
-      /* Wait for beacon to sync */
+          /* Sync with the beacons */
 
-      dev->radio->state.wait_for_beacon = true;
+          dev->radio->state.sftrack = true;
+        }
     }
   else
     {
       /* Need un-slotted CSMA-CA */
 
+      dev->rtc->ops->stop(dev);
       dev->radio->state.slotted = false;
+      dev->radio->state.sftrack = false;
     }
 
   leave_critical_section(flags);
 
-  return OK;
+  return ret;
 #else
   return -ENOTSUP;
 #endif
@@ -962,8 +972,10 @@ nrf53_radioi8_register(struct nrf53_radio_board_s *board)
 
   DEBUGASSERT(dev->rtc->ops->setup);
   DEBUGASSERT(dev->rtc->ops->start);
+  DEBUGASSERT(dev->rtc->ops->sync);
   DEBUGASSERT(dev->rtc->ops->stop);
   DEBUGASSERT(dev->rtc->ops->reset);
+  DEBUGASSERT(dev->rtc->ops->elapsed);
 #endif
 
   /* Connect MAC ops */
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_radio.c 
b/arch/arm/src/nrf53/nrf53_ieee802154_radio.c
index 2ec33faa29f..0709edb4fbd 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_radio.c
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_radio.c
@@ -168,6 +168,9 @@ static void nrf53_radioi8_rx_parse(struct 
nrf53_radioi8_dev_s *dev,
                                    uint8_t *ftype, uint8_t *cmdtype);
 static void nrf53_radioi8_ack_transmit(struct nrf53_radioi8_dev_s *dev);
 static bool nrf53_radioi8_filter(struct nrf53_radioi8_dev_s *dev);
+#ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
+static bool nrf53_radioi8_coordbeacon(struct nrf53_radioi8_dev_s *dev);
+#endif
 #if NRF53_GTS_SLOTS > 0
 static void nrf53_radioi8_gts_setup(struct nrf53_radioi8_dev_s *dev,
                                     uint8_t fifo, struct iob_s *frame);
@@ -559,6 +562,52 @@ static bool nrf53_radioi8_filter(struct 
nrf53_radioi8_dev_s *dev)
   return false;
 }
 
+#ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
+/****************************************************************************
+ * Name: nrf53_radioi8_coordbeacon
+ *
+ * Description:
+ *   The received frame is a beacon of our coordinator (IEEE 802.15.4-2003
+ *   7.5.4.1).
+ *
+ ****************************************************************************/
+
+static bool nrf53_radioi8_coordbeacon(struct nrf53_radioi8_dev_s *dev)
+{
+  uint8_t *rx = &dev->radio->rxbuf[1];
+  uint8_t  eaddr[IEEE802154_EADDRSIZE];
+  uint8_t  mode;
+  int      i;
+
+  if ((rx[0] & IEEE802154_FRAMECTRL_FTYPE) != IEEE802154_FRAME_BEACON ||
+      !IEEE802154_PANIDCMP(&rx[3], dev->state.addr.panid))
+    {
+      return false;
+    }
+
+  mode = ((rx[1] << 8) & IEEE802154_FRAMECTRL_SADDR) >>
+         IEEE802154_FRAMECTRL_SHIFT_SADDR;
+
+  if (mode == IEEE802154_ADDRMODE_SHORT)
+    {
+      return IEEE802154_SADDRCMP(&rx[5], dev->state.coordaddr.saddr);
+    }
+  else if (mode == IEEE802154_ADDRMODE_EXTENDED)
+    {
+      /* Sent least significant octet first */
+
+      for (i = 0; i < IEEE802154_EADDRSIZE; i++)
+        {
+          eaddr[i] = rx[5 + IEEE802154_EADDRSIZE - 1 - i];
+        }
+
+      return IEEE802154_EADDRCMP(eaddr, dev->state.coordaddr.eaddr);
+    }
+
+  return false;
+}
+#endif
+
 #if NRF53_GTS_SLOTS > 0
 /****************************************************************************
  * Name: nrf53_radioi8_gts_setup
@@ -1892,24 +1941,12 @@ static void nrf53_radioi8_state_rx(struct 
nrf53_radioi8_dev_s *dev)
     }
 
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
-  /* TODO: resync with beacon ? */
+  /* The superframe started with the SHR of the coordinator beacon */
 
-  if (dev->radio->state.wait_for_beacon == true)
+  if (dev->radio->state.sftrack && dev->radio->state.waitack == false &&
+      nrf53_radioi8_coordbeacon(dev))
     {
-      uint16_t *fc = (uint16_t *)&rxbuf[0];
-
-      /* TODO: NOT TESTES, should we check panid here ? */
-
-      if (((*fc & IEEE802154_FRAMECTRL_FTYPE) == IEEE802154_FRAME_BEACON) &&
-          IEEE802154_PANIDCMP(IEEE802154_PANID_UNSPEC,
-                              &dev->state.addr.panid))
-        {
-          /* Start RTC */
-
-          dev->rtc->ops->start(dev);
-
-          dev->radio->state.wait_for_beacon = false;
-        }
+      dev->rtc->ops->sync(dev, rxbuf[0]);
     }
 #endif
 
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_radio.h 
b/arch/arm/src/nrf53/nrf53_ieee802154_radio.h
index 5c84c0a0b81..c50bed096dd 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_radio.h
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_radio.h
@@ -56,6 +56,21 @@
                                        IEEE802154_TURN_AROUND_TIME +    \
                                        10 + 12)
 
+/* RADIO ramp-up time in fast ramp-up mode */
+
+#define NRF53_RADIOI8_RAMPUP_US       (40)
+
+/* Air time of a frame with the given PHR: SHR, PHR and PSDU, 32 us/octet */
+
+#define NRF53_RADIOI8_FRAME_US(phr)   (((phr) + 6) * 2 * IEEE802154_SYMBOL_US)
+
+/* IFS after a frame with the given PHR */
+
+#define NRF53_RADIOI8_IFS_US(phr)                       \
+  (((phr) > IEEE802154_MAX_SIFS_FRAME_SIZE ?            \
+    IEEE802154_LIFS_SYMBOLS : IEEE802154_SIFS_SYMBOLS) * \
+   IEEE802154_SYMBOL_US)
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -112,7 +127,7 @@ struct nrf53_radioi8_radio_data_s
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
   /* Superframe data */
 
-  bool    wait_for_beacon;      /* Device wait for beacon */
+  bool    sftrack;              /* Device tracks the beacons */
   bool    ble;                  /* Batter life extension */
   bool    beacon_pending;       /* A beacon waits for the radio */
   uint8_t bsn;                  /* macBSN, the beacon sequence number */
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_rtc.c 
b/arch/arm/src/nrf53/nrf53_ieee802154_rtc.c
index 8734a35aa09..f70c110e7e1 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_rtc.c
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_rtc.c
@@ -44,10 +44,6 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
-#  warning Beacon and superframe support work in progress
-#endif
-
 #ifndef CONFIG_NRF53_RTC0
 #  error CONFIG_NRF53_RTC0 is needed to handle radio timings
 #endif
@@ -56,16 +52,27 @@
 
 #define NRF53_IEEE802154_RTC0   (0)
 
-/* RTC prescaler set to 0, freq = 32.768kHz, resolution = 30.517 us */
+/* RTC prescaler set to 0, freq = 32.768kHz, 1 tick = 15625 / 512 us */
 
 #define NRF53_RTC_PRESCALER     (0)
-#define NRF53_RTC_FREQUENCY     (32768)
+#define NRF53_RTC_TICK_NUM      (15625)
+#define NRF53_RTC_TICK_DEN      (512)
+
+/* 24-bit counter */
 
-#define NRF53_RTC_RESOLUTION_NS (30517)
+#define NRF53_RTC_COUNTER_BITS  (24)
+#define NRF53_RTC_COUNTER_MASK  ((1 << NRF53_RTC_COUNTER_BITS) - 1)
 
-/* 31 * 30.517us = 946.027us */
+/* A compare value closer than 2 ticks to the counter may not match */
 
-#define NRF53_RTC_TIMESLOT_CC   (31)
+#define NRF53_RTC_CC_MARGIN     (2)
+#define NRF53_RTC_CC_MARGIN_US  ((NRF53_RTC_CC_MARGIN * NRF53_RTC_TICK_NUM + \
+                                  NRF53_RTC_TICK_DEN - 1) / NRF53_RTC_TICK_DEN)
+
+/* Superframe events compare channel */
+
+#define NRF53_RTC_CC            (NRF53_RTC_CC0)
+#define NRF53_RTC_EVT           (NRF53_RTC_EVT_COMPARE0)
 
 /****************************************************************************
  * Private Function Prototypes
@@ -76,8 +83,12 @@
 static int nrf53_radioi8_rtc(struct nrf53_radioi8_dev_s *dev,
                              struct ieee802154_superframespec_s *sfspec);
 static int nrf53_radioi8_rtc_start(struct nrf53_radioi8_dev_s *dev);
+static int nrf53_radioi8_rtc_sync(struct nrf53_radioi8_dev_s *dev,
+                                  uint8_t phr);
 static int nrf53_radioi8_rtc_stop(struct nrf53_radioi8_dev_s *dev);
 static void nrf53_radioi8_rtc_reset(struct nrf53_radioi8_dev_s *dev);
+static bool nrf53_radioi8_rtc_elapsed(struct nrf53_radioi8_dev_s *dev,
+                                      uint32_t *us);
 
 /* Interrupts logic */
 
@@ -92,10 +103,12 @@ static int nrf53_radioi8_isr_rtc(int irq, void *context, 
void *arg);
 
 static struct nrf53_radioi8_rtc_ops_s g_radioi8_rtc_ops =
 {
-  .setup = nrf53_radioi8_rtc,
-  .start = nrf53_radioi8_rtc_start,
-  .stop  = nrf53_radioi8_rtc_stop,
-  .reset = nrf53_radioi8_rtc_reset
+  .setup   = nrf53_radioi8_rtc,
+  .start   = nrf53_radioi8_rtc_start,
+  .sync    = nrf53_radioi8_rtc_sync,
+  .stop    = nrf53_radioi8_rtc_stop,
+  .reset   = nrf53_radioi8_rtc_reset,
+  .elapsed = nrf53_radioi8_rtc_elapsed
 };
 
 /* RTC instance */
@@ -107,69 +120,171 @@ static struct nrf53_radioi8_rtc_s g_radioi8_rtc;
  ****************************************************************************/
 
 /****************************************************************************
- * Name: nrf53_radioi8_rtc
+ * Name: nrf53_radioi8_rtc_ticks
  *
  * Description:
- *   Configure RTC events according to superframe spec.
+ *   Get the 64-bit RTC counter.  Must be called with the radio locked.
  *
  ****************************************************************************/
 
-static int nrf53_radioi8_rtc(struct nrf53_radioi8_dev_s *dev,
-                             struct ieee802154_superframespec_s *sfspec)
+static uint64_t nrf53_radioi8_rtc_ticks(struct nrf53_radioi8_rtc_s *rtc)
 {
-  uint32_t   bi     = 0;
-  uint32_t   sd     = 0;
-  uint32_t   cap    = 0;
-  irqstate_t flags;
+  uint32_t ovf = rtc->ovf;
+  uint32_t cnt = 0;
 
-  flags = enter_critical_section();
+  NRF53_RTC_GETCOUNTER(rtc->rtc, &cnt);
+
+  /* Overflow not handled yet */
+
+  if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_EVT_OVRFLW))
+    {
+      NRF53_RTC_GETCOUNTER(rtc->rtc, &cnt);
+      ovf += 1;
+    }
+
+  return ((uint64_t)ovf << NRF53_RTC_COUNTER_BITS) | cnt;
+}
+
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc_now
+ *
+ * Description:
+ *   Get the current time in us.  Must be called with the radio locked.
+ *
+ ****************************************************************************/
+
+static uint64_t nrf53_radioi8_rtc_now(struct nrf53_radioi8_rtc_s *rtc)
+{
+  return nrf53_radioi8_rtc_ticks(rtc) * NRF53_RTC_TICK_NUM /
+         NRF53_RTC_TICK_DEN;
+}
+
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc_alarm
+ *
+ * Description:
+ *   Schedule a superframe event.  The compare value matches on every
+ *   counter wrap, the interrupt handler ignores the matches before the
+ *   event time.  Must be called with the radio locked.
+ *
+ ****************************************************************************/
+
+static void nrf53_radioi8_rtc_alarm(struct nrf53_radioi8_rtc_s *rtc,
+                                    uint8_t evt, uint64_t time)
+{
+  uint64_t ticks = time * NRF53_RTC_TICK_DEN / NRF53_RTC_TICK_NUM;
+  uint64_t now   = nrf53_radioi8_rtc_ticks(rtc);
+
+  if (ticks < now + NRF53_RTC_CC_MARGIN)
+    {
+      ticks = now + NRF53_RTC_CC_MARGIN;
+    }
+
+  rtc->evt      = evt;
+  rtc->evt_time = time;
+
+  NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_EVT);
+  NRF53_RTC_SETCC(rtc->rtc, NRF53_RTC_CC, ticks & NRF53_RTC_COUNTER_MASK);
+  NRF53_RTC_ENABLEEVT(rtc->rtc, NRF53_RTC_EVT);
+  NRF53_RTC_ENABLEINT(rtc->rtc, NRF53_RTC_EVT);
+}
+
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc_cancel
+ *
+ * Description:
+ *   Cancel the scheduled superframe event.  Must be called with the radio
+ *   locked.
+ *
+ ****************************************************************************/
 
-  /* Stop RTC and clear the counter */
+static void nrf53_radioi8_rtc_cancel(struct nrf53_radioi8_rtc_s *rtc)
+{
+  NRF53_RTC_DISABLEINT(rtc->rtc, NRF53_RTC_EVT);
+  NRF53_RTC_DISABLEEVT(rtc->rtc, NRF53_RTC_EVT);
+  NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_EVT);
 
-  NRF53_RTC_STOP(dev->rtc->rtc);
-  NRF53_RTC_CLEAR(dev->rtc->rtc);
+  rtc->evt = NRF53_SFEVT_NONE;
+}
 
-  /* Initialize BI counter */
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc_next
+ *
+ * Description:
+ *   Schedule the next superframe event after the superframe start.  Must
+ *   be called with the radio locked.
+ *
+ ****************************************************************************/
 
-  bi = ((IEEE802154_BASE_SUPERFRAME_DURATION *
-        (2 << sfspec->beaconorder) *
-         IEEE802154_SYMBOL_US * 1000)  /
-        NRF53_RTC_RESOLUTION_NS);
-  NRF53_RTC_SETCC(dev->rtc->rtc, NRF53_RTC_BI, bi);
+static void nrf53_radioi8_rtc_next(struct nrf53_radioi8_dev_s *dev)
+{
+  struct nrf53_radioi8_rtc_s *rtc = dev->rtc;
 
-  /* Initialize SD counter */
+  if (rtc->sd < rtc->bi)
+    {
+      nrf53_radioi8_rtc_alarm(rtc, NRF53_SFEVT_SDEND,
+                              rtc->sf_start + rtc->sd);
+    }
+  else
+    {
+      /* No inactive portion, the MAC updates the beacon from now */
 
-  sd = ((IEEE802154_BASE_SUPERFRAME_DURATION *
-         (2 << sfspec->sforder) *
-         IEEE802154_SYMBOL_US * 1000) /
-        NRF53_RTC_RESOLUTION_NS);
-  NRF53_RTC_SETCC(dev->rtc->rtc, NRF53_RTC_SD, sd);
+      if (work_available(&dev->rtc->inactive_work))
+        {
+          work_queue(HPWORK, &dev->rtc->inactive_work,
+                     nrf53_radioi8_work_inactive, dev, 0);
+        }
 
-  /* Initialize CAP counter */
+      nrf53_radioi8_rtc_alarm(rtc, NRF53_SFEVT_START,
+                              rtc->sf_start + rtc->bi -
+                              NRF53_RADIOI8_RAMPUP_US);
+    }
+}
 
-  cap = ((sfspec->final_capslot *
-          IEEE802154_TIMESLOT_US * 1000) /
-         NRF53_RTC_RESOLUTION_NS);
-  NRF53_RTC_SETCC(dev->rtc->rtc, NRF53_RTC_CAP, cap);
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc
+ *
+ * Description:
+ *   Configure the superframe timings according to superframe spec.
+ *
+ ****************************************************************************/
 
-  /* Initialize timeslot counter */
+static int nrf53_radioi8_rtc(struct nrf53_radioi8_dev_s *dev,
+                             struct ieee802154_superframespec_s *sfspec)
+{
+  struct nrf53_radioi8_rtc_s *rtc = dev->rtc;
+  uint32_t                    slot;
+  irqstate_t                  flags;
 
-  dev->rtc->rtc_timeslot = NRF53_RTC_TIMESLOT_CC;
-  NRF53_RTC_SETCC(dev->rtc->rtc, NRF53_RTC_TIMESLOT, dev->rtc->rtc_timeslot);
+  if (sfspec->beaconorder > 14 ||
+      (sfspec->sforder > sfspec->beaconorder && sfspec->sforder != 15))
+    {
+      return -EINVAL;
+    }
 
-  /* Configure interrupts */
+  flags = enter_critical_section();
 
-  NRF53_RTC_ENABLEINT(dev->rtc->rtc, NRF53_RTC_BI);
-  NRF53_RTC_ENABLEINT(dev->rtc->rtc, NRF53_RTC_SD);
-  NRF53_RTC_ENABLEINT(dev->rtc->rtc, NRF53_RTC_CAP);
-  NRF53_RTC_ENABLEINT(dev->rtc->rtc, NRF53_RTC_TIMESLOT);
+  /* BI = aBaseSuperframeDuration * 2^BO, SD = aBaseSuperframeDuration *
+   * 2^SO, the CAP ends with the final CAP slot (IEEE 802.15.4-2003 7.5.1.1)
+   */
 
-  /* Configure events */
+  rtc->bi = (IEEE802154_BASE_SUPERFRAME_DURATION * IEEE802154_SYMBOL_US) <<
+            sfspec->beaconorder;
 
-  NRF53_RTC_ENABLEEVT(dev->rtc->rtc, NRF53_RTC_BI);
-  NRF53_RTC_ENABLEEVT(dev->rtc->rtc, NRF53_RTC_SD);
-  NRF53_RTC_ENABLEEVT(dev->rtc->rtc, NRF53_RTC_CAP);
-  NRF53_RTC_ENABLEEVT(dev->rtc->rtc, NRF53_RTC_TIMESLOT);
+  if (sfspec->sforder == 15)
+    {
+      /* The superframe is not active after the beacon */
+
+      rtc->sd  = 0;
+      rtc->cap = 0;
+    }
+  else
+    {
+      slot     = (IEEE802154_BASE_SLOT_DURATION * IEEE802154_SYMBOL_US) <<
+                 sfspec->sforder;
+      rtc->sd  = slot * IEEE802154_NUM_SUPERFRAME_SLOTS;
+      rtc->cap = slot * (sfspec->final_capslot + 1);
+    }
 
   leave_critical_section(flags);
 
@@ -180,13 +295,54 @@ static int nrf53_radioi8_rtc(struct nrf53_radioi8_dev_s 
*dev,
  * Name: nrf53_radioi8_rtc_start
  *
  * Description:
- *   Start RTC.
+ *   Start transmitting beacons.
  *
  ****************************************************************************/
 
 static int nrf53_radioi8_rtc_start(struct nrf53_radioi8_dev_s *dev)
 {
-  NRF53_RTC_START(dev->rtc->rtc);
+  struct nrf53_radioi8_rtc_s *rtc = dev->rtc;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  rtc->sf_start = nrf53_radioi8_rtc_now(rtc) + NRF53_RTC_CC_MARGIN_US +
+                  NRF53_RADIOI8_RAMPUP_US;
+  rtc->running  = false;
+
+  nrf53_radioi8_rtc_alarm(rtc, NRF53_SFEVT_START,
+                          rtc->sf_start - NRF53_RADIOI8_RAMPUP_US);
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc_sync
+ *
+ * Description:
+ *   Synchronize with the beacon just received, the superframe started
+ *   with its SHR.
+ *
+ ****************************************************************************/
+
+static int nrf53_radioi8_rtc_sync(struct nrf53_radioi8_dev_s *dev,
+                                  uint8_t phr)
+{
+  struct nrf53_radioi8_rtc_s *rtc = dev->rtc;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
+  nrf53_radioi8_trace_put(RADIO_TRACE_SFSYNC, phr);
+
+  rtc->sf_start = nrf53_radioi8_rtc_now(rtc) - NRF53_RADIOI8_FRAME_US(phr);
+  rtc->capstart = NRF53_RADIOI8_FRAME_US(phr) + NRF53_RADIOI8_IFS_US(phr);
+  rtc->running  = true;
+
+  leave_critical_section(flags);
+
   return OK;
 }
 
@@ -194,13 +350,21 @@ static int nrf53_radioi8_rtc_start(struct 
nrf53_radioi8_dev_s *dev)
  * Name: nrf53_radioi8_rtc_stop
  *
  * Description:
- *   Stop RTC.
+ *   Stop the superframe.
  *
  ****************************************************************************/
 
 static int nrf53_radioi8_rtc_stop(struct nrf53_radioi8_dev_s *dev)
 {
-  NRF53_RTC_STOP(dev->rtc->rtc);
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  nrf53_radioi8_rtc_cancel(dev->rtc);
+  dev->rtc->running = false;
+
+  leave_critical_section(flags);
+
   return OK;
 }
 
@@ -208,20 +372,81 @@ static int nrf53_radioi8_rtc_stop(struct 
nrf53_radioi8_dev_s *dev)
  * Name: nrf53_radioi8_rtc_reset
  *
  * Description:
- *   Reset RTC.
+ *   Reset RTC, the counter runs from now on.
  *
  ****************************************************************************/
 
 static void nrf53_radioi8_rtc_reset(struct nrf53_radioi8_dev_s *dev)
 {
+  struct nrf53_radioi8_rtc_s *rtc = dev->rtc;
+  irqstate_t                  flags;
+
+  flags = enter_critical_section();
+
   /* Configure RTC - freq = 32.768 kHz */
 
-  NRF53_RTC_STOP(dev->rtc->rtc);
-  NRF53_RTC_SETPRE(dev->rtc->rtc, NRF53_RTC_PRESCALER);
+  nrf53_radioi8_rtc_cancel(rtc);
+  NRF53_RTC_STOP(rtc->rtc);
+  NRF53_RTC_CLEAR(rtc->rtc);
+  NRF53_RTC_SETPRE(rtc->rtc, NRF53_RTC_PRESCALER);
+
+  /* Count overflows */
+
+  NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_EVT_OVRFLW);
+  NRF53_RTC_ENABLEEVT(rtc->rtc, NRF53_RTC_EVT_OVRFLW);
+  NRF53_RTC_ENABLEINT(rtc->rtc, NRF53_RTC_EVT_OVRFLW);
 
   /* Reset data */
 
-  dev->rtc->rtc_timeslot = 0;
+  rtc->ovf      = 0;
+  rtc->sf_start = 0;
+  rtc->running  = false;
+
+  NRF53_RTC_START(rtc->rtc);
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: nrf53_radioi8_rtc_elapsed
+ *
+ * Description:
+ *   Time in us since the superframe start.
+ *
+ ****************************************************************************/
+
+static bool nrf53_radioi8_rtc_elapsed(struct nrf53_radioi8_dev_s *dev,
+                                      uint32_t *us)
+{
+  struct nrf53_radioi8_rtc_s *rtc = dev->rtc;
+  uint64_t                    now;
+  irqstate_t                  flags;
+  bool                        ret = false;
+
+  flags = enter_critical_section();
+
+  if (rtc->running)
+    {
+      now = nrf53_radioi8_rtc_now(rtc);
+      if (now < rtc->sf_start)
+        {
+          *us = 0;
+        }
+      else if (now - rtc->sf_start > UINT32_MAX)
+        {
+          *us = UINT32_MAX;
+        }
+      else
+        {
+          *us = now - rtc->sf_start;
+        }
+
+      ret = true;
+    }
+
+  leave_critical_section(flags);
+
+  return ret;
 }
 
 /****************************************************************************
@@ -256,94 +481,72 @@ static int nrf53_radioi8_isr_rtc(int irq, void *context, 
void *arg)
   struct nrf53_radioi8_dev_s *dev = (struct nrf53_radioi8_dev_s *)arg;
   struct nrf53_radioi8_rtc_s *rtc = NULL;
   irqstate_t                  flags;
+  uint8_t                     evt;
 
   DEBUGASSERT(dev != NULL);
   rtc = dev->rtc;
 
   flags = enter_critical_section();
 
-  /* End of CAP */
-
-  if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_CAP))
+  if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_EVT_OVRFLW))
     {
-      nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_RTCCAP, 0);
-
-      /* TODO */
-
-      /* Clear event */
-
-      NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_CAP);
+      NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_EVT_OVRFLW);
+      rtc->ovf += 1;
     }
 
-  /* End of active portion */
-
-  else if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_SD))
+  if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_EVT))
     {
-      nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_RTCSD, 0);
-
-      /* Schedule work */
+      NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_EVT);
 
-      DEBUGASSERT(work_available(&dev->rtc->inactive_work));
-      work_queue(HPWORK, &dev->rtc->inactive_work,
-                 nrf53_radioi8_work_inactive, dev, 0);
+      /* A match before the event time is a counter wrap */
 
-      /* Reset timeslot */
-
-      rtc->rtc_timeslot = NRF53_RTC_TIMESLOT_CC;
-
-      /* Clear event */
-
-      NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_SD);
-    }
-
-  /* Beacon interval */
-
-  else if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_BI))
-    {
-      nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_RTCBI, 0);
-
-      /* Transmit beacon if we are not endpoint */
-
-      if (dev->state.devmode != NRF53_DEVMODE_ENDPOINT)
+      evt = rtc->evt;
+      if (evt == NRF53_SFEVT_NONE ||
+          nrf53_radioi8_rtc_ticks(rtc) <
+          rtc->evt_time * NRF53_RTC_TICK_DEN / NRF53_RTC_TICK_NUM)
         {
-          /* Transmit data from beaconbuf */
-
-          dev->radio->ops->beacon_tx(dev);
+          goto out;
         }
 
-      /* Clear event */
+      rtc->evt = NRF53_SFEVT_NONE;
 
-      NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_BI);
+      /* Superframe start */
 
-      /* Next cycle */
+      if (evt == NRF53_SFEVT_START)
+        {
+          nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_RTCBI, 0);
 
-      NRF53_RTC_TRGOVRFLW(rtc->rtc);
+          rtc->sf_start = rtc->evt_time + NRF53_RADIOI8_RAMPUP_US;
+          rtc->capstart = NRF53_RADIOI8_FRAME_US(dev->radio->beaconbuf[0]) +
+                          NRF53_RADIOI8_IFS_US(dev->radio->beaconbuf[0]);
+          rtc->running  = true;
 
-      /* TODO: resync with beacon ? */
-    }
-
-  /* Timeslot in active portion */
+          /* Transmit data from beaconbuf */
 
-  if (NRF53_RTC_CHECKINT(rtc->rtc, NRF53_RTC_TIMESLOT))
-    {
-      nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_RTCTIMESLOT, 0);
+          dev->radio->ops->beacon_tx(dev);
 
-      /* TODO: how to sync transmission with timeslot ?
-       *       do we need count every timeslot here ?
-       *       or wait for the timeslot we are interested in ?
-       *       or just use txdelay ?
-       */
+          nrf53_radioi8_rtc_next(dev);
+        }
 
-      /* Update timeslot */
+      /* End of active portion */
 
-      rtc->rtc_timeslot += NRF53_RTC_TIMESLOT_CC;
-      NRF53_RTC_SETCC(rtc->rtc, NRF53_RTC_TIMESLOT, rtc->rtc_timeslot);
+      else if (evt == NRF53_SFEVT_SDEND)
+        {
+          nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_RTCSD, 0);
 
-      /* Clear event */
+          if (work_available(&dev->rtc->inactive_work))
+            {
+              work_queue(HPWORK, &dev->rtc->inactive_work,
+                         nrf53_radioi8_work_inactive, dev, 0);
+            }
 
-      NRF53_RTC_ACKINT(rtc->rtc, NRF53_RTC_TIMESLOT);
+          nrf53_radioi8_rtc_alarm(rtc, NRF53_SFEVT_START,
+                                  rtc->sf_start + rtc->bi -
+                                  NRF53_RADIOI8_RAMPUP_US);
+        }
     }
 
+out:
   leave_critical_section(flags);
 
   return OK;
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_rtc.h 
b/arch/arm/src/nrf53/nrf53_ieee802154_rtc.h
index 9d22f7d679d..7f3dbbe6ca7 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_rtc.h
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_rtc.h
@@ -29,6 +29,11 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <nuttx/wqueue.h>
+
 #include "nrf53_rtc.h"
 
 /****************************************************************************
@@ -39,18 +44,18 @@
  * Public Types
  ****************************************************************************/
 
-/* RTC events */
+/* Superframe events */
 
-enum nrf53_ieee802154_rtc_e
+enum nrf53_ieee802154_sfevt_e
 {
-  NRF53_RTC_BI       = 0,       /* Beacon Interval interval (BI) */
-  NRF53_RTC_TIMESLOT = 1,       /* Time slot */
-  NRF53_RTC_CAP      = 2,       /* Contention Access Period (CAP) */
-  NRF53_RTC_SD       = 3        /* Super Frame Duration (SD) */
+  NRF53_SFEVT_NONE  = 0,        /* No event scheduled */
+  NRF53_SFEVT_START = 1,        /* Superframe start, beacon TX */
+  NRF53_SFEVT_SDEND = 2         /* End of the active portion */
 };
 
 /* Forward reference */
 
+struct ieee802154_superframespec_s;
 struct nrf53_radioi8_rtc_s;
 struct nrf53_radioi8_dev_s;
 
@@ -58,22 +63,30 @@ struct nrf53_radioi8_dev_s;
 
 struct nrf53_radioi8_rtc_ops_s
 {
-  /* Configure RTC events according to superframe spec */
+  /* Configure the superframe timings according to superframe spec */
 
   int (*setup)(struct nrf53_radioi8_dev_s *dev,
                struct ieee802154_superframespec_s *sfspec);
 
-  /* Start RTC */
+  /* Start transmitting beacons */
 
   int (*start)(struct nrf53_radioi8_dev_s *dev);
 
-  /* Stop RTC */
+  /* A beacon with the given PHR was just received */
+
+  int (*sync)(struct nrf53_radioi8_dev_s *dev, uint8_t phr);
+
+  /* Stop the superframe */
 
   int (*stop)(struct nrf53_radioi8_dev_s *dev);
 
   /* Reset RTC */
 
   void (*reset)(struct nrf53_radioi8_dev_s *dev);
+
+  /* Time in us since the superframe start, false if not synchronized */
+
+  bool (*elapsed)(struct nrf53_radioi8_dev_s *dev, uint32_t *us);
 };
 
 /* RTC interface */
@@ -88,15 +101,24 @@ struct nrf53_radioi8_rtc_s
 
   struct nrf53_radioi8_rtc_ops_s *ops;
 
-#ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
   /* For deferring inactive state work to the work queue */
 
   struct work_s inactive_work;
 
+  /* Superframe timings in us */
+
+  uint64_t sf_start;            /* Start of the current superframe */
+  uint64_t evt_time;            /* Time of the scheduled event */
+  uint32_t bi;                  /* Beacon interval */
+  uint32_t sd;                  /* Superframe duration */
+  uint32_t cap;                 /* End of the CAP */
+  uint32_t capstart;            /* Start of the CAP, after the beacon IFS */
+
   /* RTC state */
 
-  uint32_t rtc_timeslot;
-#endif
+  uint32_t ovf;                 /* Counter overflows */
+  uint8_t  evt;                 /* Scheduled event */
+  bool     running;             /* Superframe timing valid */
 };
 
 /****************************************************************************
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_trace.c 
b/arch/arm/src/nrf53/nrf53_ieee802154_trace.c
index 55eed55fd46..7160cc2ee50 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_trace.c
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_trace.c
@@ -57,8 +57,6 @@ static const char *g_radio_trace_str[] =
   "TIM IRQ: TIM WAIT ACK",
   "TIM IRQ: TIM CSMA DELAY",
   "RTC IRQ: RTC SD",
-  "RTC IRQ: RTC CAP",
-  "RTC IRQ: RTC TIMESLOT",
   "RTC IRQ: RTC BI",
 
   "WORK: RX",
@@ -78,6 +76,7 @@ static const char *g_radio_trace_str[] =
   "NOACK",
   "DROPFRAME",
   "TXTRYAGAIN",
+  "SFSYNC",
 };
 
 /* Trace data */
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_trace.h 
b/arch/arm/src/nrf53/nrf53_ieee802154_trace.h
index 5eb5bf77808..439c7b0ed50 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_trace.h
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_trace.h
@@ -68,8 +68,6 @@ enum radio_trace_type_e
   RADIO_TRACE_IRQ_TIMWAITACK,
   RADIO_TRACE_IRQ_TIMCSMADELAY,
   RADIO_TRACE_IRQ_RTCSD,
-  RADIO_TRACE_IRQ_RTCCAP,
-  RADIO_TRACE_IRQ_RTCTIMESLOT,
   RADIO_TRACE_IRQ_RTCBI,
 
   /* Works */
@@ -93,6 +91,7 @@ enum radio_trace_type_e
   RADIO_TRACE_NOACK,
   RADIO_TRACE_DROPFRAME,
   RADIO_TRACE_TXRETRY,
+  RADIO_TRACE_SFSYNC,
 };
 
 /****************************************************************************

Reply via email to