Category : Intermediate

IR LEDs for a Pi NoIR Camera

For a while now I’ve been meaning to put together a board with a few IR LEDs for a Pi NoIR Camera…

The Pi NoIR camera is an add on for the Raspberry Pi that uses the CSI-2 camera interface on the Pi. It’s just like a normal camera except it has no IR filter (hence NoIR).
This means it can capture in the IR range as well as the visible light range of the spectrum. This is good for dark or nighttime shots where you can ‘light up’ the scene with IR light (that is not visible to the human eye) instead of ‘normal’ visible (white) light.

The Pi NoIR Camera itself does not come with any IR light source. So for nighttime photography is pretty useless on it’s own.

The IR LEDs for a Pi NoIR Camera circuit is pretty simple to build. A few IR LEDs (I got some from Amazon that draw about 20mA and drop somewhere between 1.2 to 1.4 volts) and some resistors. Each LED needs it’s own current limiting resistor (this question gives a good explanation of why). You could just run the LEDs and resistors from a +5v and ground connection directly. However I wanted the LEDs to be switchable by a GPIO pin. As I planned to use 4 LEDs I’d need to be switching ~80mA so I’d need a transistor. The transistor would be driven from a GPIO pin so I’d need a resistor there too.

The circuit I put together look like this:

IR LEDs for a Pi NoIR Camera - Circuit

Calculating the resistor values was pretty easy.

IR LED current limiting resistors

We know the LEDs draw up to 20mA (0.02 A) and drop between 1.2 and 1.4 volts. We want to drive them close to 20mA to get maximum brightness from them.

5v – 1.3v (average) = 3.7v / 0.02 A = 185 Ohms. So I selected 220 Ohms to be on the safe side.

Transistor base resistor

We want the current on the base to be limited to a reasonable value so that we’re not pulling too much from the GPIO pin.
With an HFE of around 100, a 2N2222 only needs about 1mA to drive 100mA through the load. I may add more LEDs in the future, so I opted for something that would give me ~4mA at the base.

3.3v – 0.6v = 2.7v / 0.004 A = 675 Ohms. So I opted for 560 Ohms which will give around 4.8mA.

I soldered this all up on some veroboard with 3 header pins to connect up the +5v, Gnd and GPIO pin:

IR LEDs for a Pi NoIR Camera - Veroboard

Next, I connected it up to my Raspberry Pi (GPIO pin 23) and set that GPIO to an output and high. Switched off the lights. Took a raspistill image on my other Pi (with the NoIR camera connected) and you can see it works :

IR LEDs for a Pi NoIR Camera - Result

So, the little IR LEDs for a Pi NoIR Camera project was completed in an hour or so. Next up will be something a bit more complex (for me) – trying some outdoor, nighttime photography…

How To Make A Raspberry Pi Shutdown Button

After one too many times of forgetting to shutdown my (headless) Raspberry Pi before shutting down my PC/laptop (and resorting to just pulling the power plug), I decided I needed a button to shut it down gracefully – a ‘Raspberry Pi Shutdown Button’…

There’s lots of solutions around for this, but I decided to re-invent the wheel (as usual)…

Making a Raspberry Pi Shutdown Button

This is a fairly simple project, with a little bit of easy soldering required. I had all the bits I needed laying around in various component boxes. It’s not a lot and is likely to cost less than £1 for one. However, typically, you can’t buy these items in ones, they come in quantities of twenty or fifty. Even so the total cost should be much less than £10 and you’ll have a bunch of useful parts left over.
Here’s the list of what you’ll need (with links to buy the components if you don’t have them):

Raspberry Pi Shutdown Button - Parts

Step 1 – The Button.

First we work out which legs of the button are shorted when the button is pushed. Using the multi-meter determine which two pins get shorted together when the button is pushed. There will be two sets of 2 pins that get shorted (as the button has four legs). We only need one set, so the other two legs we simply break off (bending them back and forward multiple times works well).

Step 2 – The Jumper Wire.

The jumper wire gets folded in half and cut in two at the middle point, so that we have two bits of similar lengths, each with the female connector on one end. The other end we strip two or three millimeters of insulation from. As an aside, I like to use yellow or white for these kind of things as Red, Green, Black all make me think ‘power supply lines’.

