2.1 CAN 2.0/CAN FD Driver
2.1.1 Introduction
Overview
CAN FD (Controller Area Network Flexible Data-Rate) is a two-wire data communication protocol typically used for broadcasting sensor data and control information between different parts of electronic instrumentation and control systems. This protocol is generally used in modern high performance vehicles.
The MPLAB® Code Configurator (MCC) Melody CAN FD Driver generates a portable abstract interface for CAN hardware functions. The associated CAN Peripheral Library (PLIB) will generate the hardware-specific implementation.
This reference document covers implementation of the CAN FD Driver only. The implementation of CAN FD and CAN 2.0 Driver are almost similar. The additional features supported by CAN FD are mentioned wherever applicable.
Features
- CAN FD operating frequency.
- Nominal(Arbitration) Bit Rate.
- Data Bit Rate - Supported only in CAN FD mode.
- Configurable FIFO for Transmit and Receive operation.
- Configurable FIFO depth, payload and transmit priority.
- User can provide Custom Name for the FIFOs.
- Interrupt based Transmit and Receive operations.
- Supports both SID(11 bit) and EID(29 bit) type Message IDs.
- 12 bit SIDs supported only in CAN FD base frames.
- Displays Permissible ID based on Message IDs allowed for a given filter. Permissible ID is a binary depiction of Message ID that can pass through filter.
2.1.2 Module Documentation
2.1.2.1 CAN-FD Use Cases
These use cases are also applicable for CAN 2.0 Driver. For CAN 2.0 configuration, make sure that the data byte length is not more than 8 bytes.
2.1.2.1.1 Transmission of CAN frames
Use Case 1: Transmit CAN FD Message Periodically
This example shows how to transmit a CAN FD message with an Extended ID of 0x1FFFF, DLC of 16, data values of 0 to 15, and with bit rate switching enabled. The message is transmitted periodically every 1s.
This example assumes that a UART is configured with STDIO enabled for the printf functions to properly work.
#include "mcc_generated_files/system/system.h" #define DATA_BYTE_LENGTH (16) #define TIME_1S (1000) void CANFD_Example_TransmitFrames(void) { uint8_t transmitData[DATA_BYTE_LENGTH]; enum CAN_TX_MSG_REQUEST_STATUS transmitStatus; struct CAN_MSG_OBJ transmitMsgObj; SYSTEM_Initialize(); //Assign values to the data bytes to be transmitted for (uint8_t i = 0; i < DATA_BYTE_LENGTH; i++) { transmitData [i] = i + 1; } // Create a transmit message object of the required frame consisting of message id, control bits and payload. if (CAN_NORMAL_FD_MODE == CAN_NODE.OperationModeGet()) { transmitMsgObj.msgId = 0x1FFFF; transmitMsgObj.field.formatType = CAN_FD_FORMAT; transmitMsgObj.field.brs = CAN_BRS_MODE; transmitMsgObj.field.frameType = CAN_FRAME_DATA; transmitMsgObj.field.idType = CAN_FRAME_EXT; transmitMsgObj.field.dlc = DLC_16; transmitMsgObj.data = transmitData; } while (1) { // Before transmitting any message, the Transmitter FIFO status needs to be checked if (CAN_TX_FIFO_AVAILABLE == CAN_NODE.TransmitFIFOStatusGet(CAN1_TXQ)) { // Writes a message object to CAN TX FIFO and returns the status of CAN transmit message transmitStatus = CAN_NODE.Transmit(CAN1_TXQ, &transmitMsgObj); // Checking cause of error if Transmit message object was not successfully placed into transmitter FIFO if (CAN_TX_MSG_REQUEST_SUCCESS != transmitStatus) { if (CAN_TX_MSG_REQUEST_DLC_EXCEED_ERROR == transmitStatus) { printf("Transmit Error : Message object DLC size exceeds the FIFO configured DLC size \r\n"); } else if (CAN_TX_MSG_REQUEST_BRS_ERROR == transmitStatus) { printf("Transmit error : Bit rate switching not enabled for FIFO \r\n"); } else if (CAN_TX_MSG_REQUEST_FIFO_FULL == transmitStatus) { printf("Transmit error : Transmit FIFO full \r\n"); } } else { printf("Message transmitted successfully \r\n"); } } else { printf("Transmit FIFO FULL \n"); } __delay_ms(TIME_1S); } }
The custom name of CAN1 Driver Interface can be changed by the user in the Melody Driver User interface. This allows defining a structure with application specific name using the 'Custom Name' field as shown below. Application specific name allows the portability of APIs.
2.1.2.1.2 Receiving CAN frames
Use Case 2: Receive a CAN FD Message from a Particular FIFO (Interrupt Method)
This example shows how to check and read a CAN message from FIFO1 using the interrupt method.
#include "mcc_generated_files/system/system.h" #define DATA_BYTE_LENGTH (16) volatile bool msgReceivedInFIFO1 = false; volatile struct CAN_MSG_OBJ receiveMsgObj; void CAN1_UserFIFO1InterruptHandler(void); void CANFD_Example_Receive_FIFO1_Interrupt(void) { SYSTEM_Initialize(); // Enable the Global Interrupts INTERRUPT_GlobalInterruptEnable(); // Set user interrupt handler which is called whenever the Receive buffer of FIFO1 is not empty. CAN1_FIFO1NotEmptyCallbackRegister(CAN1_UserFIFO1InterruptHandler); while (1) { //Checking if any message was read from FIFO1.If true, print the data bytes of message frame received in the terminal. if (msgReceivedInFIFO1 == true) { printf("\r\nThe data received from CAN message: \r\n"); for (uint8_t i = 0; i < DATA_BYTE_LENGTH; i++) { printf("%d \t", receiveMsgObj.data[i]); } msgReceivedInFIFO1 = false; } } } void CAN1_UserFIFO1InterruptHandler(void) { // Reads the message object from the specified CAN receive FIFO CAN_NODE.ReceiveMessageGet(FIFO1, &receiveMsgObj); msgReceivedInFIFO1 = true; }
Use Case 3: Receive a CAN FD Message from a Particular FIFO (Polling Method)
This example shows how to check and read a CAN message from FIFO1 using the polling method.
#include "mcc_generated_files/system/system.h" #define DATA_BYTE_LENGTH (16) void CANFD_Eaxmple_Receive_From_FIFO1_Polling(void) { struct CAN_MSG_OBJ receiveMsgObj; SYSTEM_Initialize(); while (1) { //Check if the receive FIFO (FIFO1) is not empty if (CAN_RX_MSG_AVAILABLE == (CAN_NODE.ReceiveFIFOStatusGet(CAN1_FIFO_1) & CAN_RX_MSG_AVAILABLE)) { //Reads the receive message object from the specified CAN Receive FIFO CAN_NODE.ReceiveMessageGet(CAN1_FIFO_1, &receiveMsgObj); // Read the data byte of message received and print it on terminal printf("\nThe data received from CAN message: \r\n"); for (uint8_t i = 0; i < DATA_BYTE_LENGTH; i++) { printf("%d \t", receiveMsgObj.data[i]); } } } }
Use Case 4: Receive a CAN FD Message from any FIFO (Polling Method)
This example shows how to check and read a CAN message from any FIFO using polling method.
#include "mcc_generated_files/system/system.h" #define DATA_BYTE_LENGTH (16) void CANFD_Example_Receive_From_Any_FIFO(void) { struct CAN_MSG_OBJ receiveMsgObj; SYSTEM_Initialize(); while (1) { //Checking if messages are received in any of the RX FIFO if (CAN_NODE.ReceivedMessageCountGet() > 0) { // Reads a receive message object from CAN RX FIFO by polling each of the RX FIFO. if (true == CAN_NODE.Receive(&receiveMsgObj)) { // Read the data byte of message received and print it on terminal printf("\nThe data received from CAN message: \r\n"); for (uint8_t i = 0; i < DATA_BYTE_LENGTH; i++) { printf("%d \t", receiveMsgObj.data[i]); } } else { printf("Error : Message read from FIFO failed \r\n"); } } } }
2.1.2.1.3 Sleep and Wakeup Example
Use Case 5: Low power sleep mode and wake-up sequence
This example shows how to use low power sleep mode with CAN FD and the wake-up due to activity in the CAN bus.
#include "mcc_generated_files/system/system.h" volatile bool busWakeUpOccured = false; void CAN1_SleepAndWakeUpUserInterruptHandler(void); void CANFD_Example_Sleep_Wakeup_Sequence(void) { SYSTEM_Initialize(); CAN_NODE.BusWakeUpActivityCallbackRegister(CAN1_SleepAndWakeUpUserInterruptHandler); // Enable the Global Interrupts INTERRUPT_GlobalInterruptEnable(); /* * Switching CAN FD Module to disable mode. This has to be done before calling * SLEEP instruction. Also enable Wake up interrupt whenever bus activity is detected */ CAN_NODE.SleepMode(); //Checking if CAN module has entered to Disable mode if (CAN_DISABLE_MODE == CAN_NODE.OperationModeGet()) { printf("[*] System entering into sleep.\r\n"); //Once CAN module is in disable mode, the system is put to sleep after sleep mode request Sleep(); /* The module wakes up from sleep whenever any activity is detected on CAN receive line * ie when a falling edge is detected on CAN Rx line. * A flag is set in user interrupt handler to monitor if system woke up from sleep mode * due to activity in CAN Rx line */ NOP(); if (busWakeUpOccured == true) { printf("[*] System wakeup and CAN module wake-up due to activity in CAN bus\r\n"); // Recover to Normal mode if (CAN_OP_MODE_REQUEST_SUCCESS == CAN_NODE.OperationModeSet(CAN_CONFIGURATION_MODE)) { if (CAN_OP_MODE_REQUEST_SUCCESS == CAN_NODE.OperationModeSet(CAN_NORMAL_FD_MODE)) { printf("CAN module switched to Normal CAN FD mode \r\n"); } } busWakeUpOccured = false; } else { printf("System wake up due to event other than can bus activity \r\n "); } } } void CAN1_SleepAndWakeUpUserInterruptHandler(void) { busWakeUpOccured = true; }
2.1.3 Class Documentation
2.1.3.1 CAN_INTERFACE Struct Reference
Contains the function pointers of CAN driver.
2.1.3.1.1 Detailed Description
Contains the function pointers of CAN driver.
#include <can_interface.h>
Public Attributes
void(* Initialize )(void)
void(* Deinitialize )(void)
enum CAN_OP_MODE_STATUS(* OperationModeSet )(const enum CAN_OP_MODES requestMode)
enum CAN_OP_MODES(* OperationModeGet )(void)
enum CAN_TX_MSG_REQUEST_STATUS(* Transmit )(const enum CAN_TX_FIFO_CHANNELS fifoChannel, struct CAN_MSG_OBJ *txCanMsg)
enum CAN_TX_FIFO_STATUS(* TransmitFIFOStatusGet )(const enum CAN_TX_FIFO_CHANNELS fifoChannel)
bool(* IsTxErrorPassive )(void)
bool(* IsTxErrorWarning )(void)
bool(* IsTxErrorActive )(void)
bool(* Receive )(struct CAN_MSG_OBJ *rxCanMsg)
bool(* ReceiveMessageGet )(const enum CAN_RX_FIFO_CHANNELS fifoChannel, struct CAN_MSG_OBJ *rxCanMsg)
uint8_t(* ReceivedMessageCountGet )(void)
uint8_t(* ReceiveFIFOStatusGet )(const enum CAN_RX_FIFO_CHANNELS fifoChannel)
bool(* IsRxErrorPassive )(void)
bool(* IsRxErrorWarning )(void)
bool(* IsRxErrorActive )(void)
bool(* IsBusOff )(void)
void(* SleepMode )(void)
void(* InvalidMessageCallbackRegister )(void(*CallbackHandler)(void))
void(* BusWakeUpActivityCallbackRegister )(void(*CallbackHandler)(void))
void(* BusErrorCallbackRegister )(void(*CallbackHandler)(void))
void(* ModeChangeCallbackRegister )(void(*CallbackHandler)(void))
void(* SystemErrorCallbackRegister )(void(*CallbackHandler)(void))
void(* TxAttemptCallbackRegister )(void(*CallbackHandler)(void))
void(* RxBufferOverFlowCallbackRegister )(void(*CallbackHandler)(void))
void(* Tasks )(void)
2.1.3.1.2 Member Data Documentation
BusErrorCallbackRegister
void(* BusErrorCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_BusErrorCallbackRegister e.g. CAN1_BusErrorCallbackRegister
BusWakeUpActivityCallbackRegister
void(* BusWakeUpActivityCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_BusWakeUpActivityCallbackRegister e.g. CAN1_BusWakeUpActivityCallbackRegister
Deinitialize
void(* Deinitialize) (void)
Pointer to CANx_Deinitialize e.g. CAN1_Deinitialize
Initialize
void(* Initialize) (void)
Pointer to CANx_Initialize e.g. CAN1_Initialize
InvalidMessageCallbackRegister
void(* InvalidMessageCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_InvalidMessageCallbackRegister e.g. CAN1_InvalidMessageCallbackRegister
IsBusOff
bool(* IsBusOff) (void)
Pointer to CANx_IsBusOff e.g. CAN1_IsBusOff
IsRxErrorActive
bool(* IsRxErrorActive) (void)
Pointer to CANx_IsRxErrorActive e.g. CAN1_IsRxErrorActive
IsRxErrorPassive
bool(* IsRxErrorPassive) (void)
Pointer to CANx_IsRxErrorPassive e.g. CAN1_IsRxErrorPassive
IsRxErrorWarning
bool(* IsRxErrorWarning) (void)
Pointer to CANx_IsRxErrorWarning e.g. CAN1_IsRxErrorWarning
IsTxErrorActive
bool(* IsTxErrorActive) (void)
Pointer to CANx_IsTxErrorActive e.g. CAN1_IsTxErrorActive
IsTxErrorPassive
bool(* IsTxErrorPassive) (void)
Pointer to CANx_IsTxErrorPassive e.g. CAN1_IsTxErrorPassive
IsTxErrorWarning
bool(* IsTxErrorWarning) (void)
Pointer to CANx_IsTxErrorWarning e.g. CAN1_IsTxErrorWarning
ModeChangeCallbackRegister
void(* ModeChangeCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_ModeChangeCallbackRegister e.g. CAN1_ModeChangeCallbackRegister
OperationModeGet
enum CAN_OP_MODES(* OperationModeGet) (void)
Pointer to CANx_OperationModeGet e.g. CAN1_OperationModeGet
OperationModeSet
enum CAN_OP_MODE_STATUS(* OperationModeSet) (const enum CAN_OP_MODES requestMode)
Pointer to CANx_OperationModeSet e.g. CAN1_OperationModeSet
Receive
bool(* Receive) (struct CAN_MSG_OBJ *rxCanMsg)
Pointer to CANx_Receive e.g. CAN1_Receive
ReceivedMessageCountGet
uint8_t(* ReceivedMessageCountGet) (void)
Pointer to CANx_ReceivedMessageCountGet e.g. CAN1_ReceivedMessageCountGet
ReceiveFIFOStatusGet
uint8_t(* ReceiveFIFOStatusGet) (const enum CAN_RX_FIFO_CHANNELS fifoChannel)
Pointer to CANx_ReceiveFIFOStatusGet e.g. CAN1_ReceiveFIFOStatusGet
ReceiveMessageGet
bool(* ReceiveMessageGet) (const enum CAN_RX_FIFO_CHANNELS fifoChannel, struct CAN_MSG_OBJ *rxCanMsg)
Pointer to CANx_ReceiveMessageGet e.g. CAN1_ReceiveMessageGet
RxBufferOverFlowCallbackRegister
void(* RxBufferOverFlowCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_RxBufferOverFlowCallbackRegister e.g. CAN1_RxBufferOverFlowCallbackRegister
SleepMode
void(* SleepMode) (void)
Pointer to CANx_Sleep e.g. CAN1_Sleep
SystemErrorCallbackRegister
void(* SystemErrorCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_SystemErrorCallbackRegister e.g. CAN1_SystemErrorCallbackRegister
Tasks
void(* Tasks) (void)
Pointer to CANx_Tasks e.g. CAN1_Tasks (Supported only in polling mode)
Transmit
enum CAN_TX_MSG_REQUEST_STATUS(* Transmit) (const enum CAN_TX_FIFO_CHANNELS fifoChannel, struct CAN_MSG_OBJ *txCanMsg)
Pointer to CANx_Transmit e.g. CAN1_Transmit
TransmitFIFOStatusGet
enum CAN_TX_FIFO_STATUS(* TransmitFIFOStatusGet) (const enum CAN_TX_FIFO_CHANNELS fifoChannel)
Pointer to CANx_TransmitFIFOStatusGet e.g. CAN1_TransmitFIFOStatusGet
TxAttemptCallbackRegister
void(* TxAttemptCallbackRegister) (void(*CallbackHandler)(void))
Pointer to CANx_TxAttemptCallbackRegister e.g. CAN1_TxAttemptCallbackRegister
2.1.4 File Documentation
2.1.4.1 source/can_examples.dox File Reference
2.1.4.2 source/can_interface.h File Reference
This is the interface header file for the CAN driver.
#include <stdbool.h> #include <stdint.h> #include "can_types.h"
2.1.4.2.1 Data structures
struct CAN_INTERFACE
Contains the function pointers of CAN driver.
2.1.4.2.2 Detailed Description
This is the interface header file for the CAN driver.
CAN Generated Driver Interface Header File