Sparkfun's RGB LED Matrix - Serial Interface

ATTENTION: There is an alternative firmware for this device, that allows you to display 4096 colors, instead of 255 with the default firmware. Please refer to https://github.com/fornellas/SFRGBLEDMatrix for more information on how to install it. Information below is for use with Sparkfun's default firmware.

This page documents Arduino interfacing with Sparkfun's LED Matrix - Serial Interface - Red/Green/Blue product. The provided datasheet gives an overview, but the hardware has some particular behaviors not documented anywhere. Please read the datasheet first, then continue reading the next sections to understand its behavior.

Warning: the documentation here apply to firmware v4, not v5! Please read the caveats session below.

Device characteristics

The hardware consists of an RGB LED Matrix on top of a PCB, which contains some additional hardware for easier use of the matrix. The matrix itself has 36 pins, but you will only need 3 wires (excluding GND and 5V) to communicate with it through the additional PCB. This is because the PCB has an ATmega168 micro controller, which can be interfaced through SPI. The micro controller comes pre-loaded with a firmware, which can be overwritten by the user. This however will require additional hardware.

Device characteristics:

  • 8x8 RGB LEDs matrix (192 LEDs total)
  • 255 colors capable (not 256, limitation of the default firmware, see caveats below)
    • 8 shades of red
    • 8 shades of green
    • 4 shades of blue
  • Interfacing via SPI
  • Support for daisy-chain operation (up to 8 boards).

The default firmware

The default firmware runs a frame buffer program, which reads image data via SPI and sends it to the LED Matrix. The datasheet states that the device behaves like this:

  1. Assert SS
  2. Delay 500us
  3. Transfer 64 bytes (image data)
  4. De-assert SS

Also, the default firmware will show you a smile splash screen at the first 10 boots.

Daisy-chain operation

The board has connectors allowing you to attach one to another. You interface only with the first board, sending image data. When you send more data that can fit on the first board (64 bytes), the first board passes its buffer to the second board, and so on. When data has arrived to all of the boards, all of them show off their new image data.

To accomplish this, each board has a configuration, of how many boars exists in a row. The datasheet states that the following procedure must be done to reconfigure the boards:

  1. Assert SS
  2. Delay 500us
  3. Send '%' byte.
  4. Send a byte representing the number of boards (for 2 boards, send 00000010)
  5. De-assert SS

Each board will then behave like this:

  1. Receive frames (64 bytes) and pass its old frame buffer to the next board.
  2. Each time the number of frames received is equal to the number of boards in the row, it will show off its frame buffer.

This behavior avoids tearing in a row.

Configuration status at start up

Each board, when booted, will print a pattern on a corner (continuing on the row above if it can not fit), to show on the number of boards configured (L=black, R=red, G=green, B=blue):

  • 1 board: RRGGBB
  • 2 boards: LRRGGBB
  • 3 boards: LLRRGGBB

and so on (up to 8).

Caveats

The default firmware v4 has some caveats documented below. There is new version v5, fixing those bugs. You will have to follow the instructinos to update it.

  • Partial frame transfers (sending less than 64 bytes between SS assertion and de-assertion) can corrupt the display.
    • This means that there is a risk of, when you load a new firmware to the board, when the new program starts at your Arduino, the default firmware on the LED matrix can show corrupted images.
    • This is probably because the default firmware has some internal counter, which starts when it powers on, and is not reset on SS assertion / de-assertion.
    • The only way around this, is to always power off / power on the device when the problem happens. A good practice is to always do that when you load a new sketch to the Arduino, and not spend hours debugging your code thinking is it which is corrupting the display.
    • If SPI communication error happens, some bytes won't be transfered and the display will corrupt the image. Although rare at regular operation, it can happen.
  • Daisy chain board configuration is somehow broken. The datasheet says to assert SS, send '%', send number of boards and de-assert SS. However, the following sequence also reprogram the board: assert SS, send initial image data, send '%', send final image data, de-assert SS. The '%' byte in theory can be a valid color, but the firmware always treat it as a reconfiguration command.
    • One way around that (without patching the firmware) is to always check the value of the color before sending. If the color is '%', send (2<<5)&(1<<2)&1 instead (a similar color).
    • Another way is to simply make sure your software never use the '%' color.

