Create a gist now

Instantly share code, notes, and snippets.

@jperkin /rpio.md
Last active Sep 4, 2016

Raspberry Pi GPIO Comparison

Comparing node.js GPIO implementations

Here are two simple programs testing the performance of my rpio library against popular alternatives which use the /sys interface (with the number of npm stars indicated for a rough idea of popularity).

rpi-gpio (9 stars)

This test is based on an example on the rpi-gpio page.

As modules which uses /sys depend upon asynchronous behaviour they require callbacks to ensure that the next operation starts only when the previous one has completed.

var gpio = require('rpi-gpio');

var count = 1000000;

gpio.setup(9, gpio.DIR_OUT, on);

function on() {
    if (count-- == 0) {
        gpio.destroy();
        return;
    }
    gpio.write(9, 1, off);
}

function off() {
    gpio.write(9, 0, on);
}

onoff (12 stars)

onoff provides a nice and simple synchronous interface as well as async, with the synchronous interface being faster for simple tests like this.

var Gpio = require('onoff').Gpio,
    led = new Gpio(9, 'out'),
    count = 1000000;

while (count-- != 0) {
        led.writeSync(1);
        led.writeSync(0);
}

wiring-pi (5 stars)

wiring-pi is quite similar to rpio, but uses Gordon Henderson's wiring-pi library for access rather than bcm2835. As such it has comparable simplicity and speed to rpio.

var wpi = require('wiring-pi');

var count = 1000000;

wpi.wiringPiSetupGpio();
wpi.pinMode(9, wpi.OUTPUT);

while (count-- != 0) {
        wpi.digitalWrite(9, 1);
        wpi.digitalWrite(9, 0);
}

rpio

rpio directly calls the underlying hardware thanks to the bcm2835 library, so there is no need for asynchronous handling and callbacks, we can just write directly as fast as possible and ordering is guaranteed to be preserved.

var rpio = require('rpio');

/*
 * Use GPIOxx numbering to match the rpi-gpio example.  rpio defaults to the physical
 * mapping, i.e. P01-P40, as it is simpler and portable across different models.
 *
 * Alternatively, remove the rpio.init() call completely and replace '9' with '21'.
 */
rpio.init({mapping: 'gpio'});
rpio.open(9, rpio.OUTPUT);

for (var i = 0; i < 1000000; i++) {
    rpio.write(9, 1);
    rpio.write(9, 0);
}

In 0.9.0 I added the .writebuf() API call which makes this even faster, by writing the values from a Buffer directly to a pin:

var rpio = require('../lib/rpio');

var buf = new Buffer(1000000);

rpio.init({mapping: 'gpio'});
rpio.open(9, rpio.OUTPUT);

for (var i = 0; i < buf.length; i+=2) {
        buf[i] = 1;
        buf[i+1] = 0;
}

rpio.writebuf(9, buf);

Results

I ran each multiple times and took the fastest run.

  • rpi-gpio
$ time sudo node rpi-gpio.js

real    11m41.023s
user    6m45.430s
sys     6m29.480s
  • onoff
$ time sudo node onoff.js

real    0m11.136s
user    0m5.040s
sys     0m6.090s
  • wiring-pi
$ time sudo node wiring-pi.js

real    0m2.022s
user    0m1.930s
sys     0m0.050s
  • rpio (.write())
$ time sudo node rpio.js

real    0m2.907s
user    0m2.850s
sys     0m0.040s
  • rpio (.writebuf())
$ time sudo node rpio-writebuf.js

real    0m0.684s
user    0m0.660s
sys     0m0.020s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment