CAN Library
The mikroBasic PRO for AVR 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 depend on 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 :
- CAN library routines are supported for these devices : AT90CAN32, AT90CAN64, AT90CAN128, ATMEGA16M1, ATMEGA32M1 and ATMEGA64M1.
- Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus.
- Consult the CAN standard about CAN bus termination resistance.
Library Routines
- CANSetOperationMode
- CANGetOperationMode
- CANInitialize
- CANSetBaudRate
- CANSetMask
- CANSetFilter
- CANRead
- CANWrite
CANSetOperationMode
| Prototype |
sub procedure CANSetOperationMode(dim mode, wait_flag as byte) |
|---|---|
| Returns |
Nothing. |
| Description |
Sets CAN to requested mode, i.e. copies Parameter
|
| Requires |
CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. 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 |
CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. 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. The Config mode is internaly set by this function. Upon a execution of this function Normal mode is set. Filter registers are set according to flag value: if (CAN_CONFIG_FLAGS and _CAN_CONFIG_XTD_MSG) <> 0 ' Set all filters to XTD_MSG else if (config and _CAN_CONFIG_STD_MSG) <> 0 ' Set all filters to STD_MSG else ' Set half of the filters to STD, and the rest to XTD_MSG. Parameters:
|
| 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_MSG_TYPE_BIT and
_CAN_CONFIG_STD_MSG
...
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:
|
| Requires |
CAN must be in Config mode; otherwise the function will be ignored. CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. 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_MSG_TYPE_BIT and
_CAN_CONFIG_STD_MSG
...
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 Parameters:
|
| Requires |
CAN must be in Config mode; otherwise the function will be ignored. CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. 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 |
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 Parameters:
|
| Requires |
CAN must be in Config mode; otherwise the function will be ignored. CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
| Example |
' Set id of filter F1 to 3: CANSetFilter(CAN_RX_FILTER_1, 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:
|
| Requires |
CAN must be in mode in which receiving is possible. CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. 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:
|
| Requires |
CAN must be in Normal mode. CAN routines are currently supported only by AT90CANXXX and ATMEGAXXM1 MCUs. 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)
|
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 = 0x0A ' Use this to access opmode bits const _CAN_MODE_STANDBY = 0x00 const _CAN_MODE_ENABLE = 0x02 const _CAN_MODE_LISTEN = 0x08
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_SAMPLE_BIT = 0x01 const _CAN_CONFIG_SAMPLE_ONCE = 0xFE ' XXXX XXX0 const _CAN_CONFIG_SAMPLE_THRICE = 0xFF ' XXXX XXX1 const _CAN_CONFIG_MSG_TYPE_BIT = 0x10 const _CAN_CONFIG_STD_MSG = 0xEF ' XXX0 XXXX const _CAN_CONFIG_XTD_MSG = 0xFF ' XXX1 XXXX
You may use bitwise and to form config byte out of these values. For example:
init = _CAN_CONFIG_SAMPLE_THRICE and
_CAN_CONFIG_STD_MSG
...
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_CONMOB_DIS = 0x3F ' 00XX XXXX messsage objects work modes const _CAN_CONMOB_EN_TX = 0x7F ' 01XX XXXX const _CAN_CONMOB_EN_RX = 0xBF ' 10XX XXXX const _CAN_CONMOB_EN_FRAME = 0xFF ' 11XX XXXX const _CAN_IDE_FRAME_BIT = 0x10 ' Identifier Extension const _CAN_IDE_STD_FRAME = 0xEF ' XXX0 XXXX const _CAN_IDE_XTD_FRAME = 0xFF ' XXX1 XXXX const _CAN_RTR_BIT = 0x20 const _CAN_NO_RTR_FRAME = 0xFF ' XX1XXXXX const _CAN_RTR_FRAME = 0xDF ' XX0XXXXX const _CAN_TX = 0x01 ' Transmitter Busy const _CAN_TX_NO_BSY = 0xFE ' XXXX XXX0 const _CAN_TX_BSY = 0xFF ' XXXX XXX1
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 and
_CAN_TX_XTD_FRAME and
_CAN_TX_NO_RTR_FRAME
...
CANWrite(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 = 0x08 ' Receiver Busy const _CAN_RX_NO_BSY = 0xF7 ' XXXX 0XXX const _CAN_RX_BSY = 0xFF ' XXXX 1XXX
You may use bitwise and to adjust the appropriate flags. For example:
if (MsgFlag and _CAN_RX_BSY) = 0 then ... ' Receiver is busy.
CAN_MASK
CAN_MASK constants define mask codes. Function CANSetMask expects one of these as its argument:
const CAN_RX_MASK_0 = 0x00 const CAN_RX_MASK_1 = 0x01 const CAN_RX_MASK_2 = 0x02 const CAN_RX_MASK_3 = 0x03 const CAN_RX_MASK_4 = 0x04 const CAN_RX_MASK_5 = 0x05 const CAN_RX_MASK_6 = 0x06 const CAN_RX_MASK_7 = 0x07 const CAN_RX_MASK_8 = 0x08 const CAN_RX_MASK_9 = 0x09 const CAN_RX_MASK_10 = 0x0A const CAN_RX_MASK_11 = 0x0B const CAN_RX_MASK_12 = 0x0C const CAN_RX_MASK_13 = 0x0D const CAN_RX_MASK_14 = 0x0E
CAN_FILTER
CAN_FILTER constants define filter codes. Function CANSetFilter expects one of these as its argument:
const CAN_RX_FILTER_0 = 0x00 const CAN_RX_FILTER_1 = 0x01 const CAN_RX_FILTER_2 = 0x02 const CAN_RX_FILTER_3 = 0x03 const CAN_RX_FILTER_4 = 0x04 const CAN_RX_FILTER_5 = 0x05 const CAN_RX_FILTER_6 = 0x06 const CAN_RX_FILTER_7 = 0x07 const CAN_RX_FILTER_8 = 0x08 const CAN_RX_FILTER_9 = 0x09 const CAN_RX_FILTER_10 = 0x0A const CAN_RX_FILTER_11 = 0x0B const CAN_RX_FILTER_12 = 0x0C const CAN_RX_FILTER_13 = 0x0D const CAN_RX_FILTER_14 = 0x0E
CAN_MOB
CAN_MOB constants define flags related to transmission of a CAN message :
const _CAN_EN_MOB0_BIT = 0x0001 ' Flags, set to 1 if the appropriate MOb is in use. When the appropriate operation ends, TXOK or RXOK are set to 1 const _CAN_EN_MOB1_BIT = 0x0002 const _CAN_EN_MOB2_BIT = 0x0004 const _CAN_EN_MOB3_BIT = 0x0008 const _CAN_EN_MOB4_BIT = 0x0010 const _CAN_EN_MOB5_BIT = 0x0020 const _CAN_EN_MOB6_BIT = 0x0040 const _CAN_EN_MOB7_BIT = 0x0080 const _CAN_EN_MOB8_BIT = 0x0100 const _CAN_EN_MOB9_BIT = 0x0200 const _CAN_EN_MOB10_BIT = 0x0400 const _CAN_EN_MOB11_BIT = 0x0800 const _CAN_EN_MOB12_BIT = 0x1000 const _CAN_EN_MOB13_BIT = 0x2000 const _CAN_EN_MOB14_BIT = 0x4000 const _CAN_CONFIG_STMOB_TXOK = 0x40 ' X1XX XXXX From the CAN MOb Status Register const _CAN_CONFIG_STMOB_RXOK = 0x20 ' XX1X XXXX Receive OK const _CAN_CONFIG_STMOB_BERR = 0x10 ' XXX1 XXXX Bit Error (Only in transmission) const _CAN_CONFIG_STMOB_SERR = 0x08 ' XXXX 1XXX Stuff Error const _CAN_CONFIG_STMOB_CERR = 0x04 ' XXXX X1XX CRC Error const _CAN_CONFIG_STMOB_FERR = 0x02 ' XXXX XX1X Form Error const _CAN_CONFIG_STMOB_AERR = 0x01 ' XXXX XXX1 Acknowledgment Error
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:
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 = 0x00 ' clear PORTC
DDRC = 0xFF ' set PORTC as output
Msg_Rcvd = 0
Can_Init_Flags = 0 '
Can_Send_Flags = 0 ' clear flags
Can_Rcv_Flags = 0 '
Can_Send_Flags = _CAN_IDE_XTD_FRAME ' form value to be used
and _CAN_NO_RTR_FRAME ' with CANWrite
Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE ' form value to be used
and _CAN_CONFIG_XTD_MSG ' with CANInit
ID_1st = 12111
ID_2nd = 3
RxTx_Data[0] = 9
CANInitialize(1,6,3,3,1,Can_Init_Flags) ' initialize external CAN module
CANSetOperationMode(_CAN_MODE_STANDBY,0xFF) ' set STANDBY mode
'-----------------------------------------------------------'
CANSetFilter(CAN_RX_FILTER_3, -1, _CAN_CONFIG_XTD_MSG) '
CANSetFilter(CAN_RX_FILTER_4, ID_2nd, _CAN_CONFIG_XTD_MSG) ' set ID filter of 4th filter to 2nd node ID
CANSetFilter(CAN_RX_FILTER_5, -1, _CAN_CONFIG_XTD_MSG) ' and ones to other filters
CANSetFilter(CAN_RX_FILTER_6, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_7, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_8, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_9, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_10, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_11, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_12, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_13, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_14, -1, _CAN_CONFIG_XTD_MSG)
'-----------------------------------------------------------'
' set all mask bits of masks[3..14] to all ones
'-----------------------------------------------------------'
CANSetMask(CAN_RX_MASK_3, -1, _CAN_CONFIG_XTD_MSG) ' set all mask bits of masks[3..14] to all ones
CANSetMask(CAN_RX_MASK_4, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_5, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_6, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_7, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_8, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_9, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_10, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_11, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_12, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_13, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_14, -1, _CAN_CONFIG_XTD_MSG)
'-----------------------------------------------------------'
CANSetOperationMode(_CAN_MODE_ENABLE,0xFF) ' set ENABLE mode
RxTx_Data[0] = 9 ' set initial data to be sent
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 CAN node:
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 = 0x00 ' clear PORTC
DDRC = 0xFF ' set PORTC as output
Msg_Rcvd = 0
Can_Init_Flags = 0 '
Can_Send_Flags = 0 ' clear flags
Can_Rcv_Flags = 0 '
Can_Send_Flags = _CAN_IDE_XTD_FRAME ' form value to be used
and _CAN_NO_RTR_FRAME ' with CANWrite
Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE ' form value to be used
and _CAN_CONFIG_XTD_MSG ' with CANInit
ID_1st = 12111
ID_2nd = 3
RxTx_Data[0] = 9
CANInitialize(1,6,3,3,1,Can_Init_Flags) ' initialize external CAN module
CANSetOperationMode(_CAN_MODE_STANDBY,0xFF) ' set STANDBY mode
'-----------------------------------------------------------'
CANSetFilter(CAN_RX_FILTER_3, -1, _CAN_CONFIG_XTD_MSG) '
CANSetFilter(CAN_RX_FILTER_4, ID_2nd, _CAN_CONFIG_XTD_MSG) ' set ID filter of 4th filter to 2nd node ID
CANSetFilter(CAN_RX_FILTER_5, -1, _CAN_CONFIG_XTD_MSG) ' and ones to other filters
CANSetFilter(CAN_RX_FILTER_6, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_7, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_8, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_9, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_10, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_11, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_12, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_13, -1, _CAN_CONFIG_XTD_MSG)
CANSetFilter(CAN_RX_FILTER_14, -1, _CAN_CONFIG_XTD_MSG)
'-----------------------------------------------------------'
' set all mask bits of masks[3..14] to all ones
'-----------------------------------------------------------'
CANSetMask(CAN_RX_MASK_3, -1, _CAN_CONFIG_XTD_MSG) ' set all mask bits of masks[3..14] to all ones
CANSetMask(CAN_RX_MASK_4, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_5, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_6, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_7, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_8, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_9, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_10, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_11, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_12, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_13, -1, _CAN_CONFIG_XTD_MSG)
CANSetMask(CAN_RX_MASK_14, -1, _CAN_CONFIG_XTD_MSG)
'-----------------------------------------------------------'
CANSetOperationMode(_CAN_MODE_ENABLE,0xFF) ' set ENABLE 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.
What do you think about this topic ? Send us feedback!




