Merged in paulpatience/nuttx/stm32_can (pull request #29)
STM32 CAN: Add support for both RX FIFOs
This commit is contained in:
commit
7de267645e
@ -75,8 +75,11 @@
|
|||||||
#define STM32_CAN_MCR_OFFSET 0x0000 /* CAN master control register */
|
#define STM32_CAN_MCR_OFFSET 0x0000 /* CAN master control register */
|
||||||
#define STM32_CAN_MSR_OFFSET 0x0004 /* CAN master status register */
|
#define STM32_CAN_MSR_OFFSET 0x0004 /* CAN master status register */
|
||||||
#define STM32_CAN_TSR_OFFSET 0x0008 /* CAN transmit status register */
|
#define STM32_CAN_TSR_OFFSET 0x0008 /* CAN transmit status register */
|
||||||
|
|
||||||
|
#define STM32_CAN_RFR_OFFSET(m) (0x000c+((m)<<2))
|
||||||
#define STM32_CAN_RF0R_OFFSET 0x000c /* CAN receive FIFO 0 register */
|
#define STM32_CAN_RF0R_OFFSET 0x000c /* CAN receive FIFO 0 register */
|
||||||
#define STM32_CAN_RF1R_OFFSET 0x0010 /* CAN receive FIFO 1 register */
|
#define STM32_CAN_RF1R_OFFSET 0x0010 /* CAN receive FIFO 1 register */
|
||||||
|
|
||||||
#define STM32_CAN_IER_OFFSET 0x0014 /* CAN interrupt enable register */
|
#define STM32_CAN_IER_OFFSET 0x0014 /* CAN interrupt enable register */
|
||||||
#define STM32_CAN_ESR_OFFSET 0x0018 /* CAN error status register */
|
#define STM32_CAN_ESR_OFFSET 0x0018 /* CAN error status register */
|
||||||
#define STM32_CAN_BTR_OFFSET 0x001c /* CAN bit timing register */
|
#define STM32_CAN_BTR_OFFSET 0x001c /* CAN bit timing register */
|
||||||
@ -127,8 +130,8 @@
|
|||||||
#define STM32_CAN_FFA1R_OFFSET 0x0214 /* CAN filter FIFO assignment register */
|
#define STM32_CAN_FFA1R_OFFSET 0x0214 /* CAN filter FIFO assignment register */
|
||||||
#define STM32_CAN_FA1R_OFFSET 0x021c /* CAN filter activation register */
|
#define STM32_CAN_FA1R_OFFSET 0x021c /* CAN filter activation register */
|
||||||
|
|
||||||
/* There are 14 or 28 filter banks (depending) on the device. Each filter bank is
|
/* There are 14 or 28 filter banks (depending) on the device.
|
||||||
* composed of two 32-bit registers, CAN_FiR:
|
* Each filter bank is composed of two 32-bit registers, CAN_FiR:
|
||||||
* F0R1 Offset 0x240
|
* F0R1 Offset 0x240
|
||||||
* F0R2 Offset 0x244
|
* F0R2 Offset 0x244
|
||||||
* F1R1 Offset 0x248
|
* F1R1 Offset 0x248
|
||||||
@ -445,7 +448,7 @@
|
|||||||
|
|
||||||
/* CAN filter master register */
|
/* CAN filter master register */
|
||||||
|
|
||||||
#define CAN_FMR_FINIT (1 << 0) /* Bit 0: Filter Init Mode */
|
#define CAN_FMR_FINIT (1 << 0) /* Bit 0: Filter Init Mode */
|
||||||
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
|
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
|
||||||
# define CAN_FMR_CAN2SB_SHIFT (8) /* Bits 13-8: CAN2 start bank */
|
# define CAN_FMR_CAN2SB_SHIFT (8) /* Bits 13-8: CAN2 start bank */
|
||||||
# define CAN_FMR_CAN2SB_MASK (0x3f << CAN_FMR_CAN2SB_SHIFT)
|
# define CAN_FMR_CAN2SB_MASK (0x3f << CAN_FMR_CAN2SB_SHIFT)
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
* Copyright (C) 2011, 2016 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2011, 2016 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
|
* Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved.
|
||||||
|
* Author: Paul Alexander Patience <paul-a.patience@polymtl.ca>
|
||||||
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@ -103,13 +106,13 @@
|
|||||||
|
|
||||||
struct stm32_can_s
|
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 canrx[2]; /* CAN RX FIFO 0/1 IRQ number */
|
||||||
uint8_t cantx; /* CAN TX 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 control registers */
|
uint32_t base; /* Base address of the CAN control registers */
|
||||||
uint32_t fbase; /* Base address of the CAN filter registers */
|
uint32_t fbase; /* Base address of the CAN filter registers */
|
||||||
uint32_t baud; /* Configured baud */
|
uint32_t baud; /* Configured baud */
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -118,14 +121,19 @@ struct stm32_can_s
|
|||||||
|
|
||||||
/* CAN Register access */
|
/* CAN Register access */
|
||||||
|
|
||||||
static uint32_t can_getreg(struct stm32_can_s *priv, int offset);
|
static uint32_t can_getreg(FAR struct stm32_can_s *priv, int offset);
|
||||||
static uint32_t can_getfreg(struct stm32_can_s *priv, int offset);
|
static uint32_t can_getfreg(FAR struct stm32_can_s *priv, int offset);
|
||||||
static void can_putreg(struct stm32_can_s *priv, int offset, uint32_t value);
|
static void can_putreg(FAR struct stm32_can_s *priv, int offset,
|
||||||
static void can_putfreg(struct stm32_can_s *priv, int offset, uint32_t value);
|
uint32_t value);
|
||||||
|
static void can_putfreg(FAR struct stm32_can_s *priv, int offset,
|
||||||
|
uint32_t value);
|
||||||
#ifdef CONFIG_CAN_REGDEBUG
|
#ifdef CONFIG_CAN_REGDEBUG
|
||||||
static void can_dumpctrlregs(struct stm32_can_s *priv, FAR const char *msg);
|
static void can_dumpctrlregs(FAR struct stm32_can_s *priv,
|
||||||
static void can_dumpmbregs(struct stm32_can_s *priv, FAR const char *msg);
|
FAR const char *msg);
|
||||||
static void can_dumpfiltregs(struct stm32_can_s *priv, FAR const char *msg);
|
static void can_dumpmbregs(FAR struct stm32_can_s *priv,
|
||||||
|
FAR const char *msg);
|
||||||
|
static void can_dumpfiltregs(FAR struct stm32_can_s *priv,
|
||||||
|
FAR const char *msg);
|
||||||
#else
|
#else
|
||||||
# define can_dumpctrlregs(priv,msg)
|
# define can_dumpctrlregs(priv,msg)
|
||||||
# define can_dumpmbregs(priv,msg)
|
# define can_dumpmbregs(priv,msg)
|
||||||
@ -147,14 +155,16 @@ 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_rxinterrupt(int irq, FAR void *context, int rxmb);
|
||||||
static int can_txinterrupt(int irq, void *context);
|
static int can_rx0interrupt(int irq, FAR void *context);
|
||||||
|
static int can_rx1interrupt(int irq, FAR void *context);
|
||||||
|
static int can_txinterrupt(int irq, FAR void *context);
|
||||||
|
|
||||||
/* Initialization */
|
/* Initialization */
|
||||||
|
|
||||||
static int can_bittiming(struct stm32_can_s *priv);
|
static int can_bittiming(FAR struct stm32_can_s *priv);
|
||||||
static int can_cellinit(struct stm32_can_s *priv);
|
static int can_cellinit(FAR struct stm32_can_s *priv);
|
||||||
static int can_filterinit(struct stm32_can_s *priv);
|
static int can_filterinit(FAR struct stm32_can_s *priv);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
@ -178,7 +188,11 @@ static const struct can_ops_s g_canops =
|
|||||||
static struct stm32_can_s g_can1priv =
|
static struct stm32_can_s g_can1priv =
|
||||||
{
|
{
|
||||||
.port = 1,
|
.port = 1,
|
||||||
.canrx0 = STM32_IRQ_CAN1RX0,
|
.canrx =
|
||||||
|
{
|
||||||
|
STM32_IRQ_CAN1RX0,
|
||||||
|
STM32_IRQ_CAN1RX1,
|
||||||
|
},
|
||||||
.cantx = STM32_IRQ_CAN1TX,
|
.cantx = STM32_IRQ_CAN1TX,
|
||||||
.filter = 0,
|
.filter = 0,
|
||||||
.base = STM32_CAN1_BASE,
|
.base = STM32_CAN1_BASE,
|
||||||
@ -197,7 +211,11 @@ static struct can_dev_s g_can1dev =
|
|||||||
static struct stm32_can_s g_can2priv =
|
static struct stm32_can_s g_can2priv =
|
||||||
{
|
{
|
||||||
.port = 2,
|
.port = 2,
|
||||||
.canrx0 = STM32_IRQ_CAN2RX0,
|
.canrx =
|
||||||
|
{
|
||||||
|
STM32_IRQ_CAN2RX0,
|
||||||
|
STM32_IRQ_CAN2RX1,
|
||||||
|
},
|
||||||
.cantx = STM32_IRQ_CAN2TX,
|
.cantx = STM32_IRQ_CAN2TX,
|
||||||
.filter = CAN_NFILTERS / 2,
|
.filter = CAN_NFILTERS / 2,
|
||||||
.base = STM32_CAN2_BASE,
|
.base = STM32_CAN2_BASE,
|
||||||
@ -285,23 +303,23 @@ static uint32_t can_vgetreg(uint32_t addr)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t can_getreg(struct stm32_can_s *priv, int offset)
|
static uint32_t can_getreg(FAR struct stm32_can_s *priv, int offset)
|
||||||
{
|
{
|
||||||
return can_vgetreg(priv->base + offset);
|
return can_vgetreg(priv->base + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t can_getfreg(struct stm32_can_s *priv, int offset)
|
static uint32_t can_getfreg(FAR struct stm32_can_s *priv, int offset)
|
||||||
{
|
{
|
||||||
return can_vgetreg(priv->fbase + offset);
|
return can_vgetreg(priv->fbase + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static uint32_t can_getreg(struct stm32_can_s *priv, int offset)
|
static uint32_t can_getreg(FAR struct stm32_can_s *priv, int offset)
|
||||||
{
|
{
|
||||||
return getreg32(priv->base + offset);
|
return getreg32(priv->base + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t can_getfreg(struct stm32_can_s *priv, int offset)
|
static uint32_t can_getfreg(FAR struct stm32_can_s *priv, int offset)
|
||||||
{
|
{
|
||||||
return getreg32(priv->fbase + offset);
|
return getreg32(priv->fbase + offset);
|
||||||
}
|
}
|
||||||
@ -338,23 +356,27 @@ static void can_vputreg(uint32_t addr, uint32_t value)
|
|||||||
putreg32(value, addr);
|
putreg32(value, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void can_putreg(struct stm32_can_s *priv, int offset, uint32_t value)
|
static void can_putreg(FAR struct stm32_can_s *priv, int offset,
|
||||||
|
uint32_t value)
|
||||||
{
|
{
|
||||||
can_vputreg(priv->base + offset, value);
|
can_vputreg(priv->base + offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void can_putfreg(struct stm32_can_s *priv, int offset, uint32_t value)
|
static void can_putfreg(FAR struct stm32_can_s *priv, int offset,
|
||||||
|
uint32_t value)
|
||||||
{
|
{
|
||||||
can_vputreg(priv->fbase + offset, value);
|
can_vputreg(priv->fbase + offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static void can_putreg(struct stm32_can_s *priv, int offset, uint32_t value)
|
static void can_putreg(FAR struct stm32_can_s *priv, int offset,
|
||||||
|
uint32_t value)
|
||||||
{
|
{
|
||||||
putreg32(value, priv->base + offset);
|
putreg32(value, priv->base + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void can_putfreg(struct stm32_can_s *priv, int offset, uint32_t value)
|
static void can_putfreg(FAR struct stm32_can_s *priv, int offset,
|
||||||
|
uint32_t value)
|
||||||
{
|
{
|
||||||
putreg32(value, priv->fbase + offset);
|
putreg32(value, priv->fbase + offset);
|
||||||
}
|
}
|
||||||
@ -375,7 +397,8 @@ static void can_putfreg(struct stm32_can_s *priv, int offset, uint32_t value)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_CAN_REGDEBUG
|
#ifdef CONFIG_CAN_REGDEBUG
|
||||||
static void can_dumpctrlregs(struct stm32_can_s *priv, FAR const char *msg)
|
static void can_dumpctrlregs(FAR struct stm32_can_s *priv,
|
||||||
|
FAR const char *msg)
|
||||||
{
|
{
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
@ -419,7 +442,8 @@ static void can_dumpctrlregs(struct stm32_can_s *priv, FAR const char *msg)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_CAN_REGDEBUG
|
#ifdef CONFIG_CAN_REGDEBUG
|
||||||
static void can_dumpmbregs(struct stm32_can_s *priv, FAR const char *msg)
|
static void can_dumpmbregs(FAR struct stm32_can_s *priv,
|
||||||
|
FAR const char *msg)
|
||||||
{
|
{
|
||||||
if (msg)
|
if (msg)
|
||||||
{
|
{
|
||||||
@ -479,7 +503,8 @@ static void can_dumpmbregs(struct stm32_can_s *priv, FAR const char *msg)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifdef CONFIG_CAN_REGDEBUG
|
#ifdef CONFIG_CAN_REGDEBUG
|
||||||
static void can_dumpfiltregs(struct stm32_can_s *priv, FAR const char *msg)
|
static void can_dumpfiltregs(FAR struct stm32_can_s *priv,
|
||||||
|
FAR const char *msg)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -553,8 +578,8 @@ static void can_reset(FAR struct can_dev_s *dev)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable interrupts momentary to stop any ongoing CAN event processing and
|
/* Disable interrupts momentarily to stop any ongoing CAN event processing
|
||||||
* to prevent any concurrent access to the AHB1RSTR register.
|
* and to prevent any concurrent access to the AHB1RSTR register.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
flags = enter_critical_section();
|
flags = enter_critical_section();
|
||||||
@ -592,7 +617,8 @@ 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 RX0 irq: %d TX irq: %d\n", priv->port, priv->canrx0, priv->cantx);
|
canllvdbg("CAN%d RX0 irq: %d RX1 irq: %d TX irq: %d\n",
|
||||||
|
priv->port, priv->canrx[0], priv->canrx[1], priv->cantx);
|
||||||
|
|
||||||
/* CAN cell initialization */
|
/* CAN cell initialization */
|
||||||
|
|
||||||
@ -616,28 +642,41 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||||||
}
|
}
|
||||||
can_dumpfiltregs(priv, "After filter initialization");
|
can_dumpfiltregs(priv, "After filter initialization");
|
||||||
|
|
||||||
/* Attach the CAN RX FIFO 0 interrupt and TX interrupts. The others are not used */
|
/* Attach the CAN RX FIFO 0/1 interrupts and TX interrupts.
|
||||||
|
* The others are not used.
|
||||||
|
*/
|
||||||
|
|
||||||
ret = irq_attach(priv->canrx0, can_rx0interrupt);
|
ret = irq_attach(priv->canrx[0], can_rx0interrupt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
canlldbg("Failed to attach CAN%d RX0 IRQ (%d)", priv->port, priv->canrx0);
|
canlldbg("Failed to attach CAN%d RX0 IRQ (%d)",
|
||||||
|
priv->port, priv->canrx[0]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = irq_attach(priv->canrx[1], can_rx1interrupt);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
canlldbg("Failed to attach CAN%d RX1 IRQ (%d)",
|
||||||
|
priv->port, priv->canrx[1]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = irq_attach(priv->cantx, can_txinterrupt);
|
ret = irq_attach(priv->cantx, can_txinterrupt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
canlldbg("Failed to attach CAN%d TX IRQ (%d)", priv->port, priv->cantx);
|
canlldbg("Failed to attach CAN%d TX IRQ (%d)",
|
||||||
|
priv->port, priv->cantx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable the interrupts at the NVIC. Interrupts arestill disabled in
|
/* Enable the interrupts at the NVIC. Interrupts are still disabled in
|
||||||
* the CAN module. Since we coming out of reset here, there should be
|
* the CAN module. Since we coming out of reset here, there should be
|
||||||
* no pending interrupts.
|
* no pending interrupts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
up_enable_irq(priv->canrx0);
|
up_enable_irq(priv->canrx[0]);
|
||||||
|
up_enable_irq(priv->canrx[1]);
|
||||||
up_enable_irq(priv->cantx);
|
up_enable_irq(priv->cantx);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -663,14 +702,16 @@ 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 and TX interrupts */
|
/* Disable the RX FIFO 0/1 and TX interrupts */
|
||||||
|
|
||||||
up_disable_irq(priv->canrx0);
|
up_disable_irq(priv->canrx[0]);
|
||||||
|
up_disable_irq(priv->canrx[1]);
|
||||||
up_disable_irq(priv->cantx);
|
up_disable_irq(priv->cantx);
|
||||||
|
|
||||||
/* Detach the RX FIFO 0 and TX interrupts */
|
/* Detach the RX FIFO 0/1 and TX interrupts */
|
||||||
|
|
||||||
irq_detach(priv->canrx0);
|
irq_detach(priv->canrx[0]);
|
||||||
|
irq_detach(priv->canrx[1]);
|
||||||
irq_detach(priv->cantx);
|
irq_detach(priv->cantx);
|
||||||
|
|
||||||
/* And reset the hardware */
|
/* And reset the hardware */
|
||||||
@ -699,16 +740,16 @@ static void can_rxint(FAR struct can_dev_s *dev, bool enable)
|
|||||||
|
|
||||||
canllvdbg("CAN%d enable: %d\n", priv->port, enable);
|
canllvdbg("CAN%d enable: %d\n", priv->port, enable);
|
||||||
|
|
||||||
/* Enable/disable the FIFO 0 message pending interrupt */
|
/* Enable/disable the FIFO 0/1 message pending interrupt */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_IER_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_IER_OFFSET);
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
regval |= CAN_IER_FMPIE0;
|
regval |= CAN_IER_FMPIE0 | CAN_IER_FMPIE1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
regval &= ~CAN_IER_FMPIE0;
|
regval &= ~(CAN_IER_FMPIE0 | CAN_IER_FMPIE1);
|
||||||
}
|
}
|
||||||
can_putreg(priv, STM32_CAN_IER_OFFSET, regval);
|
can_putreg(priv, STM32_CAN_IER_OFFSET, regval);
|
||||||
}
|
}
|
||||||
@ -817,7 +858,8 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||||||
int dlc;
|
int dlc;
|
||||||
int txmb;
|
int txmb;
|
||||||
|
|
||||||
canllvdbg("CAN%d ID: %d DLC: %d\n", priv->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
|
canllvdbg("CAN%d ID: %d DLC: %d\n",
|
||||||
|
priv->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
|
||||||
|
|
||||||
/* Select one empty transmit mailbox */
|
/* Select one empty transmit mailbox */
|
||||||
|
|
||||||
@ -843,7 +885,8 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||||||
/* Clear TXRQ, RTR, IDE, EXID, and STID fields */
|
/* Clear TXRQ, RTR, IDE, EXID, and STID fields */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb));
|
regval = can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb));
|
||||||
regval &= ~(CAN_TIR_TXRQ | CAN_TIR_RTR | CAN_TIR_IDE | CAN_TIR_EXID_MASK | CAN_TIR_STID_MASK);
|
regval &= ~(CAN_TIR_TXRQ | CAN_TIR_RTR | CAN_TIR_IDE |
|
||||||
|
CAN_TIR_EXID_MASK | CAN_TIR_STID_MASK);
|
||||||
can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval);
|
can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval);
|
||||||
|
|
||||||
/* Set up the ID, standard 11-bit or extended 29-bit. */
|
/* Set up the ID, standard 11-bit or extended 29-bit. */
|
||||||
@ -886,17 +929,17 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||||||
|
|
||||||
if (dlc > 1)
|
if (dlc > 1)
|
||||||
{
|
{
|
||||||
tmp = (uint32_t)*ptr++;
|
tmp = (uint32_t)*ptr++;
|
||||||
regval |= tmp << CAN_TDLR_DATA1_SHIFT;
|
regval |= tmp << CAN_TDLR_DATA1_SHIFT;
|
||||||
|
|
||||||
if (dlc > 2)
|
if (dlc > 2)
|
||||||
{
|
{
|
||||||
tmp = (uint32_t)*ptr++;
|
tmp = (uint32_t)*ptr++;
|
||||||
regval |= tmp << CAN_TDLR_DATA2_SHIFT;
|
regval |= tmp << CAN_TDLR_DATA2_SHIFT;
|
||||||
|
|
||||||
if (dlc > 3)
|
if (dlc > 3)
|
||||||
{
|
{
|
||||||
tmp = (uint32_t)*ptr++;
|
tmp = (uint32_t)*ptr++;
|
||||||
regval |= tmp << CAN_TDLR_DATA3_SHIFT;
|
regval |= tmp << CAN_TDLR_DATA3_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -912,17 +955,17 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||||||
|
|
||||||
if (dlc > 5)
|
if (dlc > 5)
|
||||||
{
|
{
|
||||||
tmp = (uint32_t)*ptr++;
|
tmp = (uint32_t)*ptr++;
|
||||||
regval |= tmp << CAN_TDHR_DATA5_SHIFT;
|
regval |= tmp << CAN_TDHR_DATA5_SHIFT;
|
||||||
|
|
||||||
if (dlc > 6)
|
if (dlc > 6)
|
||||||
{
|
{
|
||||||
tmp = (uint32_t)*ptr++;
|
tmp = (uint32_t)*ptr++;
|
||||||
regval |= tmp << CAN_TDHR_DATA6_SHIFT;
|
regval |= tmp << CAN_TDHR_DATA6_SHIFT;
|
||||||
|
|
||||||
if (dlc > 7)
|
if (dlc > 7)
|
||||||
{
|
{
|
||||||
tmp = (uint32_t)*ptr++;
|
tmp = (uint32_t)*ptr++;
|
||||||
regval |= tmp << CAN_TDHR_DATA7_SHIFT;
|
regval |= tmp << CAN_TDHR_DATA7_SHIFT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -970,11 +1013,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_ALL_MAILBOXES) != 0)
|
return (regval & CAN_ALL_MAILBOXES) != 0;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@ -1005,29 +1044,26 @@ static bool can_txempty(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_ALL_MAILBOXES) == CAN_ALL_MAILBOXES)
|
return (regval & CAN_ALL_MAILBOXES) == CAN_ALL_MAILBOXES;
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: can_rx0interrupt
|
* Name: can_rxinterrupt
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* CAN RX FIFO 0 interrupt handler
|
* CAN RX FIFO 0/1 interrupt handler
|
||||||
*
|
*
|
||||||
* Input Parameters:
|
* Input Parameters:
|
||||||
* irq - The IRQ number of the interrupt.
|
* irq - The IRQ number of the interrupt.
|
||||||
* context - The register state save array at the time of the interrupt.
|
* context - The register state save array at the time of the interrupt.
|
||||||
|
* rxmb - The RX mailbox number.
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* Zero on success; a negated errno on failure
|
* Zero on success; a negated errno on failure
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int can_rx0interrupt(int irq, void *context)
|
static int can_rxinterrupt(int irq, FAR void *context, int rxmb)
|
||||||
{
|
{
|
||||||
FAR struct can_dev_s *dev = NULL;
|
FAR struct can_dev_s *dev = NULL;
|
||||||
FAR struct stm32_can_s *priv;
|
FAR struct stm32_can_s *priv;
|
||||||
@ -1038,11 +1074,11 @@ static int can_rx0interrupt(int irq, void *context)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2)
|
#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2)
|
||||||
if (g_can1priv.canrx0 == irq)
|
if (g_can1priv.canrx[rxmb] == irq)
|
||||||
{
|
{
|
||||||
dev = &g_can1dev;
|
dev = &g_can1dev;
|
||||||
}
|
}
|
||||||
else if (g_can2priv.canrx0 == irq)
|
else if (g_can2priv.canrx[rxmb] == irq)
|
||||||
{
|
{
|
||||||
dev = &g_can2dev;
|
dev = &g_can2dev;
|
||||||
}
|
}
|
||||||
@ -1057,9 +1093,9 @@ static int can_rx0interrupt(int irq, void *context)
|
|||||||
#endif
|
#endif
|
||||||
priv = dev->cd_priv;
|
priv = dev->cd_priv;
|
||||||
|
|
||||||
/* Verify that a message is pending in FIFO 0 */
|
/* Verify that a message is pending in the FIFO */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_RF0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RFR_OFFSET(rxmb));
|
||||||
npending = (regval & CAN_RFR_FMP_MASK) >> CAN_RFR_FMP_SHIFT;
|
npending = (regval & CAN_RFR_FMP_MASK) >> CAN_RFR_FMP_SHIFT;
|
||||||
if (npending < 1)
|
if (npending < 1)
|
||||||
{
|
{
|
||||||
@ -1067,11 +1103,18 @@ static int can_rx0interrupt(int irq, void *context)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
can_dumpmbregs(priv, "RX0 interrupt");
|
if (rxmb == 0)
|
||||||
|
{
|
||||||
|
can_dumpmbregs(priv, "RX0 interrupt");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
can_dumpmbregs(priv, "RX1 interrupt");
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the CAN identifier. */
|
/* Get the CAN identifier. */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_RI0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RIR_OFFSET(rxmb));
|
||||||
|
|
||||||
#ifdef CONFIG_CAN_EXTID
|
#ifdef CONFIG_CAN_EXTID
|
||||||
if ((regval & CAN_RIR_IDE) != 0)
|
if ((regval & CAN_RIR_IDE) != 0)
|
||||||
@ -1104,22 +1147,22 @@ static int can_rx0interrupt(int irq, void *context)
|
|||||||
|
|
||||||
/* Extract the RTR bit */
|
/* Extract the RTR bit */
|
||||||
|
|
||||||
hdr.ch_rtr = (regval & CAN_RIR_RTR) != 0 ? true : false;
|
hdr.ch_rtr = (regval & CAN_RIR_RTR) != 0;
|
||||||
|
|
||||||
/* Get the DLC */
|
/* Get the DLC */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_RDT0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RDTR_OFFSET(rxmb));
|
||||||
hdr.ch_dlc = (regval & CAN_RDTR_DLC_MASK) >> CAN_RDTR_DLC_SHIFT;
|
hdr.ch_dlc = (regval & CAN_RDTR_DLC_MASK) >> CAN_RDTR_DLC_SHIFT;
|
||||||
|
|
||||||
/* Save the message data */
|
/* Save the message data */
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_RDL0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RDLR_OFFSET(rxmb));
|
||||||
data[0] = (regval & CAN_RDLR_DATA0_MASK) >> CAN_RDLR_DATA0_SHIFT;
|
data[0] = (regval & CAN_RDLR_DATA0_MASK) >> CAN_RDLR_DATA0_SHIFT;
|
||||||
data[1] = (regval & CAN_RDLR_DATA1_MASK) >> CAN_RDLR_DATA1_SHIFT;
|
data[1] = (regval & CAN_RDLR_DATA1_MASK) >> CAN_RDLR_DATA1_SHIFT;
|
||||||
data[2] = (regval & CAN_RDLR_DATA2_MASK) >> CAN_RDLR_DATA2_SHIFT;
|
data[2] = (regval & CAN_RDLR_DATA2_MASK) >> CAN_RDLR_DATA2_SHIFT;
|
||||||
data[3] = (regval & CAN_RDLR_DATA3_MASK) >> CAN_RDLR_DATA3_SHIFT;
|
data[3] = (regval & CAN_RDLR_DATA3_MASK) >> CAN_RDLR_DATA3_SHIFT;
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_RDH0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RDHR_OFFSET(rxmb));
|
||||||
data[4] = (regval & CAN_RDHR_DATA4_MASK) >> CAN_RDHR_DATA4_SHIFT;
|
data[4] = (regval & CAN_RDHR_DATA4_MASK) >> CAN_RDHR_DATA4_SHIFT;
|
||||||
data[5] = (regval & CAN_RDHR_DATA5_MASK) >> CAN_RDHR_DATA5_SHIFT;
|
data[5] = (regval & CAN_RDHR_DATA5_MASK) >> CAN_RDHR_DATA5_SHIFT;
|
||||||
data[6] = (regval & CAN_RDHR_DATA6_MASK) >> CAN_RDHR_DATA6_SHIFT;
|
data[6] = (regval & CAN_RDHR_DATA6_MASK) >> CAN_RDHR_DATA6_SHIFT;
|
||||||
@ -1129,17 +1172,57 @@ static int can_rx0interrupt(int irq, void *context)
|
|||||||
|
|
||||||
ret = can_receive(dev, &hdr, data);
|
ret = can_receive(dev, &hdr, data);
|
||||||
|
|
||||||
/* Release the FIFO0 */
|
/* Release the FIFO */
|
||||||
|
|
||||||
#ifndef CONFIG_CAN_EXTID
|
#ifndef CONFIG_CAN_EXTID
|
||||||
errout:
|
errout:
|
||||||
#endif
|
#endif
|
||||||
regval = can_getreg(priv, STM32_CAN_RF0R_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_RFR_OFFSET(rxmb));
|
||||||
regval |= CAN_RFR_RFOM;
|
regval |= CAN_RFR_RFOM;
|
||||||
can_putreg(priv, STM32_CAN_RF0R_OFFSET, regval);
|
can_putreg(priv, STM32_CAN_RFR_OFFSET(rxmb), regval);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: can_rx0interrupt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* CAN RX FIFO 0 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_rx0interrupt(int irq, FAR void *context)
|
||||||
|
{
|
||||||
|
return can_rxinterrupt(irq, context, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: can_rx1interrupt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* CAN RX FIFO 1 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_rx1interrupt(int irq, FAR void *context)
|
||||||
|
{
|
||||||
|
return can_rxinterrupt(irq, context, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: can_txinterrupt
|
* Name: can_txinterrupt
|
||||||
*
|
*
|
||||||
@ -1155,7 +1238,7 @@ errout:
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int can_txinterrupt(int irq, void *context)
|
static int can_txinterrupt(int irq, FAR void *context)
|
||||||
{
|
{
|
||||||
FAR struct can_dev_s *dev = NULL;
|
FAR struct can_dev_s *dev = NULL;
|
||||||
FAR struct stm32_can_s *priv;
|
FAR struct stm32_can_s *priv;
|
||||||
@ -1304,7 +1387,7 @@ static int can_txinterrupt(int irq, void *context)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int can_bittiming(struct stm32_can_s *priv)
|
static int can_bittiming(FAR struct stm32_can_s *priv)
|
||||||
{
|
{
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
uint32_t brp;
|
uint32_t brp;
|
||||||
@ -1401,7 +1484,7 @@ static int can_bittiming(struct stm32_can_s *priv)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int can_cellinit(struct stm32_can_s *priv)
|
static int can_cellinit(FAR struct stm32_can_s *priv)
|
||||||
{
|
{
|
||||||
volatile uint32_t timeout;
|
volatile uint32_t timeout;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
@ -1415,11 +1498,6 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||||||
regval &= ~CAN_MCR_SLEEP;
|
regval &= ~CAN_MCR_SLEEP;
|
||||||
can_putreg(priv, STM32_CAN_MCR_OFFSET, regval);
|
can_putreg(priv, STM32_CAN_MCR_OFFSET, regval);
|
||||||
|
|
||||||
/* Configure CAN behavior. Priority driven request order, not message ID. */
|
|
||||||
|
|
||||||
regval |= CAN_MCR_TXFP;
|
|
||||||
can_putreg(priv, STM32_CAN_MCR_OFFSET, regval);
|
|
||||||
|
|
||||||
/* Enter initialization mode */
|
/* Enter initialization mode */
|
||||||
|
|
||||||
regval |= CAN_MCR_INRQ;
|
regval |= CAN_MCR_INRQ;
|
||||||
@ -1457,7 +1535,8 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
regval = can_getreg(priv, STM32_CAN_MCR_OFFSET);
|
regval = can_getreg(priv, STM32_CAN_MCR_OFFSET);
|
||||||
regval &= ~(CAN_MCR_TXFP | CAN_MCR_RFLM | CAN_MCR_NART | CAN_MCR_AWUM | CAN_MCR_ABOM | CAN_MCR_TTCM);
|
regval &= ~(CAN_MCR_TXFP | CAN_MCR_RFLM | CAN_MCR_NART |
|
||||||
|
CAN_MCR_AWUM | CAN_MCR_ABOM | CAN_MCR_TTCM);
|
||||||
can_putreg(priv, STM32_CAN_MCR_OFFSET, regval);
|
can_putreg(priv, STM32_CAN_MCR_OFFSET, regval);
|
||||||
|
|
||||||
/* Configure bit timing. */
|
/* Configure bit timing. */
|
||||||
@ -1492,7 +1571,8 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||||||
|
|
||||||
if (timeout < 1)
|
if (timeout < 1)
|
||||||
{
|
{
|
||||||
canlldbg("ERROR: Timed out waiting to exit initialization mode: %08x\n", regval);
|
canlldbg("ERROR: Timed out waiting to exit initialization mode: %08x\n",
|
||||||
|
regval);
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
@ -1531,7 +1611,7 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int can_filterinit(struct stm32_can_s *priv)
|
static int can_filterinit(FAR struct stm32_can_s *priv)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
uint32_t bitmask;
|
uint32_t bitmask;
|
||||||
@ -1540,7 +1620,7 @@ static int can_filterinit(struct stm32_can_s *priv)
|
|||||||
|
|
||||||
/* Get the bitmask associated with the filter used by this CAN block */
|
/* Get the bitmask associated with the filter used by this CAN block */
|
||||||
|
|
||||||
bitmask = ((uint32_t)1) << priv->filter;
|
bitmask = (uint32_t)1 << priv->filter;
|
||||||
|
|
||||||
/* Enter filter initialization mode */
|
/* Enter filter initialization mode */
|
||||||
|
|
||||||
@ -1548,6 +1628,17 @@ static int can_filterinit(struct stm32_can_s *priv)
|
|||||||
regval |= CAN_FMR_FINIT;
|
regval |= CAN_FMR_FINIT;
|
||||||
can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval);
|
can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval);
|
||||||
|
|
||||||
|
/* Assign half the filters to CAN1, half to CAN2 */
|
||||||
|
|
||||||
|
#if defined(CONFIG_STM32_CONNECTIVITYLINE) || \
|
||||||
|
defined(CONFIG_STM32_STM32F20XX) || \
|
||||||
|
defined(CONFIG_STM32_STM32F40XX)
|
||||||
|
regval = can_getfreg(priv, STM32_CAN_FMR_OFFSET);
|
||||||
|
regval &= CAN_FMR_CAN2SB_MASK;
|
||||||
|
regval |= (CAN_NFILTERS / 2) << CAN_FMR_CAN2SB_SHIFT;
|
||||||
|
can_putfreg(priv, STM32_CAN_FMR_OFFSET, regval);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Disable the filter */
|
/* Disable the filter */
|
||||||
|
|
||||||
regval = can_getfreg(priv, STM32_CAN_FA1R_OFFSET);
|
regval = can_getfreg(priv, STM32_CAN_FA1R_OFFSET);
|
||||||
@ -1560,12 +1651,12 @@ static int can_filterinit(struct stm32_can_s *priv)
|
|||||||
regval |= bitmask;
|
regval |= bitmask;
|
||||||
can_putfreg(priv, STM32_CAN_FS1R_OFFSET, regval);
|
can_putfreg(priv, STM32_CAN_FS1R_OFFSET, regval);
|
||||||
|
|
||||||
/* There are 14 or 28 filter banks (depending) on the device. Each filter bank is
|
/* There are 14 or 28 filter banks (depending) on the device.
|
||||||
* composed of two 32-bit registers, CAN_FiR:
|
* Each filter bank is composed of two 32-bit registers, CAN_FiR:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
can_putfreg(priv, STM32_CAN_FIR_OFFSET(priv->filter, 1), 0);
|
can_putfreg(priv, STM32_CAN_FIR_OFFSET(priv->filter, 1), 0);
|
||||||
can_putfreg(priv, STM32_CAN_FIR_OFFSET(priv->filter, 2), 0);
|
can_putfreg(priv, STM32_CAN_FIR_OFFSET(priv->filter, 2), 0);
|
||||||
|
|
||||||
/* Set Id/Mask mode for the filter */
|
/* Set Id/Mask mode for the filter */
|
||||||
|
|
||||||
@ -1613,7 +1704,7 @@ static int can_filterinit(struct stm32_can_s *priv)
|
|||||||
|
|
||||||
FAR struct can_dev_s *stm32_caninitialize(int port)
|
FAR struct can_dev_s *stm32_caninitialize(int port)
|
||||||
{
|
{
|
||||||
struct can_dev_s *dev = NULL;
|
FAR struct can_dev_s *dev = NULL;
|
||||||
|
|
||||||
canvdbg("CAN%d\n", port);
|
canvdbg("CAN%d\n", port);
|
||||||
|
|
||||||
@ -1662,4 +1753,3 @@ FAR struct can_dev_s *stm32_caninitialize(int port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_CAN && (CONFIG_STM32_CAN1 || CONFIG_STM32_CAN2) */
|
#endif /* CONFIG_CAN && (CONFIG_STM32_CAN1 || CONFIG_STM32_CAN2) */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user