aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/platforms/STM32/can_lld.c
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-02-03 10:29:01 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2013-02-03 10:29:01 +0000
commit92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0 (patch)
tree7137b92e04fff3e94c0db7318dd9611d3c22d45d /os/hal/platforms/STM32/can_lld.c
parent184a71345c6a36a9a8664eda8fbcc3ea728267a8 (diff)
downloadChibiOS-92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0.tar.gz
ChibiOS-92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0.tar.bz2
ChibiOS-92bf9bdac3071fc6586f3bb2f2445e3e7c5cefd0.zip
Added CAN2 support. Tested on the STM32F4xx only.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5105 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal/platforms/STM32/can_lld.c')
-rw-r--r--os/hal/platforms/STM32/can_lld.c402
1 files changed, 303 insertions, 99 deletions
diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c
index 0b4a918db..75de38353 100644
--- a/os/hal/platforms/STM32/can_lld.c
+++ b/os/hal/platforms/STM32/can_lld.c
@@ -39,11 +39,16 @@
/* Driver exported variables. */
/*===========================================================================*/
-/** @brief ADC1 driver identifier.*/
+/** @brief CAN1 driver identifier.*/
#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__)
CANDriver CAND1;
#endif
+/** @brief CAN2 driver identifier.*/
+#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__)
+CANDriver CAND2;
+#endif
+
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
@@ -52,101 +57,159 @@ CANDriver CAND1;
/* Driver local functions. */
/*===========================================================================*/
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
/**
- * @brief CAN1 TX interrupt handler.
+ * @brief Programs the filters.
*
- * @isr
+ * @param[in] can2sb number of the first filter assigned to CAN2
+ * @param[in] num number of entries in the filters array, if zero then
+ * a default filter is programmed
+ * @param[in] cfp pointer to the filters array, can be @p NULL if
+ * (num == 0)
+ *
+ * @notapi
*/
-CH_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) {
+static void can_lld_set_filters(uint32_t can2sb,
+ uint32_t num,
+ const CANFilter *cfp) {
- CH_IRQ_PROLOGUE();
+ /* Temporarily enabling CAN1 clock.*/
+ rccEnableCAN1(FALSE);
+
+ /* Filters initialization.*/
+ CAN1->FMR = (CAN1->FMR & 0xFFFF0000) | (can2sb << 8) | CAN_FMR_FINIT;
+ if (num > 0) {
+ uint32_t i, fmask;
+
+ /* All filters cleared.*/
+ CAN1->FA1R = 0;
+ CAN1->FM1R = 0;
+ CAN1->FS1R = 0;
+ CAN1->FFA1R = 0;
+ for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) {
+ CAN1->sFilterRegister[i].FR1 = 0;
+ CAN1->sFilterRegister[i].FR2 = 0;
+ }
+
+ /* Scanning the filters array.*/
+ for (i = 0; i < num; i++) {
+ fmask = 1 << cfp->filter;
+ if (cfp->mode)
+ CAN1->FM1R |= fmask;
+ if (cfp->scale)
+ CAN1->FS1R |= fmask;
+ if (cfp->assignment)
+ CAN1->FFA1R |= fmask;
+ CAN1->sFilterRegister[cfp->filter].FR1 = cfp->register1;
+ CAN1->sFilterRegister[cfp->filter].FR2 = cfp->register2;
+ CAN1->FA1R |= fmask;
+ cfp++;
+ }
+ }
+ else {
+ /* Setting up a single default filter that enables everything for both
+ CANs.*/
+ CAN1->sFilterRegister[0].FR1 = 0;
+ CAN1->sFilterRegister[0].FR2 = 0;
+ CAN1->sFilterRegister[can2sb].FR1 = 0;
+ CAN1->sFilterRegister[can2sb].FR2 = 0;
+ CAN1->FM1R = 0;
+ CAN1->FFA1R = 0;
+ CAN1->FS1R = 1 | (1 << can2sb);
+ CAN1->FA1R = 1 | (1 << can2sb);
+ }
+ CAN1->FMR &= ~CAN_FMR_FINIT;
+
+ /* Clock disabled, it will be enabled again in can_lld_start().*/
+ rccDisableCAN1(FALSE);
+}
+
+/**
+ * @brief Common TX ISR handler.
+ *
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
+ */
+static void can_lld_tx_handler(CANDriver *canp) {
/* No more events until a message is transmitted.*/
- CAN1->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2;
+ canp->can->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2;
chSysLockFromIsr();
- while (chSemGetCounterI(&CAND1.txsem) < 0)
- chSemSignalI(&CAND1.txsem);
- chEvtBroadcastI(&CAND1.txempty_event);
+ while (chSemGetCounterI(&canp->txsem) < 0)
+ chSemSignalI(&canp->txsem);
+ chEvtBroadcastI(&canp->txempty_event);
chSysUnlockFromIsr();
-
- CH_IRQ_EPILOGUE();
}
-/*
- * @brief CAN1 RX0 interrupt handler.
+/**
+ * @brief Common RX0 ISR handler.
*
- * @isr
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
*/
-CH_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) {
+static void can_lld_rx0_handler(CANDriver *canp) {
uint32_t rf0r;
- CH_IRQ_PROLOGUE();
-
- rf0r = CAN1->RF0R;
+ rf0r = canp->can->RF0R;
if ((rf0r & CAN_RF0R_FMP0) > 0) {
/* No more receive events until the queue 0 has been emptied.*/
- CAN1->IER &= ~CAN_IER_FMPIE0;
+ canp->can->IER &= ~CAN_IER_FMPIE0;
chSysLockFromIsr();
- while (chSemGetCounterI(&CAND1.rxsem) < 0)
- chSemSignalI(&CAND1.rxsem);
- chEvtBroadcastI(&CAND1.rxfull_event);
+ while (chSemGetCounterI(&canp->rxsem) < 0)
+ chSemSignalI(&canp->rxsem);
+ chEvtBroadcastI(&canp->rxfull_event);
chSysUnlockFromIsr();
}
if ((rf0r & CAN_RF0R_FOVR0) > 0) {
/* Overflow events handling.*/
- CAN1->RF0R = CAN_RF0R_FOVR0;
+ canp->can->RF0R = CAN_RF0R_FOVR0;
chSysLockFromIsr();
- chEvtBroadcastFlagsI(&CAND1.error_event, CAN_OVERFLOW_ERROR);
+ chEvtBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR);
chSysUnlockFromIsr();
}
-
- CH_IRQ_EPILOGUE();
}
/**
- * @brief CAN1 RX1 interrupt handler.
+ * @brief Common RX1 ISR handler.
+ * @note Not used, must not be invoked, defaulted to an halt.
*
- * @isr
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
*/
-CH_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) {
-
- CH_IRQ_PROLOGUE();
-
- chSysHalt(); /* Not supported (yet).*/
+static void can_lld_rx1_handler(CANDriver *canp) {
- CH_IRQ_EPILOGUE();
+ (void)canp;
+ chSysHalt();
}
/**
- * @brief CAN1 SCE interrupt handler.
+ * @brief Common SCE ISR handler.
*
- * @isr
+ * @param[in] canp pointer to the @p CANDriver object
+ *
+ * @notapi
*/
-CH_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {
+static void can_lld_sce_handler(CANDriver *canp) {
uint32_t msr;
- CH_IRQ_PROLOGUE();
-
- msr = CAN1->MSR;
- CAN1->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI;
+ msr = canp->can->MSR;
+ canp->can->MSR = CAN_MSR_ERRI | CAN_MSR_WKUI | CAN_MSR_SLAKI;
/* Wakeup event.*/
if (msr & CAN_MSR_WKUI) {
- CAND1.state = CAN_READY;
- CAND1.can->MCR &= ~CAN_MCR_SLEEP;
+ canp->state = CAN_READY;
+ canp->can->MCR &= ~CAN_MCR_SLEEP;
chSysLockFromIsr();
- chEvtBroadcastI(&CAND1.wakeup_event);
+ chEvtBroadcastI(&canp->wakeup_event);
chSysUnlockFromIsr();
}
/* Error event.*/
if (msr & CAN_MSR_ERRI) {
flagsmask_t flags;
- uint32_t esr = CAN1->ESR;
+ uint32_t esr = canp->can->ESR;
- CAN1->ESR &= ~CAN_ESR_LEC;
+ canp->can->ESR &= ~CAN_ESR_LEC;
flags = (flagsmask_t)(esr & 7);
if ((esr & CAN_ESR_LEC) > 0)
flags |= CAN_FRAMING_ERROR;
@@ -154,13 +217,131 @@ CH_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {
chSysLockFromIsr();
/* The content of the ESR register is copied unchanged in the upper
half word of the listener flags mask.*/
- chEvtBroadcastFlagsI(&CAND1.error_event, flags | (flagsmask_t)(esr < 16));
+ chEvtBroadcastFlagsI(&canp->error_event, flags | (flagsmask_t)(esr < 16));
chSysUnlockFromIsr();
}
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_CAN_USE_CAN1 || defined(__DOXYGEN__)
+/**
+ * @brief CAN1 TX interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN1_TX_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND1);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/*
+ * @brief CAN1 RX0 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN1_RX0_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_rx0_handler(&CAND1);
CH_IRQ_EPILOGUE();
}
+/**
+ * @brief CAN1 RX1 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN1_RX1_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_rx1_handler(&CAND1);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN1 SCE interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN1_SCE_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_sce_handler(&CAND1);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_CAN_USE_CAN1 */
+
+#if STM32_CAN_USE_CAN2 || defined(__DOXYGEN__)
+/**
+ * @brief CAN2 TX interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN2_TX_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_tx_handler(&CAND2);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/*
+ * @brief CAN2 RX0 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN2_RX0_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_rx0_handler(&CAND2);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN2 RX1 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN2_RX1_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_rx1_handler(&CAND2);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief CAN2 SCE interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(STM32_CAN2_SCE_HANDLER) {
+
+ CH_IRQ_PROLOGUE();
+
+ can_lld_sce_handler(&CAND2);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_CAN_USE_CAN2 */
+
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@@ -177,6 +358,19 @@ void can_lld_init(void) {
canObjectInit(&CAND1);
CAND1.can = CAN1;
#endif
+#if STM32_CAN_USE_CAN2
+ /* Driver initialization.*/
+ canObjectInit(&CAND2);
+ CAND2.can = CAN2;
+#endif
+
+ /* Filters initialization.*/
+#if STM32_HAS_CAN2
+ can_lld_set_filters(STM32_CAN_MAX_FILTERS / 2, 0, NULL);
+#else
+ can_lld_set_filters(STM32_CAN_MAX_FILTERS, 0, NULL);
+#endif
+
}
/**
@@ -202,6 +396,19 @@ void can_lld_start(CANDriver *canp) {
rccEnableCAN1(FALSE);
}
#endif
+#if STM32_CAN_USE_CAN2
+ if (&CAND2 == canp) {
+ nvicEnableVector(STM32_CAN2_TX_NUMBER,
+ CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
+ nvicEnableVector(STM32_CAN2_RX0_NUMBER,
+ CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
+ nvicEnableVector(STM32_CAN2_RX1_NUMBER,
+ CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
+ nvicEnableVector(STM32_CAN2_SCE_NUMBER,
+ CORTEX_PRIORITY_MASK(STM32_CAN_CAN2_IRQ_PRIORITY));
+ rccEnableCAN2(FALSE);
+ }
+#endif
/* Entering initialization mode. */
canp->state = CAN_STARTING;
@@ -212,56 +419,12 @@ void can_lld_start(CANDriver *canp) {
canp->can->BTR = canp->config->btr;
/* MCR initialization.*/
canp->can->MCR = canp->config->mcr;
- /* Filters initialization.*/
- canp->can->FMR |= CAN_FMR_FINIT;
- if (canp->config->num > 0) {
- uint32_t i, fmask;
- CAN_FilterRegister_TypeDef *cfp;
-
- canp->can->FA1R = 0;
- canp->can->FM1R = 0;
- canp->can->FS1R = 0;
- canp->can->FFA1R = 0;
- cfp = canp->can->sFilterRegister;
- fmask = 1;
- for (i = 0; i < STM32_CAN_MAX_FILTERS; i++) {
- if (i < canp->config->num) {
- if (canp->config->filters[i].mode)
- canp->can->FM1R |= fmask;
- if (canp->config->filters[i].scale)
- canp->can->FS1R |= fmask;
- if (canp->config->filters[i].assignment)
- canp->can->FFA1R |= fmask;
- cfp->FR1 = canp->config->filters[i].register1;
- cfp->FR2 = canp->config->filters[i].register2;
- canp->can->FA1R |= fmask;
- }
- else {
- cfp->FR1 = 0;
- cfp->FR2 = 0;
- }
- /* Gives a chance for preemption since this is a rather long loop.*/
- chSysUnlock();
- cfp++;
- fmask <<= 1;
- chSysLock();
- }
- }
- else {
- /* Setup a default filter.*/
- canp->can->sFilterRegister[0].FR1 = 0;
- canp->can->sFilterRegister[0].FR2 = 0;
- canp->can->FM1R = 0;
- canp->can->FFA1R = 0;
- canp->can->FS1R = 1;
- canp->can->FA1R = 1;
- }
- canp->can->FMR &= ~CAN_FMR_FINIT;
+
/* Interrupt sources initialization.*/
canp->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;
+ CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE |
+ CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE |
+ CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
}
/**
@@ -286,6 +449,17 @@ void can_lld_stop(CANDriver *canp) {
rccDisableCAN1(FALSE);
}
#endif
+#if STM32_CAN_USE_CAN2
+ if (&CAND2 == canp) {
+ CAN2->MCR = 0x00010002; /* Register reset value. */
+ CAN2->IER = 0x00000000; /* All sources disabled. */
+ nvicDisableVector(STM32_CAN2_TX_NUMBER);
+ nvicDisableVector(STM32_CAN2_RX0_NUMBER);
+ nvicDisableVector(STM32_CAN2_RX1_NUMBER);
+ nvicDisableVector(STM32_CAN2_SCE_NUMBER);
+ rccDisableCAN2(FALSE);
+ }
+#endif
}
}
@@ -409,6 +583,36 @@ void can_lld_wakeup(CANDriver *canp) {
}
#endif /* CAN_USE_SLEEP_MODE */
+/**
+ * @brief Programs the filters.
+ * @note This is an STM32-specific API.
+ *
+ * @param[in] can2sb number of the first filter assigned to CAN2
+ * @param[in] num number of entries in the filters array, if zero then
+ * a default filter is programmed
+ * @param[in] cfp pointer to the filters array, can be @p NULL if
+ * (num == 0)
+ *
+ * @api
+ */
+void canSTM32SetFilters(uint32_t can2sb, uint32_t num, const CANFilter *cfp) {
+
+ chDbgCheck((can2sb > 1) && (can2sb < STM32_CAN_MAX_FILTERS) &&
+ (num < STM32_CAN_MAX_FILTERS),
+ "canSTM32SetFilters");
+
+#if STM32_CAN_USE_CAN1
+ chDbgAssert(CAND1.state == CAN_STOP,
+ "canSTM32SetFilters(), #1", "invalid state");
+#endif
+#if STM32_CAN_USE_CAN2
+ chDbgAssert(CAND2.state == CAN_STOP,
+ "canSTM32SetFilters(), #2", "invalid state");
+#endif
+
+ can_lld_set_filters(can2sb, num, cfp);
+}
+
#endif /* HAL_USE_CAN */
/** @} */