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 3ecb65006895bf70a70da3f681a0ccdab57f82d6
Author: raiden00pl <[email protected]>
AuthorDate: Thu Oct 22 15:38:54 2026 +0200

    arch/arm/nrf52,nrf53,nrf54l: start the next IEEE 802.15.4 frame from one 
place
    
    The delayed TX, the CSMA poll, the ACK TX done, the TX done and the
    missing ACK each decided on their own when a waiting frame could start,
    and disagreed: a CSMA frame deferred by an ACK TX stayed deferred when a
    delayed TX took the radio first, and a retry after a missing ACK
    disabled the radio while it transmitted an ACK. One txnext() starts the
    waiting delayed TX, else the waiting CSMA TX, else restores RX, once no
    frame, ACK TX, energy detection or CSMA backoff owns the radio.
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <[email protected]>
---
 arch/arm/src/nrf52/nrf52_ieee802154.c         |  55 +-------
 arch/arm/src/nrf52/nrf52_ieee802154_priv.h    |   6 +-
 arch/arm/src/nrf52/nrf52_ieee802154_radio.c   | 190 +++++++++++++-------------
 arch/arm/src/nrf52/nrf52_ieee802154_radio.h   |   4 +
 arch/arm/src/nrf53/nrf53_ieee802154.c         |  55 +-------
 arch/arm/src/nrf53/nrf53_ieee802154_priv.h    |   6 +-
 arch/arm/src/nrf53/nrf53_ieee802154_radio.c   | 190 +++++++++++++-------------
 arch/arm/src/nrf53/nrf53_ieee802154_radio.h   |   4 +
 arch/arm/src/nrf54l/nrf54l_ieee802154.c       |  55 +-------
 arch/arm/src/nrf54l/nrf54l_ieee802154_priv.h  |   6 +-
 arch/arm/src/nrf54l/nrf54l_ieee802154_radio.c | 190 +++++++++++++-------------
 arch/arm/src/nrf54l/nrf54l_ieee802154_radio.h |   4 +
 12 files changed, 333 insertions(+), 432 deletions(-)

diff --git a/arch/arm/src/nrf52/nrf52_ieee802154.c 
b/arch/arm/src/nrf52/nrf52_ieee802154.c
index 4c5e6934bd5..c79dc69ffac 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154.c
@@ -593,7 +593,6 @@ static int nrf52_radioi8_txdelayed(struct 
ieee802154_radio_s *radio,
                                    uint32_t symboldelay)
 {
   struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)radio;
-  irqstate_t                  flags;
   int                         ret = OK;
 
   /* Get exclusive access to the radio device */
@@ -606,57 +605,17 @@ static int nrf52_radioi8_txdelayed(struct 
ieee802154_radio_s *radio,
 
   /* There should never be more than one of these transactions at once. */
 
-  DEBUGASSERT(!dev->state.txdelayed_busy && !dev->state.txdelayed_pending);
-
-  dev->state.txdelayed_desc = txdesc;
-
-  /* The radio sends one frame at a time, start this transaction when the
-   * CSMA transaction is done.
-   */
-
-  if (dev->radio->state.csma_busy)
-    {
-      dev->state.txdelayed_pending = true;
-      dev->state.txdelayed_delay   = symboldelay;
-      goto out;
-    }
-
-  /* Not interrupted by the ACK TX interrupt that starts a busy transaction */
-
-  flags = enter_critical_section();
-
-  dev->state.txdelayed_busy = true;
-
-  /* Wait for ACKTX done - we start transmission in
-   * nrf52_radioi8_state_acktx()
-   */
-
-  if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX)
-    {
-      leave_critical_section(flags);
-      goto out;
-    }
+  DEBUGASSERT(!dev->state.txdelayed_busy);
 
-  /* Setup TX */
+  dev->state.txdelayed_desc    = txdesc;
+  dev->state.txdelayed_delay   = symboldelay;
+  dev->state.txdelayed_busy    = true;
+  dev->state.txdelayed_pending = true;
 
-  dev->radio->ops->norm_setup(dev, txdesc->frame, false);
+  /* Sent once the radio is free */
 
-  if (symboldelay == 0)
-    {
-      /* Send now */
-
-      dev->radio->ops->norm_trigger(dev);
-    }
-  else
-    {
-      /* Run TIMER - TX is handled in timer isr */
-
-      dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY, symboldelay);
-    }
-
-  leave_critical_section(flags);
+  dev->radio->ops->txnext(dev, 0);
 
-out:
   nxmutex_unlock(&dev->lock);
   return OK;
 }
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_priv.h 
b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
index 9aadc2598a9..8af61b306df 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
@@ -95,9 +95,9 @@ struct nrf52_radioi8_state_s
 
   /* TX state */
 
-  bool     txdelayed_busy;      /* No CSMA transfer */
-  bool     txdelayed_pending;   /* No CSMA transfer waits for CSMA */
-  bool     csma_pending;        /* CSMA transfer waits for ACK TX */
+  bool     txdelayed_busy;      /* No CSMA transfer owned by the radio */
+  bool     txdelayed_pending;   /* No CSMA transfer not started yet */
+  bool     csma_pending;        /* CSMA transfer not started yet */
   uint32_t txdelayed_delay;     /* Delay of the pending no CSMA transfer */
 
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c 
b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
index 2ca5e9401d4..d4b025f4d2a 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
@@ -200,6 +200,8 @@ static int nrf52_radioi8_gtspoll(struct nrf52_radioi8_dev_s 
*dev);
 
 /* Interrupts logic */
 
+static void nrf52_radioi8_txnext(struct nrf52_radioi8_dev_s *dev,
+                                 uint32_t mindelay);
 static void nrf52_radioi8_work_noack(void *arg);
 static void nrf52_radioi8_work_rx(void *arg);
 static void nrf52_radioi8_work_tx(void *arg);
@@ -247,6 +249,7 @@ static struct nrf52_radioi8_radio_ops_s g_radioi8_radio_ops 
=
   .setcca       = nrf52_radioi8_setcca,
   .norm_setup   = nrf52_radioi8_norm_setup,
   .norm_trigger = nrf52_radioi8_norm_trigger,
+  .txnext       = nrf52_radioi8_txnext,
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
   .beacon_setup = nrf52_radioi8_beacon_setup,
   .beacon_tx    = nrf52_radioi8_beacon_tx,
