From bb806fe4c18e628b546291dab906928ebdb46627 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 2 Jan 2018 11:17:31 +0000 Subject: Added callbacks capability to the CAN driver. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@11213 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/hal_can.h | 69 ++++++++++++++++++- os/hal/ports/STM32/LLD/CANv1/hal_can_lld.c | 106 +++++++++-------------------- os/hal/ports/STM32/LLD/CANv1/hal_can_lld.h | 51 +++++++++++++- os/hal/src/hal_can.c | 17 ++++- os/hal/templates/hal_can_lld.h | 51 +++++++++++++- 5 files changed, 212 insertions(+), 82 deletions(-) (limited to 'os/hal') 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 @@ -188,11 +188,27 @@ /* Driver data structures and types. */ /*===========================================================================*/ +/** + * @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 not 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 @@ -67,11 +67,27 @@ /* Driver data structures and types. */ /*===========================================================================*/ +/** + * @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; /** @@ -183,9 +199,38 @@ typedef struct { * @brief Exiting sleep state event. */ 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 not 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. */ -- cgit v1.2.3