Step 3 – The Heat Shrink Tubing.

For the thinner piece (2mm diameter) of tubing, we cut it in half (so each piece is around 20mm long). For the thicker piece (6mm diameter), we cut it into two lengths, one is 1/3 and the other is 2/3 (so for a 40mm long piece, one of the cut pieces would be about 13mm long and the other 27mm long). Lengths do not have to be accurate – these figures are just a guide (we can be a bit ‘rustic’).

Now we should have something like the image below.

Raspberry Pi Shutdown Button - Cutting

Step 4 – Placing the Heat Shrink Tubing.

I usually find myself staring at some left heat shrink after I’ve finished soldering. Then realize that I forgot to put it on, and have to redo it all. So, make sure you put the heat shrink on first. You want to (in order):

  • Hold both wire lengths together and slip the thicker tubing over both (from the end with no connectors).
  • Now slip each thin bit of tubing over a different one of the wires.
  • All you should have left is the shorter, thicker bit of heat shrink tubing.

Raspberry Pi Shutdown Button - Wire Prep

Step 5 – Soldering Time.

The soldering involved is really easy. Essentially you want one wire connected to each leg of the button. It doesn’t matter which way around it is.

  • ‘Tin’ the ends of both wires.
  • ‘Tin’ both the button legs.
  • Solder a wire to each leg.

Step 6 – Shrinking.

All that is left on the hardware side is to shrink the tubing. You need to push the two thinner pieces (one on each wire) as far as possible towards the button legs. Try to ensure that there is no bare wire or bare leg visible. Now shrink both of those so that they hold tight. Next push the thicker tubing over the two bits you just shrunk. It doesn’t have to go all the way. It is more just to hold the wires together. Now shrink that too.

Now the final shorter, thicker bit of tubing I push over the two connectors (it should be a fairly tight fit). This just makes it easier to insert the connector as one unit rather than as two separate wires.

Raspberry Pi Shutdown Button - Wiring Done

Great the hardware is now done. You can place the connector onto P1 connector pins 20 (Ground) and 22 (GPIO 25) and we can write the software that monitors the button and does the shutdown.

Raspberry Pi Shutdown Button - Plugged In 1Raspberry Pi Shutdown Button - Plugged In 2

Step 7 – The Software.

So, our button is connected between GPIO 25 and ground. We’ll want our software to:

  • Set up GPIO 25 as an input.
  • Set up GPIO 25 as pulled high by default
  • Wait for GPIO 25 to go low (button pressed)
  • Make sure GPIO 25 stays low for a set time (to avoid shutdowns on accidental presses)

I’m going to do this in a simple bash script. I’m also going to make sure the script runs when the Raspberry Pi boots.

To set and monitor the GPIO pins we’re going to use the ‘gpio’ utility that ships with Raspbian Jesse.
We’re going to check every second to see if the pin is low. If it is we’re going to check again in another 5 seconds that it is still low. If that is the case then we are going to shutdown (and halt).
We’ll keep it user friendly by issuing a terminal message to all users when the shutdown happens.

Here is the code for the script (shutdown.sh)

#!/bin/bash

# Raspberry Pi Shutdown Button Script

# Wait for a minute – to let everything settle.
sleep(60)

# Set up GPIO pin 25 as input and pull-up
gpio -g mode 25 in
gpio -g mode 25 up
sleep(5)

# wait for pin to go low
while [ true ]
do
if [ “$(gpio -g read 25)” == ‘0’ ]
then
echo “Hold button to shutdown Pi…”
sleep 5
if [ “$(gpio -g read 25)” == “0” ]
then
echo “Raspberry Pi Shutting Down!”
sudo halt &
exit 0
fi
fi
sleep 1
done

When you have written the script make sure you make it executable:

chmod +x shutdown.sh

To ensure it runs on every boot you need to edit your /etc/rc.local file, so in terminal type:

sudo nano /etc/rc.local

and add the following to the end of the file, but before the final ‘exit 0’ line:

# Raspberry Pi Shutdown Button Monitor Script
printf “Starting Raspberry Pi Shutdown Button Monitor Script”
sudo /home/pi/shutdown.sh &

That’s us done. You now have a button that you can hold for ~5 seconds and it will cleanly shutdown your Raspberry Pi.

If you want to make things a little neater you can use some hot glue to secure your button to the case you are using. I glued mine to the end of the case, above the micro USB power connector. All it needed was a small dab for the base of the button and a small dab for the wires to hold it straight. There is less chance of it being mistakenly pressed when glued there, and it’s out the way. It looks pretty clean there too.

Raspberry Pi Shutdown Button - Finished

Raspberry Pi Outdoor Music Player Project

This project, a Raspberry Pi Outdoor Music Player had been germinating in my mind for a while. We’d had a few BBQs and found that running an extension outside to plug the iPod and speaker system into was a bit of a pain.

Requirements

I had seen a whole bunch of MP3 players housed in old / up-cycled ammo boxes, and I wanted something similar. The thing I wasn’t too keen on was most of them only had play/pause and fwd/back buttons. I wanted something that I could play music on, have playlists and stream internet radio on. So the requirements list was shaping up a bit like this:

  • 6 to 8 hours battery life (and batteries that could be easily swapped / recharged).
  • Internet access (for streaming radio stations).
  • Web front end (for control, generating playlists etc.)
  • Reasonable volume (enough to be heard at a family BBQ, and but not enough to annoy the neighbours).
  • Rugged enclosure, that can handle itself outside.

The Parts

IMG_20160704_194517

Enclosure

Whilst an ammo box is rugged and cool, I wasn’t too sure how a Wi-Fi adapter would fare trying to get a decent signal from inside a metal box. So, something else was needed, something rugged and non metal. Looking around the garage I spied some old plastic boxes that housed power tools. One of those would be ideal. I chose a Bosch Cordless Drill/Driver box that was empty anyway. If I hacked it about, it wouldn’t be a big loss if anything went wrong and I had to bin it.

Brain

This was a ‘no brainer’ (pun intended) – I would use a Raspberry Pi. I had a spare Model B+ (with 2 USB ports), so I could attach a Wi-Fi USB dongle and a USB memory stick to hold a local music library. That also allows me to change / improve the software as needed, and it can play from the local library, stream from the garage server, or Google Play Music, and the GPIO pins would allow me to drive a LCD display to show track information etc. if I chose to do that in the future. The Raspberry Pi also has an audio out jack, so driving the amp / speakers wouldn’t be an issue.

For software I decided to go with MPD (Music Player Daemon). This is fairly ubiquitous in Raspberry Pi Music Systems, and rightly so. It gets the job done well, has a ton of clients across all platforms and is easy to get installed working. For the front end I found ympd which is a great application, single file, self contained that you run and it acts as a web server (so no apache, nginx, lighttp needed) listening on a port of your choice. The UI has a nice clean functional look too.The only issue is that it doesn’t (yet) do playlist management/creation (I’ll be looking into adding that later).

Amplifier

The audio output from the Raspberry Pi itself is fine for headphones, but is not really good enough to drive a set of speakers directly. So, I wanted to feed a stereo audio amplifier from the Pi and have the amplifier drive the speakers. Initially I went with a 12 volt 15watt amplifier module, but after a few problems with this (see below), I swapped to one of these 5 volt stereo 3W=3W watt amplifier modules.

Speakers

For the speakers I needed something that fitted into the space available in the plastic case, and that would fit into a flat area on the outer part of the case. I found some 4 inch 4 Ohm speakers from Maplin, for the princely sum of £2.99 each. They were a perfect fit for the space I had available in the box. If you can’t get them from Maplin they you can try these from Amazon.

Battery

I originally planned to use some spare LiPo batteries that I had laying around. I had 2200mAh 3S batteries available that would provide around 11-13 volts. After having audio noise problems (see build below) trying to use a DC-DC (buck) converter to get this down to 5 volts for the Raspberry Pi, I abandoned this and reverted to an Anker 20,600mAh portable battery pack that I had anyway. I normally carry this portable charger around with me, and when needed in the Raspberry Pi Outdoor Music Player I just plug it in and we’re ready to go. I may have to buy one to keep in the box rather than swapping it around every time.