@@ -1271,10 +1274,10 @@ errout:
 }
 
 /****************************************************************************
- * Name: nrf52_radioi8_dopoll_csma
+ * Name: nrf52_radioi8_rxrestore
  *
  * Description:
- *   Out-of-sequence TX poll.
+ *   Enable RX if the radio is idle.
  *
  ****************************************************************************/
 
@@ -1288,48 +1291,87 @@ static void nrf52_radioi8_rxrestore(struct 
nrf52_radioi8_dev_s *dev)
     }
 }
 
-static void nrf52_radioi8_txpending(struct nrf52_radioi8_dev_s *dev)
+/****************************************************************************
+ * Name: nrf52_radioi8_txnext
+ *
+ * Description:
+ *   Start the next frame if the radio is free: the delayed TX that waits,
+ *   else the CSMA TX that waits, else restore RX.  mindelay is the IFS a
+ *   delayed TX keeps after the ACK TX that deferred it.
+ *
+ ****************************************************************************/
+
+static void nrf52_radioi8_txnext(struct nrf52_radioi8_dev_s *dev,
+                                 uint32_t mindelay)
 {
   irqstate_t flags;
+  uint32_t   delay;
 
-  /* Start the no CSMA transaction that waited for the CSMA transaction */
-
-  if (dev->state.txdelayed_pending)
-    {
-      flags = enter_critical_section();
+  flags = enter_critical_section();
 
-      dev->state.txdelayed_pending = false;
-      dev->state.txdelayed_busy    = true;
+  /* A frame on the air, an armed frame, an ACK TX, an energy detection
+   * or a CSMA transaction between its backoffs owns the radio.
+   */
 
-      /* An ACK TX in progress starts it when done */
+  if (dev->radio->state.csma_busy ||
+      (dev->state.txdelayed_busy && !dev->state.txdelayed_pending) ||
+      (dev->radio->state.state != NRF52_RADIO_STATE_DISABLED &&
+       dev->radio->state.state != NRF52_RADIO_STATE_RX))
+    {
+      leave_critical_section(flags);
+      return;
+    }
 
-      if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX)
-        {
-          leave_critical_section(flags);
-          return;
-        }
+  /* The delayed TX first, it can be the response to a received frame */
 
+  if (dev->state.txdelayed_pending)
+    {
+      dev->state.txdelayed_pending = false;
       nrf52_radioi8_norm_setup(dev, dev->state.txdelayed_desc->frame,
                                false);
 
-      if (dev->state.txdelayed_delay == 0)
+      delay = MAX(dev->state.txdelayed_delay, mindelay);
+      if (delay == 0)
         {
           nrf52_radioi8_norm_trigger(dev);
         }
       else
         {
-          dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY,
-                               dev->state.txdelayed_delay);
+          dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY, delay);
         }
+    }
 
-      leave_critical_section(flags);
+  /* Then the CSMA TX, its backoff keeps the IFS */
+
+  else if (dev->state.csma_pending)
+    {
+      dev->state.csma_pending = false;
+      nrf52_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
+      nrf52_radioi8_norm_trigger(dev);
+    }
+
+  /* Nothing to send, restore RX */
+
+  else if (dev->radio->state.rxrestore)
+    {
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+      dev->radio->state.rxrestore = false;
     }
+
+  leave_critical_section(flags);
 }
 
+/****************************************************************************
+ * Name: nrf52_radioi8_dopoll_csma
+ *
+ * Description:
+ *   Out-of-sequence TX poll.
+ *
+ ****************************************************************************/
+
 void nrf52_radioi8_dopoll_csma(void *arg)
 {
   struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
-  irqstate_t                  flags;
   int                         len = 0;
 
   /* Get exclusive access to the driver */
@@ -1341,7 +1383,7 @@ void nrf52_radioi8_dopoll_csma(void *arg)
   /* If this a CSMA transaction and we have room in the CSMA */
 
   if (!dev->radio->state.csma_busy && !dev->state.csma_pending &&
-      !dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
+      !dev->state.txdelayed_busy)
     {
       wlinfo("Polling for frame\n");
       len = dev->radiocb->poll(dev->radiocb, false, &dev->state.csma_desc);
@@ -1350,24 +1392,8 @@ void nrf52_radioi8_dopoll_csma(void *arg)
         {
           wlinfo("Frame received. Frame length: %d\n", len);
 
-          flags = enter_critical_section();
-
-          /* An ACK TX in progress starts the transaction when done */
-
-          if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX)
-            {
-              dev->state.csma_pending = true;
-            }
-          else
-            {
-              /* Setup the CSMA transaction */
-
-              dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame,
-                                          true);
-              dev->radio->ops->norm_trigger(dev);
-            }
-
-          leave_critical_section(flags);
+          dev->state.csma_pending = true;
+          nrf52_radioi8_txnext(dev, 0);
         }
     }
 
