CAN Library

mikroBasic 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:

  Important :

Library Routines

CANSetOperationMode

Prototype

sub procedure CANSetOperationMode(dim mode, wait_flag as byte)

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 (see CAN 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, $FF)

CANGetOperationMode

Prototype

sub function CANGetOperationMode() as byte

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 then
...

CANInitialize

Prototype

sub procedure CANInitialize(dim SJW, BRP, PHSEG1, PHSEG2, PROPSEG, CAN_CONFIG_FLAGS as byte)

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 and _CAN_CONFIG_VALID_XTD_MSG) <> 0
  ' Set all filters to XTD_MSG
else if (config and _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 (see CAN 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  and
        _CAN_CONFIG_PHSEG2_PRG_ON  and
        _CAN_CONFIG_STD_MSG        and
        _CAN_CONFIG_DBL_BUFFER_ON  and
        _CAN_CONFIG_VALID_XTD_MSG  and
        _CAN_CONFIG_LINE_FILTER_OFF
...
CANInitialize(1, 1, 3, 3, 1, init)   ' Initialize CAN

CANSetBaudRate

Prototype

sub procedure CANSetBaudRate(dim SJW, BRP, PHSEG1, PHSEG2, PROPSEG, CAN_CONFIG_FLAGS as byte)

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 (see CAN 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  and
        _CAN_CONFIG_PHSEG2_PRG_ON  and
        _CAN_CONFIG_STD_MSG        and
        _CAN_CONFIG_DBL_BUFFER_ON  and
        _CAN_CONFIG_VALID_XTD_MSG  and
        _CAN_CONFIG_LINE_FILTER_OFF
...
CANSetBaudRate(1, 1, 3, 3, 1, init)

CANSetMask

Prototype

sub procedure CANSetMask(dim CAN_MASK as byte, dim value as longint, dim CAN_CONFIG_FLAGS as byte)

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 (see CAN constants)
  • 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 $FFFFFFFF.
' Complement will do the trick and fill it up with ones.

CANSetFilter

Prototype

sub procedure CANSetFilter(dim CAN_FILTER as byte, dim value as longint, dim CAN_CONFIG_FLAGS as byte)

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 (see CAN constants)
  • 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

sub function CANRead(dim byref id as longint, dim byref data as byte[8], dim byref datalen, CAN_RX_MSG_FLAGS as byte) as byte

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 (see CAN 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
dim len, rcv, rx as byte
dim id  as longint
dim data as byte[8]

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

CANWrite

Prototype

sub function CANWrite(dim id as longint, dim byref data as byte[8], dim datalen, CAN_TX_MSG_FLAGS as byte) as byte

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 (see CAN 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
dim id as longint
dim tx, data as byte

' ...
tx = _CAN_TX_PRIORITY_0 and
     _CAN_TX_XTD_FRAME
' ...
CANWrite(id, data, 2, tx)

CANSetTxIdleLevel

Prototype

sub procedrue CANSetTxIdleLevel(dim driveHighState as byte)

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 _CAN_MODE_BITS    = $E0  ' Use it to access mode bits
const _CAN_MODE_NORMAL  = 0
const _CAN_MODE_SLEEP   = $20
const _CAN_MODE_LOOP    = $40
const _CAN_MODE_LISTEN  = $60
const _CAN_MODE_CONFIG  = $80

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 _CAN_CONFIG_DEFAULT         = $FF  ' 11111111

const _CAN_CONFIG_PHSEG2_PRG_BIT  = $01
const _CAN_CONFIG_PHSEG2_PRG_ON   = $FF  ' XXXXXXX1
const _CAN_CONFIG_PHSEG2_PRG_OFF  = $FE  ' XXXXXXX0

const _CAN_CONFIG_LINE_FILTER_BIT = $02
const _CAN_CONFIG_LINE_FILTER_ON  = $FF  ' XXXXXX1X
const _CAN_CONFIG_LINE_FILTER_OFF = $FD  ' XXXXXX0X

const _CAN_CONFIG_SAMPLE_BIT      = $04
const _CAN_CONFIG_SAMPLE_ONCE     = $FF  ' XXXXX1XX
const _CAN_CONFIG_SAMPLE_THRICE   = $FB  ' XXXXX0XX

const _CAN_CONFIG_MSG_TYPE_BIT    = $08
const _CAN_CONFIG_STD_MSG         = $FF  ' XXXX1XXX
const _CAN_CONFIG_XTD_MSG         = $F7  ' XXXX0XXX

const _CAN_CONFIG_DBL_BUFFER_BIT  = $10
const _CAN_CONFIG_DBL_BUFFER_ON   = $FF  ' XXX1XXXX
const _CAN_CONFIG_DBL_BUFFER_OFF  = $EF  ' XXX0XXXX

const _CAN_CONFIG_MSG_BITS        = $60
const _CAN_CONFIG_ALL_MSG         = $FF  ' X11XXXXX
const _CAN_CONFIG_VALID_XTD_MSG   = $DF  ' X10XXXXX
const _CAN_CONFIG_VALID_STD_MSG   = $BF  ' X01XXXXX
const _CAN_CONFIG_ALL_VALID_MSG   = $9F  ' X00XXXXX

You may use bitwise and to form config byte out of these values. For example:

Copy Code To ClipboardCopy Code To Clipboard
init =  _CAN_CONFIG_SAMPLE_THRICE and
        _CAN_CONFIG_PHSEG2_PRG_ON and
        _CAN_CONFIG_STD_MSG       and
        _CAN_CONFIG_DBL_BUFFER_ON and
        _CAN_CONFIG_VALID_XTD_MSG and
        _CAN_CONFIG_LINE_FILTER_OFF
...
CANInitialize(1, 1, 3, 3, 1, init)   ' Initialize CAN

CAN_TX_MSG_FLAGS

CAN_TX_MSG_FLAGS are flags related to transmission of a CAN message:

const _CAN_TX_PRIORITY_BITS  = $03
const _CAN_TX_PRIORITY_0     = $FC  ' XXXXXX00
const _CAN_TX_PRIORITY_1     = $FD  ' XXXXXX01
const _CAN_TX_PRIORITY_2     = $FE  ' XXXXXX10
const _CAN_TX_PRIORITY_3     = $FF  ' XXXXXX11

const _CAN_TX_FRAME_BIT      = $08
const _CAN_TX_STD_FRAME      = $FF  ' XXXXX1XX
const _CAN_TX_XTD_FRAME      = $F7  ' XXXXX0XX

const _CAN_TX_RTR_BIT        = $40
const _CAN_TX_NO_RTR_FRAME   = $FF  ' X1XXXXXX
const _CAN_TX_RTR_FRAME      = $BF  ' X0XXXXXX

You may use bitwise and to adjust the appropriate flags. For example:

Copy Code To ClipboardCopy Code To Clipboard
' form value to be used with CANSendMessage:
send_config =  _CAN_TX_PRIORITY_0 and
               _CAN_TX_XTD_FRAME  and
               _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 _CAN_RX_FILTER_BITS  = $07  ' Use it to access filter bits
const _CAN_RX_FILTER_1     = $00
const _CAN_RX_FILTER_2     = $01
const _CAN_RX_FILTER_3     = $02
const _CAN_RX_FILTER_4     = $03
const _CAN_RX_FILTER_5     = $04
const _CAN_RX_FILTER_6     = $05
const _CAN_RX_OVERFLOW     = $08  ' Set if Overflowed; else clear
const _CAN_RX_INVALID_MSG  = $10  ' Set if invalid; else clear
const _CAN_RX_XTD_FRAME    = $20  ' Set if XTD message; else clear
const _CAN_RX_RTR_FRAME    = $40  ' Set if RTR message; else clear
const _CAN_RX_DBL_BUFFERED = $80  ' Set if message was
                                 '   hardware double-buffered

You may use bitwise and to adjust the appropriate flags. For example:

Copy Code To ClipboardCopy Code To Clipboard
if (MsgFlag and CAN_RX_OVERFLOW) = 0 then
  ...
  ' 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 CAN_MASK_B1  = 0
const CAN_MASK_B2  = 1

CAN_FILTER

CAN_FILTER constants define filter codes. Function CANSetFilter expects one of these as its argument:

const _CAN_FILTER_B1_F1  = 0
const _CAN_FILTER_B1_F2  = 1
const _CAN_FILTER_B2_F1  = 2
const _CAN_FILTER_B2_F2  = 3
const _CAN_FILTER_B2_F3  = 4
const _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 CANSPI node:

Copy Code To ClipboardCopy Code To Clipboard
program CAN_1st

dim Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags as byte  ' can flags
    Rx_Data_Len as byte                             ' received data length in bytes
    RxTx_Data as byte[8]                            ' can rx/tx data buffer
    Msg_Rcvd as byte                                ' reception flag
    ID_1st, ID_2nd as longint                       ' node IDs
    Rx_ID as longint

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 and           ' form value to be used
                   _CAN_TX_XTD_FRAME and            '     with CANWrite
                   _CAN_TX_NO_RTR_FRAME

  Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE and    ' form value to be used
                   _CAN_CONFIG_PHSEG2_PRG_ON and    ' with CANInit
                   _CAN_CONFIG_XTD_MSG and
                   _CAN_CONFIG_DBL_BUFFER_ON and
                   _CAN_CONFIG_VALID_XTD_MSG
  
  ID_1st = 12111
  ID_2nd = 3
  RxTx_Data[0] = 9                                           ' set initial data to be sent
  
  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

  CANWrite(ID_1st, RxTx_Data, 1, Can_Send_Flags)             ' send initial message

  while TRUE
      Msg_Rcvd = CANRead(Rx_ID , RxTx_Data , Rx_Data_Len, Can_Rcv_Flags)
      if ((Rx_ID = ID_2nd) and (Msg_Rcvd <> 0)) <> 0 then
          PORTC = RxTx_Data[0]                               ' output data at PORTC
          RxTx_Data[0] = RxTx_Data[0] + 1
          Delay_ms(10)
          CANWrite(ID_1st, RxTx_Data, 1, Can_Send_Flags)     ' send incremented data back
      end if
  wend
end.

Code for the second CANSPI node:

Copy Code To ClipboardCopy Code To Clipboard
program CAN_2nd

dim Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags as byte ' CAN flags
    Rx_Data_Len as byte                                    ' received data length in bytes
    RxTx_Data as byte[8]                                   ' can rx/tx data buffer
    Msg_Rcvd as byte                                       ' reception flag
    ID_1st, ID_2nd as longint                              ' node IDs
    Rx_ID as longint

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 and                   ' form value to be used
                   _CAN_TX_XTD_FRAME and                    '     with CANWrite
                   _CAN_TX_NO_RTR_FRAME

  Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE and            ' form value to be used
                   _CAN_CONFIG_PHSEG2_PRG_ON and            ' with CANInit
                   _CAN_CONFIG_XTD_MSG and
                   _CAN_CONFIG_DBL_BUFFER_ON and
                   _CAN_CONFIG_VALID_XTD_MSG and
                   _CAN_CONFIG_LINE_FILTER_OFF

  ID_1st = 12111
  ID_2nd = 3
  RxTx_Data[0] = 9                                           ' set initial data to be sent

  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 true                                                             ' endless loop
    Msg_Rcvd = CANRead(Rx_ID , RxTx_Data , Rx_Data_Len, Can_Rcv_Flags)   ' receive message
    if ((Rx_ID = ID_1st) and (Msg_Rcvd <> 0)) <> 0 then                  ' if message received check id
      PORTC = RxTx_Data[0]                                               ' id correct, output data at PORTC
      Inc(RxTx_Data[0])                                                  ' increment received data
      CANWrite(ID_2nd, RxTx_Data, 1, Can_Send_Flags)                     ' send incremented data back
    end if
  wend
end.

HW Connection

Example of interfacing CAN transceiver with MCU and bus

Example of interfacing CAN transceiver with MCU and bus

Copyright (c) 2002-2012 mikroElektronika. All rights reserved.
What do you think about this topic ? Send us feedback!
Want more examples and libraries? 
Find them on LibStock - A place for the code