APA102 Led strip (image from Kiwi electronics)

LED-strips are awesome things, and they aren’t hard to use if you know how to use them, but only íf you know how to use them. While there may be many guides to connecting it to an Arduino, guides on using it with the Raspberry Pi are quite sparse, and not everything might be as straightforward as it seems. We’ll be using C++ and the wiringPi library to drive an APA102 led strip.

Connecting the strip to the Pi

The APA102 requires 5V, while the raspberry pi uses 3.3V logic, so we’ll have to shift the voltage with a level shifter. Luckily, these are extremely cheap, and in china they go for as little as €0,76. You’ll have to supply it with 3.3V from the pi on the low voltage (LV) side, and with 5V from your power supply on the high voltage (HV) side. Then use either two of the four level shifting pins to connect the strip to your Pi’s SPI interface:

Strip Raspberry Pi Power Supply
VCC - +
CLKI SCLK (pin 23) -
SDI MOSI (pin 19) -
GND - -

Enabling SPI

To enable SPI, open an SSH connection to the Raspberry:

sudo raspi-config

Scroll to advanced options, and then SPI. Enable the SPI interface and reboot the pi. To check whether the SPI module is enabled, run the following command:

sudo lsmod

A list of enabled modules should appear, look for spi-bcm2708. If it appears in the list, SPI should be working properly.

How the APA102 works

The APA102 works by sending bytes through the SPI interface. It is started by sending 32 bits containing 0, then a 32-bit frame for every LED in the strip, and then 32 bits containing 1. Every LED frame contains a constant part (binary 111), 5 bits containing the brightness of the LED, and 3 8-bit integers containing the blue, green and red components respectively.

bits 1-3 bits 4-8 bits 9-16 bits 17-24 bits 25-32
111 Brightness Blue Green Red

Using WiringPi to control the APA102

First, we’ll need to initialize wiringPi and the SPI extension:

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

int main() {
  wiringPiSetup();
  if(wiringPiSPISetup(0, 6000000) < 0) {
    std::cerr << "wiringPiSPISetup failed" << std::endl;
  }
}

After that, we send the opening bits and closing bits:

uint8_t buf[1];
for(int i = 0; i < 4; i++) {
  buf[0] = 0x00;
  wiringPiSPIDataRW(0, buf, 1);
}

//The magic happens here

for(int i = 0; i < 4; i++) {
  buf[0] = 0xFF;
  wiringPiSPIDataRW(0, buf, 1);
}

So, in between those two statements we’ll need to send the data to the LEDs. For this example, we’ll just make everything red. But before that, there is one very important to note (it took me about an hour to find out why my code didn’t work), namely the fact that we’re setting the buf variable in each iteration of the for-loop. This is because wiringPiSPIDataRW writes the incoming data to the supplied uint8_t array, so if you want to write the same data multiple times without creating a huge array, you’ll have to reset the value after each call to wiringPiSPIDataRW.

Creating a LED frame

So, as we saw before, every LED frame contains a constant part, a brightness part, and a color part. The easiest way of creating a frame is just using an uint8_t array and writing the blue, green and red components to the second, third and fourth element respectively. To obtain the first element, we bitwise or 0b111000000 with the brightness we want to use, where the brightness is a number from 0 and 31:

void WriteLED(uint8_t r, uint8_t g, uint8_t b, uint8_t brightness) {
  uint8_t led_frame[4];
  led_frame[0] = 0b11100000 | (0b00011111 & brightness);
  led_frame[1] = b;
  led_frame[2] = g;
  led_frame[3] = r;

  wiringPiSPIDataRW(0, led_frame, 4);
}

Of course, you don’t need to put this in a function and you can just reuse the same buffer for every frame, but do remember to reset the frame every iteration.

With this LED strip you can create some quite awesome effects, and that is something I’ll cover sometime later. Until then, the complete code can be found in this github gist