mirror of
https://github.com/apache/nuttx.git
synced 2026-09-11 13:16:33 +00:00
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 <dahl.jakejacob@gmail.com>
This commit is contained in:
parent
80d432051a
commit
e6696d5d27
1 changed files with 53 additions and 36 deletions
|
|
@ -516,6 +516,50 @@ static void imxrt_reset(struct imxrt_driver_s *priv);
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Function: imxrt_txmb_next
|
||||
*
|
||||
* Description:
|
||||
* 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:
|
||||
* The mailbox index to use, or TOTALMBCOUNT if none is available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t imxrt_txmb_next(struct imxrt_driver_s *priv)
|
||||
{
|
||||
uint32_t mbi = RXMBCOUNT + 1;
|
||||
uint32_t next = RXMBCOUNT + 1;
|
||||
|
||||
while (mbi < TOTALMBCOUNT)
|
||||
{
|
||||
struct mb_s *mb = flexcan_get_mb(priv, mbi);
|
||||
if (mb->cs.code == CAN_TXMB_DATAORREMOTE)
|
||||
{
|
||||
next = mbi + 1;
|
||||
}
|
||||
|
||||
mbi++;
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: imxrt_txringfull
|
||||
*
|
||||
|
|
@ -533,21 +577,7 @@ static void imxrt_reset(struct imxrt_driver_s *priv);
|
|||
|
||||
static bool imxrt_txringfull(struct imxrt_driver_s *priv)
|
||||
{
|
||||
uint32_t mbi = RXMBCOUNT + 1;
|
||||
struct mb_s *mb;
|
||||
|
||||
while (mbi < TOTALMBCOUNT)
|
||||
{
|
||||
mb = flexcan_get_mb(priv, mbi);
|
||||
if (mb->cs.code != CAN_TXMB_DATAORREMOTE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
mbi++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
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;
|
||||
mbi = imxrt_txmb_next(priv);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue