Arduino CBUS Library Instructions 1.1
Arduino CBUS Library Instructions 1.1
Introduction
This set of libraries implements a complete CBUS module using the Arduino environment. A
minimum of additional code is required to create a fully-functional FLiM-compliant module.
No additional code need be written to integrate with FCU or JMRI or to learn events.
Features include:
All five libraries a required although the LED and switch libraries can be used standalone in
other projects if you find them useful. The download links are:
CBUS - https://github.com/obdevel/CBUS
CBUS2515 - https://github.com/obdevel/CBUS2515
CBUSLED - https://github.com/obdevel/CBUSLED
CBUSswitch - https://github.com/obdevel/CBUSswitch
CBUSconfig - https://github.com/obdevel/CBUSconfig
You can now also download these from the Library Manager in the Arduino IDE. This will also
prompt you when updated versions are released.
You will also need to install the following two 3rd party libraries:
ACAN2515 - https://github.com/pierremolinaro/acan2515
Streaming - https://github.com/janelia-arduino/Streaming
For people who may have used other CAN bus libraries (e.g. MCP_CAN), note that the
ACAN2515 library implements interrupt handling and configurable send/receive buffers, so
there is no need to code this yourself.
I expect to add further implementations of the CBUS library for other CAN bus controllers,
such as those integrated in MCUs such as AT90CAN, ESP32, etc.
Hardware
• an Arduino processor board, e.g. Uno, Nano, Mega, Pro Mini, etc
• a CAN bus module based on the MCP2515 chip (available from multiple eBay sellers)
• two LEDs (green and yellow/amber) with 1K resistors
• a pushbutton switch
As an alternative, I have designed a generic through-hole PCB containing all the above, as
well as a 64K EEPROM chip. It has no module-specific components, but all spare IO pins are
brought out to headers. The design files are available on the MERG wiki at:
https://www.merg.org.uk/merg_wiki/doku.php?id=projects:canxmas
Connect the green LED with its current-limiting resistor between Arduino pin 4 and GND
Connect the yellow LED with its current-limiting resistor between Arduino pin 5 and GND
Connect the pushbutton switch between Arduino pin 6 and GND
Pinouts for other modules (e.g. Mega) are well-documented on the Internet.
The CBUS library includes a starter sketch in the example folder (CAN_empty.ino). This
creates a complete but ‘empty’ module with no specific personality.
// local header
#include "defs.h"
3. declare the module parameter variables and set the module’s name:
// assign to CBUS
CBUS.setParams(params);
CBUS.setName(mname);
(c) configure the LEDs and pushbutton switch, and check for power-on reset:
(d) register two user-defined functions, to be called when (i) a learned event is received and
(ii) for every CAN frame received:
// register our CBUS event handler, to receive event messages of learned events
CBUS.setEventHandler(eventhandler);
(e) assign the switch and LEDs and indicate the current module mode (FLiM or SLiM):
(f) configure the CAN bus parameters and start CBUS message processing:
void loop() {
//
/// do CBUS message, switch and LED processing
//
CBUS.process();
}
5. implement a simple user-defined function to handle received events (note that EVs and
NVs number from one, not zero):
6. implement a simple user-defined function to handle all received CAN bus frames:
Serial << "[ " << (msg->id & 0x7f) << "] [" << msg->len << "] [";
Header File
The example sketch includes a module-specific header file (defs.h) which defines some local
constants, as follows:
// constants
static const byte VER_MAJ = 1; // code major version
static const char VER_MIN = 'a'; // code minor version
static const byte VER_BETA = 0; // code beta sub-version
static const byte MODULE_ID = 99; // CBUS module type
Consumer Modules
A user-defined event handler function is called whenever a CBUS accessory event that has
previously been learned is received; this is the entry point for implementing a Consumer
module. It goes without saying that this function will not be called until the module has been
taught at least one event.
byte index;
This is the index into the module’s event table. The Event Variables (EVs) can then be
located.
CANFrame *msg;
Bytes 5-7 are additional data bytes that are send by some opcodes. See the CBUS
Developers’ Guide for more information on opcodes.
A further user-defined function can be called for every CAN bus frame received. It receives a
pointer to the CAN frame object, as above. This may prove useful for modules that need to
be aware of more than just learned accessory events, for example a module that needs to
read NVs from other modules.
Producer Modules
A Producer module will need to send CBUS messages when something of interest happens in
‘the outside world’, e.g. a switch is pressed, a loco is detected, etc. It is up to you to define
the following items for any CBUS messages you wish to send:
This code fragment (not in the example sketch) shows how to send a simple ON event
message with event number 1 and no additional data bytes:
// the opcode
msg.data[0] = OPC_ACON;
Note also that the NN and EN are 16-bit integers and each occupy two (8-bit) bytes of the
message. The Arduino macros highByte() and lowByte() return the appropriate byte part
from a 16-bit integer. See the CBUS Developers’ Guide for a full discussion of short and long
events and the meaning of NN and EN.
Module Reset
The Arduino environment provides no easy way to pre-program the microcontroller’s on-chip
EEPROM. To ensure that the contents of the EEPROM are cleared and set to sensible
defaults, the CBUSconfig library provides a simple method for resetting the module. This is
shown in the example program included with the library.
Hold down the pushbutton switch as you power-on the module. Then, as a safety
precaution, press and hold the switch for a further 5 seconds. The module will then reset the
EEPROM contents and reboot. The Node Number and CANID will both be set to zero.
The module can only be reset whilst in SLiM mode (with the green LED illuminated). If, due
to random EEPROM data, the module starts up in FLiM mode (with the yellow LED
illuminated), or you want to reset the module at any time in the future, hold the switch
down for 6 seconds to revert to SLiM mode. You can then proceed to reset the module.
The library does not currently support SLiM mode; that is, there is no provision for setting
the node number or learning events by hardware switches. Therefore, you must use FCU or
JMRI to configure your module in FLiM mode. This is in common with most newer MERG CBUS
modules.
Support for SLiM configuration and event learning may be added as a future enhancement if
demand exists.
The library prints copious debug information but by default this code is commented out.
Selected lines can be uncommented to help with code debugging and development, but note
that this will increase the program size and memory consumption.