FRIENDz

FAILURE IS THE SIGN OF SUCCESS!!

Connect CAN Protocol with PIC

The mikroC PRO for PIC provides a library (driver) for working with the CAN module.
The CAN is a very robust protocol that has error detection and signalization, self–checking and fault confinement. Faulty CAN data and remote frames are re-transmitted automatically, similar to the Ethernet.
Data transfer rates depends on the distance. For example, 1 Mbit/s can be achieved at network lengths below 40m while 250 Kbit/s can be achieved at network lengths below 250m. The greater distance the lower maximum bitrate that can be achieved. The lowest bitrate defined by the standard is 200Kbit/s. Cables used are shielded twisted pairs.
CAN supports two message formats:
  • Standard format, with 11 identifier bits, and
  • Extended format, with 29 identifier bits
  Important :
  • Consult the CAN standard about CAN bus termination resistance.

Library Routines

  • CANSetOperationMode
  • CANGetOperationMode
  • CANInitialize
  • CANSetBaudRate
  • CANSetMask
  • CANSetFilter
  • CANRead
  • CANWrite
  • CANSetTxIdleLevel

CANSetOperationMode

Prototype void CANSetOperationMode(unsigned short mode, unsigned short wait_flag);
Returns Nothing.
Description Sets CAN to requested mode, i.e. copies mode to CANSTAT. Parameter mode needs to be one of CAN_OP_MODE constants .
Parameter wait_flag needs to be either 0 or 0xFF:
  • If set to 0xFF, this is a blocking call – the function won’t “return” until the requested mode is set.
  • If 0, this is a non-blocking call. It does not verify if CAN module is switched to requested mode or not. Caller must use CANGetOperationMode to verify correct operation mode before performing mode specific operation.
Requires Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
CANSetOperationMode(_CAN_MODE_CONFIG, 0xFF);

CANGetOperationMode

Prototype unsigned short CANGetOperationMode();
Returns Current opmode.
Description Function returns current operational mode of CAN module.
Requires Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
if (CANGetOperationMode() == _CAN_MODE_NORMAL) { ... };

CANInitialize

Prototype void CANInitialize(char SJW, char BRP, char PHSEG1, char PHSEG2, char PROPSEG, char CAN_CONFIG_FLAGS);
Returns Nothing.
Description Initializes CAN. All pending transmissions are aborted. Sets all mask registers to 0 to allow all messages.
Filter registers are set according to flag value:
if (CAN_CONFIG_FLAGS & _CAN_CONFIG_VALID_XTD_MSG != 0)
  // Set all filters to XTD_MSG
else if (config & _CAN_CONFIG_VALID_STD_MSG != 0)
  // Set all filters to STD_MSG
else
  // Set half of the filters to STD, and the rest to XTD_MSG.
Parameters:
  • SJW as defined in datasheet (1–4)
  • BRP as defined in datasheet (1–64)
  • PHSEG1 as defined in datasheet (1–8)
  • PHSEG2 as defined in datasheet (1–8)
  • PROPSEG as defined in datasheet (1–8)
  • CAN_CONFIG_FLAGS is formed from predefined constants 
Requires CAN must be in Config mode; otherwise the function will be ignored.
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
init = _CAN_CONFIG_SAMPLE_THRICE &
       _CAN_CONFIG_PHSEG2_PRG_ON &
       _CAN_CONFIG_STD_MSG       &
       _CAN_CONFIG_DBL_BUFFER_ON &
       _CAN_CONFIG_VALID_XTD_MSG &
       _CAN_CONFIG_LINE_FILTER_OFF;
...
CANInitialize(1, 1, 3, 3, 1, init);   // initialize CAN

CANSetBaudRate

