Computing stuff tied to the physical world

Using WiringPi with RasPi RF

To communicate using the RFM69 on Linux, we will need a driver – somewhat like the one for LPC8xx µC’s, but with a completely different way of communicating over SPI.

This is where the C++ template based design of the rf69.h implementation kicks in. We can re-use the same code as is, by simply passing it a different SPI device class implementation:

#include <wiringPi.h>
#include <wiringPiSPI.h>

template< int N, int S =0 >
class SpiDev {
  public:
    static void master (int div) {
      wiringPiSetup();
      wiringPiSPISetup (N, 4000000);
    }

    static uint8_t rwReg (uint8_t cmd, uint8_t val) {
      uint8_t data[2] = { cmd, val };
      if (wiringPiSPIDataRW (N, data, 2) == -1) {
        printf("SPI error\n");
        return 0;
      }
      return data[1];
    }
};

typedef SpiDev<0> SpiDev0;
typedef SpiDev<1> SpiDev1;

This is based on the excellent WiringPi library by Gordon Henderson, which creates an Arduino-like environment for controlling pins and devices, but on the Raspberry Pi. The two environments couldn’t be more different, but as it turns out, WiringPi succeeds admirably well in hiding many of those differences.

WiringPi needs to be downloaded and installed on the Raspberry Pi before it can be used. See these instructions for how to do this.

On an Odroid C1 running Ubuntu 14.04, a slightly modified version the WiringPi library is already present (as “apt” package). It currently supports SPI device 0 only, not 0 and 1.

The result of all this is that even on a Raspberry Pi (and Odroid C1, etc), we can re-use the RF69 driver from the embello project and create a driver in our code using this line:

    RF69<SpiDev0> rf;

Note that this driver is incompatible with the RF12 driver! It uses the RFM69’s native packet mode, which has “len” and “hdr” bytes in a different order. This hardware-imposed order of fields is different from the RF12 packets used in the JeeLib library. But RFM69 native packet mode has several nice benefits: 1) full-packet buffering, 2) hardware-checked CRC, and 3) the ability to enable 128-bit AES encryption in hardware. Full-packet buffering is what makes it possible to drive the RFM69 from a Raspberry Pi without any hard real-time constraints (whereas the RFM12 has to be serviced within 200 µs – at all times).

Here is a test application for Linux, which is almost identical to this one for LPC8xx µC’s.

Being Linux, the build process is completely different though, and uses this Makefile:

CXXFLAGS += -I../arch-raspi -I../driver
LDLIBS = -lwiringPi -lwiringPiDev -lpthread

all: rf69spi

clean:
        rm -f *.o rf69spi

A sample build, assuming you have cloned the embello repository from GitHub:

$ cd embello/lib/test-raspi-linux
$ make
g++ -I../arch-raspi -I../driver rf69spi.cpp \
  -lwiringPi -lwiringPiDev -lpthread -o rf69spi
$

To run this code, we need superuser privileges, as follows:

$ sudo ./rf69spi

[rf69try]
OK 8018c00102 (57+0:6)
 > #1, 1b
OK 8018c1010203 (58+0:6)
OK 8018c201020304 (58-256:6)
 > #2, 2b
OK 8018c30102030405 (58-26:6)
OK 8018c4010203040506 (58+0:6)
 > #3, 3b
OK 8018c501020304050607 (58-256:6)

As you can see, packets are coming in (“OK …”) and being sent out (“> …”). The packets are from an attached FTDI interface with LPC8xx and RFM69 in this case.

Note: before trying any of this, make sure you have enabled SPI using the raspi-config utility. On the Odroid C1, you can add an “spicc” line to /etc/modules and reboot.

Busy polling

There is one drawback with this naive design: it’s continuously polling the SPI bus, once every millisecond that is – due to the delay(1) in the main loop.

On embedded µC’s, this is fine since there is nothing else they need to do anyway, but on Linux it’s a bit wasteful. It slows down the rest of the system, by consuming 10..30% of all available processing power (a dual- or quad-core processor has a slight advantage here).

The proper way to implement this on Linux this is to use a GPIO pin in interrupt mode plus the pselect() call on Linux, which will suspend the application until there is an actual change on the GPIO pin. We have GPIO pins 23 and 24 tied to the RFM69’s DIO0 and DIO2, respectively – ready to be used for just this purpose.

But for now, the crude polling approach will have to do. It works fine. If you want to reduce the processor load, you could increase the delay to 2 or 3 milliseconds as workaround.

[Back to article index]