m2m-can
v1.0.9
Published
A simple can-bus communication system based on socketCAN.
Downloads
41
Maintainers
Readme
m2m-can
m2m-can is a basic can-bus library based on SocketCAN using a simple and easy API. Open and connect the can interface to the can-bus. Once connected, your device can start sending or receiving data to/from the can-bus.
- Supported devices
- Node.js version requirement
- Setup Raspberry Pi to use can-bus (using MCP2515 CAN module)
- Installation
- Quick Tour
Supported devices
- Raspberry Pi Models: B+, 2, 3, Zero & Zero W, Compute Module 3, 3B+, 3A+, 4B (generally all 40-pin models)
Node.js version requirement
- Node.js versions: 10.x, 11.x, 12.x, 14.x, 16.x. Ideally the latest LTS version.
Installation
$ npm install m2m-can
Raspberry Pi peripheral access (GPIO, I2C, SPI and PWM).
For projects requiring raspberry pi peripheral access such as GPIO, I2C, SPI and PWM, you will need to install array-gpio module.
$ npm install array-gpio
Quick Tour
On can-bus communication, each device should either be sending or receiving data to/from other devices on the network but not both.
Master application
'use strict';
const can = require('m2m-can');
let temp = null, random = null;
/* temperature can-bus device frame id */
const temp_id = '025';
/* random can-bus device frame id */
const random_id = '035';
/* master can-bus frame id or can node id */
const master_id = '00C';
/* open can0 interface, set bitrate to 500000 Hz */
// defaults to txqueuelen = 1000, rs = 100
can.open('can0', 500000, function(err){
if(err) return console.error('can0 interface open error', err.message);
// if can0 was opened successfully, you'll see an output - ip link set can0 up with txqueuelen 1000 and bitrate 500000 - success
// read all frame data from CAN bus from all frame id's sending data to CAN bus
can.read('can0', function(err, fdata){
if(err) return console.log('can read error', err.message);
console.log('read all frame data', fdata);
});
// read only random frame data from CAN bus using the random_id
can.read('can0', {id:random_id}, function(err, fdata){
if(err) return console.log('can read error', err.message);
console.log('can-random frame data', fdata);
// { id: '035', len: 3, data: [ 12, 52 ], filter: '035', change: true }
// data[0] - integer value
// data[1] - integer value
random = fdata.data[0].toString() + fdata.data[1].toString();
console.log('random data', random); // 1252
});
// read only temperature frame data from CAN bus using the temp_id
can.read('can0', {id:temp_id} , function(err, fdata){
if(err) return console.log('can read error', err.message);
console.log('can-temp frame data', fdata);
// { id: '025', len: 2, data: [ 18, 94 ], filter: '025', change: true }
// data[0] - integer value
// data[1] - fractional value
temp = fdata.data[0] + '.' + fdata.data[1];
console.log('temperature data', temp); // 18.94
});
});
Slave1 application
'use strict';
const can = require('m2m-can');
const r = require('array-gpio');
/* using the built-in MCP9808 chip library for capturing temperature data using i2c */
let i2c = require('./node_modules/array-gpio/examples/i2c9808.js');
/* setup gpio output pins for led status indicator using array-gpio */
let led1 = r.out(33); // set gpio output pin 33 for can device status led
let led2 = r.out(35); // set gpio output pin 35 for data change status led
/* can-bus temperature device id */
const temp_id = '025';
can.open('can0', 500000, function(err){
if(err) return console.error('can0 interface open error', err.message);
led1.on();
led2.off();
// watch for changes in your data
can.watch('can0', {id:temp_id}, (err, data) => { // watch interval defaults to 100 ms
if(err) return console.error('can watch error', err.message);
// set payload property to your data source
data.payload = i2c.getTemp();
// if temp data value has changed, send data to CAN bus from temp_id
if(data.change === true){
console.log('send temp data', data.payload);
led2.pulse(200);
can.send('can0', temp_id, data.payload);
}
else{
console.log('no data change');
}
});
});
Slave2 application
'use strict';
const can = require('m2m-can');
const r = require('array-gpio');
/* setup can bus device led status indicator using array-gpio */
let led1 = r.out(33); // can device status
let led2 = r.out(35); // data change status
// can-bus device random id
const random_id = '035';
can.open('can0', 500000, function(err){
if(err) return console.error('can0 interface open error', err.message);
led1.on();
led2.off();
can.watch('can0', {id:random_id}, (err, data) => {
if(err) return console.error('can watch error', err.message);
data.payload = 1010 + Math.floor(( Math.random() * 200) + 100);
// if random value has changed, send data to CAN bus from random_id
// since a new value will be generated everytime, it will always send data to CAN bus
if(data.change){
console.log('send random data', data.payload);
can.send('can0', random_id, data.payload);
led2.pulse(200);
}
else{
console.log('no data change');
}
});
});
Can-bus setup
Pin Connection
RPI GPIO Header MCP2515 CAN Module
PIN NAME PIN
#01 3.3V ------------------ VCC
#06 GND ----------------- GND
#19 SPI_MOSI ---------- SI
#21 SPI_MISO ---------- SO
#22 GPIO25 ------------- INT
#23 SPI_SCLK ---------- SCK/CLK
#24 SPI_CE0 ------------ CS
- Open the Raspberry Pi config.txt file using an editor.
$ sudo mousepad /boot/config.txt
or
$ sudo leafpad /boot/config.txt
- Uncomment the following section to enable SPI.
dtparam=spi=on
- Add the following as additional SPI setup.
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25
- Comment the following section. This is not needed.
# dtoverlay=spi0-hw-cs
Save the config.txt file. Reboot the Raspberry Pi.
Verify the SPI configuration. The CAN module should be initialized.
$ dmesg | grep -i spi
The result will look like as shown below.
[ 8.544607] mcp251x spi0.0 can0: MCP2515 successfully initialized.
By the same command you can check the CAN module if it was started by default:
$ dmesg | grep -i can
The result will look like as shown below.
[ 9.793497] CAN device driver interface
[ 9.819174] mcp251x spi0.0 can0: MCP2515 successfully initialized.
[ 271.563711] IPv6: ADDRCONF(NETDEV_CHANGE): can0: link becomes ready
[ 271.695497] can: controller area network core
[ 271.711043] can: raw protocol
If for any reason this is not the case, you can add the CAN module at system start:
$ sudo nano /etc/modules
Add "can" in a new line, save the file and reboot.
Optional additional CAN utilities.
- Install Linux can utility for SocketCAN (https://github.com/linux-can/can-utils).
$ sudo apt-get install can-utils
- Set the clock speed.
$ sudo ip link set can0 up type can bitrate 500000
If the device is busy as shown below:
$ RTNETLINK answers: Device or resource busy
Shutdown the CAN interface as shown below:
$ sudo ifconfig can0 down
And then restart it as shown below:
$ sudo ifconfig can0 up
- Listen for any data in the CAN bus.
$ candump any
- Send some data to the CAN bus.
$ cansend can0 111#FF
- Below are some examples.
Wrong CAN-frame format! Try:
<can_id>#{R|data} for CAN 2.0 frames
<can_id>##<flags>{data} for CAN FD frames
<can_id> can have 3 (SFF) or 8 (EFF) hex chars
{data} has 0..8 (0..64 CAN FD) ASCII hex-values (optionally separated by '.')
<flags> a single ASCII Hex value (0 .. F) which defines canfd_frame.flags
e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / 5AA# / 123##1 / 213##311
1F334455#1122334455667788 / 123#R for remote transmission request.
can-utils https://github.com/linux-can/can-utils