/***************************************************************************//** * @file * @brief Controller Area Network API ******************************************************************************* * # License * Copyright 2018 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #ifndef EM_CAN_H #define EM_CAN_H #include "em_bus.h" #include "em_device.h" #include #if defined(CAN_COUNT) && (CAN_COUNT > 0) #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** * @addtogroup can * @{ ******************************************************************************/ /******************************************************************************* ******************************* DEFINES *********************************** ******************************************************************************/ /******************************************************************************* ******************************** ENUMS ************************************ ******************************************************************************/ /** CAN Status codes. */ typedef enum { /** No error occurred during the last CAN bus event. */ canErrorNoError = CAN_STATUS_LEC_NONE, /** * More than 5 equal bits in a sequence have occurred in a part of a received * message where this is not allowed. */ canErrorStuff = CAN_STATUS_LEC_STUFF, /** A fixed format part of a received frame has the wrong format. */ canErrorForm = CAN_STATUS_LEC_FORM, /** The message this CAN Core transmitted was not acknowledged by another node. */ canErrorAck = CAN_STATUS_LEC_ACK, /** A wrong monitored bus value : dominant when the module wants to send a recessive. */ canErrorBit1 = CAN_STATUS_LEC_BIT1, /** A wrong monitored bus value : recessive when the module intends to send a dominant. */ canErrorBit0 = CAN_STATUS_LEC_BIT0, /** CRC check sum incorrect. */ canErrorCrc = CAN_STATUS_LEC_CRC, /** Unused. No new error since the CPU wrote this value. */ canErrorUnused = CAN_STATUS_LEC_UNUSED } CAN_ErrorCode_TypeDef; /** CAN peripheral mode. */ typedef enum { /** CAN peripheral in Normal mode : ready to send and receive messages. */ canModeNormal, /** CAN peripheral in Basic mode : no use of the RAM. */ canModeBasic, /** * CAN peripheral in Loopback mode : input from the CAN bus is disregarded * and comes from TX instead. */ canModeLoopBack, /** * CAN peripheral in SilentLoopback mode : input from the CAN bus is * disregarded and comes from TX instead ; no output on the CAN bus. */ canModeSilentLoopBack, /** CAN peripheral in Silent mode : no output on the CAN bus. If required to * send a dominant bit, it's rerouted internally so that the CAN module * monitors it but the CAN bus stays recessive. */ canModeSilent } CAN_Mode_TypeDef; /******************************************************************************* ******************************* STRUCTS *********************************** ******************************************************************************/ /** CAN Message Object TypeDef structure. LSBs is used. */ typedef struct { /** A message number of this Message Object, [1 - 32]. */ uint8_t msgNum; /** ID extended if true, standard if false. */ bool extended; /** * ID of the message with 11 bits (standard) or 28 bits (extended). * LSBs are used for both. */ uint32_t id; /** Data Length Code [0 - 8]. */ uint8_t dlc; /** A pointer to data, [0 - 8] bytes. */ uint8_t data[8]; /** A mask for ID filtering. */ uint32_t mask; /** Enable the use of 'extended' value for filtering. */ bool extendedMask; /** Enable the use of 'direction' value for filtering. */ bool directionMask; } CAN_MessageObject_TypeDef; /** CAN initialization structure. */ typedef struct { /** True to set the CAN Device in normal mode after initialization. */ bool enable; /** True to reset messages during initialization. */ bool resetMessages; /** Default bitrate. */ uint32_t bitrate; /** Default Propagation Time Segment. */ uint8_t propagationTimeSegment; /** Default Phase Buffer Segment 1. */ uint8_t phaseBufferSegment1; /** Default Phase Buffer Segment 2. */ uint8_t phaseBufferSegment2; /** Default Synchronization Jump Width. */ uint8_t synchronisationJumpWidth; } CAN_Init_TypeDef; /** * Default initialization of CAN_Init_TypeDef. The total duration of a bit with * these default parameters is 10 tq (time quantum : tq = brp/fsys, brp being * the baudrate prescaler and being set according to the wanted bitrate, fsys * beeing the CAN device frequency). */ #define CAN_INIT_DEFAULT \ { \ true, /** Set the CAN Device in normal mode after initialization. */ \ true, /** Reset messages during initialization. */ \ 100000, /** Set bitrate to 100 000 */ \ 1, /** Set the Propagation Time Segment to 1. */ \ 4, /** Set the Phase Buffer Segment 1 to 4. */ \ 4, /** Set the Phase Buffer Segment 2 to 4. */ \ 1 /** Set the Synchronization Jump Width to 1. */ \ } /******************************************************************************* ***************************** PROTOTYPES ********************************** ******************************************************************************/ void CAN_Init(CAN_TypeDef *can, const CAN_Init_TypeDef *init); uint32_t CAN_GetClockFrequency(CAN_TypeDef *can); bool CAN_MessageLost(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum); void CAN_SetRoute(CAN_TypeDef *can, bool active, uint16_t pinRxLoc, uint16_t pinTxLoc); void CAN_SetBitTiming(CAN_TypeDef *can, uint32_t bitrate, uint16_t propagationTimeSegment, uint16_t phaseBufferSegment1, uint16_t phaseBufferSegment2, uint16_t synchronisationJumpWidth); void CAN_SetMode(CAN_TypeDef *can, CAN_Mode_TypeDef mode); void CAN_SetIdAndFilter(CAN_TypeDef *can, uint8_t interface, bool useMask, const CAN_MessageObject_TypeDef *message, bool wait); void CAN_ConfigureMessageObject(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum, bool valid, bool tx, bool remoteTransfer, bool endOfBuffer, bool wait); void CAN_SendMessage(CAN_TypeDef *can, uint8_t interface, const CAN_MessageObject_TypeDef *message, bool wait); bool CAN_ReadMessage(CAN_TypeDef *can, uint8_t interface, CAN_MessageObject_TypeDef *message); void CAN_AbortSendMessage(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum, bool wait); void CAN_ResetMessages(CAN_TypeDef *can, uint8_t interface); void CAN_Reset(CAN_TypeDef *can); void CAN_WriteData(CAN_TypeDef *can, uint8_t interface, const CAN_MessageObject_TypeDef *message); void CAN_SendRequest(CAN_TypeDef *can, uint8_t interface, uint8_t msgNum, bool wait); /***************************************************************************//** * @brief * Enable the Host Controller to send messages. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] enable * True to enable CAN device, false to disable it. If the CAN device is * enabled, it goes to normal mode (the default working mode). ******************************************************************************/ __STATIC_INLINE void CAN_Enable(CAN_TypeDef *can, bool enable) { BUS_RegBitWrite(&can->CTRL, _CAN_CTRL_INIT_SHIFT, (enable ? 0 : 1)); } /***************************************************************************//** * @brief * Give the communication capabilities state. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * True if the Host Controller can send messages, false otherwise. ******************************************************************************/ __STATIC_INLINE bool CAN_IsEnabled(CAN_TypeDef *can) { return (can->CTRL & _CAN_CTRL_INIT_MASK) == 0; } /***************************************************************************//** * @brief * Waiting function. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] interface * Indicate which Message Interface Register to use. * ******************************************************************************/ __STATIC_INLINE void CAN_ReadyWait(CAN_TypeDef *can, uint8_t interface) { while ((_CAN_MIR_CMDREQ_BUSY_MASK & can->MIR[interface].CMDREQ) != 0) { } } /***************************************************************************//** * @brief * Get the last error code and clear its register. * * @param[in] can * Pointer to CAN peripheral register block. * * @return * return Last error code. ******************************************************************************/ __STATIC_INLINE CAN_ErrorCode_TypeDef CAN_GetLastErrorCode(CAN_TypeDef *can) { CAN_ErrorCode_TypeDef errorCode = (CAN_ErrorCode_TypeDef) (can->STATUS & _CAN_STATUS_LEC_MASK); can->STATUS |= ~_CAN_STATUS_LEC_MASK; return errorCode; } /***************************************************************************//** * @brief * Indicate which message objects have received new data. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * State of MESSAGEDATA register indicating which message objects have received * new data. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_HasNewdata(CAN_TypeDef *can) { return can->MESSAGEDATA; } /***************************************************************************//** * @brief * Clear one or more pending CAN status interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * Pending CAN status interrupt source(s) to clear. ******************************************************************************/ __STATIC_INLINE void CAN_StatusIntClear(CAN_TypeDef *can, uint32_t flags) { can->IF1IFC = flags; } /***************************************************************************//** * @brief * Disable CAN status interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status interrupt source(s) to disable. ******************************************************************************/ __STATIC_INLINE void CAN_StatusIntDisable(CAN_TypeDef *can, uint32_t flags) { can->IF1IEN &= ~flags; } /***************************************************************************//** * @brief * Enable CAN status interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status interrupt source(s) to enable. ******************************************************************************/ __STATIC_INLINE void CAN_StatusIntEnable(CAN_TypeDef *can, uint32_t flags) { can->IF1IEN |= flags; } /***************************************************************************//** * @brief * Get pending CAN status interrupt flags. * * @note * This function does not clear event bits. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * CAN interrupt source(s) pending. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_StatusIntGet(CAN_TypeDef *can) { return can->IF1IF; } /***************************************************************************//** * @brief * Get pending and enabled CAN status interrupt flags. * * @note * This function does not clear event bits. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * CAN interrupt source(s) pending and enabled. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_StatusIntGetEnabled(CAN_TypeDef *can) { uint32_t ien; ien = can->IF1IEN; return can->IF1IF & ien; } /***************************************************************************//** * @brief * Set one or more CAN status interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status interrupt source(s) to set to pending. ******************************************************************************/ __STATIC_INLINE void CAN_StatusIntSet(CAN_TypeDef *can, uint32_t flags) { can->IF1IFS = flags; } /***************************************************************************//** * @brief * Get CAN status. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * A value of CAN register STATUS. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_StatusGet(CAN_TypeDef *can) { return can->STATUS & ~_CAN_STATUS_LEC_MASK; } /***************************************************************************//** * @brief * Clear CAN status. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN status bits to clear. ******************************************************************************/ __STATIC_INLINE void CAN_StatusClear(CAN_TypeDef *can, uint32_t flags) { can->STATUS &= ~flags; } /***************************************************************************//** * @brief * Get the error count. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * Error count. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_GetErrorCount(CAN_TypeDef *can) { return can->ERRCNT; } /***************************************************************************//** * @brief * Clear one or more pending CAN message interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * Pending CAN message interrupt source(s) to clear. ******************************************************************************/ __STATIC_INLINE void CAN_MessageIntClear(CAN_TypeDef *can, uint32_t flags) { can->IF0IFC = flags; } /***************************************************************************//** * @brief * Disable CAN message interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN message interrupt source(s) to disable. ******************************************************************************/ __STATIC_INLINE void CAN_MessageIntDisable(CAN_TypeDef *can, uint32_t flags) { can->IF0IEN &= ~flags; } /***************************************************************************//** * @brief * Enable CAN message interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN message interrupt source(s) to enable. ******************************************************************************/ __STATIC_INLINE void CAN_MessageIntEnable(CAN_TypeDef *can, uint32_t flags) { can->IF0IEN |= flags; } /***************************************************************************//** * @brief * Get pending CAN message interrupt flags. * * @note * This function does not clear event bits. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * CAN message interrupt source(s) pending. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_MessageIntGet(CAN_TypeDef *can) { return can->IF0IF; } /***************************************************************************//** * @brief * Get CAN message interrupt flags that are pending and enabled. * * @note * This function does not clear event bits. * * @param[in] can * A pointer to the CAN peripheral register block. * * @return * CAN message interrupt source(s) pending and enabled. ******************************************************************************/ __STATIC_INLINE uint32_t CAN_MessageIntGetEnabled(CAN_TypeDef *can) { uint32_t ien; ien = can->IF0IEN; return can->IF0IF & ien; } /***************************************************************************//** * @brief * Set one or more CAN message interrupts. * * @param[in] can * A pointer to the CAN peripheral register block. * * @param[in] flags * CAN message interrupt source(s) to set as pending. ******************************************************************************/ __STATIC_INLINE void CAN_MessageIntSet(CAN_TypeDef *can, uint32_t flags) { can->IF0IFS = flags; } /** @} (end addtogroup can) */ #ifdef __cplusplus } #endif #endif /* defined(CAN_COUNT) && (CAN_COUNT > 0) */ #endif /* EM_CAN_H */