Prototype void CANSetBaudRate(char SJW, char BRP, char PHSEG1, char PHSEG2, char PROPSEG, char CAN_CONFIG_FLAGS);
Returns Nothing.
Description Sets CAN baud rate. Due to complexity of CAN protocol, you cannot simply force a bps value. Instead, use this function when CAN is in Config mode. Refer to datasheet for details.
Parameters:
  • SJW as defined in datasheet (1–4)
  • BRP as defined in datasheet (1–64)
  • PHSEG1 as defined in datasheet (1–8)
  • PHSEG2 as defined in datasheet (1–8)
  • PROPSEG as defined in datasheet (1–8)
  • CAN_CONFIG_FLAGS is formed from predefined constants
Requires CAN must be in Config mode; otherwise the function will be ignored.
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
init = _CAN_CONFIG_SAMPLE_THRICE &
       _CAN_CONFIG_PHSEG2_PRG_ON &
       _CAN_CONFIG_STD_MSG       &
       _CAN_CONFIG_DBL_BUFFER_ON &
       _CAN_CONFIG_VALID_XTD_MSG &
       _CAN_CONFIG_LINE_FILTER_OFF;
...
CANSetBaudRate(1, 1, 3, 3, 1, init);

CANSetMask

Prototype void CANSetMask(char CAN_MASK, long value, char CAN_CONFIG_FLAGS);
Returns Nothing.
Description Function sets mask for advanced filtering of messages. Given value is bit adjusted to appropriate buffer mask registers.
Parameters:
  • CAN_MASK is one of predefined constant values 
  • value is the mask register value
  • CAN_CONFIG_FLAGS selects type of message to filter, either _CAN_CONFIG_XTD_MSG or _CAN_CONFIG_STD_MSG
Requires CAN must be in Config mode; otherwise the function will be ignored.
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
// Set all mask bits to 1, i.e. all filtered bits are relevant:
CANSetMask(_CAN_MASK_B1, -1, _CAN_CONFIG_XTD_MSG);

// Note that -1 is just a cheaper way to write 0xFFFFFFFF.
   Complement will do the trick and fill it up with ones.

CANSetFilter

Prototype void CANSetFilter(char CAN_FILTER, long value, char CAN_CONFIG_FLAGS);
Returns Nothing.
Description Function sets message filter. Given value is bit adjusted to appropriate buffer mask registers.
Parameters:
  • CAN_FILTER is one of predefined constant values 
  • value is the filter register value
  • CAN_CONFIG_FLAGS selects type of message to filter, either _CAN_CONFIG_XTD_MSG or _CAN_CONFIG_STD_MSG
Requires CAN must be in Config mode; otherwise the function will be ignored.
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
// Set id of filter B1_F1 to 3:
CANSetFilter(_CAN_FILTER_B1_F1, 3, _CAN_CONFIG_XTD_MSG);

CANRead

Prototype char CANRead(long *id, char *data, char *datalen, char *CAN_RX_MSG_FLAGS);
Returns Message from receive buffer or zero if no message found.
Description Function reads message from receive buffer. If at least one full receive buffer is found, it is extracted and returned. If none found, function returns zero.
Parameters:
  • id is message identifier
  • data is an array of bytes up to 8 bytes in length
  • datalen is data length, from 1–8.
  • CAN_RX_MSG_FLAGS is value formed from constants
Requires CAN must be in mode in which receiving is possible.
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
char rcv, rx, len, data[8];
long id;

// ...
rx = 0;
// ...
rcv = CANRead(id, data, len, rx);

CANWrite

Prototype unsigned short CANWrite(long id, char *data, char datalen, char CAN_TX_MSG_FLAGS);
Returns Returns zero if message cannot be queued (buffer full).
Description If at least one empty transmit buffer is found, function sends message on queue for transmission. If buffer is full, function returns 0.
Parameters:
  • id is CAN message identifier. Only 11 or 29 bits may be used depending on message type (standard or extended)
  • data is array of bytes up to 8 bytes in length
  • datalen is data length from 1–8
  • CAN_TX_MSG_FLAGS is value formed from constants 
Requires CAN must be in Normal mode.
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
char tx, data;
long id;

// ...
tx = _CAN_TX_PRIORITY_0 &
     _CAN_TX_XTD_FRAME;
// ...
CANWrite(id, data, 2, tx);