The Raspberry Pi Outdoor Music Player Build

I put this project together in 3 stages, each of around 1 hour.

Stage 1 – Case Mods

The first part of this was to cut out cardboard templates for the speakers – this allowed me to place them on the case and see where the best fit was. When I was happy with the position I then marked it and cut the holes. For the cutting I started each with a holes drilled all the way around, then did the rest with a Stanley knife / box cutter.

IMG_20160704_194603IMG_20160704_194627IMG_20160704_195944IMG_20160704_201928IMG_20160704_201945

Next was the internal case mods. This will vary depending on the case you use. For me the plastic risers and dividers inside were thin enough to cut with the Stanley knife, so it was a quick job. Just find suitable spaces for the Raspberry Pi, the amp, the battery and cut those to the size required. You’ll also want to cut out some routing for the power and audio cables. I routed these around the outside of the box, but whatever suits you best.
Note: Initially I mounted the 15W amp on it’s side, screwed into one of the dividers (see image below), but the 3W+3W (smaller) amp had an adjustable pot on it and was designed to be mount through the chassis.

raspberry pi outdoor music player

15W 12v Amp mounted

raspberry pi outdoor music player

6W 5v Amp mounted

 

The final product looked like this:

IMG_20160724_102922

Stage 2 – Connecting Everything

This stage required a little soldering. Basically I took a 3.5mm audio cable I had laying around and cut off one end. I then found the right connections for Ground, Left Audio and Right Audio and soldered those to a 3 pin header socket I had. This was then connected to the 3 pin header on the amp board. The output of the amp board is a + and – audio signal for each channel. I used 2 pin cables to plug into the headers on the board, cut off the other ends and soldered the cables directly to the speaker + and – tabs.

For Raspberry Pi power I ran a USB to micro USB cable from the battery to the Raspberry Pi (just as you normally would). For the power to the amp board, I first considered hacking about another USB to micro USB cable. Then I remembered I had some little micro USB socket boards that I’d bought in bulk some time ago. I plugged in the second USB to micro USB cable to that board and soldered the +5V and Ground connections from that board to the amp board.

IMG_20160913_131031

Everything was now connected  – time to start on the software side.

Stage 3 – The Software

This is still a (kind of) work in progress stage. To get the first version working I installed mpd and the command line client (mpc) on the Raspberry Pi:

sudo apt-get install mpd mpc

Next I used the command line client to add a stream (Heart Radio) and told it to play:

mpc add http://media-ice.musicradio.com/HeartBerkshireMP3
mpc play

Not much happened at first, but I turned up the volume on the amp board (using the on board potentiometer) and then it worked well, so I knew I had things connected and working correctly.

So far so good, but I didn’t want to be SSHing into the Raspberry Pi to add or change songs. I also wanted to get a local cache of all my music on there. A 64GB USB stick would easily hold my music collection with room to grow. So, I copied all music from my home server to the USB stick and inserted it into a USB socket. You could also simply copy all your music onto the Raspberry Pi SD card itself (assuming you have enough spare storage). The default location that MPD looks for music files is /var/lib/mpd/music so best to copy your files there.
If you go the USB route then you have to tell mpd where the base folder is for your music. This is done in the config file, so a few more commands at the terminal:

sudo nano /etc/mpd.conf

Now find the line with the setting music_directory and edit the path to your USB drive. On my machine that was /mnt/usb/music. You may have to restart the mpd daemon after this, to do so:

sudo service mpd restart

That sorts out the playing of music, now we just need a simple way for a user to interact with it. For that I wanted a web interface, so that anyone (of my family or guests) could connect and chose songs to add to the queue. Initially I thought that would mean a full blown web server, database, PHP stack, however a google around found me ympd. This a self contained app that uses web sockets to serve up web pages dynamically. The author has done a really neat job of using bootstrap and JavaScript to provide a clean and functional user interface.

ympd_ss

There are simple instructions on the website to get this installed and running. Essentially, download it, extract it and run it.
I wanted it to be run automatically so I moved the app :

mv ympd /usr/bin