@@ -1444,13 +1470,11 @@ static int nrf52_radioi8_gtspoll(struct 
nrf52_radioi8_dev_s *dev)
 static void nrf52_radioi8_work_noack(void *arg)
 {
   struct nrf52_radioi8_dev_s *dev   = (struct nrf52_radioi8_dev_s *)arg;
-  struct nrf52_radio_dev_s   *lower = NULL;
   struct ieee802154_txdesc_s *tx    = NULL;
   bool                       *busy  = NULL;
   bool                        csma  = false;
 
   DEBUGASSERT(dev);
-  lower = dev->radio->lower;
 
   nrf52_radioi8_trace_put(RADIO_TRACE_WORK_NOACK, 0);
 
@@ -1460,7 +1484,9 @@ static void nrf52_radioi8_work_noack(void *arg)
     {
     }
 
-  if (dev->state.txdelayed_busy)
+  /* The frame on the air, a delayed TX may still wait for the radio */
+
+  if (dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       tx   = dev->state.txdelayed_desc;
       busy = &dev->state.txdelayed_busy;
@@ -1475,18 +1501,25 @@ static void nrf52_radioi8_work_noack(void *arg)
 
   if (tx->retrycount > 0)
     {
-      /* Disable RX */
-
-      NRF52_RADIO_PUTREG(lower, NRF52_RADIO_TASKS_DISABLE_OFFSET, 1);
-
-      /* Try again, CSMA-CA starts again for each attempt */
+      /* Try again as a new transaction once the radio is free, CSMA-CA
+       * starts again for each attempt
+       */
 
       tx->retrycount -= 1;
       nrf52_radioi8_trace_put(RADIO_TRACE_TXRETRY, tx->retrycount);
-      dev->radio->state.NB = 0;
-      dev->radio->state.BE = dev->radio->state.min_be;
-      nrf52_radioi8_norm_setup(dev, tx->frame, csma);
-      nrf52_radioi8_norm_trigger(dev);
+
+      if (csma)
+        {
+          dev->radio->state.csma_busy = false;
+          dev->state.csma_pending     = true;
+        }
+      else
+        {
+          dev->state.txdelayed_pending = true;
+          dev->state.txdelayed_delay   = 0;
+        }
+
+      nrf52_radioi8_txnext(dev, 0);
       nxmutex_unlock(&dev->lock);
       return;
     }
@@ -1501,13 +1534,14 @@ static void nrf52_radioi8_work_noack(void *arg)
   if (csma)
     {
       dev->state.csma_desc = NULL;
-      nrf52_radioi8_txpending(dev);
     }
   else
     {
       dev->state.txdelayed_desc = NULL;
     }
 
+  nrf52_radioi8_txnext(dev, 0);
+
   /* Unlock the radio device and poll for the next CSMA transaction */
 
   nxmutex_unlock(&dev->lock);
@@ -1646,7 +1680,9 @@ static void nrf52_radioi8_work_tx(void *arg)
 
   status = IEEE802154_STATUS_SUCCESS;
 
-  if (dev->state.txdelayed_busy)
+  /* The frame on the air, a delayed TX may still wait for the radio */
+
+  if (dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       /* Inform the next layer of the transmission success/failure */
 
@@ -1668,9 +1704,10 @@ static void nrf52_radioi8_work_tx(void *arg)
       /* We are now done with the transaction */
 
       dev->radio->state.csma_busy = false;
-      nrf52_radioi8_txpending(dev);
     }
 
+  nrf52_radioi8_txnext(dev, 0);
+
   /* Unlock the radio device and poll for the next CSMA transaction, RX is
    * restored there if the radio is idle.
    */
@@ -1707,7 +1744,7 @@ static void nrf52_radioi8_work_busy(void *arg)
   dev->radiocb->txdone(dev->radiocb, dev->state.csma_desc);
   dev->state.csma_desc = NULL;
   dev->radio->state.csma_busy = false;
-  nrf52_radioi8_txpending(dev);
+  nrf52_radioi8_txnext(dev, 0);
 
   /* Unlock the radio device and poll for the next CSMA transaction */
 
@@ -2087,44 +2124,11 @@ static void nrf52_radioi8_state_acktx(struct 
nrf52_radioi8_dev_s *dev)
 {
   nrf52_radioi8_trace_put(RADIO_TRACE_IRQ_ACKTX, 0);
 
-  /* Handle pending TX */
+  /* Start the TX that waited for the ACK TX, after the IFS */
 
-  if (dev->state.txdelayed_busy)
-    {
-      nrf52_radioi8_norm_setup(dev,
-                               dev->state.txdelayed_desc->frame,
-                               false);
-
-      /* Send with timer to keep IFS */
-
-      if (dev->radio->state.rxlong)
-        {
-          dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY,
-                               IEEE802154_LIFS_SYMBOLS);
-        }
-      else
-        {
-          dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY,
-                               IEEE802154_SIFS_SYMBOLS);
-        }
-    }
-
-  /* Start the CSMA transaction that waited for the ACK TX */
-
-  else if (dev->state.csma_pending)
-    {
-      dev->state.csma_pending = false;
-      nrf52_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
-      nrf52_radioi8_norm_trigger(dev);
-    }
-
-  /* Restore RX */
-
-  else if (dev->radio->state.rxrestore)
-    {
-      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
-      dev->radio->state.rxrestore = false;
-    }
+  nrf52_radioi8_txnext(dev, dev->radio->state.rxlong ?
+                            IEEE802154_LIFS_SYMBOLS :
+                            IEEE802154_SIFS_SYMBOLS);
 }
 
 /****************************************************************************
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.h 
b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
index 6319dce9699..419e776043c 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.h
@@ -165,6 +165,10 @@ struct nrf52_radioi8_radio_ops_s
 
   void (*norm_trigger)(struct nrf52_radioi8_dev_s *dev);
 
+  /* Start the next frame that waits for the radio, after mindelay */
+
+  void (*txnext)(struct nrf52_radioi8_dev_s *dev, uint32_t mindelay);
+
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
   /* Setup a beacon frame transfe */
 
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154.c 
b/arch/arm/src/nrf53/nrf53_ieee802154.c
index 67afdba3009..6abb37db573 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154.c
+++ b/arch/arm/src/nrf53/nrf53_ieee802154.c
@@ -593,7 +593,6 @@ static int nrf53_radioi8_txdelayed(struct 
ieee802154_radio_s *radio,
                                    uint32_t symboldelay)
 {
   struct nrf53_radioi8_dev_s *dev = (struct nrf53_radioi8_dev_s *)radio;
-  irqstate_t                  flags;
   int                         ret = OK;
 
   /* Get exclusive access to the radio device */
@@ -606,57 +605,17 @@ static int nrf53_radioi8_txdelayed(struct 
ieee802154_radio_s *radio,
 
   /* There should never be more than one of these transactions at once. */
 
-  DEBUGASSERT(!dev->state.txdelayed_busy && !dev->state.txdelayed_pending);
-
-  dev->state.txdelayed_desc = txdesc;
-
-  /* The radio sends one frame at a time, start this transaction when the
-   * CSMA transaction is done.
-   */
-
-  if (dev->radio->state.csma_busy)
-    {
-      dev->state.txdelayed_pending = true;
-      dev->state.txdelayed_delay   = symboldelay;
-      goto out;
-    }
-
-  /* Not interrupted by the ACK TX interrupt that starts a busy transaction */
-
-  flags = enter_critical_section();
-
-  dev->state.txdelayed_busy = true;
-
-  /* Wait for ACKTX done - we start transmission in
-   * nrf53_radioi8_state_acktx()
-   */
-
-  if (dev->radio->state.state == NRF53_RADIO_STATE_ACKTX)
-    {
-      leave_critical_section(flags);
-      goto out;
-    }
+  DEBUGASSERT(!dev->state.txdelayed_busy);
 
-  /* Setup TX */
+  dev->state.txdelayed_desc    = txdesc;
+  dev->state.txdelayed_delay   = symboldelay;
+  dev->state.txdelayed_busy    = true;
+  dev->state.txdelayed_pending = true;
 
-  dev->radio->ops->norm_setup(dev, txdesc->frame, false);
+  /* Sent once the radio is free */
 
-  if (symboldelay == 0)
-    {
-      /* Send now */
-
-      dev->radio->ops->norm_trigger(dev);
-    }
-  else
-    {
-      /* Run TIMER - TX is handled in timer isr */
-
-      dev->tim->ops->setup(dev, NRF53_TIMER_CHAN_TXDELAY, symboldelay);
-    }
-
-  leave_critical_section(flags);
+  dev->radio->ops->txnext(dev, 0);
 
-out:
   nxmutex_unlock(&dev->lock);
   return OK;
 }
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_priv.h 
b/arch/arm/src/nrf53/nrf53_ieee802154_priv.h
index c745e44902d..2f13284a47a 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_priv.h
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_priv.h
@@ -95,9 +95,9 @@ struct nrf53_radioi8_state_s
 
   /* TX state */
 
-  bool     txdelayed_busy;      /* No CSMA transfer */
-  bool     txdelayed_pending;   /* No CSMA transfer waits for CSMA */
-  bool     csma_pending;        /* CSMA transfer waits for ACK TX */
+  bool     txdelayed_busy;      /* No CSMA transfer owned by the radio */
+  bool     txdelayed_pending;   /* No CSMA transfer not started yet */
+  bool     csma_pending;        /* CSMA transfer not started yet */
   uint32_t txdelayed_delay;     /* Delay of the pending no CSMA transfer */
 
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_radio.c 
b/arch/arm/src/nrf53/nrf53_ieee802154_radio.c
index 1d4595fbb95..24e153c058f 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_radio.c
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_radio.c
@@ -200,6 +200,8 @@ static int nrf53_radioi8_gtspoll(struct nrf53_radioi8_dev_s 
*dev);
 
 /* Interrupts logic */
 
+static void nrf53_radioi8_txnext(struct nrf53_radioi8_dev_s *dev,
+                                 uint32_t mindelay);
 static void nrf53_radioi8_work_noack(void *arg);
 static void nrf53_radioi8_work_rx(void *arg);
 static void nrf53_radioi8_work_tx(void *arg);
@@ -247,6 +249,7 @@ static struct nrf53_radioi8_radio_ops_s g_radioi8_radio_ops 
=
   .setcca       = nrf53_radioi8_setcca,
   .norm_setup   = nrf53_radioi8_norm_setup,
   .norm_trigger = nrf53_radioi8_norm_trigger,
+  .txnext       = nrf53_radioi8_txnext,
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
   .beacon_setup = nrf53_radioi8_beacon_setup,
   .beacon_tx    = nrf53_radioi8_beacon_tx,
@@ -1271,10 +1274,10 @@ errout:
 }
 
 /****************************************************************************
- * Name: nrf53_radioi8_dopoll_csma
+ * Name: nrf53_radioi8_rxrestore
  *
  * Description:
- *   Out-of-sequence TX poll.
+ *   Enable RX if the radio is idle.
  *
  ****************************************************************************/
 
