[imxrt] Fix FlexCAN tx dropping frames

This commit is contained in:
Peter van der Perk 2021-02-02 15:21:56 +01:00 committed by Alan Carvalho de Assis
parent 5447f28742
commit 22437698f1
2 changed files with 76 additions and 19 deletions

View File

@ -78,8 +78,8 @@
#define FLAGEFF (1 << 31) /* Extended frame format */ #define FLAGEFF (1 << 31) /* Extended frame format */
#define FLAGRTR (1 << 30) /* Remote transmission request */ #define FLAGRTR (1 << 30) /* Remote transmission request */
#define RXMBCOUNT 5 #define RXMBCOUNT 10
#define TXMBCOUNT 2 #define TXMBCOUNT 4
#define TOTALMBCOUNT RXMBCOUNT + TXMBCOUNT #define TOTALMBCOUNT RXMBCOUNT + TXMBCOUNT
#define IFLAG1_RX ((1 << RXMBCOUNT)-1) #define IFLAG1_RX ((1 << RXMBCOUNT)-1)
@ -473,12 +473,16 @@ static void imxrt_setfreeze(uint32_t base, uint32_t freeze);
static uint32_t imxrt_waitmcr_change(uint32_t base, static uint32_t imxrt_waitmcr_change(uint32_t base,
uint32_t mask, uint32_t mask,
uint32_t target_state); uint32_t target_state);
static uint32_t imxrt_waitesr2_change(uint32_t base,
uint32_t mask,
uint32_t target_state);
/* Interrupt handling */ /* Interrupt handling */
static void imxrt_receive(FAR struct imxrt_driver_s *priv, static void imxrt_receive(FAR struct imxrt_driver_s *priv,
uint32_t flags); uint32_t flags);
static void imxrt_txdone(FAR void *arg); static void imxrt_txdone_work(FAR void *arg);
static void imxrt_txdone(FAR struct imxrt_driver_s *priv);
static int imxrt_flexcan_interrupt(int irq, FAR void *context, static int imxrt_flexcan_interrupt(int irq, FAR void *context,
FAR void *arg); FAR void *arg);
@ -604,6 +608,7 @@ static int imxrt_transmit(FAR struct imxrt_driver_s *priv)
if (mbi == TXMBCOUNT) if (mbi == TXMBCOUNT)
{ {
nwarn("No TX MB available mbi %" PRIi32 "\r\n", mbi); nwarn("No TX MB available mbi %" PRIi32 "\r\n", mbi);
NETDEV_TXERRORS(&priv->dev);
return 0; /* No transmission for you! */ return 0; /* No transmission for you! */
} }
@ -764,6 +769,8 @@ static int imxrt_txpoll(struct net_driver_s *dev)
{ {
if (!devif_loopback(&priv->dev)) if (!devif_loopback(&priv->dev))
{ {
imxrt_txdone(priv);
/* Send the packet */ /* Send the packet */
imxrt_transmit(priv); imxrt_transmit(priv);
@ -772,9 +779,14 @@ static int imxrt_txpoll(struct net_driver_s *dev)
* not, return a non-zero value to terminate the poll. * not, return a non-zero value to terminate the poll.
*/ */
if (imxrt_txringfull(priv)) if ((getreg32(priv->base + IMXRT_CAN_ESR2_OFFSET) &
(CAN_ESR2_IMB | CAN_ESR2_VPS)) ==
(CAN_ESR2_IMB | CAN_ESR2_VPS))
{ {
return -EBUSY; if (!imxrt_txringfull(priv))
{
return -EBUSY;
}
} }
} }
} }
@ -929,23 +941,18 @@ static void imxrt_receive(FAR struct imxrt_driver_s *priv,
* Function: imxrt_txdone * Function: imxrt_txdone
* *
* Description: * Description:
* An interrupt was received indicating that the last TX packet(s) is done * Check transmit interrupt flags and clear them
* *
* Input Parameters: * Input Parameters:
* priv - Reference to the driver state structure * priv - Reference to the driver state structure
* *
* Returned Value: * Returned Value:
* None * None.
*
* Assumptions:
* Global interrupts are disabled by the watchdog logic.
* We are not in an interrupt context so that we can lock the network.
* *
****************************************************************************/ ****************************************************************************/
static void imxrt_txdone(FAR void *arg) static void imxrt_txdone(FAR struct imxrt_driver_s *priv)
{ {
FAR struct imxrt_driver_s *priv = (FAR struct imxrt_driver_s *)arg;
uint32_t flags; uint32_t flags;
uint32_t mbi; uint32_t mbi;
uint32_t mb_bit; uint32_t mb_bit;
@ -976,13 +983,38 @@ static void imxrt_txdone(FAR void *arg)
mb_bit <<= 1; mb_bit <<= 1;
} }
}
/****************************************************************************
* Function: imxrt_txdone_work
*
* Description:
* An interrupt was received indicating that the last TX packet(s) is done
*
* Input Parameters:
* priv - Reference to the driver state structure
*
* Returned Value:
* None
*
* Assumptions:
* Global interrupts are disabled by the watchdog logic.
* We are not in an interrupt context so that we can lock the network.
*
****************************************************************************/
static void imxrt_txdone_work(FAR void *arg)
{
FAR struct imxrt_driver_s *priv = (FAR struct imxrt_driver_s *)arg;
imxrt_txdone(priv);
/* There should be space for a new TX in any event. Poll the network for /* There should be space for a new TX in any event. Poll the network for
* new XMIT data * new XMIT data
*/ */
net_lock(); net_lock();
devif_poll(&priv->dev, imxrt_txpoll); devif_timer(&priv->dev, 0, imxrt_txpoll);
net_unlock(); net_unlock();
} }
@ -1038,7 +1070,7 @@ static int imxrt_flexcan_interrupt(int irq, FAR void *context,
flags = getreg32(priv->base + IMXRT_CAN_IMASK1_OFFSET); flags = getreg32(priv->base + IMXRT_CAN_IMASK1_OFFSET);
flags &= ~(IFLAG1_TX); flags &= ~(IFLAG1_TX);
putreg32(flags, priv->base + IMXRT_CAN_IMASK1_OFFSET); putreg32(flags, priv->base + IMXRT_CAN_IMASK1_OFFSET);
work_queue(CANWORK, &priv->irqwork, imxrt_txdone, priv, 0); work_queue(CANWORK, &priv->irqwork, imxrt_txdone_work, priv, 0);
} }
} }
@ -1189,6 +1221,26 @@ static uint32_t imxrt_waitfreezeack_change(uint32_t base,
return imxrt_waitmcr_change(base, CAN_MCR_FRZACK, target_state); return imxrt_waitmcr_change(base, CAN_MCR_FRZACK, target_state);
} }
static uint32_t imxrt_waitesr2_change(uint32_t base, uint32_t mask,
uint32_t target_state)
{
const uint32_t timeout = 1000;
uint32_t wait_ack;
for (wait_ack = 0; wait_ack < timeout; wait_ack++)
{
uint32_t state = (getreg32(base + IMXRT_CAN_ESR2_OFFSET) & mask);
if (state == target_state)
{
return true;
}
up_udelay(10);
}
return false;
}
/**************************************************************************** /****************************************************************************
* Function: imxrt_ifup * Function: imxrt_ifup
* *
@ -1293,7 +1345,9 @@ static void imxrt_txavail_work(FAR void *arg)
* packet. * packet.
*/ */
if (!imxrt_txringfull(priv)) if (imxrt_waitesr2_change(priv->base,
(CAN_ESR2_IMB | CAN_ESR2_VPS),
(CAN_ESR2_IMB | CAN_ESR2_VPS)))
{ {
/* No, there is space for another transfer. Poll the network for /* No, there is space for another transfer. Poll the network for
* new XMIT data. * new XMIT data.

View File

@ -266,11 +266,14 @@ static int devif_poll_can_connections(FAR struct net_driver_s *dev,
{ {
/* Perform the packet TX poll */ /* Perform the packet TX poll */
can_poll(dev, can_conn); if (dev == can_conn->dev)
{
can_poll(dev, can_conn);
/* Call back into the driver */ /* Call back into the driver */
bstop = callback(dev); bstop = callback(dev);
}
} }
return bstop; return bstop;