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/
In brief;
- Scan the i2c bus for your device.
- Download the code needed.
- Compile.
- 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.
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 ~ $ cd 8x8matrixscroll/
3. Compile the program
Compile the program with;
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.
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;
- Start the Oscillator.
- Turn the Display on.
- Set the brightness.
- 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 & 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 & i)
printf("#");
else
printf(".");
i >>= 1;
}
printf("\n");
}
int displayImage(__u16 bmp[], int res, int daddress, int file)
{
int i;
for(i=0; i<8; i++)
{
block[i] = (bmp[i]&0xfe) >>1 |
(bmp[i]&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("Closing file and turning off the LED Matrix\n");
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, "Usage: %s <i2c-bus> <i2c-address> <text to scroll>\n", 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, "/dev/i2c-%d", i2cbus);
file = open(filename, O_RDWR);
if (file<0) {
if (errno == ENOENT) {
fprintf(stderr, "Error: Could not open file "
"/dev/i2c-%d: %s\n", i2cbus, strerror(ENOENT));
}
else {
fprintf(stderr, "Error: Could not open file "
"`%s': %s\n", filename, strerror(errno));
if (errno == EACCES)
fprintf(stderr, "Run as root?\n");
}
exit(1);
}
if (ioctl(file, I2C_SLAVE, address) < 0) {
fprintf(stderr,
"Error: Could not set address to 0x%02x: %s\n",
address, strerror(errno));
return -errno;
}
res = i2c_smbus_write_byte(file, daddress);
if (res < 0) {
fprintf(stderr, "Warning - write failed, filename=%s, daddress=%d\n",
filename, daddress);
}
daddress = 0x21; // Start oscillator (page 10)
printf("writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0x81; // Display on, blinking off (page 11)
printf("writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0xef; // Full brightness (page 15)
printf("Full brightness writing: 0x%02x\n", daddress);
res = i2c_smbus_write_byte(file, daddress);
daddress = 0x00; // Start writing to address 0 (page 13)
printf("Start writing to address 0 writing: 0x%02x\n", 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]);
}
}
}
}
}
Pingback: Raspberry Pi and an 8×8 LED Matrix, using C. #piday #raspberrypi @Raspberry_Pi « adafruit industries blog
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
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’.
D’oh! I skimmed the code, looking for a ‘delay’ statement of some sort – I don’t know how I missed that. Thanks again!
/rob