From 48506ff3481afe8e2490e78a451852bc4bbb1c0b Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 22 Feb 2013 13:42:10 +0000 Subject: [PATCH] CAN driver revision, work in progress. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@5299 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/can.h | 15 ++++- os/hal/platforms/STM32/can_lld.c | 108 ++++++++++++++++++++++--------- os/hal/platforms/STM32/can_lld.h | 38 +++++++++-- os/hal/src/can.c | 28 +++++--- testhal/STM32F30x/CAN/main.c | 9 +-- 5 files changed, 147 insertions(+), 51 deletions(-) diff --git a/os/hal/include/can.h b/os/hal/include/can.h index 683f79a97..234981448 100644 --- a/os/hal/include/can.h +++ b/os/hal/include/can.h @@ -61,6 +61,11 @@ #define CAN_OVERFLOW_ERROR 16 /** @} */ +/** + * @brief Special TX mailbox identifier. + */ +#define CAN_ANY_TX_MAILBOX 0 + /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -135,8 +140,14 @@ extern "C" { void canObjectInit(CANDriver *canp); void canStart(CANDriver *canp, const CANConfig *config); void canStop(CANDriver *canp); - msg_t canTransmit(CANDriver *canp, const CANTxFrame *ctfp, systime_t timeout); - msg_t canReceive(CANDriver *canp, CANRxFrame *crfp, systime_t timeout); + msg_t canTransmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp, + systime_t timeout); + msg_t canReceive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp, + systime_t timeout); #if CAN_USE_SLEEP_MODE void canSleep(CANDriver *canp); void canWakeup(CANDriver *canp); diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c index 6c12cc145..785ca3482 100644 --- a/os/hal/platforms/STM32/can_lld.c +++ b/os/hal/platforms/STM32/can_lld.c @@ -467,16 +467,28 @@ void can_lld_stop(CANDriver *canp) { * @brief Determines whether a frame can be transmitted. * * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_TX_MAILBOX for any mailbox * - * @return The queue space availability. + * @return The queue space availability. * @retval FALSE no space in the transmit queue. * @retval TRUE transmit slot available. * * @notapi */ -bool_t can_lld_can_transmit(CANDriver *canp) { +bool_t can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { - return (canp->can->TSR & CAN_TSR_TME) != 0; + switch (mailbox) { + case CAN_ANY_TX_MAILBOX: + return (canp->can->TSR & CAN_TSR_TME) != 0; + case 1: + return (canp->can->TSR & CAN_TSR_TME0) != 0; + case 2: + return (canp->can->TSR & CAN_TSR_TME1) != 0; + case 3: + return (canp->can->TSR & CAN_TSR_TME2) != 0; + default: + return FALSE; + } } /** @@ -484,15 +496,29 @@ bool_t can_lld_can_transmit(CANDriver *canp) { * * @param[in] canp pointer to the @p CANDriver object * @param[in] ctfp pointer to the CAN frame to be transmitted + * @param[in] mailbox mailbox number, @p CAN_ANY_TX_MAILBOX for any mailbox * * @notapi */ -void can_lld_transmit(CANDriver *canp, const CANTxFrame *ctfp) { +void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp) { uint32_t tir; CAN_TxMailBox_TypeDef *tmbp; /* Pointer to a free transmission mailbox.*/ - tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24]; + switch (mailbox) { + case CAN_ANY_TX_MAILBOX: + tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24]; + case 1: + tmbp = &canp->can->sTxMailBox[0]; + case 2: + tmbp = &canp->can->sTxMailBox[1]; + case 3: + tmbp = &canp->can->sTxMailBox[2]; + default: + return; + } /* Preparing the message.*/ if (ctfp->IDE) @@ -510,16 +536,18 @@ void can_lld_transmit(CANDriver *canp, const CANTxFrame *ctfp) { * @brief Determines whether a frame has been received. * * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number * - * @return The queue space availability. + * @return The queue space availability. * @retval FALSE no space in the transmit queue. * @retval TRUE transmit slot available. * * @notapi */ -bool_t can_lld_can_receive(CANDriver *canp) { +bool_t can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { - return (canp->can->RF0R & CAN_RF0R_FMP0) > 0; + return mailbox == 0 ? (canp->can->RF0R & CAN_RF0R_FMP0) > 0 : + (canp->can->RF1R & CAN_RF1R_FMP1) > 0; } /** @@ -527,34 +555,54 @@ bool_t can_lld_can_receive(CANDriver *canp) { * * @param[in] canp pointer to the @p CANDriver object * @param[out] crfp pointer to the buffer where the CAN frame is copied + * @param[in] mailbox mailbox number * * @notapi */ -void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) { - uint32_t r; +void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp) { + uint32_t rir, rdtr; - /* Fetches the message.*/ - r = canp->can->sFIFOMailBox[0].RIR; - crfp->RTR = (r & CAN_RI0R_RTR) >> 1; - crfp->IDE = (r & CAN_RI0R_IDE) >> 2; + if (mailbox == 0) { + /* Fetches the message.*/ + rir = canp->can->sFIFOMailBox[0].RIR; + rdtr = canp->can->sFIFOMailBox[0].RDTR; + crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR; + crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR; + + /* Releases the mailbox.*/ + canp->can->RF0R = CAN_RF0R_RFOM0; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0) + canp->can->IER |= CAN_IER_FMPIE0; + } + else { + /* Fetches the message.*/ + rir = canp->can->sFIFOMailBox[1].RIR; + rdtr = canp->can->sFIFOMailBox[1].RDTR; + crfp->data32[0] = canp->can->sFIFOMailBox[1].RDLR; + crfp->data32[1] = canp->can->sFIFOMailBox[1].RDHR; + + /* Releases the mailbox.*/ + canp->can->RF1R = CAN_RF1R_RFOM1; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->can->RF1R & CAN_RF1R_FMP1) == 0) + canp->can->IER |= CAN_IER_FMPIE1; + } + crfp->RTR = (rir & CAN_RI0R_RTR) >> 1; + crfp->IDE = (rir & CAN_RI0R_IDE) >> 2; if (crfp->IDE) - crfp->EID = r >> 3; + crfp->EID = rir >> 3; else - crfp->SID = r >> 21; - r = canp->can->sFIFOMailBox[0].RDTR; - crfp->DLC = r & CAN_RDT0R_DLC; - crfp->FMI = (uint8_t)(r >> 8); - crfp->TIME = (uint16_t)(r >> 16); - crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR; - crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR; - - /* Releases the mailbox.*/ - canp->can->RF0R = CAN_RF0R_RFOM0; - - /* If the queue is empty re-enables the interrupt in order to generate - events again.*/ - if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0) - canp->can->IER |= CAN_IER_FMPIE0; + crfp->SID = rir >> 21; + crfp->DLC = rdtr & CAN_RDT0R_DLC; + crfp->FMI = (uint8_t)(rdtr >> 8); + crfp->TIME = (uint16_t)(rdtr >> 16); } #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) diff --git a/os/hal/platforms/STM32/can_lld.h b/os/hal/platforms/STM32/can_lld.h index 132cd207a..a15226f4a 100644 --- a/os/hal/platforms/STM32/can_lld.h +++ b/os/hal/platforms/STM32/can_lld.h @@ -50,6 +50,16 @@ */ #define CAN_SUPPORTS_SLEEP TRUE +/** + * @brief This implementation supports three transmit mailboxes. + */ +#define CAN_TX_MAILBOXES 3 + +/** + * @brief This implementation supports two receive mailboxes. + */ +#define CAN_RX_MAILBOXES 3 + /** * @name CAN registers helper macros * @{ @@ -130,6 +140,11 @@ /* Driver data structures and types. */ /*===========================================================================*/ +/** + * @brief Type of a transmission mailbox index. + */ +typedef uint32_t canmbx_t; + /** * @brief CAN transmission frame. * @note Accessing the frame data as word16 or word32 is not portable because @@ -270,14 +285,21 @@ typedef struct { * repeatedly invoking @p chReceive() when listening to this event. * This behavior minimizes the interrupt served by the system * because CAN traffic. + * @note The flags associated to the listeners will indicate which + * receive mailboxes become non-empty. */ EventSource rxfull_event; /** - * @brief One or more transmission slots become available. + * @brief One or more transmission mailbox become available. + * @note The flags associated to the listeners will indicate which + * transmit mailboxes become empty. + * */ EventSource txempty_event; /** * @brief A CAN bus error happened. + * @note The flags associated to the listeners will indicate the + * error(s) that have occurred. */ EventSource error_event; #if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) @@ -319,10 +341,16 @@ extern "C" { void can_lld_init(void); void can_lld_start(CANDriver *canp); void can_lld_stop(CANDriver *canp); - bool_t can_lld_can_transmit(CANDriver *canp); - void can_lld_transmit(CANDriver *canp, const CANTxFrame *crfp); - bool_t can_lld_can_receive(CANDriver *canp); - void can_lld_receive(CANDriver *canp, CANRxFrame *ctfp); + bool_t can_lld_is_tx_empty(CANDriver *canp, + canmbx_t mailbox); + void can_lld_transmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *crfp); + bool_t can_lld_is_rx_nonempty(CANDriver *canp, + canmbx_t mailbox); + void can_lld_receive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *ctfp); #if CAN_USE_SLEEP_MODE void can_lld_sleep(CANDriver *canp); void can_lld_wakeup(CANDriver *canp); diff --git a/os/hal/src/can.c b/os/hal/src/can.c index 18d7b302b..e0d47d5c5 100644 --- a/os/hal/src/can.c +++ b/os/hal/src/can.c @@ -145,6 +145,7 @@ void canStop(CANDriver *canp) { * @note Trying to transmit while in sleep mode simply enqueues the thread. * * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number, @p CAN_ANY_TX_MAILBOX for any mailbox * @param[in] ctfp pointer to the CAN frame to be transmitted * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: @@ -158,21 +159,26 @@ void canStop(CANDriver *canp) { * * @api */ -msg_t canTransmit(CANDriver *canp, const CANTxFrame *ctfp, systime_t timeout) { +msg_t canTransmit(CANDriver *canp, + canmbx_t mailbox, + const CANTxFrame *ctfp, + systime_t timeout) { - chDbgCheck((canp != NULL) && (ctfp != NULL), "canTransmit"); + chDbgCheck((canp != NULL) && (ctfp != NULL) && + (mailbox <= CAN_TX_MAILBOXES), + "canTransmit"); chSysLock(); chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), "canTransmit(), #1", "invalid state"); - while ((canp->state == CAN_SLEEP) || !can_lld_can_transmit(canp)) { + while ((canp->state == CAN_SLEEP) || !can_lld_is_tx_empty(canp, mailbox)) { msg_t msg = chSemWaitTimeoutS(&canp->txsem, timeout); if (msg != RDY_OK) { chSysUnlock(); return msg; } } - can_lld_transmit(canp, ctfp); + can_lld_transmit(canp, mailbox, ctfp); chSysUnlock(); return RDY_OK; } @@ -183,6 +189,7 @@ msg_t canTransmit(CANDriver *canp, const CANTxFrame *ctfp, systime_t timeout) { * @note Trying to receive while in sleep mode simply enqueues the thread. * * @param[in] canp pointer to the @p CANDriver object + * @param[in] mailbox mailbox number * @param[out] crfp pointer to the buffer where the CAN frame is copied * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: @@ -198,21 +205,26 @@ msg_t canTransmit(CANDriver *canp, const CANTxFrame *ctfp, systime_t timeout) { * * @api */ -msg_t canReceive(CANDriver *canp, CANRxFrame *crfp, systime_t timeout) { +msg_t canReceive(CANDriver *canp, + canmbx_t mailbox, + CANRxFrame *crfp, + systime_t timeout) { - chDbgCheck((canp != NULL) && (crfp != NULL), "canReceive"); + chDbgCheck((canp != NULL) && (crfp != NULL) && + (mailbox >= 1) && (mailbox < CAN_RX_MAILBOXES), + "canReceive"); chSysLock(); chDbgAssert((canp->state == CAN_READY) || (canp->state == CAN_SLEEP), "canReceive(), #1", "invalid state"); - while ((canp->state == CAN_SLEEP) || !can_lld_can_receive(canp)) { + while ((canp->state == CAN_SLEEP) || !can_lld_is_rx_nonempty(canp, mailbox)) { msg_t msg = chSemWaitTimeoutS(&canp->rxsem, timeout); if (msg != RDY_OK) { chSysUnlock(); return msg; } } - can_lld_receive(canp, crfp); + can_lld_receive(canp, mailbox, crfp); chSysUnlock(); return RDY_OK; } diff --git a/testhal/STM32F30x/CAN/main.c b/testhal/STM32F30x/CAN/main.c index a534b9dbf..978c31c1b 100644 --- a/testhal/STM32F30x/CAN/main.c +++ b/testhal/STM32F30x/CAN/main.c @@ -24,14 +24,11 @@ /* * Internal loopback mode, 500KBaud, automatic wakeup, automatic recover * from abort mode. - * See section 22.7.7 on the STM32 reference manual. */ static const CANConfig cancfg = { CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP, CAN_BTR_LBKM | CAN_BTR_SJW(0) | CAN_BTR_TS2(1) | - CAN_BTR_TS1(8) | CAN_BTR_BRP(6), - 0, - NULL + CAN_BTR_TS1(8) | CAN_BTR_BRP(6) }; /* @@ -48,7 +45,7 @@ static msg_t can_rx(void *p) { while(!chThdShouldTerminate()) { if (chEvtWaitAnyTimeout(ALL_EVENTS, MS2ST(100)) == 0) continue; - while (canReceive(&CAND1, &rxmsg, TIME_IMMEDIATE) == RDY_OK) { + while (canReceive(&CAND1, 1, &rxmsg, TIME_IMMEDIATE) == RDY_OK) { /* Process message.*/ palTogglePad(GPIOE, GPIOE_LED3_RED); } @@ -74,7 +71,7 @@ static msg_t can_tx(void * p) { txmsg.data32[1] = 0x00FF00FF; while (!chThdShouldTerminate()) { - canTransmit(&CAND1, &txmsg, MS2ST(100)); + canTransmit(&CAND1, CAN_ANY_TX_MAILBOX, &txmsg, MS2ST(100)); chThdSleepMilliseconds(500); } return 0;