Fix bug in STM32 CAN: It must be interrupt driven
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4295 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
163a0dbe4a
commit
d49ecb78a0
@ -162,6 +162,8 @@
|
|||||||
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/stm3210e-eval/README.txt?view=log"><b><i>README.txt</i></b></a>
|
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/stm3210e-eval/README.txt?view=log"><b><i>README.txt</i></b></a>
|
||||||
| | |- stm3240g-eval/
|
| | |- stm3240g-eval/
|
||||||
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/stm3240g-eval/README.txt?view=log"><b><i>README.txt</i></b></a>
|
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/stm3240g-eval/README.txt?view=log"><b><i>README.txt</i></b></a>
|
||||||
|
| | |- stm32f4discovery/
|
||||||
|
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/stm32f4discovery/README.txt?view=log"><b><i>README.txt</i></b></a>
|
||||||
| | |- sure-pic32mx/
|
| | |- sure-pic32mx/
|
||||||
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/sure-pic32mx/README.txt?view=log"><b><i>README.txt</i></b></a>
|
| | | `- <a href="http://nuttx.svn.sourceforge.net/viewvc/nuttx/trunk/nuttx/configs/sure-pic32mx/README.txt?view=log"><b><i>README.txt</i></b></a>
|
||||||
| | |- teensy/
|
| | |- teensy/
|
||||||
|
@ -620,6 +620,8 @@ nuttx
|
|||||||
| | `- README.txt
|
| | `- README.txt
|
||||||
| |- stm3240g-eval/
|
| |- stm3240g-eval/
|
||||||
| | `- README.txt
|
| | `- README.txt
|
||||||
|
| |- stm32f4discovery/
|
||||||
|
| | `- README.txt
|
||||||
| |- sure-pic32mx/
|
| |- sure-pic32mx/
|
||||||
| | `- README.txt
|
| | `- README.txt
|
||||||
| |- teensy/
|
| |- teensy/
|
||||||
|
@ -70,6 +70,10 @@
|
|||||||
|
|
||||||
#define INAK_TIMEOUT 65535
|
#define INAK_TIMEOUT 65535
|
||||||
|
|
||||||
|
/* Mailboxes ****************************************************************/
|
||||||
|
|
||||||
|
#define CAN_ALL_MAILBOXES (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)
|
||||||
|
|
||||||
/* Debug ********************************************************************/
|
/* Debug ********************************************************************/
|
||||||
/* Non-standard debug that may be enabled just for testing CAN */
|
/* Non-standard debug that may be enabled just for testing CAN */
|
||||||
|
|
||||||
@ -97,6 +101,7 @@ struct stm32_can_s
|
|||||||
{
|
{
|
||||||
uint8_t port; /* CAN port number (1 or 2) */
|
uint8_t port; /* CAN port number (1 or 2) */
|
||||||
uint8_t canrx0; /* CAN RX FIFO 0 IRQ number */
|
uint8_t canrx0; /* CAN RX FIFO 0 IRQ number */
|
||||||
|
uint8_t cantx; /* CAN TX IRQ number */
|
||||||
uint8_t filter; /* Filter number */
|
uint8_t filter; /* Filter number */
|
||||||
uint32_t base; /* Base address of the CAN registers */
|
uint32_t base; /* Base address of the CAN registers */
|
||||||
uint32_t baud; /* Configured baud */
|
uint32_t baud; /* Configured baud */
|
||||||
@ -136,6 +141,7 @@ static bool can_txempty(FAR struct can_dev_s *dev);
|
|||||||
/* CAN interrupt handling */
|
/* CAN interrupt handling */
|
||||||
|
|
||||||
static int can_rx0interrupt(int irq, void *context);
|
static int can_rx0interrupt(int irq, void *context);
|
||||||
|
static int can_txinterrupt(int irq, void *context);
|
||||||
|
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
@ -167,8 +173,10 @@ static struct stm32_can_s g_can1priv =
|
|||||||
.port = 1,
|
.port = 1,
|
||||||
#if defined(CONFIG_STM32_STM32F10XX) && !defined(CONFIG_STM32_CONNECTIVITY_LINE)
|
#if defined(CONFIG_STM32_STM32F10XX) && !defined(CONFIG_STM32_CONNECTIVITY_LINE)
|
||||||
.canrx0 = STM32_IRQ_USBLPCANRX0,
|
.canrx0 = STM32_IRQ_USBLPCANRX0,
|
||||||
|
.cantx = STM32_IRQ_USBHPCANTX,
|
||||||
#else
|
#else
|
||||||
.canrx0 = STM32_IRQ_CAN1RX0,
|
.canrx0 = STM32_IRQ_CAN1RX0,
|
||||||
|
.cantx = STM32_IRQ_CAN1TX,
|
||||||
#endif
|
#endif
|
||||||
.filter = 0,
|
.filter = 0,
|
||||||
.base = STM32_CAN1_BASE,
|
.base = STM32_CAN1_BASE,
|
||||||
@ -187,6 +195,7 @@ static struct stm32_can_s g_can2priv =
|
|||||||
{
|
{
|
||||||
.port = 2,
|
.port = 2,
|
||||||
.canrx0 = STM32_IRQ_CAN2RX0,
|
.canrx0 = STM32_IRQ_CAN2RX0,
|
||||||
|
.cantx = STM32_IRQ_CAN2TX,
|
||||||
.filter = CAN_NFILTERS / 2,
|
.filter = CAN_NFILTERS / 2,
|
||||||
.base = STM32_CAN2_BASE,
|
.base = STM32_CAN2_BASE,
|
||||||
.baud = CONFIG_CAN2_BAUD,
|
.baud = CONFIG_CAN2_BAUD,
|
||||||
@ -545,7 +554,7 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||||||
FAR struct stm32_can_s *priv = dev->cd_priv;
|
FAR struct stm32_can_s *priv = dev->cd_priv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
canllvdbg("CAN%d irq: %d\n", priv->port, priv->canrx0);
|
canllvdbg("CAN%d RX0 irq: %d TX irq: %d\n", priv->port, priv->canrx0, priv->cantx);
|
||||||
|
|
||||||
/* CAN cell initialization */
|
/* CAN cell initialization */
|
||||||
|
|
||||||
@ -569,7 +578,7 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||||||
}
|
}
|
||||||
can_dumpfiltregs(priv, "After filter initialization");
|
can_dumpfiltregs(priv, "After filter initialization");
|
||||||
|
|
||||||
/* Attach only the CAN RX FIFO 0 interrupt. The others are not used */
|
/* Attach the CAN RX FIFO 0 interrupt and TX interrupts. The others are not used */
|
||||||
|
|
||||||
ret = irq_attach(priv->canrx0, can_rx0interrupt);
|
ret = irq_attach(priv->canrx0, can_rx0interrupt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@ -578,12 +587,20 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable only the CAN RX FIFO 0 interrupts at the NVIC. Interrupts are
|
ret = irq_attach(priv->cantx, can_txinterrupt);
|
||||||
* still disabled in the CAN module. Since we coming out of reset here,
|
if (ret < 0)
|
||||||
* there should be no pending interrupts.
|
{
|
||||||
|
canlldbg("Failed to attach CAN%d TX IRQ (%d)", priv->port, priv->cantx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable the interrupts at the NVIC. Interrupts arestill disabled in
|
||||||
|
* the CAN module. Since we coming out of reset here, there should be
|
||||||
|
* no pending interrupts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_enable_irq(priv->canrx0);
|
up_enable_irq(priv->canrx0);
|
||||||
|
up_enable_irq(priv->cantx);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,13 +625,15 @@ static void can_shutdown(FAR struct can_dev_s *dev)
|
|||||||
|
|
||||||
canllvdbg("CAN%d\n", priv->port);
|
canllvdbg("CAN%d\n", priv->port);
|
||||||
|
|
||||||
/* Disable the RX FIFO 0 interrupt */
|
/* Disable the RX FIFO 0 and TX interrupts */
|
||||||
|
|
||||||
up_disable_irq(priv->canrx0);
|
up_disable_irq(priv->canrx0);
|
||||||
|
up_disable_irq(priv->cantx);
|
||||||
|
|
||||||
/* Detach the RX FIFO 0 interrupt */
|
/* Detach the RX FIFO 0 and TX interrupts */
|
||||||
|
|
||||||
irq_detach(priv->canrx0);
|
irq_detach(priv->canrx0);
|
||||||
|
irq_detach(priv->cantx);
|
||||||
|
|
||||||
/* And reset the hardware */
|
/* And reset the hardware */
|
||||||
|
|
||||||
@ -672,7 +691,19 @@ static void can_rxint(FAR struct can_dev_s *dev, bool enable)
|
|||||||
|
|
||||||
static void can_txint(FAR struct can_dev_s *dev, bool enable)
|
static void can_txint(FAR struct can_dev_s *dev, bool enable)
|
||||||
{
|
{
|
||||||
/* This driver does not use the TX interrupt */
|
FAR struct stm32_can_s *priv = dev->cd_priv;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
canllvdbg("CAN%d enable: %d\n", priv->port, enable);
|
||||||
|
|
||||||
|
/* Support only disabling the transmit mailbox interrupt */
|
||||||
|
|
||||||
|
if (!enable)
|
||||||
|
{
|
||||||
|
regval = can_getreg(priv, STM32_CAN_IER_OFFSET);
|
||||||
|
regval &= ~CAN_IER_TMEIE;
|
||||||
|
can_putreg(priv, STM32_CAN_IER_OFFSET, regval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -853,19 +884,18 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||||||
}
|
}
|
||||||
can_putreg(priv, STM32_CAN_TDHR_OFFSET(txmb), regval);
|
can_putreg(priv, STM32_CAN_TDHR_OFFSET(txmb), regval);
|
||||||
|
|
||||||
|
/* Enable the transmit mailbox empty interrupt (may already be enabled) */
|
||||||
|
|
||||||
|
regval = can_getreg(priv, STM32_CAN_IER_OFFSET);
|
||||||
|
regval |= CAN_IER_TMEIE;
|
||||||
|
can_putreg(priv, STM32_CAN_IER_OFFSET, regval);
|
||||||
|
|
||||||
/* Request transmission */
|
/* Request transmission */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb));
|
regval = can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb));
|
||||||
regval |= CAN_TIR_TXRQ; /* Transmit Mailbox Request */
|
regval |= CAN_TIR_TXRQ; /* Transmit Mailbox Request */
|
||||||
can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval);
|
can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval);
|
||||||
|
|
||||||
/* Tell the upper half that the tansfer is finished now. We would have to
|
|
||||||
* take the transfer complete interrupt to know it "really" finished. So
|
|
||||||
* although the transfer is not finished, all of the upper half resources
|
|
||||||
* are now available so makes sense to call can_txdone now.
|
|
||||||
*/
|
|
||||||
|
|
||||||
(void)can_txdone(dev);
|
|
||||||
can_dumpmbregs(priv, "After send");
|
can_dumpmbregs(priv, "After send");
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -894,15 +924,7 @@ static bool can_txready(FAR struct can_dev_s *dev)
|
|||||||
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
||||||
canllvdbg("CAN%d TSR: %08x\n", priv->port, regval);
|
canllvdbg("CAN%d TSR: %08x\n", priv->port, regval);
|
||||||
|
|
||||||
if ((regval & CAN_TSR_TME0) != 0)
|
if ((regval & CAN_ALL_MAILBOXES) != 0)
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if ((regval & CAN_TSR_TME1) != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if ((regval & CAN_TSR_TME2) != 0)
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -932,24 +954,16 @@ static bool can_txempty(FAR struct can_dev_s *dev)
|
|||||||
FAR struct stm32_can_s *priv = dev->cd_priv;
|
FAR struct stm32_can_s *priv = dev->cd_priv;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
/* Return false if any mailbox is unavailable */
|
/* Return true if all mailboxes are available */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
||||||
canllvdbg("CAN%d TSR: %08x\n", priv->port, regval);
|
canllvdbg("CAN%d TSR: %08x\n", priv->port, regval);
|
||||||
|
|
||||||
if ((regval & CAN_TSR_TME0) == 0)
|
if ((regval & CAN_ALL_MAILBOXES) == CAN_ALL_MAILBOXES)
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
else if ((regval & CAN_TSR_TME1) == 0)
|
return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if ((regval & CAN_TSR_TME2) == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1056,7 +1070,128 @@ errout:
|
|||||||
regval = can_getreg(priv, STM32_CAN_RF0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RF0R_OFFSET);
|
||||||
regval |= CAN_RFR_RFOM;
|
regval |= CAN_RFR_RFOM;
|
||||||
can_putreg(priv, STM32_CAN_RF0R_OFFSET, regval);
|
can_putreg(priv, STM32_CAN_RF0R_OFFSET, regval);
|
||||||
return ret;
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: can_txinterrupt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* CAN TX mailbox complete interrupt handler
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* irq - The IRQ number of the interrupt.
|
||||||
|
* context - The register state save array at the time of the interrupt.
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* Zero on success; a negated errno on failure
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int can_txinterrupt(int irq, void *context)
|
||||||
|
{
|
||||||
|
FAR struct can_dev_s *dev = NULL;
|
||||||
|
FAR struct stm32_can_s *priv;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2)
|
||||||
|
if (g_can1priv.cantx == irq)
|
||||||
|
{
|
||||||
|
dev = &g_can1dev;
|
||||||
|
}
|
||||||
|
else if (g_can2priv.cantx == irq)
|
||||||
|
{
|
||||||
|
dev = &g_can2dev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PANIC(OSERR_UNEXPECTEDISR);
|
||||||
|
}
|
||||||
|
#elif defined(CONFIG_STM32_CAN1)
|
||||||
|
dev = &g_can1dev;
|
||||||
|
#else /* defined(CONFIG_STM32_CAN2) */
|
||||||
|
dev = &g_can2dev;
|
||||||
|
#endif
|
||||||
|
priv = dev->cd_priv;
|
||||||
|
|
||||||
|
/* Get the transmit status */
|
||||||
|
|
||||||
|
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
||||||
|
|
||||||
|
/* Check for RQCP0: Request completed mailbox 0 */
|
||||||
|
|
||||||
|
if ((regval & CAN_TSR_RQCP0) != 0)
|
||||||
|
{
|
||||||
|
/* Writing '1' to RCP0 clears RCP0 and all the status bits (TXOK0,
|
||||||
|
* ALST0 and TERR0) for Mailbox 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
can_putreg(priv, STM32_CAN_TSR_OFFSET, CAN_TSR_RQCP0);
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
|
||||||
|
if ((regval & CAN_TSR_TXOK0) != 0)
|
||||||
|
{
|
||||||
|
/* Tell the upper half that the tansfer is finished. */
|
||||||
|
|
||||||
|
(void)can_txdone(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for RQCP1: Request completed mailbox 1 */
|
||||||
|
|
||||||
|
if ((regval & CAN_TSR_RQCP1) != 0)
|
||||||
|
{
|
||||||
|
/* Writing '1' to RCP1 clears RCP1 and all the status bits (TXOK1,
|
||||||
|
* ALST1 and TERR1) for Mailbox 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
can_putreg(priv, STM32_CAN_TSR_OFFSET, CAN_TSR_RQCP1);
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
|
||||||
|
if ((regval & CAN_TSR_TXOK1) != 0)
|
||||||
|
{
|
||||||
|
/* Tell the upper half that the tansfer is finished. */
|
||||||
|
|
||||||
|
(void)can_txdone(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for RQCP2: Request completed mailbox 2 */
|
||||||
|
|
||||||
|
if ((regval & CAN_TSR_RQCP2) != 0)
|
||||||
|
{
|
||||||
|
/* Writing '1' to RCP2 clears RCP2 and all the status bits (TXOK2,
|
||||||
|
* ALST2 and TERR2) for Mailbox 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
can_putreg(priv, STM32_CAN_TSR_OFFSET, CAN_TSR_RQCP2);
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
|
||||||
|
if ((regval & CAN_TSR_TXOK2) != 0)
|
||||||
|
{
|
||||||
|
/* Tell the upper half that the tansfer is finished. */
|
||||||
|
|
||||||
|
(void)can_txdone(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Were all transmissions complete in all mailboxes when we entered this
|
||||||
|
* handler?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((regval & CAN_ALL_MAILBOXES) == CAN_ALL_MAILBOXES)
|
||||||
|
{
|
||||||
|
/* Yes.. disable further TX interrupts */
|
||||||
|
|
||||||
|
regval = can_getreg(priv, STM32_CAN_IER_OFFSET);
|
||||||
|
regval &= ~CAN_IER_TMEIE;
|
||||||
|
can_putreg(priv, STM32_CAN_IER_OFFSET, regval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
@ -1403,6 +1403,9 @@ configs/stm32140g-eval
|
|||||||
microcontroller (ARM Cortex-M4 with FPU). This port uses a GNU Cortex-M4
|
microcontroller (ARM Cortex-M4 with FPU). This port uses a GNU Cortex-M4
|
||||||
toolchain (such as CodeSourcery).
|
toolchain (such as CodeSourcery).
|
||||||
|
|
||||||
|
configs/stm32f4discovery
|
||||||
|
STMicro STM32F4-Discovery board boased on the STMIcro STM32F407VGT6 MCU.
|
||||||
|
|
||||||
configs/sure-pic32mx
|
configs/sure-pic32mx
|
||||||
The "Advanced USB Storage Demo Board," Model DB-DP11215, from Sure
|
The "Advanced USB Storage Demo Board," Model DB-DP11215, from Sure
|
||||||
Electronics (http://www.sureelectronics.net/). This board features
|
Electronics (http://www.sureelectronics.net/). This board features
|
||||||
@ -1416,8 +1419,8 @@ configs/teensy
|
|||||||
on an Atmel AT90USB1286 MCU.
|
on an Atmel AT90USB1286 MCU.
|
||||||
|
|
||||||
configs/twr-k60n512
|
configs/twr-k60n512
|
||||||
Kinetis K60 Cortex-M4 MCU. This port uses the FreeScale TWR-K60N512
|
Kinetis K60 Cortex-M4 MCU. This port uses the FreeScale TWR-K60N512
|
||||||
development board.
|
development board.
|
||||||
|
|
||||||
configs/us7032evb1
|
configs/us7032evb1
|
||||||
This is a port of the Hitachi SH-1 on the Hitachi SH-1/US7032EVB1 board.
|
This is a port of the Hitachi SH-1 on the Hitachi SH-1/US7032EVB1 board.
|
||||||
|
Loading…
Reference in New Issue
Block a user