Monochrome Oled Breakouts
Monochrome Oled Breakouts
Monochrome Oled Breakouts
This is a quick tutorial for our 128x64 and 128x32 pixel monochrome OLED displays. These displays are small, only
about 1" diagonal, but very readable due to the high contrast of an OLED display. Each OLED display is made of 128x64
or 128x32 individual white OLEDs, each one is turned on or off by the controller chip. Because the display makes its
own light, no backlight is required. This reduces the power required to run the OLED and is why the display has such
high contrast; we really like this miniature display for its crispness!
All OLEDs are safe to use with 3.3V logic and power.
Simply connect GND to ground, and Vin to a 3 to 5V power supply. There will be a 3.3V output on the 3Vo pin in case
you want a regulated 3.3V supply for something else.
For most users, we suggest connecting VDD and VBAT together to 3.3V and then leaving VCC unconnected.
In recent versions of the Arduino IDE software (1.6.2 and later), this is most easily done through the Arduino Library
Manager.
Run Demo!
After installing the Adafruit_SSD1306 and Adafruit_GFX library, restart the Arduino IDE. You should now be able to
access the sample code by navigating through menus in this order:
After you've finished wiring the display as indicated on the following pages, load the example sketch to demonstrate
the capabilities of the library and display.
The OLED SSD1306 driver is based on the Adafruit GFX library which provides all the underlying graphics functions
such as drawing pixels, lines, circles, etc. For more details about what you can do with the OLED check out the GFX
library tutorial (https://adafru.it/aPx)
Select the following options (You might also want to try Horizontal if Vertical is not coming out right)
You can use the output directly with our example code
Before you start wiring, a strip of header must be soldered onto the OLED. It is not possible to "press-fit" the header, it
must be attached!
I2C or SPI
The nice thing about the 128x64 OLEDs is that they can be used with I2C (+ a reset line) or SPI. SPI is generally faster
than I2C but uses more pins. It's also easier for some microcontrollers to use SPI. Anyways, you can use either one with
this display
This matches the example code we have written. Once you get this working, you can try a different Reset pin (you
can't change the SDA and SCL pins).
(Note: If using the display with other SPI devices, D/C, CLK and DAT may be shared, but CS must be unique for each
device.)
This matches the example code we have written. Once you get this working, you can try another set of pins.
Plug the header long end down into a breadboard and place the OLED on top. Solder the short pins into the OLED
PCB.
(Note: If using the display with other SPI devices, D/C, CLK and DAT may be shared, but CS must be unique for each
device.)
This matches the example code we have written. Once you get this working, you can try another set of pins.
If you're using the 128x32 OLED, be sure to uncomment the "#define SSD1306_128_32" in the top of
Adafruit_SSD1306.h to change the buffer size
This matches the example code we have written. Once you get this working, you can change the RST pin. You cannot
change the I2C pins, those are 'fixed' in hardware
This wiring diagram is only for the older 0.96" OLED that comes with a level shifter chip. If you did not get a
level shifter chip, you have a V2.0 so please check out the other wiring tutorial!
You can use this sensor with any CircuitPython microcontroller board.
We'll cover how to wire the OLED to your CircuitPython microcontroller board. First assemble your OLED.
First make sure you are running the latest version 5.0 or later of Adafruit CircuitPython (https://adafru.it/Amd) for your
board.
Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these
libraries from Adafruit's CircuitPython library bundle (https://adafru.it/uap). Our CircuitPython starter guide has a great
page on how to install the library bundle (https://adafru.it/ABU).
If you choose, you can manually install the libraries individually on your board:
adafruit_displayio_ssd1306
adafruit_bus_device
Before continuing make sure your board's lib folder or root filesystem has the adafruit_displayio_ssd1306.mpy
and adafruit_bus_device files and folders copied over.
Next connect to the board's serial REPL (https://adafru.it/Awz) so you are at the CircuitPython >>> prompt.
https://adafru.it/FRB
https://adafru.it/FRB
Go ahead and install this in the same manner as the driver library by copying the adafruit_display_text folder over to
the lib folder on your CircuitPython device.
Displayio is only available on express board due to the smaller memory size on non-express boards.
It's easy to use OLEDs with Python and the Adafruit CircuitPython DisplayIO SSD1306 (https://adafru.it/FRA) module.
This module allows you to easily write Python code to control the display.
To demonstrate the usage, we'll initialize the library and use Python code to control the OLED from the board's Python
REPL.
I2C Initialization
If your display is connected to the board using I2C (like if using a Feather and the FeatherWing OLED) you'll first need
to initialize the I2C bus. First import the necessary modules:
import board
Now for either board run this command to create the I2C instance using the default SCL and SDA pins (which will be
marked on the boards pins if using a Feather or similar Adafruit board):
i2c = board.I2C()
After initializing the I2C interface for your firmware as described above, you can create an instance of the I2CDisplay
bus:
import displayio
import adafruit_displayio_ssd1306
display_bus = displayio.I2CDisplay(i2c, device_address=0x3c)
Finally, you can pass the display_bus in and create an instance of the SSD1306 I2C driver by running:
Now you should be seeing an image of the REPL. Note that the last two parameters to the SSD1306 class initializer
are the width and height of the display in pixels. Be sure to use the right values for the display you're using!
At this point the I2C bus and display are initialized. Skip down to the example code section.
SPI Initialization
If your display is connected to the board using SPI you'll first need to initialize the SPI bus.
import board
import displayio
import adafruit_displayio_ssd1306
displayio.release_displays()
spi = board.SPI()
tft_cs = board.D5
tft_dc = board.D6
tft_reset = board.D9
The parameters to the FourWire initializer are the pins connected to the display's DC, CS, and reset. Because we are
using keyword arguments, they can be in any position. Again make sure to use the right pin names as you have wired
up to your board!
Note that the last two parameters to the SSD1306 class initializer are the width and height of the display in pixels. Be
sure to use the right values for the display you're using!
Example Code
"""
This test will initialize the display using displayio and draw a solid white
background, a smaller black rectangle, and some white text.
"""
import board
import displayio
import terminalio
from adafruit_display_text import label
import adafruit_displayio_ssd1306
displayio.release_displays()
oled_reset = board.D9
WIDTH = 128
HEIGHT = 32 # Change to 64 if needed
BORDER = 5
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)
# Draw a label
text = "Hello World!"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF, x=28, y=HEIGHT//2-1)
splash.append(text_area)
while True:
pass
Let's take a look at the sections of code one by one. We start by importing the board so that we can
initialize SPI, displayio , terminalio for the font, a label , and the adafruit_displayio_ssd1306 driver.
import board
import displayio
import terminalio
from adafruit_display_text import label
import adafruit_displayio_ssd1306
Next we release any previously used displays. This is important because if the microprocessor is reset, the display pins
displayio.release_displays()
Next we define the reset line, which will be used for either SPI or I2C.
oled_reset = board.D9
If you're using I2C, you would use this section of code. We set the I2C object to the board's I2C with the easy shortcut
function board.I2C() . By using this function, it finds the SPI module and initializes using the default SPI
parameters. We also set the display bus to I2CDisplay which makes use of the I2C bus.
If you're using SPI, you would use this section of code. We set the SPI object to the board's SPI with the easy shortcut
function board.SPI() . By using this function, it finds the SPI module and initializes using the default SPI parameters. We
set the OLED's CS (Chip Select), and DC (Data/Command) pins. We also set the display bus to FourWire which makes
use of the SPI bus. The SSD1306 needs to be slowed down to 1MHz, so we pass in the additional baudrate parameter.
spi = board.SPI()
oled_cs = board.D5
oled_dc = board.D6
display_bus = displayio.FourWire(spi, command=oled_dc, chip_select=oled_cs,
reset=oled_reset, baudrate=1000000)
In order to make it easy to change display sizes, we'll define a few variables in one spot here. We have the display
width, the display height and the border size, which we will explain a little further below. If your display is something
different than these numbers, change them to the correct setting.
WIDTH = 128
HEIGHT = 32 # Change to 64 if needed
BORDER = 5
Finally, we initialize the driver with a width of the WIDTH variable and a height of the HEIGHT variable. If we stopped at
this point and ran the code, we would have a terminal that we could type at and have the screen update.
splash = displayio.Group(max_size=10)
display.show(splash)
Next we create a Bitmap that is the full width and height of the display. The Bitmap is like a canvas that we can draw
on. In this case we are creating the Bitmap to be the same size as the screen, but only have one color. Although the
Bitmaps can handle up to 256 different colors, the display is monochrome so we only need one. We create a Palette
with one color and set that color to 0xFFFFFF which happens to be white. If were to place a different color here,
displayio handles color conversion automatically, so it may end up black or white depending on the calculation.
With all those pieces in place, we create a TileGrid by passing the bitmap and palette and draw it at (0, 0) which
represents the display's upper left.
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)
We'll also want to place it at the position (5, 5) so that it ends up centered.
Since we are adding this after the first square, it's automatically drawn on top. Here's what it looks like now.
Labels are centered vertically, so we'll place it at half the HEIGHT for the Y coordinate and subtract one so it looks
good. We use the // operator to divide because we want a whole number returned and it's an easy way to round it.
We'll set the width to around 28 pixels make it appear to be centered horizontally, but if you want to change the text,
change this to whatever looks good to you. Let's go with some white text, so we'll pass it a value of 0xFFFFFF .
# Draw a label
text = "Hello World!"
text_area = label.Label(terminalio.FONT, text=text, color=0xFFFFFF, x=28, y=HEIGHT//2-1)
splash.append(text_area)
Finally, we place an infinite loop at the end so that the graphics screen remains in place and isn't replaced by a
terminal.
while True:
pass
We'll cover how to wire the OLED to your Raspberry Pi. First assemble your OLED.
Since there's dozens of Linux computers/boards you can use we will show wiring for Raspberry Pi. For other platforms,
please visit the guide for CircuitPython on Linux to see whether your platform is supported (https://adafru.it/BSN).
Adafruit PIOLED
If your default Python is version 3 you may need to run 'pip' instead. Just make sure you aren't trying to use
CircuitPython on Python 2.x, it isn't supported!
If that complains about pip3 not being installed, then run this first to install it:
Pillow Library
We also need PIL, the Python Imaging Library, to allow using text with custom fonts. There are several system libraries
that PIL relies on, so installing via a package manager is the easiest way to bring in everything:
dtparam=i2c_baudrate=1000000
You can use this sensor with any computer that has GPIO and Python thanks to Adafruit_Blinka, our CircuitPython-for-
Python compatibility library (https://adafru.it/BSN).
To demonstrate the usage, we'll initialize the library and use Python code to control the OLED from the board's Python
REPL.
Since we are running full CPython on our Linux/computer, we can take advantage of the powerful Pillow image
drawing library to handle text, shapes, graphics, etc. Pillow is a gold standard in image and graphics handling, you can
read about all it can do here (https://adafru.it/FU7).
I2C Initialization
If your display is connected to the board using I2C (like if using a PiOLED or Bonnet) you'll first need to initialize the I2C
bus. First import the necessary modules:
import board
import busio
Now for either board run this command to create the I2C instance using the default SCL and SDA pins of your I2C host:
After initializing the I2C interface for your firmware as described above you can create an instance of the SSD1306 I2C
driver by running:
import adafruit_ssd1306
oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
Note that the first two parameters to the SSD1306_I2C class initializer are the width and height of the display in
pixels. Be sure to use the right values for the display you're using!
At this point the I2C bus and display are initialized. Skip down to the example code section.
SPI Initialization
If your display is connected to the board using SPI you'll first need to initialize the SPI bus:
import adafruit_ssd1306
import board
import busio
import digitalio
Note the first two parameters to the SSD1306_SPI class initializer are the width and height of the display in pixels. Be
sure to use the right values for the display you're using!
The next parameters to the initializer are the pins connected to the display's DC, reset, and CS lines in that order.
Again make sure to use the right pin names as you have wired up to your board!
Example Code
"""
This demo will fill the screen with white, draw a black box on top
and then print Hello World! in the center of the display
This example is for use on (Linux) computers that are using CPython with
Adafruit Blinka to support CircuitPython libraries. CircuitPython does
not support PIL/pillow (python imaging library)!
"""
import board
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
# Change these
# to the right size for your display!
WIDTH = 128
HEIGHT = 32 # Change to 64 if needed
BORDER = 5
# Clear display.
oled.fill(0)
oled.show()
# Display image
oled.image(image)
oled.show()
Let's take a look at the sections of code one by one. We start by importing the board so that we can
initialize SPI, digitalio , several PIL modules for Image Drawing, and the adafruit_ssd1306 driver.
import board
import digitalio
from PIL import Image, ImageDraw, ImageFont
import adafruit_ssd1306
Next we define the reset line, which will be used for either SPI or I2C. If your OLED has auto-reset circuitry, you can set
the oled_reset line to None
oled_reset = digitalio.DigitalInOut(board.D4)
In order to make it easy to change display sizes, we'll define a few variables in one spot here. We have the display
WIDTH = 128
HEIGHT = 32 # Change to 64 if needed
BORDER = 5
If you're using I2C, you would use this section of code. We set the I2C object to the board's I2C with the easy shortcut
function board.I2C() . By using this function, it finds the SPI module and initializes using the default SPI
parameters. We also set up the oled with SSD1306_I2C which makes use of the I2C bus.
If you're using SPI, you would use this section of code. We set the SPI object to the board's SPI with the easy shortcut
function board.SPI() . By using this function, it finds the SPI module and initializes using the default SPI parameters. We
set the OLED's CS (Chip Select), and DC (Data/Command) pins. We also set up the OLED with SSD1306_SPI which
makes use of the SPI bus.
Next we clear the display in case it was initialized with any random artifact data.
# Clear display.
oled.fill(0)
oled.show()
Next, we need to initialize PIL to create a blank image to draw on. Think of it as a virtual canvas. Since this is a
monochrome display, we set it up for 1-bit color, meaning a pixel is either white or black. We can make use of the
OLED's width and height properties as well. Optionally, we could have used our WIDTH and HEIGHT variables.
Now we start the actual drawing. Here we are telling it we want to draw a rectangle from (0,0) , which is the upper left,
to the full width and height of the display. We want it both filled in and having an outline of white, so we pass 255 for
both numbers.
Next we will create a smaller black rectangle. The easiest way to do this is to draw another rectangle a little smaller
than the full screen with no fill or outline and place it in a specific location. In this case, we will create a rectangle that is
5 pixels smaller on each side. This is where the BORDER variable comes into use. It makes calculating the size of the
second rectangle much easier. We want the starting coordinate, which consists of the first two parameters, to be our
BORDER value. Then for the next two parameters, which are our ending coordinates, we want to subtract our border
value from the width and height. Also, because this is a zero-based coordinate system, we also need to subtract 1 from
each number.
Finally, we need to display our virtual canvas to the OLED and we do that with 2 commands. First we set the image to
the screen, then we tell it to show the image.
# Display image
oled.image(image)
oled.show()
Don't forget you MUST call oled.image(image) and oled.show() to actually display the graphics. The OLED
takes a while to draw so cluster all your drawing functions into the buffer (fast) and then display them once to
the oled (slow)
Display does not work on initial power but does work after a reset.
The OLED driver circuit needs a small amount of time to be ready after initial power. If your code tries to write to the
display too soon, it may not be ready. It will work on reset since that typically does not cycle power. If you are having
this issue, try adding a small amount of delay before trying to write to the OLED.
In Arduino, use delay() to add a few milliseconds before calling oled.begin(). Adjust the amount of delay as needed
to see how little you can get away with for your specific setup.
The display can have image burn in for any pixels left on over a long period of time - many days. Try to avoid having
the display on constantly for that length of time.
Datasheets
UG-2864HSWEG01 (https://adafru.it/aJI) Datasheet
UG-2832HSWEG02 (https://adafru.it/qrf) Datasheet
UG-2864HSWEG01 (https://adafru.it/wWD) User Guide
UG-2832HSWEG04 (https://adafru.it/qVA) Datasheet
SSD1306 (https://adafru.it/aJK) Datasheet
Files
EagleCAD PCB files for 128x32 0.91" SPI display PCB (https://adafru.it/aJL)
EagleCAD PCB files for 128x32 0.91" I2C display on GitHub (https://adafru.it/rPF)
EagleCAD PCB files for 128x64 0.96" display on GitHub (https://adafru.it/aJM)
EagleCAD PCB files for 128x64 1.3" display on GitHub (https://adafru.it/rJe)
Fritzing objects available in the Adafruit Fritzing Library (https://adafru.it/aP3)