This library is fully compatible with the MCP2515 CAN Controller ACAN2515, ACAN2515Tiny, ACAN2517 and ACAN2517FD libraries, it uses a very similar API and the same CANMessage
class for handling messages.
Two sketches are provided for demonstrating remote frame sending and receiving capabilities:
- SendReceiveRemoteFramesWithFlexCan sketch (in
flexcan-driver-example
) which uses the ACAN library, remote frames are sent and received; - SendReceiveRemoteFrames sketch (in
teensyduino-library/ACAN/examples
) which uses the FlexCan library, the first remote frame is sent, no remote frame is received.
Theses two sketches need to establish a CAN network that connects CAN0 and CAN1. You can use a single AND gate, as 74HC08, powered on 3.3V:
- AND inputs are CANT0X and CAN1TX;
- AND outputs are CAN0RX and CAN1RX.
Compiled with a CPU Speed of 180 MHz and Optimization Smallest Code with LTO.
Sketch | Code size | Ram size | Dynamic Ram size |
SendReceiveRemoteFramesWithFlexCan | 9000 bytes | 5032 bytes | 0 |
SendReceiveRemoteFrames | 9268 bytes | 2940 bytes | 1536 bytes |
ACAN is a driver for the FlexCAN module built into the Teensy 3.1 / 3.2, 3.5, 3.6 microcontroller. It supports alternates pins. The two FlexCAN modules are supported on the Teensy 3.6.
The driver supports many bit rates, as standard 62.5 kbit/s, 125 kbit/s, 250 kbit/s, 500 kbit/s, and 1 Mbit/s. An efficient CAN bit timing calculator finds settings for them, but also for exotic bit rates as 842 kbit/s. If the wished bit rate cannot be achieved, the begin
method does not configure the hardware and returns an error code.
The Teensyduino library is the
teensyduino-library/ACAN
directory. Driver API is fully described by the PDF file in theteensyduino-library/ACAN/extras
directory.
The demo sketch is in the
teensyduino-library/ACAN/examples/LoopBackDemo
directory.
Configuration is a four-step operation.
- Instanciation of the
settings
object : the constructor has one parameter: the wished CAN bit rate. Thesettings
is fully initialized. - You can override default settings. Here, we set the
mLoopBackMode
andmSelfReceptionMode
properties to true, enabling to run demo code without any additional hardware (no CAN transceiver needed). We can also for example change the receive buffer size by setting themReceiveBufferSize
property. - Calling the
begin
method configures the driver and starts CAN bus participation. Any message can be sent, any frame on the bus is received. No default filter to provide. - You check the
errorCode
value to detect configuration error(s).
void setup () {
Serial.begin (9600) ;
Serial.println ("Hello") ;
ACANSettings settings (125 * 1000) ; // 125 kbit/s
settings.mLoopBackMode = true ;
settings.mSelfReceptionMode = true ;
const uint32_t errorCode = ACAN::can0.begin (settings) ;
if (0 == errorCode) {
Serial.println ("Can0 ok") ;
}else{
Serial.print ("Error Can0: 0x") ;
Serial.println (errorCode, HEX) ;
}
}
Now, an example of the loop
function. As we have selected loop back mode, every sent frame is received.
static unsigned gSendDate = 0 ;
static unsigned gSentCount = 0 ;
static unsigned gReceivedCount = 0 ;
void loop () {
CANMessage message ;
if (gSendDate < millis ()) {
message.id = 0x542 ;
const bool ok = ACAN::can0.tryToSend (message) ;
if (ok) {
gSendDate += 2000 ;
gSentCount += 1 ;
Serial.print ("Sent: ") ;
Serial.println (gSentCount) ;
}
}
if (ACAN::can0.receive (message)) {
gReceivedCount += 1 ;
Serial.print ("Received: ") ;
Serial.println (gReceivedCount) ;
}
}
CANMessage
is the class that defines a CAN message. The message
object is fully initialized by the default constructor. Here, we set the id
to 0x542
for sending a standard data frame, without data, with this identifier.
The ACAN::can0.tryToSend
tries to send the message. It returns true
if the message has been sucessfully added to the driver transmit buffer.
The gSendDate
variable handles sending a CAN message every 2000 ms.
ACAN::can0.receive
returns true
if a message has been received, and assigned to the message
argument.
The hardware defines two kinds of filters: primary and secondary filters. Depending the driver configuration, you can have up to 14 primary filters and 18 secondary filters.
This an setup example:
ACANSettings settings (125 * 1000) ;
...
const ACANPrimaryFilter primaryFilters [] = {
ACANPrimaryFilter (kData, kExtended, 0x123456, handle_myMessage_0)
} ;
const ACANSecondaryFilter secondaryFilters [] = {
ACANSecondaryFilter (kData, kStandard, 0x234, handle_myMessage_1),
ACANSecondaryFilter (kRemote, kStandard, 0x542, handle_myMessage_2)
} ;
const uint32_t errorCode = ACAN::can0.begin (settings,
primaryFilters,
1, // Primary filter array size
secondaryFilters,
2) ; // Secondary filter array size
For example, the first filter catches extended data frames, with an identifier equal to 0x123456
. When a such frame is received, the handle_myMessage_0
function is called. In order to achieve this by-filter dispatching, you should call ACAN::can0.dispatchReceivedMessage
instead of ACAN::can0.receive
in the loop
function:
void loop () {
ACAN::can0.dispatchReceivedMessage () ; // Do not use ACAN::can0.receive any more
...
}