summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/arm/src/lpc17xx/lpc17_can.c')
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_can.c48
1 files changed, 39 insertions, 9 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_can.c b/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
index 41f823459..00c00d918 100755
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
@@ -501,9 +501,15 @@ static void can_rxint(FAR struct can_dev_s *dev, bool enable)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->cd_priv;
uint32_t regval;
+ irqstate_t flags;
canvdbg("CAN%d enable: %d\n", priv->port, enable);
+ /* The EIR register is also modifed from the interrupt handler, so we have
+ * to protect this code section.
+ */
+
+ flags = irqsave();
regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
if (enable)
{
@@ -514,6 +520,7 @@ static void can_rxint(FAR struct can_dev_s *dev, bool enable)
regval &= ~CAN_IER_RIE;
}
can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+ irqrestore(flags);
}
/****************************************************************************
@@ -534,6 +541,7 @@ static void can_txint(FAR struct can_dev_s *dev, bool enable)
{
FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->cd_priv;
uint32_t regval;
+ irqstate_t flags;
canvdbg("CAN%d enable: %d\n", priv->port, enable);
@@ -544,10 +552,20 @@ static void can_txint(FAR struct can_dev_s *dev, bool enable)
if (!enable)
{
+ /* TX interrupts are also disabled from the interrupt handler, so we have
+ * to protect this code section.
+ */
+
+ flags = irqsave();
+
+ /* Disable all TX interrupts */
+
regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
regval &= ~(CAN_IER_TIE1 | CAN_IER_TIE2 | CAN_IER_TIE3);
can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+ irqrestore(flags);
}
+
}
/****************************************************************************
@@ -684,17 +702,19 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
else if ((regval & CAN_SR_TBS3) != 0)
{
/* We have no more buffers. We will make the caller wait. First, make
- * sure that the buffer 3 TX interrupt is enabled BEFORE sending the
- * message. The TX interrupt is generated TBS3 bit in CANxSR goes from 0
- * to 1 when the TIE3 bit in CANxIER is 1. If we don't enable it now,
- * we will miss interrupts.
+ * sure that all buffer 3 interrupts are enabled BEFORE sending the
+ * message. The TX interrupt is generated TBSn bit in CANxSR goes from 0
+ * to 1 when the TIEn bit in CANxIER is 1. If we don't enable it now,
+ * we will miss the TIE3 interrupt. We enable ALL TIE interrupts here
+ * because we don't care which one finishes: When first one finishes it
+ * means that a transmit buffer is again available.
*
- * Hmmm... we could probably do better than this. Buffer 1 or 2 is much
- * more likely to complete quicker than buffer 3.
+ * NOTE: The IER is also modified from the interrupt handler, but the
+ * following is safe because interrupts are disabled here.
*/
regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
- regval |= CAN_IER_TIE3;
+ regval |= (CAN_IER_TIE1 | CAN_IER_TIE2 | CAN_IER_TIE3);
can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
/* Set up the transfer */
@@ -803,10 +823,20 @@ static void can_interrupt(FAR struct can_dev_s *dev)
can_receive(dev, hdr, (uint8_t *)data);
}
- /* Check for a transmit interrupt from buffer 3 */
+ /* Check for a transmit interrupt from buffer 1, 2, or 3 meaning that at
+ * least one TX is complete and that at least one TX buffer is available.
+ */
- if ((regval & CAN_ICR_TI3) != 0)
+ if ((regval & (CAN_ICR_TI1 | CAN_ICR_TI2 |CAN_ICR_TI3)) != 0)
{
+ /* Disable all further TX interrupts */
+
+ regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
+ regval &= ~(CAN_IER_TIE1 | CAN_IER_TIE2 | CAN_IER_TIE3);
+ can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+
+ /* Indicate that the TX is done and a new TX buffer is available */
+
can_txdone(&g_can1dev);
}
}