@@ -1288,48 +1291,87 @@ static void nrf53_radioi8_rxrestore(struct 
nrf53_radioi8_dev_s *dev)
     }
 }
 
-static void nrf53_radioi8_txpending(struct nrf53_radioi8_dev_s *dev)
+/****************************************************************************
+ * Name: nrf53_radioi8_txnext
+ *
+ * Description:
+ *   Start the next frame if the radio is free: the delayed TX that waits,
+ *   else the CSMA TX that waits, else restore RX.  mindelay is the IFS a
+ *   delayed TX keeps after the ACK TX that deferred it.
+ *
+ ****************************************************************************/
+
+static void nrf53_radioi8_txnext(struct nrf53_radioi8_dev_s *dev,
+                                 uint32_t mindelay)
 {
   irqstate_t flags;
+  uint32_t   delay;
 
-  /* Start the no CSMA transaction that waited for the CSMA transaction */
-
-  if (dev->state.txdelayed_pending)
-    {
-      flags = enter_critical_section();
+  flags = enter_critical_section();
 
-      dev->state.txdelayed_pending = false;
-      dev->state.txdelayed_busy    = true;
+  /* A frame on the air, an armed frame, an ACK TX, an energy detection
+   * or a CSMA transaction between its backoffs owns the radio.
+   */
 
-      /* An ACK TX in progress starts it when done */
+  if (dev->radio->state.csma_busy ||
+      (dev->state.txdelayed_busy && !dev->state.txdelayed_pending) ||
+      (dev->radio->state.state != NRF53_RADIO_STATE_DISABLED &&
+       dev->radio->state.state != NRF53_RADIO_STATE_RX))
+    {
+      leave_critical_section(flags);
+      return;
+    }
 
-      if (dev->radio->state.state == NRF53_RADIO_STATE_ACKTX)
-        {
-          leave_critical_section(flags);
-          return;
-        }
+  /* The delayed TX first, it can be the response to a received frame */
 
+  if (dev->state.txdelayed_pending)
+    {
+      dev->state.txdelayed_pending = false;
       nrf53_radioi8_norm_setup(dev, dev->state.txdelayed_desc->frame,
                                false);
 
-      if (dev->state.txdelayed_delay == 0)
+      delay = MAX(dev->state.txdelayed_delay, mindelay);
+      if (delay == 0)
         {
           nrf53_radioi8_norm_trigger(dev);
         }
       else
         {
-          dev->tim->ops->setup(dev, NRF53_TIMER_CHAN_TXDELAY,
-                               dev->state.txdelayed_delay);
+          dev->tim->ops->setup(dev, NRF53_TIMER_CHAN_TXDELAY, delay);
         }
+    }
 
-      leave_critical_section(flags);
+  /* Then the CSMA TX, its backoff keeps the IFS */
+
+  else if (dev->state.csma_pending)
+    {
+      dev->state.csma_pending = false;
+      nrf53_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
+      nrf53_radioi8_norm_trigger(dev);
+    }
+
+  /* Nothing to send, restore RX */
+
+  else if (dev->radio->state.rxrestore)
+    {
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+      dev->radio->state.rxrestore = false;
     }
+
+  leave_critical_section(flags);
 }
 
+/****************************************************************************
+ * Name: nrf53_radioi8_dopoll_csma
+ *
+ * Description:
+ *   Out-of-sequence TX poll.
+ *
+ ****************************************************************************/
+
 void nrf53_radioi8_dopoll_csma(void *arg)
 {
   struct nrf53_radioi8_dev_s *dev = (struct nrf53_radioi8_dev_s *)arg;
-  irqstate_t                  flags;
   int                         len = 0;
 
   /* Get exclusive access to the driver */
@@ -1341,7 +1383,7 @@ void nrf53_radioi8_dopoll_csma(void *arg)
   /* If this a CSMA transaction and we have room in the CSMA */
 
   if (!dev->radio->state.csma_busy && !dev->state.csma_pending &&
-      !dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
+      !dev->state.txdelayed_busy)
     {
       wlinfo("Polling for frame\n");
       len = dev->radiocb->poll(dev->radiocb, false, &dev->state.csma_desc);
@@ -1350,24 +1392,8 @@ void nrf53_radioi8_dopoll_csma(void *arg)
         {
           wlinfo("Frame received. Frame length: %d\n", len);
 
-          flags = enter_critical_section();
-
-          /* An ACK TX in progress starts the transaction when done */
-
-          if (dev->radio->state.state == NRF53_RADIO_STATE_ACKTX)
-            {
-              dev->state.csma_pending = true;
-            }
-          else
-            {
-              /* Setup the CSMA transaction */
-
-              dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame,
-                                          true);
-              dev->radio->ops->norm_trigger(dev);
-            }
-
-          leave_critical_section(flags);
+          dev->state.csma_pending = true;
+          nrf53_radioi8_txnext(dev, 0);
         }
     }
 
@@ -1444,13 +1470,11 @@ static int nrf53_radioi8_gtspoll(struct 
nrf53_radioi8_dev_s *dev)
 static void nrf53_radioi8_work_noack(void *arg)
 {
   struct nrf53_radioi8_dev_s *dev   = (struct nrf53_radioi8_dev_s *)arg;
-  struct nrf53_radio_dev_s   *lower = NULL;
   struct ieee802154_txdesc_s *tx    = NULL;
   bool                       *busy  = NULL;
   bool                        csma  = false;
 
   DEBUGASSERT(dev);
-  lower = dev->radio->lower;
 
   nrf53_radioi8_trace_put(RADIO_TRACE_WORK_NOACK, 0);
 
@@ -1460,7 +1484,9 @@ static void nrf53_radioi8_work_noack(void *arg)
     {
     }
 
-  if (dev->state.txdelayed_busy)
+  /* The frame on the air, a delayed TX may still wait for the radio */
+
+  if (dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       tx   = dev->state.txdelayed_desc;
       busy = &dev->state.txdelayed_busy;
@@ -1475,18 +1501,25 @@ static void nrf53_radioi8_work_noack(void *arg)
 
   if (tx->retrycount > 0)
     {
-      /* Disable RX */
-
-      NRF53_RADIO_PUTREG(lower, NRF53_RADIO_TASKS_DISABLE_OFFSET, 1);
-
-      /* Try again, CSMA-CA starts again for each attempt */
+      /* Try again as a new transaction once the radio is free, CSMA-CA
+       * starts again for each attempt
+       */
 
       tx->retrycount -= 1;
       nrf53_radioi8_trace_put(RADIO_TRACE_TXRETRY, tx->retrycount);
-      dev->radio->state.NB = 0;
-      dev->radio->state.BE = dev->radio->state.min_be;
-      nrf53_radioi8_norm_setup(dev, tx->frame, csma);
-      nrf53_radioi8_norm_trigger(dev);
+
+      if (csma)
+        {
+          dev->radio->state.csma_busy = false;
+          dev->state.csma_pending     = true;
+        }
+      else
+        {
+          dev->state.txdelayed_pending = true;
+          dev->state.txdelayed_delay   = 0;
+        }
+
+      nrf53_radioi8_txnext(dev, 0);
       nxmutex_unlock(&dev->lock);
       return;
     }
@@ -1501,13 +1534,14 @@ static void nrf53_radioi8_work_noack(void *arg)
   if (csma)
     {
       dev->state.csma_desc = NULL;
-      nrf53_radioi8_txpending(dev);
     }
   else
     {
       dev->state.txdelayed_desc = NULL;
     }
 
+  nrf53_radioi8_txnext(dev, 0);
+
   /* Unlock the radio device and poll for the next CSMA transaction */
 
   nxmutex_unlock(&dev->lock);
@@ -1646,7 +1680,9 @@ static void nrf53_radioi8_work_tx(void *arg)
 
   status = IEEE802154_STATUS_SUCCESS;
 
-  if (dev->state.txdelayed_busy)
+  /* The frame on the air, a delayed TX may still wait for the radio */
+
+  if (dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       /* Inform the next layer of the transmission success/failure */
 
@@ -1668,9 +1704,10 @@ static void nrf53_radioi8_work_tx(void *arg)
       /* We are now done with the transaction */
 
       dev->radio->state.csma_busy = false;
-      nrf53_radioi8_txpending(dev);
     }
 
+  nrf53_radioi8_txnext(dev, 0);
+
   /* Unlock the radio device and poll for the next CSMA transaction, RX is
    * restored there if the radio is idle.
    */
@@ -1707,7 +1744,7 @@ static void nrf53_radioi8_work_busy(void *arg)
   dev->radiocb->txdone(dev->radiocb, dev->state.csma_desc);
   dev->state.csma_desc = NULL;
   dev->radio->state.csma_busy = false;
-  nrf53_radioi8_txpending(dev);
+  nrf53_radioi8_txnext(dev, 0);
 
   /* Unlock the radio device and poll for the next CSMA transaction */
 
@@ -2087,44 +2124,11 @@ static void nrf53_radioi8_state_acktx(struct 
nrf53_radioi8_dev_s *dev)
 {
   nrf53_radioi8_trace_put(RADIO_TRACE_IRQ_ACKTX, 0);
 
-  /* Handle pending TX */
+  /* Start the TX that waited for the ACK TX, after the IFS */
 
-  if (dev->state.txdelayed_busy)
-    {
-      nrf53_radioi8_norm_setup(dev,
-                               dev->state.txdelayed_desc->frame,
-                               false);
-
-      /* Send with timer to keep IFS */
-
-      if (dev->radio->state.rxlong)
-        {
-          dev->tim->ops->setup(dev, NRF53_TIMER_CHAN_TXDELAY,
-                               IEEE802154_LIFS_SYMBOLS);
-        }
-      else
-        {
-          dev->tim->ops->setup(dev, NRF53_TIMER_CHAN_TXDELAY,
-                               IEEE802154_SIFS_SYMBOLS);
-        }
-    }
-
-  /* Start the CSMA transaction that waited for the ACK TX */
-
-  else if (dev->state.csma_pending)
-    {
-      dev->state.csma_pending = false;
-      nrf53_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
-      nrf53_radioi8_norm_trigger(dev);
-    }
-
-  /* Restore RX */
-
-  else if (dev->radio->state.rxrestore)
-    {
-      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
-      dev->radio->state.rxrestore = false;
-    }
+  nrf53_radioi8_txnext(dev, dev->radio->state.rxlong ?
+                            IEEE802154_LIFS_SYMBOLS :
+                            IEEE802154_SIFS_SYMBOLS);
 }
 
 /****************************************************************************
diff --git a/arch/arm/src/nrf53/nrf53_ieee802154_radio.h 
b/arch/arm/src/nrf53/nrf53_ieee802154_radio.h
index 777d3fd6ec2..d6356ce2957 100644
--- a/arch/arm/src/nrf53/nrf53_ieee802154_radio.h
+++ b/arch/arm/src/nrf53/nrf53_ieee802154_radio.h
@@ -165,6 +165,10 @@ struct nrf53_radioi8_radio_ops_s
 
   void (*norm_trigger)(struct nrf53_radioi8_dev_s *dev);
 
+  /* Start the next frame that waits for the radio, after mindelay */
+
+  void (*txnext)(struct nrf53_radioi8_dev_s *dev, uint32_t mindelay);
+
 #ifdef CONFIG_NRF53_RADIO_IEEE802154_SUPERFRAME
   /* Setup a beacon frame transfe */
 
diff --git a/arch/arm/src/nrf54l/nrf54l_ieee802154.c 
b/arch/arm/src/nrf54l/nrf54l_ieee802154.c
index f163dabe3c2..b04feaa49f8 100644
--- a/arch/arm/src/nrf54l/nrf54l_ieee802154.c
+++ b/arch/arm/src/nrf54l/nrf54l_ieee802154.c
@@ -587,7 +587,6 @@ static int nrf54l_radioi8_txdelayed(struct 
ieee802154_radio_s *radio,
                                    uint32_t symboldelay)
 {
   struct nrf54l_radioi8_dev_s *dev = (struct nrf54l_radioi8_dev_s *)radio;
-  irqstate_t                  flags;
   int                         ret = OK;
 
   /* Get exclusive access to the radio device */
@@ -600,57 +599,17 @@ static int nrf54l_radioi8_txdelayed(struct 
ieee802154_radio_s *radio,
 
   /* There should never be more than one of these transactions at once. */
 
-  DEBUGASSERT(!dev->state.txdelayed_busy && !dev->state.txdelayed_pending);
+  DEBUGASSERT(!dev->state.txdelayed_busy);
 
-  dev->state.txdelayed_desc = txdesc;
+  dev->state.txdelayed_desc    = txdesc;
+  dev->state.txdelayed_delay   = symboldelay;
+  dev->state.txdelayed_busy    = true;
+  dev->state.txdelayed_pending = true;
 
-  /* The radio sends one frame at a time, start this transaction when the
-   * CSMA transaction is done.
-   */
-
-  if (dev->radio->state.csma_busy)
-    {
-      dev->state.txdelayed_pending = true;
-      dev->state.txdelayed_delay   = symboldelay;
-      goto out;
-    }
-
-  /* Not interrupted by the ACK TX interrupt that starts a busy transaction */
-
-  flags = enter_critical_section();
-
-  dev->state.txdelayed_busy = true;
-
-  /* Wait for ACKTX done - we start transmission in
-   * nrf54l_radioi8_state_acktx()
-   */
-
-  if (dev->radio->state.state == NRF54L_RADIO_STATE_ACKTX)
-    {
-      leave_critical_section(flags);
-      goto out;
-    }
-
-  /* Setup TX */
-
-  dev->radio->ops->norm_setup(dev, txdesc->frame, false);
-
-  if (symboldelay == 0)
-    {
-      /* Send now */
-
-      dev->radio->ops->norm_trigger(dev);
-    }
-  else
-    {
-      /* Run TIMER - TX is handled in timer isr */
-
-      dev->tim->ops->setup(dev, NRF54L_TIMER_CHAN_TXDELAY, symboldelay);
-    }
+  /* Sent once the radio is free */
 
-  leave_critical_section(flags);
+  dev->radio->ops->txnext(dev, 0);
 
-out:
   nxmutex_unlock(&dev->lock);
   return OK;
 }
diff --git a/arch/arm/src/nrf54l/nrf54l_ieee802154_priv.h 
b/arch/arm/src/nrf54l/nrf54l_ieee802154_priv.h
index 5b290be1f1c..8e46ec99dab 100644
--- a/arch/arm/src/nrf54l/nrf54l_ieee802154_priv.h
+++ b/arch/arm/src/nrf54l/nrf54l_ieee802154_priv.h
@@ -86,9 +86,9 @@ struct nrf54l_radioi8_state_s
 
   /* TX state */
 
-  bool     txdelayed_busy;      /* No CSMA transfer */
-  bool     txdelayed_pending;   /* No CSMA transfer waits for CSMA */
-  bool     csma_pending;        /* CSMA transfer waits for ACK TX */
+  bool     txdelayed_busy;      /* No CSMA transfer owned by the radio */
+  bool     txdelayed_pending;   /* No CSMA transfer not started yet */
+  bool     csma_pending;        /* CSMA transfer not started yet */
   uint32_t txdelayed_delay;     /* Delay of the pending no CSMA transfer */
 };
 
diff --git a/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.c 
b/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.c
index 61333dd3331..5abe1757362 100644
--- a/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.c
+++ b/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.c
@@ -189,6 +189,8 @@ static int nrf54l_radioi8_gtspoll(struct 
nrf54l_radioi8_dev_s *dev);
 
 /* Interrupts logic */
 
+static void nrf54l_radioi8_txnext(struct nrf54l_radioi8_dev_s *dev,
+                                 uint32_t mindelay);
 static void nrf54l_radioi8_work_noack(void *arg);
 static void nrf54l_radioi8_work_rx(void *arg);
 static void nrf54l_radioi8_work_tx(void *arg);
@@ -231,6 +233,7 @@ static struct nrf54l_radioi8_radio_ops_s 
g_radioi8_radio_ops =
   .setcca       = nrf54l_radioi8_setcca,
   .norm_setup   = nrf54l_radioi8_norm_setup,
   .norm_trigger = nrf54l_radioi8_norm_trigger,
+  .txnext       = nrf54l_radioi8_txnext,
   .reset        = nrf54l_radioi8_reset,
   .csma_poll    = nrf54l_radioi8_csmapoll,
   .gts_poll     = nrf54l_radioi8_gtspoll
@@ -1108,10 +1111,10 @@ errout:
 }
 
 /****************************************************************************
- * Name: nrf54l_radioi8_dopoll_csma
+ * Name: nrf54l_radioi8_rxrestore
  *
  * Description:
- *   Out-of-sequence TX poll.
+ *   Enable RX if the radio is idle.
  *
  ****************************************************************************/
 
@@ -1125,48 +1128,87 @@ static void nrf54l_radioi8_rxrestore(struct 
nrf54l_radioi8_dev_s *dev)
     }
 }
 
