drivers/can/mcp2515.c: mcp2515 driver optimizations.

This commit is contained in:
Valmantas Paliksa 2019-04-12 11:37:08 -06:00 committed by Gregory Nutt
parent 7d112f5639
commit ca5d940b7a
5 changed files with 196 additions and 256 deletions

View File

@ -175,5 +175,10 @@ config MCP2515_CLK_FREQUENCY
default 8000000 default 8000000
range 1 25000000 range 1 25000000
config MCP2515_SPI_SCK_FREQUENCY
int "MCP2515 SPI SCK Frequency"
default 1000000
range 100000 10000000
endif # CAN_MCP2515 endif # CAN_MCP2515
endif # CAN endif # CAN

View File

@ -48,6 +48,7 @@
#include <semaphore.h> #include <semaphore.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
#include <strings.h>
#include <nuttx/irq.h> #include <nuttx/irq.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
@ -68,6 +69,10 @@
/* MCP2515 Configuration ****************************************************/ /* MCP2515 Configuration ****************************************************/
#define CAN_FRAME_MAX_DATA_LEN 8
#define SPI_TRANSFER_BUF_LEN (6 + CAN_FRAME_MAX_DATA_LEN)
#define MCP2515_NUM_TX_BUFFERS 3
/* Bit timing */ /* Bit timing */
#define MCP2515_PROPSEG CONFIG_MCP2515_PROPSEG #define MCP2515_PROPSEG CONFIG_MCP2515_PROPSEG
@ -75,7 +80,7 @@
#define MCP2515_PHSEG2 CONFIG_MCP2515_PHASESEG2 #define MCP2515_PHSEG2 CONFIG_MCP2515_PHASESEG2
#define MCP2515_TSEG1 (MCP2515_PROPSEG + MCP2515_PHSEG1) #define MCP2515_TSEG1 (MCP2515_PROPSEG + MCP2515_PHSEG1)
#define MCP2515_TSEG2 MCP2515_PHSEG2 #define MCP2515_TSEG2 MCP2515_PHSEG2
#define MCP2515_BRP ((uint8_t)(((float) MCP2515_CANCLK_FREQUENCY / \ #define MCP2515_BRP ((uint8_t)(((float)(MCP2515_CANCLK_FREQUENCY) / \
((float)(MCP2515_TSEG1 + MCP2515_TSEG2 + 1) * \ ((float)(MCP2515_TSEG1 + MCP2515_TSEG2 + 1) * \
(float)(2 * CONFIG_MCP2515_BITRATE))) - 1)) (float)(2 * CONFIG_MCP2515_BITRATE))) - 1))
#define MCP2515_SJW CONFIG_MCP2515_SJW #define MCP2515_SJW CONFIG_MCP2515_SJW
@ -108,29 +113,29 @@
/* MCP2515 Filters */ /* MCP2515 Filters */
# ifndef CONFIG_MCP2515_NSTDFILTERS #ifndef CONFIG_MCP2515_NSTDFILTERS
# define CONFIG_MCP2515_NSTDFILTERS 0 # define CONFIG_MCP2515_NSTDFILTERS 0
# endif #endif
# if (CONFIG_MCP2515_NSTDFILTERS > 128) #if (CONFIG_MCP2515_NSTDFILTERS > 128)
# error Invalid MCP25150 number of Standard Filters # error Invalid MCP25150 number of Standard Filters
# endif #endif
# ifndef CONFIG_MCP2515_NEXTFILTERS #ifndef CONFIG_MCP2515_NEXTFILTERS
# define CONFIG_MCP2515_NEXTFILTERS 0 # define CONFIG_MCP2515_NEXTFILTERS 0
# endif #endif
# if (CONFIG_MCP2515_NEXTFILTERS > 64) #if (CONFIG_MCP2515_NEXTFILTERS > 64)
# error Invalid MCP25150 number of Extended Filters # error Invalid MCP25150 number of Extended Filters
# endif #endif
# define MCP2515_STDFILTER_BYTES \ #define MCP2515_STDFILTER_BYTES \
MCP2515_ALIGN_UP(CONFIG_MCP2515_NSTDFILTERS << 2) MCP2515_ALIGN_UP(CONFIG_MCP2515_NSTDFILTERS << 2)
# define MCP2515_STDFILTER_WORDS (MCP2515_STDFILTER_BYTES >> 2) #define MCP2515_STDFILTER_WORDS (MCP2515_STDFILTER_BYTES >> 2)
# define MCP2515_EXTFILTER_BYTES \ #define MCP2515_EXTFILTER_BYTES \
MCP2515_ALIGN_UP(CONFIG_MCP2515_NEXTFILTERS << 3) MCP2515_ALIGN_UP(CONFIG_MCP2515_NEXTFILTERS << 3)
# define MCP2515_EXTFILTER_WORDS (MCP2515_EXTFILTER_BYTES >> 2) #define MCP2515_EXTFILTER_WORDS (MCP2515_EXTFILTER_BYTES >> 2)
/* MCP25150 TX buffer element size */ /* MCP25150 TX buffer element size */
@ -170,6 +175,10 @@
#define MCP2515_TXBUFFER_INTS (MCP2515_INT_TX0 | MCP2515_INT_TX1 | MCP2515_INT_TX2) #define MCP2515_TXBUFFER_INTS (MCP2515_INT_TX0 | MCP2515_INT_TX1 | MCP2515_INT_TX2)
/* Helpers ******************************************************************/
#define TXREGVAL(reg) priv->spi_txbuf[reg - MCP2515_TXB0CTRL]
/* Debug ********************************************************************/ /* Debug ********************************************************************/
/* Debug configurations that may be enabled just for testing MCP2515 */ /* Debug configurations that may be enabled just for testing MCP2515 */
@ -213,9 +222,10 @@ struct mcp2515_can_s
uint32_t olderrors; /* Used to detect the changes in error states */ uint32_t olderrors; /* Used to detect the changes in error states */
#endif #endif
uint8_t filters; /* Standard/Extende filter bit allocator. */ uint8_t filters; /* Standard/Extende filter bit allocator. */
uint8_t ntxbufs; /* Number of allocated TX Buffers */
uint8_t txbuffers; /* TX Buffers bit allocator. */ uint8_t txbuffers; /* TX Buffers bit allocator. */
FAR uint8_t *spi_txbuf;
FAR uint8_t *spi_rxbuf;
#ifdef CONFIG_MCP2515_REGDEBUG #ifdef CONFIG_MCP2515_REGDEBUG
uintptr_t regaddr; /* Last register address read */ uintptr_t regaddr; /* Last register address read */
uint32_t regval; /* Last value read from the register */ uint32_t regval; /* Last value read from the register */
@ -309,6 +319,22 @@ static const struct can_ops_s g_mcp2515ops =
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
static void mcp2515_read_2regs(FAR struct mcp2515_can_s *priv, uint8_t reg,
FAR uint8_t *v1, FAR uint8_t *v2)
{
priv->spi_txbuf[0] = MCP2515_READ;
priv->spi_txbuf[1] = reg;
SPI_LOCK(priv->config->spi, true);
SPI_SELECT(priv->config->spi, SPIDEV_CANBUS(0), true);
SPI_EXCHANGE(priv->config->spi, priv->spi_txbuf, priv->spi_rxbuf, 4);
SPI_SELECT(priv->config->spi, SPIDEV_CANBUS(0), false);
SPI_LOCK(priv->config->spi, false);
*v1 = priv->spi_rxbuf[2];
*v2 = priv->spi_rxbuf[3];
}
/**************************************************************************** /****************************************************************************
* Name: mcp2515_readregs * Name: mcp2515_readregs
* *
@ -362,6 +388,29 @@ static void mcp2515_readregs(FAR struct mcp2515_can_s *priv, uint8_t regaddr,
#endif #endif
} }
static void mcp2515_transfer(FAR struct mcp2515_can_s *priv, uint8_t len)
{
FAR struct mcp2515_config_s *config = priv->config;
(void)SPI_LOCK(config->spi, true);
/* Select the MCP2515 */
SPI_SELECT(config->spi, SPIDEV_CANBUS(0), true);
/* Send the READ command */
SPI_EXCHANGE(config->spi, priv->spi_txbuf, priv->spi_rxbuf, len);
/* Deselect the MCP2515 */
SPI_SELECT(config->spi, SPIDEV_CANBUS(0), false);
/* Unlock bus */
(void)SPI_LOCK(config->spi, false);
}
/**************************************************************************** /****************************************************************************
* Name: mcp2515_writeregs * Name: mcp2515_writeregs
* *
@ -435,6 +484,10 @@ static void mcp2515_modifyreg(FAR struct mcp2515_can_s *priv, uint8_t regaddr,
uint8_t mask, uint8_t value) uint8_t mask, uint8_t value)
{ {
FAR struct mcp2515_config_s *config = priv->config; FAR struct mcp2515_config_s *config = priv->config;
uint8_t wr[4]=
{
MCP2515_BITMOD, regaddr, mask, value
};
(void)SPI_LOCK(config->spi, true); (void)SPI_LOCK(config->spi, true);
@ -442,21 +495,7 @@ static void mcp2515_modifyreg(FAR struct mcp2515_can_s *priv, uint8_t regaddr,
SPI_SELECT(config->spi, SPIDEV_CANBUS(0), true); SPI_SELECT(config->spi, SPIDEV_CANBUS(0), true);
/* Send the Modify command */ SPI_SNDBLOCK(config->spi, wr, 4);
(void)SPI_SEND(config->spi, MCP2515_BITMOD);
/* Send the register address */
(void)SPI_SEND(config->spi, regaddr);
/* Send the mask */
(void)SPI_SEND(config->spi, mask);
/* Send the value */
(void)SPI_SEND(config->spi, value);
/* Deselect the MCP2515 */ /* Deselect the MCP2515 */
@ -539,7 +578,7 @@ static void mcp2515_dev_lock(FAR struct mcp2515_can_s *priv)
#ifdef CONFIG_CAN_EXTID #ifdef CONFIG_CAN_EXTID
static int mcp2515_add_extfilter(FAR struct mcp2515_can_s *priv, static int mcp2515_add_extfilter(FAR struct mcp2515_can_s *priv,
FAR struct canioc_extfilter_s *extconfig) FAR struct canioc_extfilter_s *extconfig)
{ {
FAR struct mcp2515_config_s *config; FAR struct mcp2515_config_s *config;
uint8_t regval; uint8_t regval;
@ -867,7 +906,7 @@ static int mcp2515_del_extfilter(FAR struct mcp2515_can_s *priv, int ndx)
****************************************************************************/ ****************************************************************************/
static int mcp2515_add_stdfilter(FAR struct mcp2515_can_s *priv, static int mcp2515_add_stdfilter(FAR struct mcp2515_can_s *priv,
FAR struct canioc_stdfilter_s *stdconfig) FAR struct canioc_stdfilter_s *stdconfig)
{ {
FAR struct mcp2515_config_s *config; FAR struct mcp2515_config_s *config;
uint8_t regval; uint8_t regval;
@ -948,7 +987,7 @@ static int mcp2515_add_stdfilter(FAR struct mcp2515_can_s *priv,
break; break;
case CAN_FILTER_RANGE: case CAN_FILTER_RANGE:
/* not supported */ /* Not supported */
break; break;
} }
@ -987,7 +1026,7 @@ static int mcp2515_add_stdfilter(FAR struct mcp2515_can_s *priv,
/* Setup the Filter */ /* Setup the Filter */
regval = (uint8_t)(((stdconfig->sf_id1) & 0x7f8) >> 3); regval = (uint8_t) (((stdconfig->sf_id1) & 0x7f8) >> 3);
mcp2515_writeregs(priv, MCP2515_RXF0SIDH + offset + mcp2515_writeregs(priv, MCP2515_RXF0SIDH + offset +
((priv->nalloc - 1) * 4), &regval, 1); ((priv->nalloc - 1) * 4), &regval, 1);
mcp2515_writeregs(priv, MCP2515_RXM0SIDH + offset, &regval, 1); mcp2515_writeregs(priv, MCP2515_RXM0SIDH + offset, &regval, 1);
@ -1166,7 +1205,8 @@ static void mcp2515_reset_lowlevel(FAR struct mcp2515_can_s *priv)
*/ */
nxsem_destroy(&priv->txfsem); nxsem_destroy(&priv->txfsem);
nxsem_init(&priv->txfsem, 0, config->ntxbuffers); nxsem_init(&priv->txfsem, 0, MCP2515_NUM_TX_BUFFERS);
priv->txbuffers = 0b111;
/* Define the current state and unlock */ /* Define the current state and unlock */
@ -1318,18 +1358,17 @@ static void mcp2515_rxint(FAR struct can_dev_s *dev, bool enable)
flags = enter_critical_section(); flags = enter_critical_section();
mcp2515_readregs(priv, MCP2515_CANINTE, &regval, 1);
if (enable) if (enable)
{ {
regval |= priv->rxints | MCP2515_ERROR_INTS; mcp2515_modifyreg(priv, MCP2515_CANINTE,
priv->rxints | MCP2515_ERROR_INTS,
priv->rxints | MCP2515_ERROR_INTS);
} }
else else
{ {
regval &= ~priv->rxints; mcp2515_modifyreg(priv, MCP2515_CANINTE, priv->rxints, ~priv->rxints);
} }
mcp2515_writeregs(priv, MCP2515_CANINTE, &regval, 1);
leave_critical_section(flags); leave_critical_section(flags);
} }
@ -1360,18 +1399,18 @@ static void mcp2515_txint(FAR struct can_dev_s *dev, bool enable)
/* Enable/disable the receive interrupts */ /* Enable/disable the receive interrupts */
flags = enter_critical_section(); flags = enter_critical_section();
mcp2515_readregs(priv, MCP2515_CANINTE, &regval, 1);
if (enable) if (enable)
{ {
regval |= priv->txints | MCP2515_ERROR_INTS; mcp2515_modifyreg(priv, MCP2515_CANINTE,
priv->txints | MCP2515_ERROR_INTS,
priv->txints | MCP2515_ERROR_INTS);
} }
else else
{ {
regval &= ~priv->txints; mcp2515_modifyreg(priv, MCP2515_CANINTE, priv->txints, ~priv->txints);
} }
mcp2515_writeregs(priv, MCP2515_CANINTE, &regval, 1);
leave_critical_section(flags); leave_critical_section(flags);
} }
@ -1425,18 +1464,18 @@ static int mcp2515_ioctl(FAR struct can_dev_s *dev, int cmd,
DEBUGASSERT(bt != NULL); DEBUGASSERT(bt != NULL);
mcp2515_readregs(priv, MCP2515_CNF1, &regval, 1); mcp2515_readregs(priv, MCP2515_CNF1, &regval, 1);
bt->bt_sjw = ((regval & CNF1_SJW_MASK) >> CNF1_SJW_SHIFT) + 1; bt->bt_sjw = ((regval & CNF1_SJW_MASK) >> CNF1_SJW_SHIFT) + 1;
brp = (((regval & CNF1_BRP_MASK) >> CNF1_BRP_SHIFT) + 1) * 2; brp = (((regval & CNF1_BRP_MASK) >> CNF1_BRP_SHIFT) + 1) * 2;
mcp2515_readregs(priv, MCP2515_CNF2, &regval, 1); mcp2515_readregs(priv, MCP2515_CNF2, &regval, 1);
bt->bt_tseg1 = ((regval & CNF2_PRSEG_MASK) >> CNF2_PRSEG_SHIFT) + 1; bt->bt_tseg1 = ((regval & CNF2_PRSEG_MASK) >> CNF2_PRSEG_SHIFT) + 1;
bt->bt_tseg1 += ((regval & CNF2_PHSEG1_MASK) >> CNF2_PHSEG1_SHIFT) + 1; bt->bt_tseg1 += ((regval & CNF2_PHSEG1_MASK) >> CNF2_PHSEG1_SHIFT) + 1;
mcp2515_readregs(priv, MCP2515_CNF3, &regval, 1); mcp2515_readregs(priv, MCP2515_CNF3, &regval, 1);
bt->bt_tseg2 = ((regval & CNF3_PHSEG2_MASK) >> CNF3_PHSEG2_SHIFT) + 1; bt->bt_tseg2 = ((regval & CNF3_PHSEG2_MASK) >> CNF3_PHSEG2_SHIFT) + 1;
bt->bt_baud = MCP2515_CANCLK_FREQUENCY / brp / bt->bt_baud = MCP2515_CANCLK_FREQUENCY / brp /
(bt->bt_tseg1 + bt->bt_tseg2 + 1); (bt->bt_tseg1 + bt->bt_tseg2 + 1);
ret = OK; ret = OK;
} }
break; break;
@ -1683,9 +1722,8 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
FAR struct mcp2515_can_s *priv; FAR struct mcp2515_can_s *priv;
FAR struct mcp2515_config_s *config; FAR struct mcp2515_config_s *config;
uint8_t regval; uint8_t regval;
uint8_t offset; uint8_t txbuf;
unsigned int nbytes; unsigned int nbytes;
unsigned int i;
DEBUGASSERT(dev); DEBUGASSERT(dev);
priv = dev->cd_priv; priv = dev->cd_priv;
@ -1697,46 +1735,20 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
config->devid, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); config->devid, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
UNUSED(config); UNUSED(config);
/* That that FIFO elements were configured.
*
* REVISIT: Dedicated TX buffers are not used by this driver.
*/
DEBUGASSERT(config->ntxbuffers > 0);
/* Select one empty transmit buffer */
mcp2515_readregs(priv, MCP2515_TXB0CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) == 0)
{
offset = MCP2515_TX0_OFFSET;
}
else
{
mcp2515_readregs(priv, MCP2515_TXB1CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) == 0)
{
offset = MCP2515_TX1_OFFSET;
}
else
{
mcp2515_readregs(priv, MCP2515_TXB2CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) == 0)
{
offset = MCP2515_TX2_OFFSET;
}
else
{
canerr("ERROR: No available transmit buffer!\n");
return -EBUSY;
}
}
}
/* Get exclusive access to the MCP2515 peripheral */ /* Get exclusive access to the MCP2515 peripheral */
mcp2515_dev_lock(priv); mcp2515_dev_lock(priv);
/* Acquire buffer */
nxsem_wait(&priv->txfsem);
DEBUGASSERT(priv->txbuffers != 0);
txbuf = ffs(priv->txbuffers) - 1;
priv->txbuffers &= ~(1 << txbuf);
/* Select one empty transmit buffer */
/* Setup the MCP2515 TX Buffer with the message to send */ /* Setup the MCP2515 TX Buffer with the message to send */
#ifdef CONFIG_CAN_EXTID #ifdef CONFIG_CAN_EXTID
@ -1747,12 +1759,12 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
/* EID7 - EID0 */ /* EID7 - EID0 */
regval = (msg->cm_hdr.ch_id & 0xff); regval = (msg->cm_hdr.ch_id & 0xff);
mcp2515_writeregs(priv, MCP2515_TXB0EID0 + offset, &regval, 1); TXREGVAL(MCP2515_TXB0EID0) = regval;
/* EID15 - EID8 */ /* EID15 - EID8 */
regval = (msg->cm_hdr.ch_id & 0xff00) >> 8; regval = (msg->cm_hdr.ch_id & 0xff00) >> 8;
mcp2515_writeregs(priv, MCP2515_TXB0EID8 + offset, &regval, 1); TXREGVAL(MCP2515_TXB0EID8) = regval;
/* EID17 and EID16 */ /* EID17 and EID16 */
@ -1762,12 +1774,12 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
/* STD2 - STD0 */ /* STD2 - STD0 */
regval |= (msg->cm_hdr.ch_id & 0x1c0000) >> 18; regval |= (msg->cm_hdr.ch_id & 0x1c0000) >> 18;
mcp2515_writeregs(priv, MCP2515_TXB0SIDL + offset, &regval, 1); TXREGVAL(MCP2515_TXB0SIDL) = regval;
/* STD10 - STD3 */ /* STD10 - STD3 */
regval = (msg->cm_hdr.ch_id & 0x1fe00000) >> 21; regval = (msg->cm_hdr.ch_id & 0x1fe00000) >> 21;
mcp2515_writeregs(priv, MCP2515_TXB0SIDH + offset, &regval, 1); TXREGVAL(MCP2515_TXB0SIDH) = regval;
} }
else else
#endif #endif
@ -1779,12 +1791,12 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
/* STD10 - STD3 */ /* STD10 - STD3 */
regval = (msg->cm_hdr.ch_id & 0x7f8) >> 3; regval = (msg->cm_hdr.ch_id & 0x7f8) >> 3;
mcp2515_writeregs(priv, MCP2515_TXB0SIDH + offset, &regval, 1); TXREGVAL(MCP2515_TXB0SIDH) = regval;
/* STD2 - STD0 */ /* STD2 - STD0 */
regval = (msg->cm_hdr.ch_id & 0x007) << 5; regval = (msg->cm_hdr.ch_id & 0x007) << 5;
mcp2515_writeregs(priv, MCP2515_TXB0SIDL + offset, &regval, 1); TXREGVAL(MCP2515_TXB0SIDL) = regval;
} }
/* Setup the DLC */ /* Setup the DLC */
@ -1796,25 +1808,22 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
regval |= TXBDLC_RTR; regval |= TXBDLC_RTR;
} }
mcp2515_writeregs(priv, MCP2515_TXB0DLC + offset, &regval, 1); TXREGVAL(MCP2515_TXB0DLC) = regval;
/* Fill the data buffer */ /* Fill the data buffer */
nbytes = msg->cm_hdr.ch_dlc; nbytes = msg->cm_hdr.ch_dlc;
for (i = 0; i < nbytes; i++) memcpy(&TXREGVAL(MCP2515_TXB0D0), msg->cm_data, nbytes);
{
/* Little endian is assumed */
regval = msg->cm_data[i]; TXREGVAL(MCP2515_TXB0CTRL) = MCP2515_LOAD_TXB(txbuf);
mcp2515_writeregs(priv, MCP2515_TXB0D0 + offset + i, &regval, 1);
}
/* And request to send the message */ mcp2515_transfer(priv, SPI_TRANSFER_BUF_LEN);
mcp2515_readregs(priv, MCP2515_TXB0CTRL, &regval, 1); /* Request to send */
regval |= TXBCTRL_TXREQ;
mcp2515_writeregs(priv, MCP2515_TXB0CTRL, &regval, 1); priv->spi_txbuf[0] = MCP2515_RTS(txbuf);
mcp2515_transfer(priv, 1);
mcp2515_dev_unlock(priv); mcp2515_dev_unlock(priv);
@ -1848,55 +1857,12 @@ static int mcp2515_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
static bool mcp2515_txready(FAR struct can_dev_s *dev) static bool mcp2515_txready(FAR struct can_dev_s *dev)
{ {
FAR struct mcp2515_can_s *priv; FAR struct mcp2515_can_s *priv;
uint8_t regval;
bool ready;
DEBUGASSERT(dev); DEBUGASSERT(dev);
priv = dev->cd_priv; priv = dev->cd_priv;
DEBUGASSERT(priv); DEBUGASSERT(priv);
/* That that FIFO elements were configured. return priv->txbuffers != 0;
*
* REVISIT: Dedicated TX buffers are not used by this driver.
*/
DEBUGASSERT(priv->config->ntxbuffers > 0);
/* Get exclusive access to the MCP2515 peripheral */
mcp2515_dev_lock(priv);
/* Select one empty transmit buffer */
mcp2515_readregs(priv, MCP2515_TXB0CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) == 0)
{
ready = true;
}
else
{
mcp2515_readregs(priv, MCP2515_TXB1CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) == 0)
{
ready = true;
}
else
{
mcp2515_readregs(priv, MCP2515_TXB2CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) == 0)
{
ready = true;
}
else
{
ready = false;
}
}
}
mcp2515_dev_unlock(priv);
return ready;
} }
/**************************************************************************** /****************************************************************************
@ -1920,55 +1886,12 @@ static bool mcp2515_txready(FAR struct can_dev_s *dev)
static bool mcp2515_txempty(FAR struct can_dev_s *dev) static bool mcp2515_txempty(FAR struct can_dev_s *dev)
{ {
FAR struct mcp2515_can_s *priv; FAR struct mcp2515_can_s *priv;
uint8_t regval;
bool empty;
DEBUGASSERT(dev); DEBUGASSERT(dev);
priv = dev->cd_priv; priv = dev->cd_priv;
DEBUGASSERT(priv); DEBUGASSERT(priv);
/* That that FIFO elements were configured. return priv->txbuffers == (1 << MCP2515_NUM_TX_BUFFERS) - 1;
*
* REVISIT: Dedicated TX buffers are not used by this driver.
*/
DEBUGASSERT(priv->config->ntxbuffers > 0);
/* Get exclusive access to the MCP2515 peripheral */
mcp2515_dev_lock(priv);
/* Select one empty transmit buffer */
mcp2515_readregs(priv, MCP2515_TXB0CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) != 0)
{
empty = false;
}
else
{
mcp2515_readregs(priv, MCP2515_TXB1CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) != 0)
{
empty = false;
}
else
{
mcp2515_readregs(priv, MCP2515_TXB2CTRL, &regval, 1);
if ((regval & TXBCTRL_TXREQ) != 0)
{
empty = false;
}
else
{
empty = true;
}
}
}
mcp2515_dev_unlock(priv);
return empty;
} }
/**************************************************************************** /****************************************************************************
@ -2116,23 +2039,23 @@ static void mcp2515_error(FAR struct can_dev_s *dev, uint8_t status,
* *
****************************************************************************/ ****************************************************************************/
#define RXREGVAL(reg) priv->spi_rxbuf[reg-MCP2515_RXB0CTRL]
static void mcp2515_receive(FAR struct can_dev_s *dev, uint8_t offset) static void mcp2515_receive(FAR struct can_dev_s *dev, uint8_t offset)
{ {
FAR struct mcp2515_can_s *priv; FAR struct mcp2515_can_s *priv;
struct can_hdr_s hdr; struct can_hdr_s hdr;
int ret; int ret;
uint8_t regval; uint8_t regval;
uint8_t data[CAN_MAXDATALEN];
DEBUGASSERT(dev); DEBUGASSERT(dev);
priv = dev->cd_priv; priv = dev->cd_priv;
DEBUGASSERT(priv); DEBUGASSERT(priv);
/* Format the CAN header */ mcp2515_readregs(priv, MCP2515_RXB0CTRL + offset, priv->spi_rxbuf,
SPI_TRANSFER_BUF_LEN);
/* Get the CAN identifier. */ regval = RXREGVAL(MCP2515_RXB0SIDL);
mcp2515_readregs(priv, MCP2515_RXB0SIDL + offset, &regval, 1);
#ifdef CONFIG_CAN_EXTID #ifdef CONFIG_CAN_EXTID
if ((regval & RXBSIDL_IDE) != 0) if ((regval & RXBSIDL_IDE) != 0)
@ -2141,36 +2064,38 @@ static void mcp2515_receive(FAR struct can_dev_s *dev, uint8_t offset)
/* EID7 - EID0 */ /* EID7 - EID0 */
mcp2515_readregs(priv, MCP2515_RXB0EID0 + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0EID0);
hdr.ch_id = regval ; hdr.ch_id = regval ;
/* EID15 - EID8 */ /* EID15 - EID8 */
mcp2515_readregs(priv, MCP2515_RXB0EID8 + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0EID8);
hdr.ch_id = hdr.ch_id | (regval << 8); hdr.ch_id = hdr.ch_id | (regval << 8);
/* EID17 and EID16 */ /* EID17 and EID16 */
mcp2515_readregs(priv, MCP2515_RXB0SIDL + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0SIDL);
hdr.ch_id = hdr.ch_id | ((regval & RXBSIDL_EID_MASK) << 16); hdr.ch_id = hdr.ch_id | ((regval & RXBSIDL_EID_MASK) << 16);
/* STD2 - STD0 */ /* STD2 - STD0 */
hdr.ch_id = hdr.ch_id | ((regval >> 5) << 18); hdr.ch_id = hdr.ch_id | ((regval >> 5) << 18);
/* STD10 - STD3 */ /* STD10 - STD3 */
mcp2515_readregs(priv, MCP2515_RXB0SIDH + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0SIDH);
hdr.ch_id = hdr.ch_id | (regval << 21); hdr.ch_id = hdr.ch_id | (regval << 21);
hdr.ch_extid = true; hdr.ch_extid = true;
} }
else else
{ {
/* Save the standard ID of the newly received message */ /* Save the standard ID of the newly received message */
mcp2515_readregs(priv, MCP2515_RXB0SIDH + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0SIDH);
hdr.ch_id = regval; hdr.ch_id = regval;
mcp2515_readregs(priv, MCP2515_RXB0SIDL + offset, &regval, 1);
regval = RXREGVAL(MCP2515_RXB0SIDL);
hdr.ch_id = (hdr.ch_id << 3) | (regval >> 5); hdr.ch_id = (hdr.ch_id << 3) | (regval >> 5);
hdr.ch_extid = false; hdr.ch_extid = false;
} }
@ -2187,9 +2112,9 @@ static void mcp2515_receive(FAR struct can_dev_s *dev, uint8_t offset)
/* Save the standard ID of the newly received message */ /* Save the standard ID of the newly received message */
mcp2515_readregs(priv, MCP2515_RXB0SIDH + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0SIDH);
hdr.ch_id = regval; hdr.ch_id = regval;
mcp2515_readregs(priv, MCP2515_RXB0SIDL + offset, &regval, 1); regval = RXREGVAL(MCP2515_RXB0SIDL);
hdr.ch_id = (hdr.ch_id << 3) | (regval >> 5); hdr.ch_id = (hdr.ch_id << 3) | (regval >> 5);
#endif #endif
@ -2200,19 +2125,17 @@ static void mcp2515_receive(FAR struct can_dev_s *dev, uint8_t offset)
/* Extract the RTR bit */ /* Extract the RTR bit */
mcp2515_readregs(priv, MCP2515_RXB0CTRL, &regval, 1); regval = RXREGVAL(MCP2515_RXB0CTRL);
hdr.ch_rtr = (regval & RXBCTRL_RXRTR) != 0; hdr.ch_rtr = (regval & RXBCTRL_RXRTR) != 0;
/* Get the DLC */ /* Get the DLC */
mcp2515_readregs(priv, MCP2515_RXB0DLC, &regval, 1); regval = RXREGVAL(MCP2515_RXB0DLC);
hdr.ch_dlc = (regval & RXBDLC_DLC_MASK) >> RXBDLC_DLC_SHIFT; hdr.ch_dlc = (regval & RXBDLC_DLC_MASK) >> RXBDLC_DLC_SHIFT;
/* Save the message data */ /* Save the message data */
mcp2515_readregs(priv, MCP2515_RXB0D0, data, (uint8_t) hdr.ch_dlc); ret = can_receive(dev, &hdr, (FAR uint8_t *) & RXREGVAL(MCP2515_RXB0D0));
ret = can_receive(dev, &hdr, (FAR uint8_t *) data);
if (ret < 0) if (ret < 0)
{ {
@ -2242,7 +2165,8 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
uint8_t ir; uint8_t ir;
uint8_t ie; uint8_t ie;
uint8_t pending; uint8_t pending;
bool handled; uint8_t clrmask;
bool handled;
DEBUGASSERT(dev); DEBUGASSERT(dev);
priv = dev->cd_priv; priv = dev->cd_priv;
@ -2255,11 +2179,16 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
{ {
/* Get the set of pending interrupts. */ /* Get the set of pending interrupts. */
mcp2515_readregs(priv, MCP2515_CANINTF, &ir, 1); mcp2515_read_2regs(priv, MCP2515_CANINTE, &ie, &ir);
mcp2515_readregs(priv, MCP2515_CANINTE, &ie, 1);
pending = (ir & ie); pending = (ir & ie);
handled = false; handled = false;
clrmask = 0;
if (pending == 0)
{
return OK;
}
/* Check for any errors */ /* Check for any errors */
@ -2267,8 +2196,8 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
{ {
/* Clear interrupt errors */ /* Clear interrupt errors */
mcp2515_modifyreg(priv, MCP2515_CANINTF, MCP2515_ERROR_INTS, pending &= ~MCP2515_ERROR_INTS;
(uint8_t)~MCP2515_ERROR_INTS); clrmask |= MCP2515_ERROR_INTS;
#ifdef CONFIG_CAN_ERRORS #ifdef CONFIG_CAN_ERRORS
/* Report errors */ /* Report errors */
@ -2307,28 +2236,36 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
/* Clear TX0 interrupt */ /* Clear TX0 interrupt */
mcp2515_modifyreg(priv, MCP2515_CANINTF, MCP2515_INT_TX0, priv->txbuffers |= (1 << 0);
~MCP2515_INT_TX0); nxsem_post(&priv->txfsem);
pending &= ~MCP2515_INT_TX0;
clrmask |= MCP2515_INT_TX0;
} }
if (pending & MCP2515_INT_TX1) if (pending & MCP2515_INT_TX1)
{ {
caninfo("TX1 is empty to transmit new message!\n"); caninfo("TX1 is empty to transmit new message!\n");
priv->txbuffers |= (1 << 1);
nxsem_post(&priv->txfsem);
/* Clear TX1 interrupt */ /* Clear TX1 interrupt */
mcp2515_modifyreg(priv, MCP2515_CANINTF, MCP2515_INT_TX1, pending &= ~MCP2515_INT_TX1;
~MCP2515_INT_TX1); clrmask |= MCP2515_INT_TX1;
} }
if (pending & MCP2515_INT_TX2) if (pending & MCP2515_INT_TX2)
{ {
caninfo("TX2 is empty to transmit new message!\n"); caninfo("TX2 is empty to transmit new message!\n");
priv->txbuffers |= (1 << 2);
nxsem_post(&priv->txfsem);
/* Clear TX2 interrupt */ /* Clear TX2 interrupt */
mcp2515_modifyreg(priv, MCP2515_CANINTF, MCP2515_INT_TX2, pending &= ~MCP2515_INT_TX2;
~MCP2515_INT_TX2); clrmask |= MCP2515_INT_TX2;
} }
handled = true; handled = true;
@ -2343,11 +2280,8 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
} }
else if ((pending & priv->txints) != 0) else if ((pending & priv->txints) != 0)
{ {
#if 0
/* Clear unhandled TX events */ /* Clear unhandled TX events */
mcp2515_putreg(priv, MCP2515_IR_OFFSET, priv->txints);
#endif
handled = true; handled = true;
} }
@ -2366,8 +2300,8 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
/* Clear RX0 interrupt */ /* Clear RX0 interrupt */
mcp2515_modifyreg(priv, MCP2515_CANINTF, MCP2515_INT_RX0, pending &= ~MCP2515_INT_RX0;
~MCP2515_INT_RX0); clrmask |= MCP2515_INT_RX0;
} }
else else
{ {
@ -2377,8 +2311,8 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
/* Clear RX1 interrupt */ /* Clear RX1 interrupt */
mcp2515_modifyreg(priv, MCP2515_CANINTF, MCP2515_INT_RX1, pending &= ~MCP2515_INT_RX1;
~MCP2515_INT_RX1); clrmask |= MCP2515_INT_RX1;
} }
} }
@ -2386,6 +2320,8 @@ static int mcp2515_interrupt(FAR struct mcp2515_config_s *config,
handled = true; handled = true;
} }
mcp2515_modifyreg(priv, MCP2515_CANINTF, clrmask, pending);
} }
while (handled); while (handled);
@ -2545,7 +2481,7 @@ FAR struct mcp2515_can_s *
/* Setup SPI frequency and mode */ /* Setup SPI frequency and mode */
SPI_SETFREQUENCY(config->spi, MCP2515_SPI_FREQUENCY); SPI_SETFREQUENCY(config->spi, CONFIG_MCP2515_SPI_SCK_FREQUENCY);
SPI_SETMODE(config->spi, MCP2515_SPI_MODE); SPI_SETMODE(config->spi, MCP2515_SPI_MODE);
SPI_SETBITS(config->spi, 8); SPI_SETBITS(config->spi, 8);
(void)SPI_HWFEATURES(config->spi, 0); (void)SPI_HWFEATURES(config->spi, 0);
@ -2555,19 +2491,21 @@ FAR struct mcp2515_can_s *
memset(priv, 0, sizeof(struct mcp2515_can_s)); memset(priv, 0, sizeof(struct mcp2515_can_s));
priv->config = config; priv->config = config;
#if 0 priv->spi_txbuf = kmm_zalloc(SPI_TRANSFER_BUF_LEN);
priv->spi_rxbuf = kmm_zalloc(SPI_TRANSFER_BUF_LEN);
/* Set the initial bit timing. This might change subsequently /* Set the initial bit timing. This might change subsequently
* due to IOCTL command processing. * due to IOCTL command processing.
*/ */
priv->btp = config->btp;
priv->fbtp = config->fbtp;
#endif
/* Initialize semaphores */ /* Initialize semaphores */
nxsem_init(&priv->locksem, 0, 1); nxsem_init(&priv->locksem, 0, 1);
nxsem_init(&priv->txfsem, 0, config->ntxbuffers); nxsem_init(&priv->txfsem, 0, MCP2515_NUM_TX_BUFFERS);
/* Initialize bitmask */
priv->txbuffers = (1 << MCP2515_NUM_TX_BUFFERS)-1;
/* And put the hardware in the initial state */ /* And put the hardware in the initial state */