CANSetTxIdleLevel

Prototype void CANSetTxIdleLevel(char driveHighState);
Returns Nothing.
Description This function sets the state of CANTX pin when recessive.
Parameters:
  • driveHighState: State of the CANTX pin. Valid values :
    Description Predefined library const
    CANTX pin will drive VDD when recessive.
    Use it when using a differential bus to avoid signal crosstalk in CANTX from other nearby pins.
    _CAN_DRIVE_HIGH_STATE_ENABLE
    CANTX pin will be tri-state when recessive. _CAN_DRIVE_HIGH_STATE_DISABLE
Requires Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
Example
CANSetTxIdleLevel(_CAN_DRIVE_HIGH_STATE_ENABLE);

CAN Constants

There is a number of constants predefined in CAN library. To be able to use the library effectively, you need to be familiar with these. You might want to check the example at the end of the chapter.

CAN_OP_MODE

CAN_OP_MODE constants define CAN operation mode. Function CANSetOperationMode expects one of these as its argument:
const char
_CAN_MODE_BITS = 0xE0, // Use this to access opmode bits
_CAN_MODE_NORMAL = 0x00,
_CAN_MODE_SLEEP = 0x20,
_CAN_MODE_LISTEN = 0x60,
_CAN_MODE_LOOP = 0x40,
_CAN_MODE_CONFIG = 0x80;


CAN_CONFIG_FLAGS

CAN_CONFIG_FLAGS constants define flags related to CAN module configuration. Functions CANInitialize and CANSetBaudRate expect one of these (or a bitwise combination) as their argument:
const char
_CAN_CONFIG_DEFAULT = 0xFF, // 11111111
_CAN_CONFIG_PHSEG2_PRG_BIT = 0x01,
_CAN_CONFIG_PHSEG2_PRG_ON = 0xFF, // XXXXXXX1
_CAN_CONFIG_PHSEG2_PRG_OFF = 0xFE, // XXXXXXX0
_CAN_CONFIG_LINE_FILTER_BIT = 0x02,
_CAN_CONFIG_LINE_FILTER_ON = 0xFF, // XXXXXX1X
_CAN_CONFIG_LINE_FILTER_OFF = 0xFD, // XXXXXX0X
_CAN_CONFIG_SAMPLE_BIT = 0x04,
_CAN_CONFIG_SAMPLE_ONCE = 0xFF, // XXXXX1XX
_CAN_CONFIG_SAMPLE_THRICE = 0xFB, // XXXXX0XX
_CAN_CONFIG_MSG_TYPE_BIT = 0x08,
_CAN_CONFIG_STD_MSG = 0xFF, // XXXX1XXX
_CAN_CONFIG_XTD_MSG = 0xF7, // XXXX0XXX
_CAN_CONFIG_DBL_BUFFER_BIT = 0x10,
_CAN_CONFIG_DBL_BUFFER_ON = 0xFF, // XXX1XXXX
_CAN_CONFIG_DBL_BUFFER_OFF = 0xEF, // XXX0XXXX
_CAN_CONFIG_MSG_BITS = 0x60,
_CAN_CONFIG_ALL_MSG = 0xFF, // X11XXXXX
_CAN_CONFIG_VALID_XTD_MSG = 0xDF, // X10XXXXX
_CAN_CONFIG_VALID_STD_MSG = 0xBF, // X01XXXXX
_CAN_CONFIG_ALL_VALID_MSG = 0x9F; // X00XXXXX
You may use bitwise AND (&) to form config byte out of these values. For example:

init = _CAN_CONFIG_SAMPLE_THRICE &
_CAN_CONFIG_PHSEG2_PRG_ON &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_STD_MSG & _CAN_CONFIG_VALID_XTD_MSG &
CANInitialize(1, 1, 3, 3, 1, init); // initialize CAN
_CAN_CONFIG_LINE_FILTER_OFF;
...

CAN_TX_MSG_FLAGS