-static void nrf54l_radioi8_txpending(struct nrf54l_radioi8_dev_s *dev)
+/****************************************************************************
+ * Name: nrf54l_radioi8_txnext
+ *
+ * Description:
+ *   Start the next frame if the radio is free: the delayed TX that waits,
+ *   else the CSMA TX that waits, else restore RX.  mindelay is the IFS a
+ *   delayed TX keeps after the ACK TX that deferred it.
+ *
+ ****************************************************************************/
+
+static void nrf54l_radioi8_txnext(struct nrf54l_radioi8_dev_s *dev,
+                                 uint32_t mindelay)
 {
   irqstate_t flags;
+  uint32_t   delay;
 
-  /* Start the no CSMA transaction that waited for the CSMA transaction */
-
-  if (dev->state.txdelayed_pending)
-    {
-      flags = enter_critical_section();
+  flags = enter_critical_section();
 
-      dev->state.txdelayed_pending = false;
-      dev->state.txdelayed_busy    = true;
+  /* A frame on the air, an armed frame, an ACK TX, an energy detection
+   * or a CSMA transaction between its backoffs owns the radio.
+   */
 
-      /* An ACK TX in progress starts it when done */
+  if (dev->radio->state.csma_busy ||
+      (dev->state.txdelayed_busy && !dev->state.txdelayed_pending) ||
+      (dev->radio->state.state != NRF54L_RADIO_STATE_DISABLED &&
+       dev->radio->state.state != NRF54L_RADIO_STATE_RX))
+    {
+      leave_critical_section(flags);
+      return;
+    }
 
-      if (dev->radio->state.state == NRF54L_RADIO_STATE_ACKTX)
-        {
-          leave_critical_section(flags);
-          return;
-        }
+  /* The delayed TX first, it can be the response to a received frame */
 
+  if (dev->state.txdelayed_pending)
+    {
+      dev->state.txdelayed_pending = false;
       nrf54l_radioi8_norm_setup(dev, dev->state.txdelayed_desc->frame,
                                false);
 
-      if (dev->state.txdelayed_delay == 0)
+      delay = MAX(dev->state.txdelayed_delay, mindelay);
+      if (delay == 0)
         {
           nrf54l_radioi8_norm_trigger(dev);
         }
       else
         {
-          dev->tim->ops->setup(dev, NRF54L_TIMER_CHAN_TXDELAY,
-                               dev->state.txdelayed_delay);
+          dev->tim->ops->setup(dev, NRF54L_TIMER_CHAN_TXDELAY, delay);
         }
+    }
 
-      leave_critical_section(flags);
+  /* Then the CSMA TX, its backoff keeps the IFS */
+
+  else if (dev->state.csma_pending)
+    {
+      dev->state.csma_pending = false;
+      nrf54l_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
+      nrf54l_radioi8_norm_trigger(dev);
+    }
+
+  /* Nothing to send, restore RX */
+
+  else if (dev->radio->state.rxrestore)
+    {
+      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
+      dev->radio->state.rxrestore = false;
     }
+
+  leave_critical_section(flags);
 }
 
+/****************************************************************************
+ * Name: nrf54l_radioi8_dopoll_csma
+ *
+ * Description:
+ *   Out-of-sequence TX poll.
+ *
+ ****************************************************************************/
+
 void nrf54l_radioi8_dopoll_csma(void *arg)
 {
   struct nrf54l_radioi8_dev_s *dev = (struct nrf54l_radioi8_dev_s *)arg;
-  irqstate_t                  flags;
   int                         len = 0;
 
   /* Get exclusive access to the driver */
@@ -1178,7 +1220,7 @@ void nrf54l_radioi8_dopoll_csma(void *arg)
   /* If this a CSMA transaction and we have room in the CSMA */
 
   if (!dev->radio->state.csma_busy && !dev->state.csma_pending &&
-      !dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
+      !dev->state.txdelayed_busy)
     {
       wlinfo("Polling for frame\n");
       len = dev->radiocb->poll(dev->radiocb, false, &dev->state.csma_desc);
@@ -1187,24 +1229,8 @@ void nrf54l_radioi8_dopoll_csma(void *arg)
         {
           wlinfo("Frame received. Frame length: %d\n", len);
 
-          flags = enter_critical_section();
-
-          /* An ACK TX in progress starts the transaction when done */
-
-          if (dev->radio->state.state == NRF54L_RADIO_STATE_ACKTX)
-            {
-              dev->state.csma_pending = true;
-            }
-          else
-            {
-              /* Setup the CSMA transaction */
-
-              dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame,
-                                          true);
-              dev->radio->ops->norm_trigger(dev);
-            }
-
-          leave_critical_section(flags);
+          dev->state.csma_pending = true;
+          nrf54l_radioi8_txnext(dev, 0);
         }
     }
 
@@ -1264,13 +1290,11 @@ static int nrf54l_radioi8_gtspoll(struct 
nrf54l_radioi8_dev_s *dev)
 static void nrf54l_radioi8_work_noack(void *arg)
 {
   struct nrf54l_radioi8_dev_s *dev   = (struct nrf54l_radioi8_dev_s *)arg;
-  struct nrf54l_radio_dev_s   *lower = NULL;
   struct ieee802154_txdesc_s *tx    = NULL;
   bool                       *busy  = NULL;
   bool                        csma  = false;
 
   DEBUGASSERT(dev);
-  lower = dev->radio->lower;
 
   nrf54l_radioi8_trace_put(RADIO_TRACE_WORK_NOACK, 0);
 
@@ -1280,7 +1304,9 @@ static void nrf54l_radioi8_work_noack(void *arg)
     {
     }
 
-  if (dev->state.txdelayed_busy)
+  /* The frame on the air, a delayed TX may still wait for the radio */
+
+  if (dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       tx   = dev->state.txdelayed_desc;
       busy = &dev->state.txdelayed_busy;
@@ -1295,18 +1321,25 @@ static void nrf54l_radioi8_work_noack(void *arg)
 
   if (tx->retrycount > 0)
     {
-      /* Disable RX */
-
-      NRF54L_RADIO_PUTREG(lower, NRF54L_RADIO_TASKS_DISABLE_OFFSET, 1);
-
-      /* Try again, CSMA-CA starts again for each attempt */
+      /* Try again as a new transaction once the radio is free, CSMA-CA
+       * starts again for each attempt
+       */
 
       tx->retrycount -= 1;
       nrf54l_radioi8_trace_put(RADIO_TRACE_TXRETRY, tx->retrycount);
-      dev->radio->state.NB = 0;
-      dev->radio->state.BE = dev->radio->state.min_be;
-      nrf54l_radioi8_norm_setup(dev, tx->frame, csma);
-      nrf54l_radioi8_norm_trigger(dev);
+
+      if (csma)
+        {
+          dev->radio->state.csma_busy = false;
+          dev->state.csma_pending     = true;
+        }
+      else
+        {
+          dev->state.txdelayed_pending = true;
+          dev->state.txdelayed_delay   = 0;
+        }
+
+      nrf54l_radioi8_txnext(dev, 0);
       nxmutex_unlock(&dev->lock);
       return;
     }
@@ -1321,13 +1354,14 @@ static void nrf54l_radioi8_work_noack(void *arg)
   if (csma)
     {
       dev->state.csma_desc = NULL;
-      nrf54l_radioi8_txpending(dev);
     }
   else
     {
       dev->state.txdelayed_desc = NULL;
     }
 
+  nrf54l_radioi8_txnext(dev, 0);
+
   /* Unlock the radio device and poll for the next CSMA transaction */
 
   nxmutex_unlock(&dev->lock);
@@ -1466,7 +1500,9 @@ static void nrf54l_radioi8_work_tx(void *arg)
 
   status = IEEE802154_STATUS_SUCCESS;
 
-  if (dev->state.txdelayed_busy)
+  /* The frame on the air, a delayed TX may still wait for the radio */
+
+  if (dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       /* Inform the next layer of the transmission success/failure */
 
@@ -1488,9 +1524,10 @@ static void nrf54l_radioi8_work_tx(void *arg)
       /* We are now done with the transaction */
 
       dev->radio->state.csma_busy = false;
-      nrf54l_radioi8_txpending(dev);
     }
 
+  nrf54l_radioi8_txnext(dev, 0);
+
   /* Unlock the radio device and poll for the next CSMA transaction, RX is
    * restored there if the radio is idle.
    */
@@ -1527,7 +1564,7 @@ static void nrf54l_radioi8_work_busy(void *arg)
   dev->radiocb->txdone(dev->radiocb, dev->state.csma_desc);
   dev->state.csma_desc = NULL;
   dev->radio->state.csma_busy = false;
-  nrf54l_radioi8_txpending(dev);
+  nrf54l_radioi8_txnext(dev, 0);
 
   /* Unlock the radio device and poll for the next CSMA transaction */
 
@@ -1836,44 +1873,11 @@ static void nrf54l_radioi8_state_acktx(struct 
nrf54l_radioi8_dev_s *dev)
 {
   nrf54l_radioi8_trace_put(RADIO_TRACE_IRQ_ACKTX, 0);
 
-  /* Handle pending TX */
+  /* Start the TX that waited for the ACK TX, after the IFS */
 
-  if (dev->state.txdelayed_busy)
-    {
-      nrf54l_radioi8_norm_setup(dev,
-                               dev->state.txdelayed_desc->frame,
-                               false);
-
-      /* Send with timer to keep IFS */
-
-      if (dev->radio->state.rxlong)
-        {
-          dev->tim->ops->setup(dev, NRF54L_TIMER_CHAN_TXDELAY,
-                               IEEE802154_LIFS_SYMBOLS);
-        }
-      else
-        {
-          dev->tim->ops->setup(dev, NRF54L_TIMER_CHAN_TXDELAY,
-                               IEEE802154_SIFS_SYMBOLS);
-        }
-    }
-
-  /* Start the CSMA transaction that waited for the ACK TX */
-
-  else if (dev->state.csma_pending)
-    {
-      dev->state.csma_pending = false;
-      nrf54l_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
-      nrf54l_radioi8_norm_trigger(dev);
-    }
-
-  /* Restore RX */
-
-  else if (dev->radio->state.rxrestore)
-    {
-      dev->macops.rxenable((struct ieee802154_radio_s *)dev, true);
-      dev->radio->state.rxrestore = false;
-    }
+  nrf54l_radioi8_txnext(dev, dev->radio->state.rxlong ?
+                            IEEE802154_LIFS_SYMBOLS :
+                            IEEE802154_SIFS_SYMBOLS);
 }
 
 /****************************************************************************
diff --git a/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.h 
b/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.h
index 71172475c49..9dddfcabf76 100644
--- a/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.h
+++ b/arch/arm/src/nrf54l/nrf54l_ieee802154_radio.h
@@ -158,6 +158,10 @@ struct nrf54l_radioi8_radio_ops_s
 
   void (*norm_trigger)(struct nrf54l_radioi8_dev_s *dev);
 
+  /* Start the next frame that waits for the radio, after mindelay */
+
+  void (*txnext)(struct nrf54l_radioi8_dev_s *dev, uint32_t mindelay);
+
   /* Reset radio state to work with IEEE 802.15.4 */
 
   int (*reset)(struct nrf54l_radioi8_radio_s *dev);

Reply via email to