Raspberry Pi and an 8×8 LED Matrix, using C.

Below is some information on how to get an 8×8 led matrix working on your Raspberry Pi using C.
I have also included the code needed to get text scrolling.

The matrix I am using is this one from Adafruit. This matrix uses a HT16K33 controller chip and communicates with the Pi via the i2c bus.


Adafruit has very good and detailed tutorials on how to solder it up and get i2c working between your Pi and the Matrix.

http://learn.adafruit.com/adafruit-led-backpack/

http://learn.adafruit.com/matrix-7-segment-led-backpack-with-the-raspberry-pi/configuring-your-pi-for-i2c


In brief;

  1. Scan the i2c bus for your device.
  2. Download the code needed.
  3. Compile.
  4. Run.



1. Scan i2c bus

Adafruit have some great instructions in the links above on how to do this.
When using i2cdetect to scan my bus, 0×70 was returned for the address of my matrix.
I am using a Rev B board and my bus is 1. If you get nothing back, check bus 0 with i2cdetect -y 0.

pi@raspberrypi ~ $sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: — – — – — – — – — – — – –
10: — – — – — – — – — – — – — – — –
20: — – — – — – — – — – — – — – — –
30: — – — – — – — – — – — – — – — –
40: — – — – — – — – — – — – — – — –
50: — – — – — – — – — – — – — – — –
60: — – — – — – — – — – — – — – — –
70: 70 — – — – — – –
pi@raspberrypi ~ $




2. Download the code
pi@raspberrypi ~ $ sudo git clone git://github.com/mwilliams03/8x8matrixscroll.git
pi@raspberrypi ~ $ cd 8x8matrixscroll/



3. Compile the program

Compile the program with;

pi@raspberrypi ~ $ sudo make matrix
cc matrix.c -o matrix
pi@raspberrypi ~ $




4. Run it!

When starting the program, you will need to specify the i2c bus, address of the matrix and the text to scroll.
The address needs to be in decimal format. If 0×70 (Hex) is returned when using i2cdetect, then this would be 112 in decimal.

pi@raspberrypi ~ $sudo ./matrix 1 112 “this is the text to scroll”




Some extra notes

Characters are displayed the wrong way
If you have characters being shown in reverse, just like a mirror image, then comment out this line.

numbers[i][y]=reverseBits(numbers[i][y]);




Stop text being displayed on the console
Comment out this line if you would like the text to not be displayed on the console.

printbitssimple(numbers[i][t]);// display  text on console




How the matrix is initialized
Some details on how the matrix is initialized;

  1. Start the Oscillator.
  2. Turn the Display on.
  3. Set the brightness.
  4. Set the address to write from.

Shown here;