… and the made it automatically start with :

sudo crontab –e

… then added

@reboot /usr/bin/ympd –webport 90

to a new line at the end of the file and saved/exited.

With all that set up you should be able to use a browser to navigate to your Raspberry Pi. I gave mine a hostname of musicpi, so I simply browse to http://musicpi.local. From the web interface you can control everything you need to. Of course, there are a ton of other clients available for mpd if you would rather control it directly from your mobile etc.

Aside – Audio Problems

It is probably worth noting that initially (with the 15W audio amp) I had a lot of noise and distortion. The amp I had chosen needed a 12v source, so I had used a 12v power supply and fed the amp as well as a DC-DC (buck) convertor to step the voltage down to 5V for the Raspberry Pi. I believe the buck converter is very noisy (switching) and this was causing the problem. As soon as I switched to the 5v amp the noise vanished. Bonus for only having a single supply voltage too.

Conclusion

IMG_20160721_230216

Overall, I’m really happy with the Raspberry Pi Outdoor Music Player Project result. A few spare (laying around) parts, combined with a cheap amp and speakers and a few hours of integrating it all together and I have a pretty cool music box. There are a few enhancements in the works for this too:

  • Change the case for an old 80s style ‘ghetto blaster’ radio cassette player.
  • [Possibly] Better working with playlists (creation, editing)
  • Some controls on the case for skipping forward/back or loading a specific playlist.
  • LCD display showing the current playlist/song/time remaining etc.

 

If you build one, or found this useful please comment below and leave a link for me to check out your project.

128×64 OLED Display interfacing with a Raspberry Pi

I had a little SSD1306 128 x 64 bit OLED display laying around from a previous Arduino project, so I thought it was time to do a bit of OLED display interfacing with a Raspberry Pi.

Display

The device I had was an I2C version of the 0.96” 128x 64 bit SSD1306 OLED module. Monochrome only. These devices are available on Amazon for £3-£4 and make for a really interesting project.  It’s only 4 wires to connect; 2 for I2C communications, and 2 for power (it can be powered from the +3.3v line on the Pi GPIO).

oled display interfacing with a raspberry pi
So, little jumper wires between 3.3v, Gnd, SDA and SCL on the GPIO header, and the device (all clearly labelled) and we are ready to start.

There are some libraries and tools available for this device from Adafruit. It is sometimes useful to begin with those, if nothing else than to make sure the device works, and you have it wired up right. However, we want to do this ourselves, so the first thing we’ll need is a copy of the data sheet to understand how the device works. Googling it, I found copies for download here, and here.

The bits we are interested in are section 8.7 Graphic Display Data RAM, and sections 9 and 10 (Command Table and Command Descriptions). It’s tough reading, but you can get there eventually.
Essentially, we want to put it into Horizontal display mode so that we are writing one byte per column (128 columns per line), then moving down to the next line and writing the next set of bytes for this line of 128 columns. I’ve tried to explain this on a post-it…

oled display interfacing with a raspberry pi

OLED display interfacing with a Raspberry Pi – Software

Now that we have the device wired up and the datasheet downloaded it is time to write some code for OLED display interfacing with a Raspberry Pi.

I’ve tried to pull out all the ‘initialization’ commands and just lump them into an array – you can look them up in the data sheet if you want to understand this in a little more detail.
Here’s the sequence for init:

unsigned char initSequence[26] = {0x00,0xAE,0xA8,0x3F,0xD3,0x00,0x40,0xA1,0xC8,0xDA,0x12,0x81,0x7F,0xA4,0xA6,0xD5,0x80,0x8D,0x14,0xD9,0x22,0xD8,0x30,0x20,0x00,0xAF};

We also have to tell the display where we want to start the data being displayed from, in our case that is the top left. The command sequence for that is as follows:

unsigned char setFullRange[7] = {0x00,0x21,0x00,0x7F,0x22,0x00,0x07};