CAN_TX_MSG_FLAGS are flags related to transmission of a CAN message:
const char
_CAN_TX_PRIORITY_BITS = 0x03,
_CAN_TX_PRIORITY_0 = 0xFC, // XXXXXX00
_CAN_TX_PRIORITY_1 = 0xFD, // XXXXXX01
_CAN_TX_PRIORITY_2 = 0xFE, // XXXXXX10
_CAN_TX_PRIORITY_3 = 0xFF, // XXXXXX11
_CAN_TX_FRAME_BIT = 0x08,
_CAN_TX_STD_FRAME = 0xFF, // XXXXX1XX
_CAN_TX_XTD_FRAME = 0xF7, // XXXXX0XX
_CAN_TX_RTR_BIT = 0x40,
_CAN_TX_NO_RTR_FRAME = 0xFF, // X1XXXXXX
_CAN_TX_RTR_FRAME = 0xBF; // X0XXXXXX
You may use bitwise AND (&) to adjust the appropriate flags. For example:

// form value to be used with CANSendMessage:
send_config = _CAN_TX_PRIORITY_0 &
_CAN_TX_XTD_FRAME &
_CAN_TX_NO_RTR_FRAME;
...
CANSendMessage(id, data, 1, send_config);

CAN_RX_MSG_FLAGS

CAN_RX_MSG_FLAGS are flags related to reception of CAN message. If a particular bit is set; corresponding meaning is TRUE or else it will be FALSE.
const char
_CAN_RX_FILTER_BITS = 0x07, // Use this to access filter bits
_CAN_RX_FILTER_1 = 0x00,
_CAN_RX_FILTER_2 = 0x01,
_CAN_RX_FILTER_4 = 0x03,
_CAN_RX_FILTER_3 = 0x02, _CAN_RX_FILTER_5 = 0x04,
_CAN_RX_OVERFLOW = 0x08, // Set if Overflowed else cleared
_CAN_RX_FILTER_6 = 0x05,
_CAN_RX_INVALID_MSG = 0x10, // Set if invalid else cleared
_CAN_RX_XTD_FRAME = 0x20, // Set if XTD message else cleared
_CAN_RX_RTR_FRAME = 0x40, // Set if RTR message else cleared
_CAN_RX_DBL_BUFFERED = 0x80; // Set if this message was hardware double-buffered
You may use bitwise AND (&) to adjust the appropriate flags. For example:

if (MsgFlag & _CAN_RX_OVERFLOW != 0) {
...
// Receiver overflow has occurred.
// We have lost our previous message.
}

CAN_MASK

CAN_MASK constants define mask codes. Function CANSetMask expects one of these as its argument:
#const char
_CAN_MASK_B1 = 0,
_CAN_MASK_B2 = 1;


CAN_FILTER

CAN_FILTER constants define filter codes. Function CANSetFilter expects one of these as its argument:
const char
_CAN_FILTER_B1_F1 = 0,
_CAN_FILTER_B1_F2 = 1,
_CAN_FILTER_B2_F2 = 3,
_CAN_FILTER_B2_F1 = 2, _CAN_FILTER_B2_F3 = 4,
_CAN_FILTER_B2_F4 = 5;

Library Example

This is a simple demonstration of CAN Library routines usage. First node initiates the communication with the second node by sending some data to its address. The second node responds by sending back the data incremented by 1. First node then does the same and sends incremented data back to second node, etc.
Code for the first CAN node:

