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 e6696d5d27e1006b6ec68e28bef08ec25a60d4f1
Author: Jacob Dahl <[email protected]>
AuthorDate: Mon Aug 24 11:30:48 2026 -0600

    arch/arm/src/imxrt: Keep FlexCAN TX mailbox allocation in order.
    
    imxrt_transmit() handed out the lowest free TX mailbox. FlexCAN breaks an
    arbitration tie between mailboxes holding equal CAN IDs by taking the lowest
    mailbox number, so refilling a just-drained low mailbox while older frames
    are still pending in higher ones puts the newer frame on the wire first.
    imxrt_txdone_work() re-polls after each individual TX completion, which is
    exactly the condition that triggers it.
    
    Every frame of a multi-frame transport transfer carries the same CAN ID, so
    this reorders transfers. On a DroneCAN bus the receiver sees a broken toggle
    bit and discards the transfer: measured on the wire, a 6-frame message from
    an i.MX RT1176 failed 82% of the time, while a node on the same bus running
    a different controller was flawless over the same capture.
    
    Hand out a mailbox above every pending one instead, and wrap back to the
    bottom only once the ring has drained. Ordering then holds for any transfer
    length; the cost is that the ring stalls at a wrap rather than refilling
    immediately.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Jacob Dahl <[email protected]>
---
 arch/arm/src/imxrt/imxrt_flexcan.c | 81 +++++++++++++++++++++++---------------
 1 file changed, 49 insertions(+), 32 deletions(-)

diff --git a/arch/arm/src/imxrt/imxrt_flexcan.c 
b/arch/arm/src/imxrt/imxrt_flexcan.c
index db50f66e90d..a6b7ff22bf1 100644
--- a/arch/arm/src/imxrt/imxrt_flexcan.c
+++ b/arch/arm/src/imxrt/imxrt_flexcan.c
@@ -517,37 +517,67 @@ static void imxrt_reset(struct imxrt_driver_s *priv);
  ****************************************************************************/
 
 /****************************************************************************
- * Function: imxrt_txringfull
+ * Function: imxrt_txmb_next
  *
  * Description:
- *   Check if all of the TX descriptors are in use.
+ *   Pick the mailbox to load the next frame into.
+ *
+ *   Every frame of a multi-frame transport transfer carries the same CAN
+ *   ID, and FlexCAN breaks an arbitration tie between mailboxes holding
+ *   equal IDs by taking the lowest mailbox number.  Handing out the
+ *   lowest *free* mailbox therefore lets a frame loaded into a
+ *   just-drained low mailbox win arbitration against older frames still
+ *   pending in higher ones, and the receiver sees the transfer out of
+ *   order.
+ *
+ *   Only ever hand out a mailbox above every pending one, and wrap back to
+ *   the bottom once the ring has drained.
  *
  * Input Parameters:
  *   priv  - Reference to the driver state structure
  *
  * Returned Value:
- *   true is the TX ring is full; false if there are free slots at the
- *   head index.
+ *   The mailbox index to use, or TOTALMBCOUNT if none is available.
  *
  ****************************************************************************/
 
-static bool imxrt_txringfull(struct imxrt_driver_s *priv)
+static uint32_t imxrt_txmb_next(struct imxrt_driver_s *priv)
 {
-  uint32_t mbi = RXMBCOUNT + 1;
-  struct mb_s *mb;
+  uint32_t mbi  = RXMBCOUNT + 1;
+  uint32_t next = RXMBCOUNT + 1;
 
   while (mbi < TOTALMBCOUNT)
     {
-      mb = flexcan_get_mb(priv, mbi);
-      if (mb->cs.code != CAN_TXMB_DATAORREMOTE)
+      struct mb_s *mb = flexcan_get_mb(priv, mbi);
+      if (mb->cs.code == CAN_TXMB_DATAORREMOTE)
         {
-          return 0;
+          next = mbi + 1;
         }
 
       mbi++;
     }
 
-  return 1;
+  return next;
+}
+
+/****************************************************************************
+ * Function: imxrt_txringfull
+ *
+ * Description:
+ *   Check if all of the TX descriptors are in use.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   true is the TX ring is full; false if there are free slots at the
+ *   head index.
+ *
+ ****************************************************************************/
+
+static bool imxrt_txringfull(struct imxrt_driver_s *priv)
+{
+  return imxrt_txmb_next(priv) >= TOTALMBCOUNT;
 }
 
 /****************************************************************************
@@ -586,34 +616,21 @@ static int imxrt_transmit(struct imxrt_driver_s *priv)
   uint32_t txmb = 0;
 #endif
 
-  mbi = RXMBCOUNT + 1;
-  mb_bit = 1 << mbi;
-
-  while (mbi < TOTALMBCOUNT)
-    {
-      /* Check whether message buffer is not currently transmitting */
-
-      struct mb_s *mb = flexcan_get_mb(priv, mbi);
-      if (mb->cs.code != CAN_TXMB_DATAORREMOTE)
-        {
-          putreg32(mb_bit, priv->base + IMXRT_CAN_IFLAG1_OFFSET);
-          break;
-        }
-
-      mb_bit <<= 1;
-      mbi++;
-#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
-      txmb++;
-#endif
-    }
+  mbi = imxrt_txmb_next(priv);
 
-  if (mbi == TOTALMBCOUNT)
+  if (mbi >= TOTALMBCOUNT)
     {
       nwarn("No TX MB available mbi %" PRIi32 "\n", mbi);
       NETDEV_TXERRORS(&priv->dev);
       return 0;       /* No transmission for you! */
     }
 
+  mb_bit = 1 << mbi;
+  putreg32(mb_bit, priv->base + IMXRT_CAN_IFLAG1_OFFSET);
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  txmb = mbi - (RXMBCOUNT + 1);
+#endif
+
 #ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
   struct timespec ts;
   clock_systime_timespec(&ts);

Reply via email to