To get these commands sequences written to the device we need to send it over the I2C bus. Make sure your I2C is enabled (run sudo raspi-config). Here is the code we will use to send data over the I2C bus:

    void writeI2C(unsigned char* data, int bytes) {
char *deviceName = (char*)”/dev/i2c-1″;
if ((i2cHandle = open(deviceName, O_RDWR)) < 0)
{
printf(“error opening I2C\n”);
}
else
{
if (ioctl(i2cHandle, I2C_SLAVE, i2cAddress) < 0)
{
printf(“Error at ioctl\n”);
}
else
{
write(i2cHandle, data, bytes);
}

// Close the i2c device bus
char *deviceName = (char*)”dev/i2c-1″;
close(*deviceName);
}

}

This simply opens the /dev/i2c-1 device, then gets a handle to our display device and writes data to it (and closes it afterwards).

When we have initialized the device we can then begin sending it data we want it to display. As you’ve seen above we just need to choose data bytes to send it that illuminate the pixels we want. For example sending 0xFF to every column (and page) will illuminate every pixel on the device. Sending 0x11 will produce 2 thin lines on each of the 8 pages (lines of characters).

That is great, but we want to send text characters to the device, how do we do that. Well the first thing we’ll need to do is to map out the characters and determine what bytes we will need to display them. Let’s start with ‘A’. You can see below that I have mapped this out over 4 bytes:

oled display interfacing with a raspberry pi

I’ve shaded in the pixels I want to illuminate to make the A character. The ‘Most Significant Bit’ (MSB) is on the bottom and the ‘Least Significant Bit’ (LSB) is at the top. You can see that I have also left the top line of pixels and the bottom line of pixels blank – this is to create a separation between each line of characters. The bytes we will need are 0x7E, 0x12, 0x12, 0x7E. We will also need to add a 0x40 byte before these to inform the display that we are sending some data to be displayed.

OLED display interfacing with a Raspberry Pi – Mini Sample App

So, if we initialize the display then send a sequence of these 5 bytes to it we’ll have the letter A displayed at the top left of the screen. Here’s the full code for an app that will display an A in the top left of the screen:

// Ken Hughes
// July 2016
#include <unistd.h>//Needed for I2C port
#include <fcntl.h>//Needed for I2C port
#include <sys/ioctl.h>//Needed for I2C port
#include <linux/i2c-dev.h>//Needed for I2C port
#include <stdio.h>
#include <string.h>

 

void writeI2C(unsigned char* data, int bytes) {
int i2cAddress = 0x3C;
int i2cHandle;

char *deviceName = (char*)”/dev/i2c-1″;
if ((i2cHandle = open(deviceName, O_RDWR)) < 0) {
printf(“error opening I2C\n”);
}
else {
if (ioctl(i2cHandle, I2C_SLAVE, i2cAddress) < 0) {
printf(“Error at ioctl\n”);
}
else {
write(i2cHandle, data, bytes);
}

// Close the i2c device bus
close(*deviceName);
}
}
int main() {

// initialise the display
unsigned char initSequence[26] = {0x00,0xAE,0xA8,0x3F,0xD3,0x00,0x40,0xA1,0xC8,0xDA,0x12,0x81,0x7F,
0xA4,0xA6,0xD5,0x80,0x8D,0x14,0xD9,0x22,0xD8,0x30,0x20,0x00,0xAF};
writeI2C(initSequence, 26);

// set the range we want to use (whole display)
unsigned char setFullRange[7] = {0x00,0x21,0x00,0x7F,0x22,0x00,0x07};
writeI2C(setFullRange,7);

// send the letter A to the display
unsigned char letterA[5] = {0x40,0x7E,0x12,0x12,0x7E};
writeI2C(letterA,5);

}

You can compile this code with the following command

gcc –o display-a display-a.cpp

oled display interfacing with a raspberry pi

OLED display interfacing with a Raspberry Pi – Full Character Set

Instead of adding the bytes for each letter multiple times we are going to create ourselves a ‘look up table’ – we want a letter H?, the code looks up H in a table and there it finds the bytes we need. This is a bit of a labourious process of working out the byte sequence for every letter (and number and punctuation character) and putting all of them into an ‘array of arrays’. It is slightly complicated further because we might have a different number of bytes for different letters. For example the ‘@’ sign needs 5 bytes whereas the letter I only needs 3. Not a problem, for each letter the first byte of the sequence will tell us how many bytes for the letter. For the case of our letter, it would look like this:

    {4, 0x7E, 0x12, 0x12, 0x7e}, //A