unsigned char Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags; // can flags
unsigned char Rx_Data_Len; // received data length in bytes
char RxTx_Data[8]; // can rx/tx data buffer
char Msg_Rcvd; // reception flag
const long ID_1st = 12111, ID_2nd = 3; // node IDs
long Rx_ID;
void main() {
PORTC = 0; // clear PORTC
TRISC = 0; // set PORTC as output
Can_Init_Flags = 0; //
Can_Send_Flags = 0; // clear flags
Can_Rcv_Flags = 0; //
Can_Send_Flags = _CAN_TX_PRIORITY_0 & // form value to be used
_CAN_TX_XTD_FRAME & // with CANWrite
_CAN_TX_NO_RTR_FRAME;
Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE & // form value to be used
_CAN_CONFIG_PHSEG2_PRG_ON & // with CANInit
_CAN_CONFIG_XTD_MSG &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_VALID_XTD_MSG;
CANInitialize(1,3,3,3,1,Can_Init_Flags); // Initialize CAN module
CANSetOperationMode(_CAN_MODE_CONFIG,0xFF); // set CONFIGURATION mode
CANSetMask(_CAN_MASK_B1,-1,_CAN_CONFIG_XTD_MSG); // set all mask1 bits to ones
CANSetMask(_CAN_MASK_B2,-1,_CAN_CONFIG_XTD_MSG); // set all mask2 bits to ones
CANSetFilter(_CAN_FILTER_B2_F4,ID_2nd,_CAN_CONFIG_XTD_MSG);// set id of filter B2_F4 to 2nd node ID
CANSetOperationMode(_CAN_MODE_NORMAL,0xFF); // set NORMAL mode
RxTx_Data[0] = 9; // set initial data to be sent
CANWrite(ID_1st, RxTx_Data, 1, Can_Send_Flags); // send initial message
while(1) { // endless loop
Msg_Rcvd = CANRead(&Rx_ID , RxTx_Data , &Rx_Data_Len, &Can_Rcv_Flags); // receive message
if ((Rx_ID == ID_2nd) && Msg_Rcvd) { // if message received check id
PORTC = RxTx_Data[0]; // id correct, output data at PORTC
RxTx_Data[0]++ ; // increment received data
Delay_ms(10);
CANWrite(ID_1st, RxTx_Data, 1, Can_Send_Flags); // send incremented data back
}
}
}
Code for the second CAN node:

unsigned char Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags; // can flags
unsigned char Rx_Data_Len; // received data length in bytes
char RxTx_Data[8]; // can rx/tx data buffer
char Msg_Rcvd; // reception flag
const long ID_1st = 12111, ID_2nd = 3; // node IDs
long Rx_ID;
void main() {
PORTC = 0; // clear PORTC
TRISC = 0; // set PORTC as output
Can_Init_Flags = 0; //
Can_Send_Flags = 0; // clear flags
Can_Rcv_Flags = 0; //
Can_Send_Flags = _CAN_TX_PRIORITY_0 & // form value to be used
_CAN_TX_XTD_FRAME & // with CANWrite
_CAN_TX_NO_RTR_FRAME;
Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE & // form value to be used
_CAN_CONFIG_PHSEG2_PRG_ON & // with CANInit
_CAN_CONFIG_XTD_MSG &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_VALID_XTD_MSG &
_CAN_CONFIG_LINE_FILTER_OFF;
CANInitialize(1,3,3,3,1,Can_Init_Flags); // initialize external CAN module
CANSetOperationMode(_CAN_MODE_CONFIG,0xFF); // set CONFIGURATION mode
CANSetMask(_CAN_MASK_B1,-1,_CAN_CONFIG_XTD_MSG); // set all mask1 bits to ones
CANSetMask(_CAN_MASK_B2,-1,_CAN_CONFIG_XTD_MSG); // set all mask2 bits to ones
CANSetFilter(_CAN_FILTER_B2_F3,ID_1st,_CAN_CONFIG_XTD_MSG);// set id of filter B2_F3 to 1st node ID
CANSetOperationMode(_CAN_MODE_NORMAL,0xFF); // set NORMAL mode
while (1) { // endless loop
Msg_Rcvd = CANRead(&Rx_ID , RxTx_Data , &Rx_Data_Len, &Can_Rcv_Flags); // receive message
if ((Rx_ID == ID_1st) && Msg_Rcvd) { // if message received check id
PORTC = RxTx_Data[0]; // id correct, output data at PORTC
RxTx_Data[0]++ ; // increment received data
CANWrite(ID_2nd, RxTx_Data, 1, Can_Send_Flags); // send incremented data back
}
}
}

HW Connection


No comments:

Post a Comment