summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/lpc17xx
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-01-10 22:29:39 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-01-10 22:29:39 +0000
commit2878c08369c4ac8819e0f6530784f22509bcab92 (patch)
tree92567fed48fbb8c44552b220ab80d17ec19cfba0 /nuttx/arch/arm/src/lpc17xx
parentb45972d006d34d588ef0bde2ebffb2de5843b0fa (diff)
downloadpx4-nuttx-2878c08369c4ac8819e0f6530784f22509bcab92.tar.gz
px4-nuttx-2878c08369c4ac8819e0f6530784f22509bcab92.tar.bz2
px4-nuttx-2878c08369c4ac8819e0f6530784f22509bcab92.zip
Fix LPC17 CAN driver; TX must be interrupt driven
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4290 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/lpc17xx')
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_can.c118
1 files changed, 90 insertions, 28 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_can.c b/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
index eab57d2a8..3539ce4af 100755
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_can.c
@@ -203,6 +203,7 @@ static void can_txint(FAR struct can_dev_s *dev, bool enable);
static int can_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg);
static int can_remoterequest(FAR struct can_dev_s *dev, uint16_t id);
static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg);
+static bool can_txready(FAR struct can_dev_s *dev);
static bool can_txempty(FAR struct can_dev_s *dev);
/* CAN interrupts */
@@ -228,6 +229,7 @@ static const struct can_ops_s g_canops =
.co_ioctl = can_ioctl,
.co_remoterequest = can_remoterequest,
.co_send = can_send,
+ .co_txready = can_txready,
.co_txempty = can_txempty,
};
@@ -739,6 +741,19 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
regval = can_getreg(priv, LPC17_CAN_SR_OFFSET);
if ((regval & CAN_SR_TBS1) != 0)
{
+ /* Make sure that buffer 1 TX interrupts are enabled BEFORE sending the
+ * message. The TX interrupt is generated when the 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 may miss the TIE1 interrupt.
+ *
+ * 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_TIE1;
+ can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+
/* Set up the transfer */
can_putreg(priv, LPC17_CAN_TFI1_OFFSET, tfi);
@@ -753,16 +768,23 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
#else
can_putreg(priv, LPC17_CAN_CMR_OFFSET, CAN_CMR_STB1 | CAN_CMR_TR);
#endif
-
- /* Tell the caller that the transfer is done. It isn't, but we have
- * more transmit buffers and this can speed things up.
- */
-
- can_txdone(dev);
}
else if ((regval & CAN_SR_TBS2) != 0)
{
- /* Set up the transfer */
+ /* Make sure that buffer 2 TX interrupts are enabled BEFORE sending the
+ * message. The TX interrupt is generated when the 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 may miss the TIE2 interrupt.
+ *
+ * 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_TIE2;
+ can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+
+ /* Set up the transfer */
can_putreg(priv, LPC17_CAN_TFI2_OFFSET, tfi);
can_putreg(priv, LPC17_CAN_TID2_OFFSET, tid);
@@ -776,29 +798,20 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
#else
can_putreg(priv, LPC17_CAN_CMR_OFFSET, CAN_CMR_STB2 | CAN_CMR_TR);
#endif
-
- /* Tell the caller that the transfer is done. It isn't, but we have
- * more transmit buffers and this can speed things up.
- */
-
- can_txdone(dev);
}
else if ((regval & CAN_SR_TBS3) != 0)
{
- /* We have no more buffers. We will make the caller wait. First, make
- * 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.
+ /* Make sure that buffer 3 TX interrupts are enabled BEFORE sending the
+ * message. The TX interrupt is generated when the 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 may miss the TIE3 interrupt.
*
* 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_TIE1 | CAN_IER_TIE2 | CAN_IER_TIE3);
+ regval |= CAN_IER_TIE3;
can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
/* Set up the transfer */
@@ -827,6 +840,27 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
}
/****************************************************************************
+ * Name: can_txready
+ *
+ * Description:
+ * Return true if the CAN hardware can accept another TX message.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * True is the CAN hardware is ready to accept another TX message.
+ *
+ ****************************************************************************/
+
+static bool can_txready(FAR struct can_dev_s *dev)
+{
+ FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->cd_priv;
+ uint32_t regval = can_getreg(priv, LPC17_CAN_SR_OFFSET);
+ return ((regval & (CAN_SR_TBS1 | CAN_SR_TBS2 | CAN_SR_TBS3)) != 0);
+}
+
+/****************************************************************************
* Name: can_txempty
*
* Description:
@@ -840,7 +874,7 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
* dev - An instance of the "upper half" can driver state structure.
*
* Returned Value:
- * Zero on success; a negated errno on failure
+ * True is there are no pending TX transfers in the CAN hardware.
*
****************************************************************************/
@@ -907,16 +941,44 @@ static void can_interrupt(FAR struct can_dev_s *dev)
can_receive(dev, hdr, (uint8_t *)data);
}
- /* 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.
- */
+ /* Check for TX buffer 1 complete */
+
+ if ((regval & CAN_ICR_TI1) != 0)
+ {
+ /* Disable all further TX buffer 1 interrupts */
+
+ regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
+ regval &= ~CAN_IER_TIE1;
+ can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+
+ /* Indicate that the TX is done and a new TX buffer is available */
- if ((regval & (CAN_ICR_TI1 | CAN_ICR_TI2 |CAN_ICR_TI3)) != 0)
+ can_txdone(dev);
+ }
+
+ /* Check for TX buffer 2 complete */
+
+ if ((regval & CAN_ICR_TI2) != 0)
+ {
+ /* Disable all further TX buffer 2 interrupts */
+
+ regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
+ regval &= ~CAN_IER_TIE2;
+ can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
+
+ /* Indicate that the TX is done and a new TX buffer is available */
+
+ can_txdone(dev);
+ }
+
+ /* Check for TX buffer 3 complete */
+
+ if ((regval & CAN_ICR_TI3) != 0)
{
- /* Disable all further TX interrupts */
+ /* Disable all further TX buffer 3 interrupts */
regval = can_getreg(priv, LPC17_CAN_IER_OFFSET);
- regval &= ~(CAN_IER_TIE1 | CAN_IER_TIE2 | CAN_IER_TIE3);
+ regval &= ~CAN_IER_TIE3;
can_putreg(priv, LPC17_CAN_IER_OFFSET, regval);
/* Indicate that the TX is done and a new TX buffer is available */