The first byte is 4, telling us there are 4 bytes in the sequence to display the letter ‘A’. Here is the sequence for the ‘@’ sign, which requires 5 bytes.

    {5, 0x7E, 0x42, 0x5A, 0x52, 0x5E}, // @

Fast forward through the section where I work out all the byte sequences and populated our ‘array of arrays’.

oled display interfacing with a raspberry pi

Now, we make sure our ‘array of arrays’ is laid out in the same sequence as the standard ASCII table. This allows us to implement a neat trick where if we subtract the ASCII value for ‘<SPACE>’ we get the correct offset into our array of arrays. So if the start of our data looks like this…

int fontData[][6] = {
{2,0×00,0x00}, // SPACE
{1,0x5E}, // !
{3,0×02,0x00,0x02}, // ”
{5,0×24,0x7E,0x24,0x7E,0x24}, // #
{5,0×44,0x4A,0x7E,0x52,0x22}, // $
{5,0×22,0x10,0x08,0x04,0x42}, // %
{5,0×34,0x4A,0x54,0x20,0x40}, // &

… and we want to display a ‘#’ character (ASCII value 35) then we subtract the ASCII value of ‘<SPACE>’ (which is 32) and get 3. Allowing us to look up the byte array at fontData[3] – which is {5, 0x24,0x7E,0x24,0x7E,0x24}
The first number (5) is the number of bytes we need to display this character, and the following 5 bytes are the actual values we send to the device to display this pattern.

OLED display interfacing with a Raspberry Pi – Bringing it all together

Now that we know how to get the correct bytes sequences we just need to pull everything together. This is a case of combining the initialization, the interpreting the desired characters into bytes sequences and the writing of the bytes to the display.

I found the easiest way to do this was to create a 128 byte array for each line…

unsigned char displayLines[8][128];

… and to set all bytes to zero to begin with …

for(int i=0; i<8; i++) {
for(int j=0; j<128; j++) {
displayLines[i][j] = 0;
}
}

Now, whenever we get text to display we begin filling up the 128 bytes of the current line …

c = toupper(c); // we only support UPPERCASE letters
int letterIdx = (c – ‘ ‘);
if(letterIdx > 64)
{
letterIdx = 65;
}

int letterBytes = fontData[letterIdx][0];
for(int i=0; i<letterBytes; i++)
{
displayLines[currentLine][curr + i] = fontData[letterIdx][1 + i];
}

displayLines[currentLine][curr + letterBytes++] = 0x00;  // single byte space between letters

We also need to make sure that the remainder of the line is filled with zeros just in case we are overwriting a line that previously had text on it.

// now fill up any left over with 0x00s on the current line
while(currByteCount < 128)
{
displayLines[currentLine][currByteCount++] = 0x00;
}

Now that we have the displayLines arrays populated with the bytes we need it is a simple case of sending them to the device over I2C. We have to create a byte sequence that is a 0x40 (‘data stream coming’ command) followed by all the bytes for the line. We do this for each line…

unsigned char buffer[129] = {0};
buffer[0] = 0x40;
for(int i=0; i<128; i++) {
buffer[1 + i] = displayLines[line][i];
}
writeI2C(buffer, 129);

… and now we have working code that we can use to call a function with some text as the parameter and have that text displayed on the OLED screen.

oled display interfacing with a raspberry pioled display interfacing with a raspberry pi

Source Code

The full source for this OLED display interfacing with a Raspberry Pi project can be found on github at : https://github.com/kjhughes097/pi-ssd1306-oled
This separates out the functionality into a ‘SSD1306’ class that you can use in other apps. It also separates the character mapping header (charmap.h) out so that it is easy to add additional characters (you could try adding lowercase letters ?).
The ‘sample’ app, display-a.cpp is self contained and shows the basic use of I2C to send data to the display. The other ‘sample’ app, oled.cpp shows how to use the class. The makefile will compile the oled app – at the command line simply type

make

Hope this has been useful. Please leave a comment below if you thought so.