View File

@ -208,7 +208,6 @@
#define TXBSIDH_SID_MASK 0xff /* Standard Identifier bits <10:3> */ #define TXBSIDH_SID_MASK 0xff /* Standard Identifier bits <10:3> */
/* TXBnSIDL TRANSMIT BUFFER n STANDARD IDENTIFIER LOW */ /* TXBnSIDL TRANSMIT BUFFER n STANDARD IDENTIFIER LOW */
#define TXBSIDL_SID_SHIFT (5) /* Bits 5-7: Standard Identifier bits <2:0> */ #define TXBSIDL_SID_SHIFT (5) /* Bits 5-7: Standard Identifier bits <2:0> */
@ -217,7 +216,6 @@
#define TXBSIDL_EID_SHIFT (0) /* Bits 0-1: Extended Identifier bits <17:16> */ #define TXBSIDL_EID_SHIFT (0) /* Bits 0-1: Extended Identifier bits <17:16> */
#define TXBSIDL_EID_MASK (0x03 << TXBSIDL_EID_MASK) #define TXBSIDL_EID_MASK (0x03 << TXBSIDL_EID_MASK)
/* TXBnEID8 TRANSMIT BUFFER n EXTENDED IDENTIFIER HIGH */ /* TXBnEID8 TRANSMIT BUFFER n EXTENDED IDENTIFIER HIGH */
#define TXBEID8_EID_MASK 0xff /* Bits 0-7: Extended Identifier bits <15:8> */ #define TXBEID8_EID_MASK 0xff /* Bits 0-7: Extended Identifier bits <15:8> */
@ -260,8 +258,9 @@
/* Bit 7: Not used */ /* Bit 7: Not used */
/* N.B.: In the datasheet DS21801D the file RXM of RXBnCTRL could to assume /* N.B.: In the datasheet DS21801D the file RXM of RXBnCTRL could to assume
the value 01 and 10 to receive only STD or EXT msgs respectively. * the value 01 and 10 to receive only STD or EXT msgs respectively.
But in a more recent datasheet DS20001801H it was removed. */ * But in a more recent datasheet DS20001801H it was removed.
*/
/* RXB1CTRL RECEIVE BUFFER 1 CONTROL */ /* RXB1CTRL RECEIVE BUFFER 1 CONTROL */
@ -421,9 +420,12 @@
#define MCP2515_LOAD_TX0 0x40 #define MCP2515_LOAD_TX0 0x40
#define MCP2515_LOAD_TX1 0x42 #define MCP2515_LOAD_TX1 0x42
#define MCP2515_LOAD_TX2 0x44 #define MCP2515_LOAD_TX2 0x44
#define MCP2515_LOAD_TXB(n) (0x40 + 2 * (n))
#define MCP2515_READ_RXB(n) (((n) == 0) ? 0x90 : 0x94)
#define MCP2515_RTS_TX0 0x81 #define MCP2515_RTS_TX0 0x81
#define MCP2515_RTS_TX1 0x82 #define MCP2515_RTS_TX1 0x82
#define MCP2515_RTS_TX2 0x84 #define MCP2515_RTS_TX2 0x84
#define MCP2515_RTS(x) (0x81+x)
#define MCP2515_RTS_ALL 0x87 #define MCP2515_RTS_ALL 0x87
#define MCP2515_READ_STATUS 0xA0 #define MCP2515_READ_STATUS 0xA0
#define MCP2515_RX_STATUS 0xB0 #define MCP2515_RX_STATUS 0xB0

