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);