daddress = 0x21; // Start oscillator
printf("writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0x81; // Display on, blinking off
printf("writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0xef; // Full brightness
printf("Full brightness writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0x00; // Start writing to address 0
printf("Start writing to address 0 writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);



The code that scrolls
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "i2c-dev.h"
#include <fcntl.h>
#include "8x8font.h"
#include <string.h>
__u16 block[I2C_SMBUS_BLOCK_MAX];
//global variables used for matrix
int res, i2cbus, daddress, address, size, file;
//Reverse the bits
unsigned  char  reverseBits(unsigned  char num)
{
unsigned  char count = sizeof(num) * 8 - 1;
unsigned  char reverse_num = num;
num >>= 1;
while(num)
{
reverse_num <<= 1;
reverse_num |= num &amp; 1;
num >>= 1;
count--;
}
reverse_num <<= count;
return reverse_num;
}
/* Print n as a binary number */
void printbitssimple(char n) {
unsigned char i;
i = 1<<(sizeof(n) * 8 - 1);
while (i > 0) {
if (n &amp; i)
printf(&quot;#&quot;);
else
printf(&quot;.&quot;);
i >>= 1;
}
printf(&quot;\n&quot;);
}
int displayImage(__u16 bmp[], int res, int daddress, int file)
{
int i;
for(i=0; i<8; i++)
{
block[i] = (bmp[i]&amp;0xfe) >>1 |
(bmp[i]&amp;0x01) << 7;
}
res = i2c_smbus_write_i2c_block_data(file, daddress, 16,
(__u8 *)block);
usleep(100000);
}
void  INThandler(int sig)
{
// Closing file and turning off Matrix
unsigned short int clear[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
displayImage(clear,res, daddress, file);
printf(&quot;Closing file and turning off the LED Matrix\n&quot;);
daddress = 0x20;
for(daddress = 0xef; daddress >= 0xe0; daddress--) {
res = i2c_smbus_write_byte(file, daddress);
}
signal(sig, SIG_IGN);
close(file);
exit(0);
}
int main(int argc, char *argv[])
{
//Exit if not enough parameters are added with the executable
if(argc != 4 ) {
fprintf(stderr, &quot;Usage:  %s <i2c-bus> <i2c-address> <text to scroll>\n&quot;, argv[0]);
exit(1);
}
char *end;
int count,cont;
char filename[20];
unsigned char letter;
int i,t,y;
i2cbus   = atoi(argv[1]);
address  = atoi(argv[2]);
daddress = 0;
char text[strlen(argv[3])+4];
signal(SIGINT, INThandler);
//Startup the matrix
size = I2C_SMBUS_BYTE;
sprintf(filename, &quot;/dev/i2c-%d&quot;, i2cbus);
file = open(filename, O_RDWR);
if (file<0) {
if (errno == ENOENT) {
fprintf(stderr, &quot;Error: Could not open file &quot;
&quot;/dev/i2c-%d: %s\n&quot;, i2cbus, strerror(ENOENT));
}
else {
fprintf(stderr, &quot;Error: Could not open file &quot;
&quot;`%s': %s\n&quot;, filename, strerror(errno));
if (errno == EACCES)
fprintf(stderr, &quot;Run as root?\n&quot;);
}
exit(1);
}
if (ioctl(file, I2C_SLAVE, address) < 0) {
fprintf(stderr,
&quot;Error: Could not set address to 0x%02x: %s\n&quot;,
address, strerror(errno));
return -errno;
}
res = i2c_smbus_write_byte(file, daddress);
if (res < 0) {
fprintf(stderr, &quot;Warning - write failed, filename=%s, daddress=%d\n&quot;,
filename, daddress);
}
daddress = 0x21; // Start oscillator (page 10)
printf(&quot;writing: 0x%02x\n&quot;, daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0x81; // Display on, blinking off (page 11)
printf(&quot;writing: 0x%02x\n&quot;, daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0xef; // Full brightness (page 15)
printf(&quot;Full brightness writing: 0x%02x\n&quot;, daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0x00; // Start writing to address 0 (page 13)
printf(&quot;Start writing to address 0 writing: 0x%02x\n&quot;, daddress);
res = i2c_smbus_write_byte(file, daddress);
//Setup the text  argument that was passed to main. remove null and add some extra spaces.
for(i = 0; i < (strlen(argv[3])) ; i++){
text[i] = argv[3][i];
}
for(i = 0; i < 4 ; i++){
text[strlen(argv[3])+i] = 32;
}
//put all the characters of the scrolling text in a contiguous block
int length = (strlen(text))-2;
int Vposition,c,character, l;
unsigned short int   displayBuffer[8][length*8];
unsigned short int   display[8];
for(i = 0; i < length ; i++){
character = (text[i]-31);
for(Vposition = 0; Vposition < 8 ; Vposition++){
displayBuffer[Vposition][i] = FONT8x8[character][Vposition];
}
}
//Text scrolling happens here
while (1){
unsigned short int   bitShifted[8];
for(letter=0; letter<(length-1); letter++){
for(y=0; y<8; y++){
for(i=0; i<8; i++){
bitShifted[i] = (displayBuffer[i][letter]) << y | (displayBuffer[i][letter+1]) >> (8-y);
bitShifted[i]  = reverseBits(bitShifted[i]);
}
displayImage(bitShifted,res, daddress, file);
for(i=0; i<8; i++){
printbitssimple( bitShifted[i]);
}
}
}
}
}




7 thoughts on “Raspberry Pi and an 8×8 LED Matrix, using C.”

  1. Thanks for the good work!

    I’m not super-proficient in C, but I had some problems with your code on my Pi, and in pursuing a solution, I noticed one interesting thing: the declaration at line 85

    int main(int argc, char *argv[3])

    is kind of non-standard, and I think a little bit wrong. I think you just want

    int main(int argc, char *argv[])

    Until I made this change, I had various odd, non-reproducible behaviors, but with that change, it’s very nice! I’d like to make it scroll faster, and if I find a mod that does so, I will surely post it here.

    Thanks again,
    Rob

  2. I’m no expert either. :-)
    And thank you, I have corrected the code.
    If you would like it to scroll faster, you can decrease the value of “usleep(100000″) in the function ‘displayimage’.

  3. Okay downloaded it and testet it, and now i want to use this instead of the adafruit python librarys because its too slow for me and you can see when the screen is being cleared.. so i’ve changed the code and tried porting it to an object-orientated program in c++ to use multiple matrices, but now i don’t know howto control the pixels on the matrix. can you help me? or do you have a program which control some pixels?

    1. This is what is used to display images to the screen. It writes a block of data (8 bytes) at a time to the matrix;
      displayImage(clear,res, daddress, file)
      .
      .
      in displayImage, this is what writes a block, (res is just used to work out if it failed);
      res = i2c_smbus_write_i2c_block_data(file, daddress, 16,(__u8 *)block);
      .
      .

      An example to clear the screen;
      unsigned short int clear[] = {0×00,0×00,0×00,0×00,0×00,0×00,0×00,0×00};
      displayImage(clear,res, daddress, file);
      .

      you could change the values in clear[] to test turning on one pixel. Eg 0×01
      .

      you could also use I2C_FUNC_SMBUS_WRITE_BYTE to write to one row only

Leave a Reply