View File

@ -571,7 +571,7 @@ struct can_dev_s
uint8_t cd_npendrtr; /* Number of pending RTR messages */ uint8_t cd_npendrtr; /* Number of pending RTR messages */
volatile uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */ volatile uint8_t cd_ntxwaiters; /* Number of threads waiting to enqueue a message */
volatile uint8_t cd_nrxwaiters; /* Number of threads waiting to receive a message */ volatile uint8_t cd_nrxwaiters; /* Number of threads waiting to receive a message */
struct list_node cd_readers; struct list_node cd_readers; /* Number of readers */
#ifdef CONFIG_CAN_ERRORS #ifdef CONFIG_CAN_ERRORS
uint8_t cd_error; /* Flags to indicate internal device errors */ uint8_t cd_error; /* Flags to indicate internal device errors */
#endif #endif

View File

@ -54,7 +54,6 @@
/* SPI BUS PARAMETERS *******************************************************/ /* SPI BUS PARAMETERS *******************************************************/
#define MCP2515_SPI_FREQUENCY (1000000) /* 1 MHz */
#define MCP2515_SPI_MODE (SPIDEV_MODE0) /* Device uses SPI Mode 0: CPOL=0, CPHA=0 */ #define MCP2515_SPI_MODE (SPIDEV_MODE0) /* Device uses SPI Mode 0: CPOL=0, CPHA=0 */
/**************************************************************************** /****************************************************************************
@ -86,10 +85,6 @@ struct mcp2515_config_s
uint8_t devid; /* MCP2515 device ID */ uint8_t devid; /* MCP2515 device ID */
uint8_t mode; /* See enum mcp2515_canmod_e */ uint8_t mode; /* See enum mcp2515_canmod_e */
uint8_t nfilters; /* Number of standard/extended filters */ uint8_t nfilters; /* Number of standard/extended filters */
uint8_t ntxbuffers; /* Number of TX Buffer available */
uint8_t txbuf0[10]; /* Transmit Buffer 0 */
uint8_t txbuf1[10]; /* Transmit Buffer 1 */
uint8_t txbuf2[10]; /* Transmit Buffer 2 */
#ifdef MCP2515_LOOPBACK #ifdef MCP2515_LOOPBACK
bool loopback; /* True: Loopback mode */ bool loopback; /* True: Loopback mode */
#endif #endif