From b748be7443a9b0a3077856a5a11ac12acbcefda9 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 3 Jan 2012 13:47:40 +0000 Subject: Improve LPC17xx CAN interrupt handling; Additions to LPC17xx SPI driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4255 42af7a65-404d-4744-a932-0658087f49c3 --- apps/examples/can/can_main.c | 6 +++- nuttx/arch/arm/src/lpc17xx/lpc17_can.c | 48 +++++++++++++++++++++++------ nuttx/arch/arm/src/lpc17xx/lpc17_internal.h | 46 ++++++++++++++++++++++++--- nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c | 24 ++++++++++----- 4 files changed, 102 insertions(+), 22 deletions(-) diff --git a/apps/examples/can/can_main.c b/apps/examples/can/can_main.c index a3a2e916a..4e12fcd08 100644 --- a/apps/examples/can/can_main.c +++ b/apps/examples/can/can_main.c @@ -216,12 +216,16 @@ int MAIN_NAME(int argc, char *argv[]) message("ERROR: Data does not match. DLC=%d\n", msgdlc); for (i = 0; i < msgdlc; i++) { - message(" %d: TX %02x RX %02x\n", txmsg.cm_data[i], rxmsg.cm_data[i]); + message(" %d: TX %02x RX %02x\n", i, txmsg.cm_data[i], rxmsg.cm_data[i]); errval = 5; goto errout_with_dev; } } + /* Report success */ + + message(" ID: %4d DLC: %d -- OK\n", msgid, msgdlc); + /* Set up for the next pass */ msgdata += msgdlc; 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); } } diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_internal.h b/nuttx/arch/arm/src/lpc17xx/lpc17_internal.h index 06ac7b47a..fdb14b4d7 100755 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_internal.h +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_internal.h @@ -47,6 +47,10 @@ #include #include +#if defined(CONFIG_LPC17_SPI) || defined(CONFIG_LPC17_SSP0) || defined(CONFIG_LPC17_SSP1) +# include +#endif + #include "up_internal.h" #include "chip.h" @@ -583,9 +587,6 @@ EXTERN void lpc17_clrpend(int irq); * ************************************************************************************/ -struct spi_dev_s; -enum spi_dev_e; - #ifdef CONFIG_LPC17_SPI EXTERN void lpc17_spiselect(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool selected); EXTERN uint8_t lpc17_spistatus(FAR struct spi_dev_s *dev, enum spi_dev_e devid); @@ -593,6 +594,7 @@ EXTERN uint8_t lpc17_spistatus(FAR struct spi_dev_s *dev, enum spi_dev_e devid); EXTERN int lpc17_spicmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool cmd); #endif #endif + #ifdef CONFIG_LPC17_SSP0 EXTERN void lpc17_ssp0select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool selected); EXTERN uint8_t lpc17_ssp0status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); @@ -600,6 +602,7 @@ EXTERN uint8_t lpc17_ssp0status(FAR struct spi_dev_s *dev, enum spi_dev_e devid) EXTERN int lpc17_ssp0cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool cmd); #endif #endif + #ifdef CONFIG_LPC17_SSP1 EXTERN void lpc17_ssp1select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool selected); EXTERN uint8_t lpc17_ssp1status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); @@ -624,14 +627,49 @@ EXTERN int lpc17_ssp1cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bo * ****************************************************************************/ -struct spi_dev_s; #ifdef CONFIG_LPC17_SPI EXTERN void spi_flush(FAR struct spi_dev_s *dev); #endif + #if defined(CONFIG_LPC17_SSP0) || defined(CONFIG_LPC17_SSP1) EXTERN void ssp_flush(FAR struct spi_dev_s *dev); #endif +/**************************************************************************** + * Name: lpc17_spi/ssp0/1register + * + * Description: + * If the board supports a card detect callback to inform the SPI-based + * MMC/SD drvier when an SD card is inserted or removed, then + * CONFIG_SPI_CALLBACK should be defined and the following function(s) must + * must be implemented. These functiosn implements the registercallback + * method of the SPI interface (see include/nuttx/spi.h for details) + * + * Input Parameters: + * dev - Device-specific state data + * callback - The funtion to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_LPC17_SPI +EXTERN int lpc17_spiregister(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, void *arg); +#endif + +#ifdef CONFIG_LPC17_SSP0 +EXTERN int lpc17_ssp0register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, void *arg); +#endif + +#ifdef CONFIG_LPC17_SSP1 +EXTERN int lpc17_ssp1register(FAR struct spi_dev_s *dev, + spi_mediachange_t callback, void *arg); +#endif + /**************************************************************************** * Name: lpc17_dmainitialize * diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c b/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c index 94f6427d0..e945ced40 100755 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_ssp.c @@ -165,18 +165,22 @@ static const struct spi_ops_s g_spi0ops = #ifndef CONFIG_SPI_OWNBUS .lock = ssp_lock, #endif - .select = lpc17_ssp0select, + .select = lpc17_ssp0select, /* Provided externally */ .setfrequency = ssp_setfrequency, .setmode = ssp_setmode, .setbits = ssp_setbits, - .status = lpc17_ssp0status, + .status = lpc17_ssp0status, /* Provided externally */ #ifdef CONFIG_SPI_CMDDATA - .cmddata = lpc17_ssp0cmddata, + .cmddata = lpc17_ssp0cmddata, /* Provided externally */ #endif .send = ssp_send, .sndblock = ssp_sndblock, .recvblock = ssp_recvblock, - .registercallback = 0, /* Not implemented */ +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc17_ssp0register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif }; static struct lpc17_sspdev_s g_ssp0dev = @@ -195,18 +199,22 @@ static const struct spi_ops_s g_spi1ops = #ifndef CONFIG_SPI_OWNBUS .lock = ssp_lock, #endif - .select = lpc17_ssp1select, + .select = lpc17_ssp1select, /* Provided externally */ .setfrequency = ssp_setfrequency, .setmode = ssp_setmode, .setbits = ssp_setbits, - .status = lpc17_ssp1status, + .status = lpc17_ssp1status, /* Provided externally */ #ifdef CONFIG_SPI_CMDDATA - .cmddata = lpc17_ssp1cmddata, + .cmddata = lpc17_ssp1cmddata, /* Provided externally */ #endif .send = ssp_send, .sndblock = ssp_sndblock, .recvblock = ssp_recvblock, - .registercallback = 0, /* Not implemented */ +#ifdef CONFIG_SPI_CALLBACK + .registercallback = lpc17_ssp1register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif }; static struct lpc17_sspdev_s g_ssp1dev = -- cgit v1.2.3