diff options
Diffstat (limited to 'os/hal')
-rw-r--r-- | os/hal/include/hal_can.h | 69 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c | 106 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h | 51 | ||||
-rw-r--r-- | os/hal/src/hal_can.c | 17 | ||||
-rw-r--r-- | os/hal/templates/hal_can_lld.h | 51 |
5 files changed, 212 insertions, 82 deletions
diff --git a/os/hal/include/hal_can.h b/os/hal/include/hal_can.h index 78bd12a20..16b487d46 100644 --- a/os/hal/include/hal_can.h +++ b/os/hal/include/hal_can.h @@ -60,7 +60,7 @@ /**
* @brief Special mailbox identifier.
*/
-#define CAN_ANY_MAILBOX 0
+#define CAN_ANY_MAILBOX 0U
/*===========================================================================*/
/* Driver pre-compile time settings. */
@@ -132,6 +132,73 @@ typedef enum { canReceiveTimeout(canp, mailbox, crfp, timeout)
/** @} */
+/**
+ * @name Low level driver helper macros
+ * @{
+ */
+#if !defined(CAN_ENFORCE_USE_CALLBACKS)
+/**
+ * @brief TX mailbox empty event.
+ */
+#define _can_tx_empty_isr(canp, flags) { \
+ osalSysLockFromISR(); \
+ osalThreadDequeueAllI(&(canp)->txqueue, MSG_OK); \
+ osalEventBroadcastFlagsI(&(canp)->txempty_event, flags); \
+ osalSysUnlockFromISR(); \
+}
+
+/**
+ * @brief RX mailbox empty full event.
+ */
+#define _can_rx_full_isr(canp, flags) { \
+ osalSysLockFromISR(); \
+ osalThreadDequeueAllI(&(canp)->rxqueue, MSG_OK); \
+ osalEventBroadcastFlagsI(&(canp)->rxfull_event, flags); \
+ osalSysUnlockFromISR(); \
+}
+
+/**
+ * @brief Error event.
+ */
+#define _can_wakeup_isr(canp) { \
+ osalSysLockFromISR(); \
+ osalEventBroadcastFlagsI(&(canp)->wakeup_event, 0U); \
+ osalSysUnlockFromISR(); \
+}
+
+/**
+ * @brief Error event.
+ */
+#define _can_error_isr(canp, flags) { \
+ osalSysLockFromISR(); \
+ osalEventBroadcastFlagsI(&(canp)->error_event, flags); \
+ osalSysUnlockFromISR(); \
+}
+#else /* defined(CAN_ENFORCE_USE_CALLBACKS) */
+#define _can_tx_empty_isr(canp, flags) { \
+ (canp)->txempty_cb(canp, flags); \
+ osalSysLockFromISR(); \
+ osalThreadDequeueAllI(&(canp)->txqueue, MSG_OK); \
+ osalSysUnlockFromISR(); \
+}
+
+#define _can_rx_full_isr(canp, flags) { \
+ (canp)->rxfull_cb(canp, flags); \
+ osalSysLockFromISR(); \
+ osalThreadDequeueAllI(&(canp)->rxqueue, MSG_OK); \
+ osalSysUnlockFromISR(); \
+}
+
+#define _can_wakeup_isr(canp) { \
+ (canp)->wakeup_cb(canp, 0U); \
+}
+
+#define _can_error_isr(canp, flags) { \
+ (canp)->error_cb(canp, flags); \
+}
+#endif /* defined(CAN_ENFORCE_USE_CALLBACKS) */
+/** @} */
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
diff --git a/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c b/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c index d0a25fb77..064e4d3b0 100644 --- a/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c +++ b/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c @@ -236,10 +236,7 @@ static void can_lld_tx_handler(CANDriver *canp) { }
/* Signaling flags and waking up threads waiting for a transmission slot.*/
- osalSysLockFromISR();
- osalThreadDequeueAllI(&canp->txqueue, MSG_OK);
- osalEventBroadcastFlagsI(&canp->txempty_event, flags);
- osalSysUnlockFromISR();
+ _can_tx_empty_isr(canp, flags);
}
/**
@@ -256,17 +253,12 @@ static void can_lld_rx0_handler(CANDriver *canp) { if ((rf0r & CAN_RF0R_FMP0) > 0) {
/* No more receive events until the queue 0 has been emptied.*/
canp->can->IER &= ~CAN_IER_FMPIE0;
- osalSysLockFromISR();
- osalThreadDequeueAllI(&canp->rxqueue, MSG_OK);
- osalEventBroadcastFlagsI(&canp->rxfull_event, CAN_MAILBOX_TO_MASK(1U));
- osalSysUnlockFromISR();
+ _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(1U));
}
if ((rf0r & CAN_RF0R_FOVR0) > 0) {
/* Overflow events handling.*/
canp->can->RF0R = CAN_RF0R_FOVR0;
- osalSysLockFromISR();
- osalEventBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR);
- osalSysUnlockFromISR();
+ _can_error_isr(canp, CAN_OVERFLOW_ERROR);
}
}
@@ -284,17 +276,12 @@ static void can_lld_rx1_handler(CANDriver *canp) { if ((rf1r & CAN_RF1R_FMP1) > 0) {
/* No more receive events until the queue 0 has been emptied.*/
canp->can->IER &= ~CAN_IER_FMPIE1;
- osalSysLockFromISR();
- osalThreadDequeueAllI(&canp->rxqueue, MSG_OK);
- osalEventBroadcastFlagsI(&canp->rxfull_event, CAN_MAILBOX_TO_MASK(2U));
- osalSysUnlockFromISR();
+ _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(2U));
}
if ((rf1r & CAN_RF1R_FOVR1) > 0) {
/* Overflow events handling.*/
canp->can->RF1R = CAN_RF1R_FOVR1;
- osalSysLockFromISR();
- osalEventBroadcastFlagsI(&canp->error_event, CAN_OVERFLOW_ERROR);
- osalSysUnlockFromISR();
+ _can_error_isr(canp, CAN_OVERFLOW_ERROR);
}
}
@@ -317,9 +304,7 @@ static void can_lld_sce_handler(CANDriver *canp) { if (msr & CAN_MSR_WKUI) {
canp->state = CAN_READY;
canp->can->MCR &= ~CAN_MCR_SLEEP;
- osalSysLockFromISR();
- osalEventBroadcastFlagsI(&canp->wakeup_event, 0);
- osalSysUnlockFromISR();
+ _can_wakeup_isr(canp);
}
#endif /* CAN_USE_SLEEP_MODE */
/* Error event.*/
@@ -335,12 +320,9 @@ static void can_lld_sce_handler(CANDriver *canp) { flags = 0;
#endif
- osalSysLockFromISR();
/* The content of the ESR register is copied unchanged in the upper
half word of the listener flags mask.*/
- osalEventBroadcastFlagsI(&canp->error_event,
- flags | (eventflags_t)(esr << 16U));
- osalSysUnlockFromISR();
+ _can_error_isr(canp, flags | (eventflags_t)(esr << 16U));
}
}
@@ -636,16 +618,42 @@ void can_lld_init(void) { /* Driver initialization.*/
canObjectInit(&CAND1);
CAND1.can = CAN1;
+#if defined(STM32_CAN1_UNIFIED_NUMBER)
+ nvicEnableVector(STM32_CAN1_UNIFIED_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+#else
+ nvicEnableVector(STM32_CAN1_TX_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN1_RX0_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN1_RX1_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN1_SCE_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
+#endif
#endif
+
#if STM32_CAN_USE_CAN2
/* Driver initialization.*/
canObjectInit(&CAND2);
CAND2.can = CAN2;
+#if defined(STM32_CAN2_UNIFIED_NUMBER)
+ nvicEnableVector(STM32_CAN2_UNIFIED_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+#else
+ nvicEnableVector(STM32_CAN2_TX_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN2_RX0_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN2_RX1_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN2_SCE_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
+#endif
#endif
+
#if STM32_CAN_USE_CAN3
/* Driver initialization.*/
canObjectInit(&CAND3);
CAND3.can = CAN3;
+#if defined(STM32_CAN3_UNIFIED_NUMBER)
+ nvicEnableVector(STM32_CAN3_UNIFIED_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+#else
+ nvicEnableVector(STM32_CAN3_TX_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN3_RX0_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN3_RX1_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+ nvicEnableVector(STM32_CAN3_SCE_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
+#endif
#endif
/* Filters initialization.*/
@@ -674,14 +682,6 @@ void can_lld_start(CANDriver *canp) { /* Clock activation.*/
#if STM32_CAN_USE_CAN1
if (&CAND1 == canp) {
-#if defined(STM32_CAN1_UNIFIED_NUMBER)
- nvicEnableVector(STM32_CAN1_UNIFIED_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
-#else
- nvicEnableVector(STM32_CAN1_TX_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN1_RX0_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN1_RX1_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN1_SCE_NUMBER, STM32_CAN_CAN1_IRQ_PRIORITY);
-#endif
rccEnableCAN1(FALSE);
}
#endif
@@ -691,28 +691,12 @@ void can_lld_start(CANDriver *canp) { osalDbgAssert(CAND1.state != CAN_STOP, "CAN1 must be started");
-#if defined(STM32_CAN2_UNIFIED_NUMBER)
- nvicEnableVector(STM32_CAN2_UNIFIED_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
-#else
- nvicEnableVector(STM32_CAN2_TX_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN2_RX0_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN2_RX1_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN2_SCE_NUMBER, STM32_CAN_CAN2_IRQ_PRIORITY);
-#endif
rccEnableCAN2(FALSE);
}
#endif
#if STM32_CAN_USE_CAN3
if (&CAND3 == canp) {
-#if defined(STM32_CAN3_UNIFIED_NUMBER)
- nvicEnableVector(STM32_CAN3_UNIFIED_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
-#else
- nvicEnableVector(STM32_CAN3_TX_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN3_RX0_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN3_RX1_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
- nvicEnableVector(STM32_CAN3_SCE_NUMBER, STM32_CAN_CAN3_IRQ_PRIORITY);
-#endif
rccEnableCAN3(FALSE);
}
#endif
@@ -758,14 +742,6 @@ void can_lld_stop(CANDriver *canp) { CAN1->MCR = 0x00010002; /* Register reset value. */
CAN1->IER = 0x00000000; /* All sources disabled. */
-#if defined(STM32_CAN1_UNIFIED_NUMBER)
- nvicDisableVector(STM32_CAN1_UNIFIED_NUMBER);
-#else
- nvicDisableVector(STM32_CAN1_TX_NUMBER);
- nvicDisableVector(STM32_CAN1_RX0_NUMBER);
- nvicDisableVector(STM32_CAN1_RX1_NUMBER);
- nvicDisableVector(STM32_CAN1_SCE_NUMBER);
-#endif
rccDisableCAN1(FALSE);
}
#endif
@@ -774,14 +750,6 @@ void can_lld_stop(CANDriver *canp) { if (&CAND2 == canp) {
CAN2->MCR = 0x00010002; /* Register reset value. */
CAN2->IER = 0x00000000; /* All sources disabled. */
-#if defined(STM32_CAN2_UNIFIED_NUMBER)
- nvicDisableVector(STM32_CAN2_UNIFIED_NUMBER);
-#else
- nvicDisableVector(STM32_CAN2_TX_NUMBER);
- nvicDisableVector(STM32_CAN2_RX0_NUMBER);
- nvicDisableVector(STM32_CAN2_RX1_NUMBER);
- nvicDisableVector(STM32_CAN2_SCE_NUMBER);
-#endif
rccDisableCAN2(FALSE);
}
#endif
@@ -790,14 +758,6 @@ void can_lld_stop(CANDriver *canp) { if (&CAND3 == canp) {
CAN3->MCR = 0x00010002; /* Register reset value. */
CAN3->IER = 0x00000000; /* All sources disabled. */
-#if defined(STM32_CAN3_UNIFIED_NUMBER)
- nvicDisableVector(STM32_CAN3_UNIFIED_NUMBER);
-#else
- nvicDisableVector(STM32_CAN3_TX_NUMBER);
- nvicDisableVector(STM32_CAN3_RX0_NUMBER);
- nvicDisableVector(STM32_CAN3_RX1_NUMBER);
- nvicDisableVector(STM32_CAN3_SCE_NUMBER);
-#endif
rccDisableCAN3(FALSE);
}
#endif
diff --git a/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h b/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h index c6c10dc12..a26377f24 100644 --- a/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h +++ b/os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h @@ -189,10 +189,26 @@ /*===========================================================================*/
/**
+ * @brief Type of a structure representing an CAN driver.
+ */
+typedef struct CANDriver CANDriver;
+
+/**
* @brief Type of a transmission mailbox index.
*/
typedef uint32_t canmbx_t;
+#if defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a CAN notification callback.
+ *
+ * @param[in] canp pointer to the @p CANDriver object triggering the
+ * callback
+ * @param[in] flags flags associated to the mailbox callback
+ */
+typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags);
+#endif
+
/**
* @brief CAN transmission frame.
* @note Accessing the frame data as word16 or word32 is not portable because
@@ -309,7 +325,7 @@ typedef struct { /**
* @brief Structure representing an CAN driver.
*/
-typedef struct {
+struct CANDriver {
/**
* @brief Driver state.
*/
@@ -326,6 +342,7 @@ typedef struct { * @brief Receive threads queue.
*/
threads_queue_t rxqueue;
+#if !defined(CAN_ENFORCE_USE_CALLBACKS)
/**
* @brief One or more frames become available.
* @note After broadcasting this event it will not be broadcasted again
@@ -345,7 +362,6 @@ typedef struct { * transmit mailboxes become empty.
* @note The upper 16 bits are transmission error flags associated
* to the transmit mailboxes.
- *
*/
event_source_t txempty_event;
/**
@@ -366,12 +382,41 @@ typedef struct { */
event_source_t wakeup_event;
#endif /* CAN_USE_SLEEP_MODE */
+#else /* defined(CAN_ENFORCE_USE_CALLBACKS) */
+ /**
+ * @brief One or more frames become available.
+ * @note After calling this function it will not be called again
+ * until the received frames queue has been completely emptied. It
+ * is <b>not</b> called for each received frame. It is
+ * responsibility of the application to empty the queue by
+ * repeatedly invoking @p chTryReceiveI().
+ * This behavior minimizes the interrupt served by the system
+ * because CAN traffic.
+ */
+ can_callback_t rxfull_cb;
+ /**
+ * @brief One or more transmission mailbox become available.
+ * @note The flags associated to the callback will indicate which
+ * transmit mailboxes become empty.
+ */
+ can_callback_t txempty_cb;
+ /**
+ * @brief A CAN bus error happened.
+ */
+ can_callback_t error_cb;
+#if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__)
+ /**
+ * @brief Exiting sleep state.
+ */
+ can_callback_t wakeup_cb;
+#endif
+#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the CAN registers.
*/
CAN_TypeDef *can;
-} CANDriver;
+};
/*===========================================================================*/
/* Driver macros. */
diff --git a/os/hal/src/hal_can.c b/os/hal/src/hal_can.c index 122e5eb76..6d174f7b6 100644 --- a/os/hal/src/hal_can.c +++ b/os/hal/src/hal_can.c @@ -67,10 +67,11 @@ void canInit(void) { */
void canObjectInit(CANDriver *canp) {
- canp->state = CAN_STOP;
- canp->config = NULL;
+ canp->state = CAN_STOP;
+ canp->config = NULL;
osalThreadQueueObjectInit(&canp->txqueue);
osalThreadQueueObjectInit(&canp->rxqueue);
+#if !defined(CAN_ENFORCE_USE_CALLBACKS)
osalEventObjectInit(&canp->rxfull_event);
osalEventObjectInit(&canp->txempty_event);
osalEventObjectInit(&canp->error_event);
@@ -78,6 +79,14 @@ void canObjectInit(CANDriver *canp) { osalEventObjectInit(&canp->sleep_event);
osalEventObjectInit(&canp->wakeup_event);
#endif
+#else /* defined(CAN_ENFORCE_USE_CALLBACKS) */
+ canp->rxfull_cb = NULL;
+ canp->txempty_cb = NULL;
+ canp->error_cb = NULL;
+#if CAN_USE_SLEEP_MODE == TRUE
+ canp->wakeup_cb = NULL;
+#endif
+#endif /* defined(CAN_ENFORCE_USE_CALLBACKS) */
}
/**
@@ -327,8 +336,10 @@ void canSleep(CANDriver *canp) { if (canp->state == CAN_READY) {
can_lld_sleep(canp);
canp->state = CAN_SLEEP;
+#if !defined(CAN_ENFORCE_USE_CALLBACKS)
osalEventBroadcastFlagsI(&canp->sleep_event, (eventflags_t)0);
osalOsRescheduleS();
+#endif
}
osalSysUnlock();
}
@@ -350,8 +361,10 @@ void canWakeup(CANDriver *canp) { if (canp->state == CAN_SLEEP) {
can_lld_wakeup(canp);
canp->state = CAN_READY;
+#if !defined(CAN_ENFORCE_USE_CALLBACKS)
osalEventBroadcastFlagsI(&canp->wakeup_event, (eventflags_t)0);
osalOsRescheduleS();
+#endif
}
osalSysUnlock();
}
diff --git a/os/hal/templates/hal_can_lld.h b/os/hal/templates/hal_can_lld.h index 14e631a1b..ca64835eb 100644 --- a/os/hal/templates/hal_can_lld.h +++ b/os/hal/templates/hal_can_lld.h @@ -68,10 +68,26 @@ /*===========================================================================*/
/**
+ * @brief Type of a structure representing an CAN driver.
+ */
+typedef struct CANDriver CANDriver;
+
+/**
* @brief Type of a transmission mailbox index.
*/
typedef uint32_t canmbx_t;
+#if defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
+/**
+ * @brief Type of a CAN notification callback.
+ *
+ * @param[in] canp pointer to the @p CANDriver object triggering the
+ * callback
+ * @param[in] flags flags associated to the mailbox callback
+ */
+typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags);
+#endif
+
/**
* @brief CAN transmission frame.
* @note Accessing the frame data as word16 or word32 is not portable because
@@ -131,7 +147,7 @@ typedef struct { /**
* @brief Structure representing an CAN driver.
*/
-typedef struct {
+struct CANDriver {
/**
* @brief Driver state.
*/
@@ -148,6 +164,7 @@ typedef struct { * @brief Receive threads queue.
*/
threads_queue_t rxqueue;
+#if !defined(CAN_ENFORCE_USE_CALLBACKS)
/**
* @brief One or more frames become available.
* @note After broadcasting this event it will not be broadcasted again
@@ -165,7 +182,6 @@ typedef struct { * @brief One or more transmission mailbox become available.
* @note The flags associated to the listeners will indicate which
* transmit mailboxes become empty.
- *
*/
event_source_t txempty_event;
/**
@@ -184,8 +200,37 @@ typedef struct { */
event_source_t wakeup_event;
#endif
+#else /* defined(CAN_ENFORCE_USE_CALLBACKS) */
+ /**
+ * @brief One or more frames become available.
+ * @note After calling this function it will not be called again
+ * until the received frames queue has been completely emptied. It
+ * is <b>not</b> called for each received frame. It is
+ * responsibility of the application to empty the queue by
+ * repeatedly invoking @p chTryReceiveI().
+ * This behavior minimizes the interrupt served by the system
+ * because CAN traffic.
+ */
+ can_callback_t rxfull_cb;
+ /**
+ * @brief One or more transmission mailbox become available.
+ * @note The flags associated to the callback will indicate which
+ * transmit mailboxes become empty.
+ */
+ can_callback_t txempty_cb;
+ /**
+ * @brief A CAN bus error happened.
+ */
+ can_callback_t error_cb;
+#if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__)
+ /**
+ * @brief Exiting sleep state.
+ */
+ can_callback_t wakeup_cb;
+#endif
+#endif
/* End of the mandatory fields.*/
-} CANDriver;
+};
/*===========================================================================*/
/* Driver macros. */
|