I2C OLED (ssd1306)

Introduction

The ssd1306 is a very common I2C OLED display controller.

It is often found on small monochrome displays up to 128x64 pixels. These displays can easily be found for under five US dollars and are extremely simple to wire up.

The most typical interface is just four wires, basically just power and I2C:

  • VCC
  • GND
  • SCL
  • SDA

However some displays also feature additional pins for a 'reset' signal and possibly an SPI interface.

If the display features a 'reset' pin, it must be connected to a digital output on our microcontroller / ioNode.

To use these displays, we provide the ssd1306 driver library, which integrates with the Graphics Framework.

Wiring

As mentioned above, the wiring for these displays is generally extremely simple.

We just need to hook up the power (VCC / GND) and I2C (SDA / SCL). Again, if a 'reset' pin is present on the display, we need to also hook it up to a digital output.

Note: some displays actually have a solder jumper (usually on the backside) to select between I2C and SPI interface. Since the ssd1306 library only uses I2C, always make sure that this solder jumper is set correctly (if present).

Using the library

To use the display driver, we must first add it to our dependencies in dfe.conf:

# ...
deps:
  - ssd1306

Initialization

Next, we need to initialize the display so we can use it with the Graphics Framework.

The easy way to do this is to simply declare our display in our substrate.

With substrate

We can declare our display in our substrate as shown below:

# 64x32 OLED Display with reset pin connected to DIO 5 (I2C addr = 0x7a)
uses :ssd1306_gfx, name: 'dsp0', width: 64, height: 32, addr: 0x7a, rst_pin: 5

However, because many displays have very similar configurations, we can also just use a standard profile:

# Generic 128x32 OLED Display with no reset pin
uses :ssd1306_gfx, name: 'dsp0', profile: :gen128x32

The table below shows available profiles:

Profile I2C address Display format
:gen128x32 0x78 128x32
:gen128x64 0x7a 128x64

We can even mix a profile with custom options if needed. For example, some displays ALMOST match these generic settings, maybe requiring only a small adjustment like the reset pin:

# Generic 128x32 OLED Display with reset pin on DIO 3
uses :ssd1306_gfx, name: 'dsp0', profile: :gen128x32, rst_pin: 3

Or maybe a slightly different I2C address:

# Generic 128x32 OLED Display (I2C addr = 0x7a)
uses :ssd1306_gfx, name: 'dsp0', profile: :gen128x32, addr: 0x7a

This will create a struct gfx_dsp *dsp0; that we can use right away.

Manual initialization (without substrate)

For those who prefer to go without the substrate, we can still initialize the display manually:

 1 #include <ssd1306/ssd1306.h>
 2 #include <gfx/dsp.h>
 3 #include <gfx/gfx.h>
 4 
 5 // OLED Display Driver
 6 struct ssd1306 dsp0_drv;
 7 
 8 // GFX Interface
 9 struct gfx_dsp dsp0_data;
10 struct gfx_dsp *dsp0;
11 
12 void init()
13 {
14     // ...
15 
16     // Display Params
17     uint8_t rst_pin = 0xff;
18     uint8_t addr = 0x78;
19     uint8_t width = 128;
20     uint8_t height = 32;
21 
22     // Initialize ssd1306 driver
23     ssd1306_init(&dsp0_drv, rst_pin, addr, width, height);
24 
25     // Initialize GFX interface
26     dsp0 = &dsp0_data;
27     gfx_dsp_init(dsp0, &dsp0_drv);
28 
29     // ...
30 }

Drawing

Once the display is initialized and we have a struct gfx_dsp *dsp0;, we can start using the Graphics Framework to actually do stuff with the display.