Interfacing

Arduino support SPI communication needed to interface with the matrix. For example, Arduino Duemilanove support SPI communication specifically through pins 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). If you have a different Arduino, please refer to your Arduino / micro controller datasheet SPI section to find the correct pins.

PS: Sparkfun's hardware has different labels for SPI pins than referred by Atmel's datasheets: SS=CS, SCK=SCLK.

Library

A library for controlling the matrix is available at:

https://github.com/fornellas/SFRGBLEDMatrix/tree/sparkfun

Example code (without the library)

The code below makes a "color showcase" and can be used as a start point to interfacing with the LED Matrix using an Arduino. It has been tested with Duemilanove, if you have a different one, please don't forget to confirm SPI pins on its datasheet!

Another sample code can be found here.

// Sample Arduino Duemilanove interface code for Sparkfun's
// LED Matrix - Serial Interface - Red/Green/Blue
// http://www.sparkfun.com/commerce/product_info.php?products_id=760
//
// Written by:
// Fabio Pugliese Ornellas
// fabio.ornellas@gmail.com

// Pin definitions for Duemilanove.
// If you have a different board, check its datasheet SPI
// documentation for the corret pins.
#define PIN_SCK  13
#define PIN_MISO 12
#define	PIN_MOSI 11
#define PIN_SS   10

// Send a single byte via SPI, taken from Atmel's datasheet example.
void sendChar(char cData){
  SPDR = cData;
  while(!(SPSR&(1<<SPIF)));
}

// Send a full frame to the LED matrix
void sendFrame(char *frame) {
  // Assert SS
  digitalWrite(PIN_SS, LOW);
  // delay as the LED Matrix datasheet's recommends
  delayMicroseconds(500);
  // send the full buffer
  for(int i=0;i<64;i++) {
    char c;
    c=*(frame+i);
    // This is needed because sending a '%' will reconfigure the
    // board for daisy chain operation
    if('%'==c)
      sendChar((2<<5)&(1<<2)&1); // similar color
    else
      sendChar(c);
  }
  // de-assert SS
  digitalWrite(PIN_SS, HIGH);
  // The LED Matrix datasheet's recommends this delay on daisy
  // chain configurations
  //delayMicroseconds(10);
}

void setup(){
  // SPI communication setup. Please refer to Atmel's datasheets
  // to understand all this. Basically it sets up the Arduino as
  // master and configure the appropriate clock speed.

  // Configuration register
  SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);
  // Status register
  SPSR = SPSR & B11111110;

  // setup pins
  pinMode(PIN_SCK, OUTPUT);
  digitalWrite(PIN_SCK, LOW); // ensure clock low
  pinMode(PIN_MOSI, OUTPUT);
  pinMode(PIN_SS, OUTPUT);
  digitalWrite(PIN_SS, HIGH); // de-assert SS
  delayMicroseconds(500); // delay as the LED Matrix datasheet's recommends

  // This section reconfigure the board to no daisy chain
  // operation.
  // This can be confirmed by an RRGGBB pattern beginning at a
  // corner, with no black LEDs before the first LED, when the
  // matrix is powered on.
  // Warning: this will take effect only after first run, power
  // off and power on!
  digitalWrite(PIN_SS, LOW);
  delayMicroseconds(500);
  sendChar('%');
  sendChar(1);
  digitalWrite(PIN_SS, HIGH);
  delayMicroseconds(10);
}

void loop(){
  char frameBuffer[64];

  // Cycle through each possible color
  for(int color=0;color<=255;color++) {
    // And populate each position of the buffer with one color
    for(int j=0;j<64;j++) {
      frameBuffer[j]=j+color;
    }
    // Send the frame to the LED Matrix
    sendFrame(frameBuffer);
    // Colors are made by blinking the LEDs very fast.
    // Decreasing this delay too much (or removing it) may lead
    // to corrupted images.
    delay(200);
  }
}

Share