From 03a0255b043e9a418e96cf3b3e0564ed2f6efe8e Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 4 Dec 2009 20:56:51 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1374 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/can_lld.c | 46 +++++++++++++++++++++---- os/hal/platforms/STM32/can_lld.h | 43 +++++++++++++++++------ os/hal/templates/can_lld.c | 29 ++++++---------- os/hal/templates/can_lld.h | 74 +++++++++++++++++++++++++++++++++------- 4 files changed, 143 insertions(+), 49 deletions(-) (limited to 'os/hal') diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c index 624f9028b..26cbadc43 100644 --- a/os/hal/platforms/STM32/can_lld.c +++ b/os/hal/platforms/STM32/can_lld.c @@ -213,6 +213,10 @@ void can_lld_start(CANDriver *canp) { } cfp++; fmask <<= 1; + /* Gives a chance for preemption since this is a rather long loop.*/ + chSysUnlock(); + chThdYield(); + chSysLock(); } } else { @@ -239,7 +243,7 @@ void can_lld_start(CANDriver *canp) { */ void can_lld_stop(CANDriver *canp) { - /* If in ready state then disables the CAN clock.*/ + /* If in ready state then disables the CAN peripheral.*/ if (canp->cd_state == CAN_READY) { #if USE_STM32_CAN1 if (&CAND1 == canp) { @@ -273,9 +277,31 @@ bool_t can_lld_can_transmit(CANDriver *canp) { * @brief Inserts a frame into the transmit queue. * * @param[in] canp pointer to the @p CANDriver object - * @param[in] cfp pointer to the CAN frame to be transmitted + * @param[in] ctfp pointer to the CAN frame to be transmitted */ void can_lld_transmit(CANDriver *canp, const CANTxFrame *ctfp) { + uint32_t tir; + CAN_TxMailBox_TypeDef *tmbp; + + /* Pointer to a free transmission mailbox.*/ + tmbp = &canp->cd_can->sTxMailBox[(canp->cd_can->TSR & CAN_TSR_CODE) >> 24]; + + /* Preparing the message.*/ + if (ctfp->cf_IDE) + tir = ((uint32_t)ctfp->cf_EID << 3) | + ((uint32_t)ctfp->cf_IDE << 2) | + ((uint32_t)ctfp->cf_RTR << 1); + else + tir = ((uint32_t)ctfp->cf_SID << 24) | + ((uint32_t)ctfp->cf_IDE << 2) | + ((uint32_t)ctfp->cf_RTR << 1); + tmbp->TDTR = ctfp->cf_DLC; + tmbp->TDLR = ctfp->cf_data32[0]; + tmbp->TDHR = ctfp->cf_data32[1]; + tmbp->TIR = tir | CAN_TI0R_TXRQ; + + /* Re-enables the interrupt in order to generate events again.*/ + canp->cd_can->IER |= CAN_IER_TMEIE; } /** @@ -296,7 +322,7 @@ bool_t can_lld_can_receive(CANDriver *canp) { * @brief Receives a frame from the input queue. * * @param[in] canp pointer to the @p CANDriver object - * @param[out] cfp pointer to the buffer where the CAN frame is copied + * @param[out] crfp pointer to the buffer where the CAN frame is copied */ void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) { uint32_t r; @@ -310,13 +336,19 @@ void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) { crfp->cf_RTR = r & CAN_RI0R_RTR; crfp->cf_IDE = r & CAN_RI0R_IDE; if (crfp->cf_IDE) - crfp->cf_ID = r >> 3; + crfp->cf_EID = r >> 3; else - crfp->cf_ID = r >> 24; + crfp->cf_SID = r >> 24; crfp->cf_data32[0] = canp->cd_can->sFIFOMailBox[0].RDLR; crfp->cf_data32[1] = canp->cd_can->sFIFOMailBox[0].RDHR; + /* Releases the mailbox.*/ canp->cd_can->RF0R |= CAN_RF0R_RFOM0; + + /* If the queue is empty re-enables the interrupt in order to generate + events again.*/ + if ((canp->cd_can->RF0R & CAN_RF0R_FMP0) == 0) + canp->cd_can->IER |= CAN_IER_FMPIE0; } #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) @@ -327,7 +359,7 @@ void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) { */ void can_lld_sleep(CANDriver *canp) { - (void)canp; + canp->cd_can->MCR |= CAN_MCR_SLEEP; } /** @@ -337,7 +369,7 @@ void can_lld_sleep(CANDriver *canp) { */ void can_lld_wakeup(CANDriver *canp) { - (void)canp; + canp->cd_can->MCR &= ~CAN_MCR_SLEEP; } #endif /* CAN_USE_SLEEP_MODE */ diff --git a/os/hal/platforms/STM32/can_lld.h b/os/hal/platforms/STM32/can_lld.h index f995ffb16..b7dff8ced 100644 --- a/os/hal/platforms/STM32/can_lld.h +++ b/os/hal/platforms/STM32/can_lld.h @@ -97,10 +97,19 @@ typedef uint32_t canstatus_t; * machine data endianness, it can be still useful for a quick filling. */ typedef struct { - uint8_t cf_DLC:4; /**< @brief Data length. */ - uint8_t cf_RTR:1; /**< @brief Frame type. */ - uint8_t cf_IDE:1; /**< @brief Identifier type. */ - uint32_t cf_ID; /**< @brief Frame identifier. */ + struct { + uint8_t cf_DLC:4; /**< @brief Data length. */ + uint8_t cf_RTR:1; /**< @brief Frame type. */ + uint8_t cf_IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t cf_SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t cf_EID:29; /**< @brief Extended identifier.*/ + }; + }; union { uint8_t cf_data8[8]; /**< @brief Frame data. */ uint16_t cf_data16[4]; /**< @brief Frame data. */ @@ -114,12 +123,23 @@ typedef struct { * machine data endianness, it can be still useful for a quick filling. */ typedef struct { - uint16_t cf_TIME; /**< @brief Time stamp. */ - uint8_t cf_FMI; /**< @brief Filter id. */ - uint8_t cf_DLC:4; /**< @brief Data length. */ - uint8_t cf_RTR:1; /**< @brief Frame type. */ - uint8_t cf_IDE:1; /**< @brief Identifier type. */ - uint32_t cf_ID; /**< @brief Frame identifier. */ + struct { + uint8_t cf_FMI; /**< @brief Filter id. */ + uint16_t cf_TIME; /**< @brief Time stamp. */ + }; + struct { + uint8_t cf_DLC:4; /**< @brief Data length. */ + uint8_t cf_RTR:1; /**< @brief Frame type. */ + uint8_t cf_IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t cf_SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t cf_EID:29; /**< @brief Extended identifier.*/ + }; + }; union { uint8_t cf_data8[8]; /**< @brief Frame data. */ uint16_t cf_data16[4]; /**< @brief Frame data. */ @@ -216,7 +236,8 @@ typedef struct { * until the received frames queue has been completely emptied. It * is not broadcasted for each received frame. It is * responsibility of the application to empty the queue by repeatedly - * invoking @p chReceive() when listening to this event. + * invoking @p chReceive() when listening to this event. This behavior + * minimizes the interrupt served by the system because CAN traffic. */ EventSource cd_rxfull_event; /** diff --git a/os/hal/templates/can_lld.c b/os/hal/templates/can_lld.c index f2f54e66d..792c4f888 100644 --- a/os/hal/templates/can_lld.c +++ b/os/hal/templates/can_lld.c @@ -63,10 +63,6 @@ void can_lld_init(void) { */ void can_lld_start(CANDriver *canp) { - if (canp->can_state == CAN_STOP) { - /* Clock activation.*/ - } - /* Configuration.*/ } /** @@ -76,8 +72,13 @@ void can_lld_start(CANDriver *canp) { */ void can_lld_stop(CANDriver *canp) { + /* If in ready state then disables the CAN peripheral.*/ + if (canp->cd_state == CAN_READY) { + + } } + /** * @brief Determines whether a frame can be transmitted. * @@ -94,16 +95,12 @@ bool_t can_lld_can_transmit(CANDriver *canp) { /** * @brief Inserts a frame into the transmit queue. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[in] cfp pointer to the CAN frame to be transmitted * - * @return The operation status. - * @retval RDY_OK frame transmitted. + * @param[in] canp pointer to the @p CANDriver object + * @param[in] ctfp pointer to the CAN frame to be transmitted */ -msg_t can_lld_transmit(CANDriver *canp, const CANFrame *cfp) { +void can_lld_transmit(CANDriver *canp, const CANTxFrame *ctfp) { - return RDY_OK; } /** @@ -122,16 +119,12 @@ bool_t can_lld_can_receive(CANDriver *canp) { /** * @brief Receives a frame from the input queue. - * - * @param[in] canp pointer to the @p CANDriver object - * @param[out] cfp pointer to the buffer where the CAN frame is copied * - * @return The operation status. - * @retval RDY_OK frame received. + * @param[in] canp pointer to the @p CANDriver object + * @param[out] crfp pointer to the buffer where the CAN frame is copied */ -msg_t can_lld_receive(CANDriver *canp, CANFrame *cfp) { +void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) { - return RDY_OK; } #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) diff --git a/os/hal/templates/can_lld.h b/os/hal/templates/can_lld.h index 14588c0d5..9b1124a18 100644 --- a/os/hal/templates/can_lld.h +++ b/os/hal/templates/can_lld.h @@ -29,6 +29,10 @@ #if CH_HAL_USE_CAN || defined(__DOXYGEN__) +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + /** * @brief This switch defines whether the driver implementation supports * a low power switch mode with automatic an wakeup feature. @@ -52,10 +56,6 @@ #define CAN_USE_SLEEP_MODE FALSE #endif /* !CAN_SUPPORTS_SLEEP */ -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ @@ -66,21 +66,63 @@ typedef uint32_t canstatus_t; /** - * @brief CAN frame. + * @brief CAN transmission frame. + * @note Accessing the frame data as word16 or word32 is not portable because + * machine data endianness, it can be still useful for a quick filling. + */ +typedef struct { + struct { + uint8_t cf_DLC:4; /**< @brief Data length. */ + uint8_t cf_RTR:1; /**< @brief Frame type. */ + uint8_t cf_IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t cf_SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t cf_EID:29; /**< @brief Extended identifier.*/ + }; + }; + union { + uint8_t cf_data8[8]; /**< @brief Frame data. */ + uint16_t cf_data16[4]; /**< @brief Frame data. */ + uint32_t cf_data32[2]; /**< @brief Frame data. */ + }; +} CANTxFrame; + +/** + * @brief CAN received frame. * @note Accessing the frame data as word16 or word32 is not portable because - * machine data endianness, it can be still useful for a quick filling. + * machine data endianness, it can be still useful for a quick filling. */ typedef struct { - uint8_t cf_DLC:4; /**< @brief Data length. */ - uint8_t cf_IDE:1; /**< @brief Identifier type. */ - uint8_t cf_RTR:1; /**< @brief Frame type. */ - uint32_t cf_id; /**< @brief Frame identifier. */ + struct { + uint8_t cf_DLC:4; /**< @brief Data length. */ + uint8_t cf_RTR:1; /**< @brief Frame type. */ + uint8_t cf_IDE:1; /**< @brief Identifier type. */ + }; + union { + struct { + uint32_t cf_SID:11; /**< @brief Standard identifier.*/ + }; + struct { + uint32_t cf_EID:29; /**< @brief Extended identifier.*/ + }; + }; union { uint8_t cf_data8[8]; /**< @brief Frame data. */ uint16_t cf_data16[4]; /**< @brief Frame data. */ uint32_t cf_data32[2]; /**< @brief Frame data. */ }; -} CANFrame; +} CANRxFrame; + +/** + * @brief CAN filter. + * @note It could not be present on some architectures. + */ +typedef struct { +} CANFilter; /** * @brief Driver configuration structure. @@ -111,6 +153,12 @@ typedef struct { Semaphore cd_rxsem; /** * @brief One or more frames become available. + * @note After broadcasting this event it will not be broadcasted again + * until the received frames queue has been completely emptied. It + * is not broadcasted for each received frame. It is + * responsibility of the application to empty the queue by repeatedly + * invoking @p chReceive() when listening to this event. This behavior + * minimizes the interrupt served by the system because CAN traffic. */ EventSource cd_rxfull_event; /** @@ -149,9 +197,9 @@ extern "C" { void can_lld_start(CANDriver *canp); void can_lld_stop(CANDriver *canp); bool_t can_lld_can_transmit(CANDriver *canp); - msg_t can_lld_transmit(CANDriver *canp, const CANFrame *cfp); + void can_lld_transmit(CANDriver *canp, const CANTxFrame *crfp); bool_t can_lld_can_receive(CANDriver *canp); - msg_t can_lld_receive(CANDriver *canp, CANFrame *cfp); + void can_lld_receive(CANDriver *canp, CANRxFrame *ctfp); #if CAN_USE_SLEEP_MODE void can_lld_sleep(CANDriver *canp); void can_lld_wakeup(CANDriver *canp); -- cgit v1.2.3