Below is some information on how to get an 8x8 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;
- 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, 0x70 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 0x70 (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]); } } } } }
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
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?
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[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
displayImage(clear,res, daddress, file);
.
you could change the values in clear[] to test turning on one pixel. Eg 0x01
.
you could also use I2C_FUNC_SMBUS_WRITE_BYTE to write to one row only
Looks like your code had html character encodings in it. Hurts my eyes! 😉
Hi any one have c or python code for display character “H” on 8×8 dots matrix raspberry
hi there, I tried doing the sudo i2detect -y 1 and it returned this error:
Error: Could not open file `/dev/i2c-1′ or `/dev/i2c/1′: No such file or directory
Help?
Have you enabled i2c?
https://ozzmaker.com/i2c/
Hello, thanks for sharing this, good job! I can confirm that your code works on my setup, too.
One improvement to make: please, use sudo only where it is necessary. Sudo only makes matters worse in this case, forcing you to use it everywhere. Pi user (or other “non-root”) privileges are sufficient for such projects.
Cheers,
Mila
you are right… I have updated the post