You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/01/05 10:33:10 UTC
[incubator-nuttx] branch master updated: stm32: add CAN error support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 5b9b381 stm32: add CAN error support
5b9b381 is described below
commit 5b9b3814f8ade12d69cdd047dd8c7623fd944c32
Author: raiden00pl <ra...@railab.me>
AuthorDate: Wed Jan 5 09:57:18 2022 +0100
stm32: add CAN error support
---
arch/arm/src/stm32/Kconfig | 1 +
arch/arm/src/stm32/stm32_can.c | 272 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 266 insertions(+), 7 deletions(-)
diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig
index 819b50e..7d52339 100644
--- a/arch/arm/src/stm32/Kconfig
+++ b/arch/arm/src/stm32/Kconfig
@@ -3388,6 +3388,7 @@ config STM32_I2C
config STM32_CAN
bool
+ select ARCH_HAVE_CAN_ERRORS
config STM32_TIM
bool
diff --git a/arch/arm/src/stm32/stm32_can.c b/arch/arm/src/stm32/stm32_can.c
index 4f8a7ec..a13640a 100644
--- a/arch/arm/src/stm32/stm32_can.c
+++ b/arch/arm/src/stm32/stm32_can.c
@@ -67,6 +67,14 @@
# undef CONFIG_STM32_CAN_REGDEBUG
#endif
+/* CAN error interrupts */
+
+#ifdef CONFIG_CAN_ERRORS
+# define STM32_CAN_ERRINT (CAN_IER_LECIE | CAN_IER_ERRIE | \
+ CAN_IER_BOFIE | CAN_IER_EPVIE | \
+ CAN_IER_EWGIE)
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -76,6 +84,9 @@ struct stm32_can_s
uint8_t port; /* CAN port number (1 or 2) */
uint8_t canrx[2]; /* CAN RX FIFO 0/1 IRQ number */
uint8_t cantx; /* CAN TX IRQ number */
+#ifdef CONFIG_CAN_ERRORS
+ uint8_t cansce; /* CAN SCE IRQ number */
+#endif
uint8_t filter; /* Filter number */
uint32_t base; /* Base address of the CAN control registers */
uint32_t fbase; /* Base address of the CAN filter registers */
@@ -138,12 +149,19 @@ static int stm32can_send(FAR struct can_dev_s *dev,
static bool stm32can_txready(FAR struct can_dev_s *dev);
static bool stm32can_txempty(FAR struct can_dev_s *dev);
+#ifdef CONFIG_CAN_ERRORS
+static void stm32can_errint(FAR struct can_dev_s *dev, bool enable);
+#endif
+
/* CAN interrupt handling */
static int stm32can_rxinterrupt(FAR struct can_dev_s *dev, int rxmb);
static int stm32can_rx0interrupt(int irq, FAR void *context, FAR void *arg);
static int stm32can_rx1interrupt(int irq, FAR void *context, FAR void *arg);
static int stm32can_txinterrupt(int irq, FAR void *context, FAR void *arg);
+#ifdef CONFIG_CAN_ERRORS
+static int stm32can_sceinterrupt(int irq, FAR void *context, FAR void *arg);
+#endif
/* Initialization */
@@ -187,6 +205,9 @@ static struct stm32_can_s g_can1priv =
STM32_IRQ_CAN1RX1,
},
.cantx = STM32_IRQ_CAN1TX,
+#ifdef CONFIG_CAN_ERRORS
+ .cansce = STM32_IRQ_CAN1SCE,
+#endif
.filter = 0,
.base = STM32_CAN1_BASE,
.fbase = STM32_CAN1_BASE,
@@ -210,6 +231,9 @@ static struct stm32_can_s g_can2priv =
STM32_IRQ_CAN2RX1,
},
.cantx = STM32_IRQ_CAN2TX,
+#ifdef CONFIG_CAN_ERRORS
+ .cansce = STM32_IRQ_CAN2SCE,
+#endif
.filter = CAN_NFILTERS / 2,
.base = STM32_CAN2_BASE,
.fbase = STM32_CAN1_BASE,
@@ -615,9 +639,16 @@ static int stm32can_setup(FAR struct can_dev_s *dev)
FAR struct stm32_can_s *priv = dev->cd_priv;
int ret;
- caninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8
- " TX irq: %" PRIu8 "\n",
- priv->port, priv->canrx[0], priv->canrx[1], priv->cantx);
+#ifdef CONFIG_CAN_ERRORS
+ ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8
+ " TX irq: %" PRIu8 " SCE irq: %" PRIu8 "\n",
+ priv->port, priv->canrx[0], priv->canrx[1], priv->cantx,
+ priv->cansce);
+#else
+ ninfo("CAN%" PRIu8 " RX0 irq: %" PRIu8 " RX1 irq: %" PRIu8
+ " TX irq: %" PRIu8 "\n",
+ priv->port, priv->canrx[0], priv->canrx[1], priv->cantx);
+#endif
/* CAN cell initialization */
@@ -672,6 +703,20 @@ static int stm32can_setup(FAR struct can_dev_s *dev)
return ret;
}
+#ifdef CONFIG_CAN_ERRORS
+ ret = irq_attach(priv->cansce, stm32can_sceinterrupt, dev);
+ if (ret < 0)
+ {
+ nerr("ERROR: Failed to attach CAN%" PRIu8 " SCE IRQ (%" PRIu8 ")",
+ priv->port, priv->cansce);
+ return ret;
+ }
+
+ /* Enable CAN error interrupts */
+
+ stm32can_errint(dev, true);
+#endif
+
/* Enable the 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.
@@ -680,6 +725,9 @@ static int stm32can_setup(FAR struct can_dev_s *dev)
up_enable_irq(priv->canrx[0]);
up_enable_irq(priv->canrx[1]);
up_enable_irq(priv->cantx);
+#ifdef CONFIG_CAN_ERRORS
+ up_enable_irq(priv->cansce);
+#endif
return OK;
}
@@ -704,17 +752,23 @@ static void stm32can_shutdown(FAR struct can_dev_s *dev)
caninfo("CAN%" PRIu8 "\n", priv->port);
- /* Disable the RX FIFO 0/1 and TX interrupts */
+ /* Disable the RX FIFO 0/1, TX and SCE interrupts */
up_disable_irq(priv->canrx[0]);
up_disable_irq(priv->canrx[1]);
up_disable_irq(priv->cantx);
+#ifdef CONFIG_CAN_ERRORS
+ up_disable_irq(priv->cansce);
+#endif
- /* Detach the RX FIFO 0/1 and TX interrupts */
+ /* Detach the RX FIFO 0/1, TX and SCE interrupts */
irq_detach(priv->canrx[0]);
irq_detach(priv->canrx[1]);
irq_detach(priv->cantx);
+#ifdef CONFIG_CAN_ERRORS
+ irq_detach(priv->cansce);
+#endif
/* And reset the hardware */
@@ -740,7 +794,7 @@ static void stm32can_rxint(FAR struct can_dev_s *dev, bool enable)
FAR struct stm32_can_s *priv = dev->cd_priv;
uint32_t regval;
- caninfo("CAN%" PRIu8 " enable: %d\n", priv->port, enable);
+ caninfo("CAN%" PRIu8 " rxint enable: %d\n", priv->port, enable);
/* Enable/disable the FIFO 0/1 message pending interrupt */
@@ -776,7 +830,7 @@ static void stm32can_txint(FAR struct can_dev_s *dev, bool enable)
FAR struct stm32_can_s *priv = dev->cd_priv;
uint32_t regval;
- caninfo("CAN%" PRIu8 " enable: %d\n", priv->port, enable);
+ caninfo("CAN%" PRIu8 " txint enable: %d\n", priv->port, enable);
/* Support only disabling the transmit mailbox interrupt */
@@ -788,6 +842,44 @@ static void stm32can_txint(FAR struct can_dev_s *dev, bool enable)
}
}
+#ifdef CONFIG_CAN_ERRORS
+/****************************************************************************
+ * Name: stm32can_errint
+ *
+ * Description:
+ * Call to enable or disable CAN error interrupts.
+ *
+ * Input Parameters:
+ * dev - An instance of the "upper half" can driver state structure.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void stm32can_errint(FAR struct can_dev_s *dev, bool enable)
+{
+ FAR struct stm32_can_s *priv = dev->cd_priv;
+ uint32_t regval = 0;
+
+ caninfo("CAN%" PRIu8 " errint enable: %d\n", priv->port, enable);
+
+ /* Enable/disable the transmit mailbox interrupt */
+
+ regval = stm32can_getreg(priv, STM32_CAN_IER_OFFSET);
+ if (enable)
+ {
+ regval |= STM32_CAN_ERRINT;
+ }
+ else
+ {
+ regval &= ~STM32_CAN_ERRINT;
+ }
+
+ stm32can_putreg(priv, STM32_CAN_IER_OFFSET, regval);
+}
+#endif
+
/****************************************************************************
* Name: stm32can_ioctl
*
@@ -1649,6 +1741,172 @@ static int stm32can_txinterrupt(int irq, FAR void *context, FAR void *arg)
return OK;
}
+#ifdef CONFIG_CAN_ERRORS
+/****************************************************************************
+ * Name: stm32can_sceinterrupt
+ *
+ * Description:
+ * CAN status change 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 stm32can_sceinterrupt(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct can_dev_s *dev = (FAR struct can_dev_s *)arg;
+ FAR struct stm32_can_s *priv = NULL;
+ struct can_hdr_s hdr;
+ uint32_t regval = 0;
+ uint16_t errbits = 0;
+ uint8_t data[CAN_ERROR_DLC];
+ int ret = OK;
+
+ DEBUGASSERT(dev != NULL && dev->cd_priv != NULL);
+ priv = dev->cd_priv;
+
+ /* Check Error Interrupt flag */
+
+ regval = stm32can_getreg(priv, STM32_CAN_MSR_OFFSET);
+ if (regval & CAN_MSR_ERRI)
+ {
+ /* Encode error bits */
+
+ errbits = 0;
+ memset(data, 0, sizeof(data));
+
+ /* Get Error statur register */
+
+ regval = stm32can_getreg(priv, STM32_CAN_ESR_OFFSET);
+
+ if (regval & CAN_ESR_EWGF)
+ {
+ /* Error warning flag */
+
+ data[1] |= (CAN_ERROR1_RXWARNING | CAN_ERROR1_TXWARNING);
+ errbits |= CAN_ERROR_CONTROLLER;
+ }
+
+ if (regval & CAN_ESR_EPVF)
+ {
+ /* Error passive flag */
+
+ data[1] |= (CAN_ERROR1_RXPASSIVE | CAN_ERROR1_TXPASSIVE);
+ errbits |= CAN_ERROR_CONTROLLER;
+ }
+
+ if (regval & CAN_ESR_BOFF)
+ {
+ /* Bus-off flag */
+
+ errbits |= CAN_ERROR_BUSOFF;
+ }
+
+ /* Last error code */
+
+ if (regval & CAN_ESR_LEC_MASK)
+ {
+ if (regval & CAN_ESR_STUFFERROR)
+ {
+ /* Stuff Error */
+
+ errbits |= CAN_ERROR_PROTOCOL;
+ data[2] |= CAN_ERROR2_STUFF;
+ }
+ else if (regval & CAN_ESR_FORMERROR)
+ {
+ /* Format Error */
+
+ errbits |= CAN_ERROR_PROTOCOL;
+ data[2] |= CAN_ERROR2_FORM;
+ }
+ else if (regval & CAN_ESR_ACKERROR)
+ {
+ /* Acknowledge Error */
+
+ errbits |= CAN_ERROR_NOACK;
+ }
+ else if (regval & CAN_ESR_BRECERROR)
+ {
+ /* Bit recessive Error */
+
+ errbits |= CAN_ERROR_PROTOCOL;
+ data[2] |= CAN_ERROR2_BIT1;
+ }
+ else if (regval & CAN_ESR_BDOMERROR)
+ {
+ /* Bit dominant Error */
+
+ errbits |= CAN_ERROR_PROTOCOL;
+ data[2] |= CAN_ERROR2_BIT0;
+ }
+ else if (regval & CAN_ESR_CRCERRPR)
+ {
+ /* Receive CRC Error */
+
+ errbits |= CAN_ERROR_PROTOCOL;
+ data[3] |= CAN_ERROR3_CRCSEQ;
+ }
+ }
+
+ /* Get transmit status register */
+
+ regval = stm32can_getreg(priv, STM32_CAN_TSR_OFFSET);
+
+ if (regval & CAN_TSR_ALST0 || regval & CAN_TSR_ALST1 ||
+ regval & CAN_TSR_ALST2)
+ {
+ /* Lost arbitration Error */
+
+ errbits |= CAN_ERROR_LOSTARB;
+ }
+
+ /* Clear TSR register */
+
+ stm32can_putreg(priv, STM32_CAN_TSR_OFFSET, regval);
+
+ /* Clear ERRI flag */
+
+ stm32can_putreg(priv, STM32_CAN_MSR_OFFSET, CAN_MSR_ERRI);
+ }
+
+ /* TODO: RX overflow and TX overflow */
+
+ /* Report a CAN error */
+
+ if (errbits != 0)
+ {
+ canerr("ERROR: errbits = %08" PRIx16 "\n", errbits);
+
+ /* Format the CAN header for the error report. */
+
+ hdr.ch_id = errbits;
+ hdr.ch_dlc = CAN_ERROR_DLC;
+ hdr.ch_rtr = 0;
+ hdr.ch_error = 1;
+#ifdef CONFIG_CAN_EXTID
+ hdr.ch_extid = 0;
+#endif
+ hdr.ch_unused = 0;
+
+ /* And provide the error report to the upper half logic */
+
+ ret = can_receive(dev, &hdr, data);
+ if (ret < 0)
+ {
+ canerr("ERROR: can_receive failed: %d\n", ret);
+ }
+ }
+
+ return ret;
+}
+#endif
+
/****************************************************************************
* Name: stm32can_bittiming
*