In my previous blog post I published a TSL2561 light sensor driver in C for Raspberry PI. In this article I will publish a user space C driver for Adafruit 4-digit 7-segment display.
This is based on a HT16K33 led driver IC, that it’s a I2C driven RAM mapping 16*8 LED controller driver.
The driver I’m posting it’s valid for the adafruit circuit only, since it’s completely based on the electronic schematic they realized.
Don’t use the driver with other circuits, since the display could not function properly.
Basically the adafruit 7-segment backpack (http://www.adafruit.com/products/879) uses 8 (rows) * 5 (columns) HT16K33 lines to drive its leds. The column number 1 is dedicated to the first digit, the second column is dedicated to the second digit, the third column is attached to the colon sign in the middle of the 4 digits, the fourth column is attached to the third digit, and the fifth colum to the fourth display digit.
While each row drives a single led of the given column.
The display columns 0, 1, 3, 4 can show numbers and some letters (A-F, n, o, i, l, L, etc…) plus a decimal point, while the column 2 can only show a colon sign (:).
A number or a letter for each digit is composed by 7 led segments, so the possibilities are few… but not so few after all (check 7seg.txt file attachment for more details on letter composition).
So, now comes the fun. How can I access the led driver memory to light display digits in C? Adafruit releases proof of concept libraries in C and python, but they don’t seem to run on my raspberry pi.
Since I am too lazy to port their code with external dependencies, I decided to write my own library in C.
#include "7seg_bp_ada.h" /* prepare the backpack driver (the first parameter is the raspberry pi i2c master controller attached to the HT16K33, the second is the i2c selection jumper) The i2c selection address can be one of HT16K33_ADDR_01 to HT16K33_ADDR_08 */ HT16K33 led_backpack1 = HT16K33_INIT(1, HT16K33_ADDR_01); /* initialize the backpack */ rc = HT16K33_OPEN(&led_backpack1); /* power on the ht16k33 */ HT16K33_ON(&led_backpack1); /* make it shining bright */ HT16K33_BRIGHTNESS(&led_backpack1, 0x0F); /* make it not blinking */ HT16K33_BLINK(&led_backpack1, HT16K33_BLINK_OFF); /* power on the display */ HT16K33_DISPLAY(&led_backpack1, HT16K33_DISPLAY_ON); /* Say hello */ HT16K33_UPDATE_DIGIT(&led_backpack1, 0, 'H', 0); // first digit HT16K33_UPDATE_DIGIT(&led_backpack1, 1, 'E', 0); // second digit // turn off the colon sign in the middle of the 4 digits HT16K33_UPDATE_DIGIT(&led_backpack1, 2, HT16K33_COLON_OFF, 0); HT16K33_UPDATE_DIGIT(&led_backpack1, 3, '#', 0); // third digit HT16K33_UPDATE_DIGIT(&led_backpack1, 4, 'o', 0); // fourth digit HT16K33_COMMIT(&led_backpack1); // commit to the display memory // call this if you want to shut down the device (power saving mode) // HT16K33_OFF(&led_backpack1); /* close things (the display remains in the conditions left) */ HT16K33_CLOSE(&led_backpack1);
I decided to release the software with the liberal apache 2 license, so feel free to use this software inside your commercial, non free software / firmware.
Below you will find the files .c and .h that you can embed into your project.
It’s helpful for me, and I hope it will be helpful for you.
Note: on Raspberry PI OS (and debian) you need libi2c-dev (apt install libi2c-dev) before compiling.
gcc -Wall -O2 -o 7seg_bp_ada.o -c 7seg_bp_ada.c
gcc -Wall -O2 -o 7seg_bp_ada_test.o -c 7seg_bp_ada_test.c
gcc -Wall -O2 -o 7seg_bp_ada_test 7seg_bp_ada.o -li2c 7seg_bp_ada_test.o
Sadly, I am getting an error when compiling:
pi@raspberrypi:/media/Data/Code/rasp/ht16k33_7seg $ sudo gcc -Wall -O2 -o 7seg_bp_ada.o -c 7seg_bp_ada.c
7seg_bp_ada.c: In function ‘HT16K33_COMMIT’:
7seg_bp_ada.c:356:6: warning: implicit declaration of function ‘i2c_smbus_write_i2c_block_data’ [-Wimplicit-function-declaration]
356 | i = i2c_smbus_write_i2c_block_data(backpack->adapter_fd, 0x00, 16, buf);
pi@raspberrypi:/media/Data/Code/rasp/ht16k33_7seg $ sudo gcc -Wall -O2 -o 7seg_bp_ada_test.o -c 7seg_bp_ada_test.c
pi@raspberrypi:/media/Data/Code/rasp/ht16k33_7seg $ sudo gcc -Wall -O2 -o 7seg_bp_ada_test 7seg_bp_ada.o 7seg_bp_ada_test.o
/usr/bin/ld: 7seg_bp_ada.o: in function `HT16K33_COMMIT’:
7seg_bp_ada.c:(.text+0x430): undefined reference to `i2c_smbus_write_i2c_block_data’
collect2: error: ld returned 1 exit status
Please, install this package:
apt install libi2c-dev
Then try with this one:
# gcc -Wall -O2 -o 7seg_bp_ada.o -c 7seg_bp_ada.c
# gcc -Wall -O2 -o 7seg_bp_ada_test.o -c 7seg_bp_ada_test.c
# gcc -Wall -O2 -o 7seg_bp_ada_test 7seg_bp_ada.o -li2c 7seg_bp_ada_test.o
Hi Dino, I know this blog post is old but just wanted to drop a line and say thanks for posting this driver. Lightweight and easy to understand, it gets the job done!
WOW! Thank you very much for your feedback!
Sure thing! I extended it to work with the Adafruit alphanum displays, do key scanning, enable interrupts for keyscan, and that type of stuff. Pretty hacky but fun to play with!
In github if you ever need that functionality.
err, bad link. here:
That works, thanks!
Many thanks, I was looking for something like this!
Unforunately, when I try compiling, I get the following error (in my own programs and the test from this site):
7seg_bp_ada_test.c: In function ‘int main()’:
7seg_bp_ada_test.c:10:26: error: expected primary-expression before ‘.’ token
7seg_bp_ada_test.c:10:26: warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x [enabled by default]
Would you have an idea what could’ve gone wrong?
If I try with the following, I don’t have any error:
dino@dam2knb:/tmp$ gcc -Wall -O2 -o 7seg_bp_ada.o -c 7seg_bp_ada.c
dino@dam2knb:/tmp$ gcc -Wall -O2 -o 7seg_bp_ada_test.o -c 7seg_bp_ada_test.c
dino@dam2knb:/tmp$ gcc -Wall -O2 -o 7seg_bp_ada_test 7seg_bp_ada.o 7seg_bp_ada_test.o
May be you are having CPP problems like class instance declaration or the like. Not a proble in 7seg_bp_ada.c.