diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-01-11 14:56:56 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-01-11 14:56:56 +0000 |
commit | c9b7fefdae9c6d234f201f2f1311c24664f62f1a (patch) | |
tree | 9b378a906b8702b7974f94a4c672e3ba9370efe5 | |
parent | 1c871cf28a9f18a9488513cf38c56abe3adad7b8 (diff) | |
download | nuttx-c9b7fefdae9c6d234f201f2f1311c24664f62f1a.tar.gz nuttx-c9b7fefdae9c6d234f201f2f1311c24664f62f1a.tar.bz2 nuttx-c9b7fefdae9c6d234f201f2f1311c24664f62f1a.zip |
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
-rw-r--r-- | nuttx/Documentation/README.html | 2 | ||||
-rwxr-xr-x | nuttx/README.txt | 2 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_can.c | 209 | ||||
-rw-r--r-- | nuttx/configs/README.txt | 7 |
4 files changed, 181 insertions, 39 deletions
diff --git a/nuttx/Documentation/README.html b/nuttx/Documentation/README.html index 5cb9e0d3e..f0321d6de 100644 --- a/nuttx/Documentation/README.html +++ b/nuttx/Documentation/README.html @@ -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> | | |- 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> + | | |- 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/ | | | `- <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/ diff --git a/nuttx/README.txt b/nuttx/README.txt index 5e8b42787..a9cdc8560 100755 --- a/nuttx/README.txt +++ b/nuttx/README.txt @@ -620,6 +620,8 @@ nuttx | | `- README.txt | |- stm3240g-eval/ | | `- README.txt + | |- stm32f4discovery/ + | | `- README.txt | |- sure-pic32mx/ | | `- README.txt | |- teensy/ diff --git a/nuttx/arch/arm/src/stm32/stm32_can.c b/nuttx/arch/arm/src/stm32/stm32_can.c index 5365601f7..9cd6c5712 100755 --- a/nuttx/arch/arm/src/stm32/stm32_can.c +++ b/nuttx/arch/arm/src/stm32/stm32_can.c @@ -70,6 +70,10 @@ #define INAK_TIMEOUT 65535 +/* Mailboxes ****************************************************************/ + +#define CAN_ALL_MAILBOXES (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2) + /* Debug ********************************************************************/ /* 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 canrx0; /* CAN RX FIFO 0 IRQ number */ + uint8_t cantx; /* CAN TX IRQ number */ uint8_t filter; /* Filter number */ uint32_t base; /* Base address of the CAN registers */ uint32_t baud; /* Configured baud */ @@ -136,6 +141,7 @@ static bool can_txempty(FAR struct can_dev_s *dev); /* CAN interrupt handling */ static int can_rx0interrupt(int irq, void *context); +static int can_txinterrupt(int irq, void *context); /* Initialization */ @@ -167,8 +173,10 @@ static struct stm32_can_s g_can1priv = .port = 1, #if defined(CONFIG_STM32_STM32F10XX) && !defined(CONFIG_STM32_CONNECTIVITY_LINE) .canrx0 = STM32_IRQ_USBLPCANRX0, + .cantx = STM32_IRQ_USBHPCANTX, #else .canrx0 = STM32_IRQ_CAN1RX0, + .cantx = STM32_IRQ_CAN1TX, #endif .filter = 0, .base = STM32_CAN1_BASE, @@ -187,6 +195,7 @@ static struct stm32_can_s g_can2priv = { .port = 2, .canrx0 = STM32_IRQ_CAN2RX0, + .cantx = STM32_IRQ_CAN2TX, .filter = CAN_NFILTERS / 2, .base = STM32_CAN2_BASE, .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; 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 */ @@ -569,7 +578,7 @@ static int can_setup(FAR struct can_dev_s *dev) } 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); if (ret < 0) @@ -578,12 +587,20 @@ static int can_setup(FAR struct can_dev_s *dev) return ret; } - /* Enable only the CAN RX FIFO 0 interrupts at the NVIC. Interrupts are - * still disabled in the CAN module. Since we coming out of reset here, - * there should be no pending interrupts. + ret = irq_attach(priv->cantx, can_txinterrupt); + if (ret < 0) + { + 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->cantx); return OK; } @@ -608,13 +625,15 @@ static void can_shutdown(FAR struct can_dev_s *dev) 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->cantx); - /* Detach the RX FIFO 0 interrupt */ + /* Detach the RX FIFO 0 and TX interrupts */ irq_detach(priv->canrx0); + irq_detach(priv->cantx); /* 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) { - /* 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); + /* 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 */ regval = can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb)); regval |= CAN_TIR_TXRQ; /* Transmit Mailbox Request */ 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"); return OK; } @@ -894,15 +924,7 @@ static bool can_txready(FAR struct can_dev_s *dev) regval = can_getreg(priv, STM32_CAN_TSR_OFFSET); canllvdbg("CAN%d TSR: %08x\n", priv->port, regval); - if ((regval & CAN_TSR_TME0) != 0) - { - return true; - } - else if ((regval & CAN_TSR_TME1) != 0) - { - return true; - } - else if ((regval & CAN_TSR_TME2) != 0) + if ((regval & CAN_ALL_MAILBOXES) != 0) { 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; 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); 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; - } - else if ((regval & CAN_TSR_TME1) == 0) - { - return false; - } - else if ((regval & CAN_TSR_TME2) == 0) - { - return false; + return true; } - return true; + return false; } /**************************************************************************** @@ -1056,7 +1070,128 @@ errout: regval = can_getreg(priv, STM32_CAN_RF0R_OFFSET); regval |= CAN_RFR_RFOM; 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; } /**************************************************************************** diff --git a/nuttx/configs/README.txt b/nuttx/configs/README.txt index 786b45332..27b3954d5 100644 --- a/nuttx/configs/README.txt +++ b/nuttx/configs/README.txt @@ -1403,6 +1403,9 @@ configs/stm32140g-eval microcontroller (ARM Cortex-M4 with FPU). This port uses a GNU Cortex-M4 toolchain (such as CodeSourcery). +configs/stm32f4discovery + STMicro STM32F4-Discovery board boased on the STMIcro STM32F407VGT6 MCU. + configs/sure-pic32mx The "Advanced USB Storage Demo Board," Model DB-DP11215, from Sure Electronics (http://www.sureelectronics.net/). This board features @@ -1416,8 +1419,8 @@ configs/teensy on an Atmel AT90USB1286 MCU. configs/twr-k60n512 - Kinetis K60 Cortex-M4 MCU. This port uses the FreeScale TWR-K60N512 - development board. + Kinetis K60 Cortex-M4 MCU. This port uses the FreeScale TWR-K60N512 + development board. configs/us7032evb1 This is a port of the Hitachi SH-1 on the Hitachi SH-1/US7032EVB1 board. |