diff options
Diffstat (limited to 'os/hal')
-rw-r--r-- | os/hal/include/can.h | 21 | ||||
-rw-r--r-- | os/hal/platforms/STM32/adc_lld.c | 2 | ||||
-rw-r--r-- | os/hal/platforms/STM32/can_lld.c | 87 | ||||
-rw-r--r-- | os/hal/platforms/STM32/can_lld.h | 12 | ||||
-rw-r--r-- | os/hal/src/can.c | 5 |
5 files changed, 114 insertions, 13 deletions
diff --git a/os/hal/include/can.h b/os/hal/include/can.h index 3637c64b0..2a385b224 100644 --- a/os/hal/include/can.h +++ b/os/hal/include/can.h @@ -30,6 +30,27 @@ #if CH_HAL_USE_CAN || defined(__DOXYGEN__)
/**
+ * @brief Errors rate warning.
+ */
+#define CAN_LIMIT_WARNING 1
+/**
+ * @brief Errors rate error.
+ */
+#define CAN_LIMIT_ERROR 2
+/**
+ * @brief Bus off condition reached.
+ */
+#define CAN_BUS_OFF_ERROR 4
+/**
+ * @brief Framing error of some kind on the CAN bus.
+ */
+#define CAN_FRAMING_ERROR 8
+/**
+ * @brief Overflow in receive queue.
+ */
+#define CAN_OVERFLOW_ERROR 16
+
+/**
* @brief Driver state machine possible states.
*/
typedef enum {
diff --git a/os/hal/platforms/STM32/adc_lld.c b/os/hal/platforms/STM32/adc_lld.c index 1213484e2..0c485c038 100644 --- a/os/hal/platforms/STM32/adc_lld.c +++ b/os/hal/platforms/STM32/adc_lld.c @@ -112,7 +112,7 @@ CH_IRQ_HANDLER(Vector6C) { void adc_lld_init(void) {
#if USE_STM32_ADC1
- /* ADC reset, ensures reset state in order to avoid truouble with JTAGs.*/
+ /* ADC reset, ensures reset state in order to avoid trouble with JTAGs.*/
RCC->APB2RSTR = RCC_APB2RSTR_ADC1RST;
RCC->APB2RSTR = 0;
diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c index 30d270a37..2e3ed43df 100644 --- a/os/hal/platforms/STM32/can_lld.c +++ b/os/hal/platforms/STM32/can_lld.c @@ -68,12 +68,24 @@ CH_IRQ_HANDLER(Vector8C) { * CAN1 RX0 interrupt handler.
*/
CH_IRQ_HANDLER(Vector90) {
+ uint32_t rf0r;
CH_IRQ_PROLOGUE();
- /* No more events until the incoming messages queues are emptied.*/
- CAN1->IER &= ~(CAN_IER_FMPIE0 | CAN_IER_FMPIE1);
- chEvtBroadcastI(&CAND1.cd_rxfull_event);
+ rf0r = CAN1->RF0R;
+ chSysLockFromIsr();
+ if ((rf0r & CAN_RF0R_FMP0) > 0) {
+ /* No more receive events until the queue 0 has been emptied.*/
+ CAN1->IER &= ~CAN_IER_FMPIE0;
+ chEvtBroadcastI(&CAND1.cd_rxfull_event);
+ }
+ if ((rf0r & CAN_RF0R_FOVR0) > 0) {
+ /* Overflow events handling.*/
+ CAN1->RF0R = CAN_RF0R_FOVR0;
+ canAddFlagsI(&CAND1, CAN_OVERFLOW_ERROR);
+ chEvtBroadcastI(&CAND1.cd_error_event);
+ }
+ chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
}
@@ -85,9 +97,7 @@ CH_IRQ_HANDLER(Vector94) { CH_IRQ_PROLOGUE();
- /* No more events until the incoming messages queues are emptied.*/
- CAN1->IER &= ~(CAN_IER_FMPIE0 | CAN_IER_FMPIE1);
- chEvtBroadcastI(&CAND1.cd_rxfull_event);
+ chSysHalt(); /* Not supported (yet).*/
CH_IRQ_EPILOGUE();
}
@@ -96,12 +106,32 @@ CH_IRQ_HANDLER(Vector94) { * CAN1 SCE interrupt handler.
*/
CH_IRQ_HANDLER(Vector98) {
+ uint32_t msr;
CH_IRQ_PROLOGUE();
- canAddFlagsI(&CAND1, 1);
- chEvtBroadcastI(&CAND1.cd_error_event);
- CAN1->MSR = CAN_MSR_ERRI;
+ msr = CAN1->MSR;
+ CAN1->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI;
+ /* Wakeup event.*/
+ if (msr & CAN_MSR_WKUI) {
+ chSysLockFromIsr();
+ chEvtBroadcastI(&CAND1.cd_wakeup_event);
+ chSysUnlockFromIsr();
+ }
+ /* Error event.*/
+ if (msr & CAN_MSR_ERRI) {
+ canstatus_t flags;
+ uint32_t esr = CAN1->ESR;
+
+ CAN1->ESR &= ~CAN_ESR_LEC;
+ flags = (canstatus_t)(esr & 7);
+ if ((esr & CAN_ESR_LEC) > 0)
+ flags |= CAN_FRAMING_ERROR;
+ chSysLockFromIsr();
+ canAddFlagsI(&CAND1, flags);
+ chEvtBroadcastI(&CAND1.cd_error_event);
+ chSysUnlockFromIsr();
+ }
CH_IRQ_EPILOGUE();
}
@@ -115,6 +145,15 @@ CH_IRQ_HANDLER(Vector98) { */
void can_lld_init(void) {
+#if USE_STM32_CAN1
+ /* CAN reset, ensures reset state in order to avoid trouble with JTAGs.*/
+ RCC->APB1RSTR = RCC_APB1RSTR_CAN1RST;
+ RCC->APB1RSTR = 0;
+
+ /* Driver initialization.*/
+ canObjectInit(&CAND1);
+ CAND1.cd_can = CAN1;
+#endif
}
/**
@@ -126,8 +165,23 @@ void can_lld_start(CANDriver *canp) { if (canp->cd_state == CAN_STOP) {
/* Clock activation.*/
+#if USE_STM32_CAN1
+ if (&CAND1 == canp) {
+ NVICEnableVector(USB_HP_CAN1_TX_IRQn, STM32_CAN1_IRQ_PRIORITY);
+ NVICEnableVector(USB_LP_CAN1_RX0_IRQn, STM32_CAN1_IRQ_PRIORITY);
+ NVICEnableVector(CAN1_RX1_IRQn, STM32_CAN1_IRQ_PRIORITY);
+ NVICEnableVector(CAN1_SCE_IRQn, STM32_CAN1_IRQ_PRIORITY);
+ RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
+ }
+#endif
}
/* Configuration.*/
+ canp->cd_can->MCR = canp->cd_config->cc_mcr;
+ canp->cd_can->BTR = canp->cd_config->cc_btr;
+ canp->cd_can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 |
+ CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE |
+ CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE |
+ CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
}
/**
@@ -137,6 +191,21 @@ void can_lld_start(CANDriver *canp) { */
void can_lld_stop(CANDriver *canp) {
+ /* If in ready state then disables the CAN clock.*/
+ if (canp->cd_state == CAN_READY) {
+#if USE_STM32_CAN1
+ if (&CAND1 == canp) {
+ CAN1->MCR = 0x00010002; /* Register reset value. */
+ CAN1->BTR = 0x01230000; /* Register reset value. */
+ CAN1->IER = 0x00000000; /* All sources disabled. */
+ NVICDisableVector(USB_HP_CAN1_TX_IRQn);
+ NVICDisableVector(USB_LP_CAN1_RX0_IRQn);
+ NVICDisableVector(CAN1_RX1_IRQn);
+ NVICDisableVector(CAN1_SCE_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN;
+ }
+#endif
+ }
}
/**
diff --git a/os/hal/platforms/STM32/can_lld.h b/os/hal/platforms/STM32/can_lld.h index a02ce15fc..422249cef 100644 --- a/os/hal/platforms/STM32/can_lld.h +++ b/os/hal/platforms/STM32/can_lld.h @@ -40,7 +40,7 @@ /*===========================================================================*/
/**
- * @brief ADC1 driver enable switch.
+ * @brief CAN1 driver enable switch.
* @details If set to @p TRUE the support for ADC1 is included.
* @note The default is @p TRUE.
*/
@@ -49,6 +49,14 @@ #endif
/**
+ * @brief CAN1 interrupt priority level setting.
+ * @note @p BASEPRI_KERNEL >= @p STM32_SPI1_IRQ_PRIORITY > @p PRIORITY_PENDSV.
+ */
+#if !defined(STM32_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_CAN1_IRQ_PRIORITY 0xB0
+#endif
+
+/**
* @brief Sleep mode related APIs inclusion switch.
* @note This switch is enforced to @p FALSE if the driver implementation
* does not support the sleep mode. @@ -159,7 +167,7 @@ typedef struct { /**
* @brief Pointer to the CAN registers. */
- CAN_TypeDef *cd_canp;
+ CAN_TypeDef *cd_can;
} CANDriver;
/*===========================================================================*/
diff --git a/os/hal/src/can.c b/os/hal/src/can.c index 698bcfbc4..7c6cdd656 100644 --- a/os/hal/src/can.c +++ b/os/hal/src/can.c @@ -50,6 +50,8 @@ void canObjectInit(CANDriver *canp) { chSemInit(&canp->cd_rxsem, 0);
chEvtInit(&canp->cd_rxfull_event);
chEvtInit(&canp->cd_txempty_event);
+ chEvtInit(&canp->cd_error_event);
+ canp->cd_status = 0;
#if CAN_USE_SLEEP_MODE
chEvtInit(&canp->cd_sleep_event);
chEvtInit(&canp->cd_wakeup_event);
@@ -90,7 +92,8 @@ void canStop(CANDriver *canp) { "canStop(), #1",
"invalid state");
can_lld_stop(canp);
- canp->cd_state = CAN_STOP;
+ canp->cd_state = CAN_STOP;
+ canp->cd_status = 0;
chSysUnlock();
}
|