Interface OLED Graphic Display Module with ESP8266 NodeMCU

Want to add little graphic pizzazz to your ESP8266 IoT projects? Or maybe you want to display IP address of your ESP8266 without resorting to serial output. These super-cool OLED (Organic Light-Emitting Diode) displays might be the perfect fit! They’re super-light, almost paper-thin, theoretically flexible, and produce a brighter and crisper picture.

OLED Display Module Overview

The OLED display module breaks out a small monochrome OLED display. It’s 128 pixels wide and 64 pixels tall, measuring 0.96″ across. It’s micro, but it still packs a punch – the OLED display is very readable due to the high contrast, and you can fit a deceivingly large amount of graphics on there.

As the display makes its own light, no backlight is required. This significantly reduces the power required to run the OLED and is why the display has such high contrast, extremely wide viewing angle and can display deep black levels.

128x64 Blue I2C OLED Display

At the heart of the module is a powerful single-chip CMOS OLED driver controller – SSD1306, which handles all the RAM buffering, so that very little work needs to be done by your ESP8266. Also the operating voltage of the SSD1306 controller is from 1.65V to 3.3V – Perfect for interfacing with 3.3V microcontrollers like ESP8266.

OLED Memory Map

To have absolute control over your OLED display module, it’s important to know about its memory map.

Regardless of the size of the OLED module, the SSD1306 driver has a built-in 1KB Graphic Display Data RAM (GDDRAM) for the screen which holds the bit pattern to be displayed. This 1K memory area is organized in 8 pages (from 0 to 7). Each page contains 128 columns/segments (block 0 to 127). And each column can store 8 bits of data (from 0 to 7). That surely tells us we have

8 pages x 128 segments x 8 bits of data = 8192 bits = 1024 bytes = 1KB memory

The whole 1K memory with pages, segments and data is highlighted below.

1KB 128x64 OLED Display RAM Memory Map

Each bit represents particular OLED pixel on the screen which can be turned ON or OFF programmatically.

The 128×64 OLED screen displays all the contents of RAM whereas 128×32 OLED screen displays only 4 pages (half content) of RAM.

Wiring OLED display module to ESP8266 NodeMCU

Enough of the theory, Let’s Go Practical! Let’s hook the display up to the ESP8266 NodeMCU.

Connections are fairly simple. Start by connecting VCC pin to the 3.3V output on the NodeMCU and connect GND to ground.

Next, Connect the SCL pin to the I2C clock D1 pin on your NodeMCU and connect the SDA pin to the I2C data D2 pin on your NodeMCU. Refer to ESP8266 NodeMCU Pinout.

The following diagram shows you how to wire everything.

Fritzing Wiring OLED Display with ESP8266 NodeMCU
Wiring OLED Display with ESP8266 NodeMCU

With that, you’re now ready to upload some code and get the display printing.

Installing Library for OLED Display Module

The SSD1306 controller of the OLED display has flexible yet complex drivers. Vast knowledge on memory addressing is required in order to use the SSD1306 controller. Fortunately, Adafruit’s SSD1306 library was written to hide away the complexities of the SSD1306 controller so that we can issue simple commands to control the display.

To install the library navigate to the Sketch > Include Library > Manage Libraries… Wait for Library Manager to download libraries index and update list of installed libraries.

Arduino Library Installation - Selecting Manage Libraries in Arduino IDE

Filter your search by typing ‘adafruit ssd1306’. There should be a couple entries. Look for Adafruit SSD1306 by Adafruit. Click on that entry, and then select Install.

Installing Adafruit SSD1306 Monochrome OLED Display Library

This Adafruit SSD1306 library is a hardware-specific library which handles lower-level functions. It needs to be paired with Adafruit GFX Library to display graphics primitives like points, lines, circles, rectangles etc. Install this library as well.

Installing Adafruit GFX Graphics Core Library

NOTE

The library allocates 1KB (128×64)/8 bits) of memory from ESP8266 as buffer. So, it can manipulate the screen buffer and then perform a bulk transfer from the ESP8266’s memory to the internal memory of the SSD1306 controller.

Modifying Adafruit SSD1306 Library

Adafruit’s SSD1306 Library isn’t set up for the 128×64 OLED displays (the one we are using right now). The display size must be changed in the Adafruit_SSD1306.h header file to make it work for us. If it is not changed, an error message saying #error (“Height incorrect, please fix Adafruit_SSD1306.h!”); may appear when attempting to verify the example sketch in the Arduino IDE:

Height incorrect, please fix Adafruit_SSD1306.h Error

In order to change the Adafruit_SSD1306.h header file, open your sketchbook location. It’s generally My Documents > Arduino. Now go to libraries > Adafruit_SSD1306

Adafruit SSD1306 Library Location

Open Adafruit_SSD1306.h file in a text editor. Scroll down the file to find the section with the SSD1306 Displays or directly go to line no. 73. Comment out #define SSD1306_128_32 and uncomment #define SSD1306_128_64 so that the code in this section looks like this:

Remove Height Incorrect Error By Changing Adafruit_SSD1306.h File

That’s it. Now save the file and restart your Arduino IDE.

ESP8266 Code – Displaying Text

Now comes the interesting stuff!

The following test sketch will print ‘Hello World!’ message on the display. It also includes

  • Displaying Inverted text
  • Displaying Numbers
  • Displaying Numbers with base (Hex, Dec)
  • Displaying ASCII symbols
  • Scrolling Text Horizontally & Vertically
  • Scrolling part of the display

This will give you complete understanding about how to use the OLED display and can serve as the basis for more practical experiments and projects.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(-1);

void setup()   
{                
	// initialize with the I2C addr 0x3C
	display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  

	// Clear the buffer.
	display.clearDisplay();

	// Display Text
	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,28);
	display.println("Hello world!");
	display.display();
	delay(2000);
	display.clearDisplay();

	// Display Inverted Text
	display.setTextColor(BLACK, WHITE); // 'inverted' text
	display.setCursor(0,28);
	display.println("Hello world!");
	display.display();
	delay(2000);
	display.clearDisplay();

	// Changing Font Size
	display.setTextColor(WHITE);
	display.setCursor(0,24);
	display.setTextSize(2);
	display.println("Hello!");
	display.display();
	delay(2000);
	display.clearDisplay();

	// Display Numbers
	display.setTextSize(1);
	display.setCursor(0,28);
	display.println(123456789);
	display.display();
	delay(2000);
	display.clearDisplay();

	// Specifying Base For Numbers
	display.setCursor(0,28);
	display.print("0x"); display.print(0xFF, HEX); 
	display.print("(HEX) = ");
	display.print(0xFF, DEC);
	display.println("(DEC)"); 
	display.display();
	delay(2000);
	display.clearDisplay();

	// Display ASCII Characters
	display.setCursor(0,24);
	display.setTextSize(2);
	display.write(3);
	display.display();
	delay(2000);
	display.clearDisplay();

	// Scroll full screen
	display.setCursor(0,0);
	display.setTextSize(1);
	display.println("Full");
	display.println("screen");
	display.println("scrolling!");
	display.display();
	display.startscrollright(0x00, 0x07);
	delay(2000);
	display.stopscroll();
	delay(1000);
	display.startscrollleft(0x00, 0x07);
	delay(2000);
	display.stopscroll();
	delay(1000);    
	display.startscrolldiagright(0x00, 0x07);
	delay(2000);
	display.startscrolldiagleft(0x00, 0x07);
	delay(2000);
	display.stopscroll();
	display.clearDisplay();

	// Scroll part of the screen
	display.setCursor(0,0);
	display.setTextSize(1);
	display.println("Scroll");
	display.println("some part");
	display.println("of the screen.");
	display.display();
	display.startscrollright(0x00, 0x00);
}

void loop() {}

The sketch starts by including four libraries viz. SPI.h, Wire.h, Adafruit_GFX.h and Adafruit_SSD1306.h. Although SPI.h library is not required for I2C OLED displays, we need to add it for the sake of compiling our program.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Next, we need to create an object of Adafruit_SSD1306.h. The Adafruit_SSD1306 constructor accepts ESP8266 pin number to which reset pin of the display is connected. As the OLED display we are using doesn’t have a RESET pin, we will send 1 to the constructor so that none of the ESP8266 pins is used as a reset for the display.

Adafruit_SSD1306 display(-1);

In setup function: we need to initialize the OLED object using begin() function. The function takes two parameters. First parameter SSD1306_SWITCHCAPVCC turns the internal charge pump circuitry ON while second parameter provides I2C address of the OLED display. I2C address of such OLED display module is generally 0x3C. It’s fixed and cannot be changed.

Next, we clear the buffer before printing our first message on the screen.

// initialize with the I2C addr 0x3C
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

// Clear the buffer.
display.clearDisplay();

Displaying simple Text (Hello World)

Displaying Text On OLED Dsiplay Module
// Display Text
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);

For displaying text on the screen, we need to set the font size. This can be done by calling setTextSize(font-size) and passing font size (starting from 1) as a parameter.

Next, we need to set the font color by calling function setTextColor(color) . Pass parameter WHITE for the dark background and pass BLACK for bright background. Now before printing the message we need to set the cursor position by calling function setCursor(X,Y). Pixels on the screen are addressed by their horizontal (X) and vertical (Y) coordinates. The coordinate system places the origin (0,0) at the top left corner, with positive X increasing to the right and positive Y increasing downward.

We can use simple print(“ ”) or println(“ ”) function to print the message on the screen just like we print data on serial monitor. Remember, println() will move the cursor to the new line.

In order for the library to perform extremely fast mathematical operations on the screen buffer (more than 100 frames per second), calls to the print functions do not immediately transfer the contents of screen buffer to the SSD1306 controller. A display() command is required to instruct the library to perform the bulk transfer from the screen buffer in the ESP8266 to the internal memory of the SSD1306 controller. As soon as the memory is being transferred, the pixels corresponding to the screen buffer will show up on the OLED display.

Displaying Inverted Text

Displaying Inverted Text On OLED Dsiplay Module
// Display Inverted Text
display.clearDisplay();
display.setTextColor(BLACK, WHITE); // 'inverted' text
display.setCursor(0,28);
display.println("Hello world!");
display.display();
delay(2000);

For displaying inverted text, we will call setTextColor(FontColor,BackgroundColor) function again. If you are paying attention, you know we passed only one parameter to this function earlier, but now we are passing two parameters. This is possible because of something called function overloading. Function overloading is the ability to create multiple functions of the same name but with different set of parameters. Calls to an overloaded function will run a specific implementation of that function depending upon the parameters passed.

In our case passing setTextColor(BLACK, WHITE) will render black text on filled background.

Scaling Font Size

Changing Font Size On OLED Dsiplay Module
// Changing Font Size
display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0,24);
display.setTextSize(2);
display.println("Hello!");
display.display();
delay(2000);

Earlier in this tutorial, we called setTextSize(font-size) function to set font size and passed 1 as parameter. You can use this function to scale the font by passing any non-negative integer.

Characters are rendered in the ratio of 7:10. Meaning, passing font size 1 will render the text at 7×10 pixels per character, passing 2 will render the text at 14×20 pixels per character and so on.

The Adafruit_GFX library is responsible for rendering font. By default the mono-spaced font is selected. However, more recent versions of the Adafruit GFX library offer the ability to use alternate fonts. Several alternate fonts come with the library, plus there’s the ability to add new ones.

Displaying Numbers

Displaying Numbers On OLED Dsiplay Module
// Display Numbers
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,28);
display.println(123456789);
display.display();
delay(2000);

Numbers can be displayed on the OLED display by just calling print() or println() function. An overloaded implementation of these functions accepts 32-bit unsigned int, so you can only display numbers from 0 to 4,294,967,295.

Specifying Base For Numbers

Displaying HEX, Decimal, OCT, Binary On OLED Dsiplay Module
// Specifying Base For Numbers
display.clearDisplay();
display.setCursor(0,28);
display.print("0x"); display.print(0xFF, HEX); 
display.print("(HEX) = ");
display.print(0xFF, DEC);
display.println("(DEC)"); 
display.display();
delay(2000);

The print() & println() functions has optional second parameter that specifies the base (format) to use; permitted values are BIN (binary, or base 2), OCT (octal, or base 8), DEC (decimal, or base 10), HEX (hexadecimal, or base 16). For floating point numbers, this parameter specifies the number of decimal places to use. For example:

  • print(78, BIN) gives “1001110”
  • print(78, OCT) gives “116”
  • print(78, DEC) gives “78”
  • print(78, HEX) gives “4E”
  • println(1.23456, 0) gives “1”
  • println(1.23456, 2) gives “1.23”
  • println(1.23456, 4) gives “1.2346”

Displaying ASCII Symbols

Displaying ASCII Symbols On OLED Dsiplay Module
// Display ASCII Characters
display.clearDisplay();
display.setCursor(0,24);
display.setTextSize(2);
display.write(3);
display.display();
delay(2000);

The print() & println() functions send data to the display as human-readable ASCII text while write() function sends binary data to the display. So, you can use this function to display ASCII symbols. In our example sending number 3 will display heart symbol.

Full Screen Scrolling

Full-Screen-Scrolling-On-OLED-Dsiplay-Module
// Scroll full screen
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println("Full");
display.println("screen");
display.println("scrolling!");
display.display();
display.startscrollright(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);
display.startscrollleft(0x00, 0x07);
delay(2000);
display.stopscroll();
delay(1000);    
display.startscrolldiagright(0x00, 0x07);
delay(2000);
display.startscrolldiagleft(0x00, 0x07);
delay(2000);
display.stopscroll();

You can scroll the display horizontally by calling startscrollright(start page, stop page) & startscrollleft(start page, stop page) functions and diagonally by calling startscrolldiagright(start page, stop page) & startscrolldiagleft(start page, stop page). All these functions accept two parameters viz. start page and stop page. Refer to OLED Memory Map section for explanation of the pages. As there are eight pages in the display from 0 to 7, you can scroll entire screen by scrolling all the pages i.e. passing parameters 0x00 and 0x07.

To stop display from scrolling you can use stopscroll() function.

Scrolling Specific Part

Scrolling Part Of The Screen On OLED Dsiplay Module
// Scroll part of the screen
display.setCursor(0,0);
display.setTextSize(1);
display.println("Scroll");
display.println("some part");
display.println("of the screen.");
display.display();
display.startscrollright(0x00, 0x00);

Sometimes we don’t want to scroll entire display. You can do that by passing proper start page and stop page information to scrolling functions. Refer to OLED Memory Map section for explanation of the pages. As there are eight pages in the display from 0 to 7, you can scroll some part of the screen by passing specific page numbers as parameters.

In our example, we passed both the parameters as 0x00. This will scroll only first page (first 8 rows) of the display.

ESP8266 Code – Basic Drawings

In this example, we’re going to try some basic drawings. This sketch demonstrates many drawing functions, including rectangles, round rectangles, circles and triangles. Try the sketch out and then we will dissect it in some detail.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(-1);

void setup()   
{                
	// initialize with the I2C addr 0x3C
	display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  

	// Clear the buffer.
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Rectangle");
	display.drawRect(0, 15, 60, 40, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Filled Rectangle");
	display.fillRect(0, 15, 60, 40, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Round Rectangle");
	display.drawRoundRect(0, 15, 60, 40, 8, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Filled Round Rectangl");
	display.fillRoundRect(0, 15, 60, 40, 8, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Circle");
	display.drawCircle(20, 35, 20, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Filled Circle");
	display.fillCircle(20, 35, 20, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Triangle");
	display.drawTriangle(30, 15, 0, 60, 60, 60, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();

	display.setTextSize(1);
	display.setTextColor(WHITE);
	display.setCursor(0,0);
	display.println("Filled Triangle");
	display.fillTriangle(30, 15, 0, 60, 60, 60, WHITE);
	display.display();
	delay(2000);
	display.clearDisplay();
}

void loop() {}

Most of the code (Including libraries and initializing display) is same as above code example, except following code snippets to draw basic drawings.

Drawing Rectangle

Drawing Rectangle On OLED Dsiplay Module
Drawing Filled Rectangle On OLED Dsiplay Module
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Rectangle");
display.drawRect(0, 15, 60, 40, WHITE);
display.display();
delay(2000);

display.clearDisplay();  
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Rectangle");
display.fillRect(0, 15, 60, 40, WHITE);
display.display();
delay(2000);

You can draw rectangle on the display by using drawRect(X-coordinate, Y-coordinate, Width, Height, color) function. Actually this function draws hollow rectangle with 1 pixel border. You can draw filled rectangle using fillRect() function.

Drawing Round Rectangle

Drawing Round Rectangle On OLED Dsiplay Module
Drawing Filled Round Rectangle On OLED Dsiplay Module
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Round Rectangle");
display.drawRoundRect(0, 15, 60, 40, 8, WHITE);
display.display();
delay(2000);

display.clearDisplay();  
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Round Rectangl");
display.fillRoundRect(0, 15, 60, 40, 8, WHITE);
display.display();
delay(2000);

You can draw round rectangle on the display by using drawRoundRect(X-coordinate, Y-coordinate, Width, Height, color) function. This function takes same parameters as drawRect() function except one additional parameter – Radius of corner rounding. Actually this function draws hollow round rectangle with 1 pixel border. You can draw filled round rectangle using fillRoundRect() function.

Drawing Circle

Drawing Circle On OLED Dsiplay Module
Drawing Filled Circle On OLED Dsiplay Module
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Circle");
display.drawCircle(20, 35, 20, WHITE);
display.display();
delay(2000);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Circle");
display.fillCircle(20, 35, 20, WHITE);
display.display();
delay(2000);

You can draw circle on the display by using drawCircle(X-coordinate of center, Y-coordinate of center, radius, color) function. This function draws hollow circle with 1 pixel border. You can draw filled circle using fillCircle() function.

Drawing Triangle

Drawing Triangle On OLED Dsiplay Module
Drawing Filled Triangle On OLED Dsiplay Module
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Triangle");
display.drawTriangle(30, 15, 0, 60, 60, 60, WHITE);
display.display();
delay(2000);

display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Filled Triangle");
display.fillTriangle(30, 15, 0, 60, 60, 60, WHITE);
display.display();
delay(2000);

You can draw triangle on the display by using drawTriangle(x0, y0, x1, y1, x2, y2, color) function. The function takes seven parameters viz. 3 X & Y coordinates of vertices of triangle and color. (X0,y0) represents top vertex, (x1,y1) represents left vertex and (x2,y2) represents right vertex.

This function draws hollow triangle with 1 pixel border. You can draw filled triangle using fillTriangle() function.

ESP8266 NodeMCU Code – Displaying Bitmap

This last example shows how to draw bitmap images to the OLED Display. This is useful for creating splash screens of company logos, making sprites or just creating fun graphics for displaying information. Copy the following code, paste it into the Arduino IDE and click upload.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(-1);

// Bitmap of MarilynMonroe Image
const unsigned char MarilynMonroe [] PROGMEM = {
	0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xf0, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xf1, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0x02, 0x78, 0x7f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfe, 0x03, 0x7c, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xfe, 0x01, 0xfe, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xfd, 0xe0, 0x03, 0xff, 0xff, 0xfc, 0x00, 0xfe, 0x0f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xfe, 0x87, 0xe0, 0xff, 0xff, 0xfc, 0x00, 0x06, 0x07, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xf9, 0xff, 0xff, 0xfc, 0x00, 0x02, 0x07, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc3, 0xc3, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xe0, 0x0c, 0x00, 0xe7, 0x81, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x02, 0x00, 0x02, 0x00, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1e, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0x3f, 0xf8, 0x00, 0x18, 0x7f, 0x1f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xf8, 0x01, 0x80, 0x03, 0xfc, 0x3f, 0xfc, 0x00, 0x70, 0xfe, 0x1f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xf0, 0x43, 0xff, 0xff, 0xf8, 0x7f, 0xf8, 0x00, 0x00, 0x7e, 0x1f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xfc, 0x00, 0x00, 0x7c, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf1, 0xef, 0xf8, 0x00, 0x01, 0xfc, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe4, 0xff, 0xff, 0xff, 0xf3, 0x80, 0xa0, 0x00, 0x07, 0xfc, 0xaf, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xec, 0x5f, 0xff, 0xff, 0xe7, 0xf0, 0x00, 0x00, 0x03, 0xfe, 0xdf, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xee, 0x7f, 0xff, 0xff, 0xc7, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xdf, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf7, 0xc7, 0xff, 0x06, 0x00, 0x03, 0xff, 0xbf, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfe, 0x5f, 0xff, 0xc7, 0x07, 0xff, 0x80, 0x00, 0x07, 0xdb, 0xbf, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0x80, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xc3, 0x0f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0x98, 0x03, 0xff, 0xf8, 0x00, 0x07, 0xe0, 0x0f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xfc, 0x01, 0x07, 0xfc, 0x1f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xcf, 0xef, 0xff, 0xff, 0xe1, 0xff, 0xfc, 0x01, 0x07, 0xf8, 0x1f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0xf8, 0x02, 0x07, 0x88, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xcf, 0xef, 0xf8, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x07, 0x84, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe7, 0xef, 0xf0, 0x04, 0x7f, 0xff, 0xc0, 0x00, 0x07, 0x84, 0x7f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x3f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x06, 0x04, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x3f, 0x7f, 0xe1, 0xf0, 0x07, 0xff, 0x80, 0x00, 0x07, 0x06, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xfe, 0x03, 0xff, 0x00, 0x00, 0x03, 0x80, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xf2, 0x3f, 0xc6, 0x7f, 0x81, 0xce, 0x00, 0x00, 0x01, 0xc1, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, 0x07, 0xc1, 0xfe, 0x00, 0x00, 0x0d, 0xc0, 0x7f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xe0, 0x3f, 0xc0, 0x01, 0xe0, 0xfc, 0x00, 0x00, 0x0f, 0xc0, 0x7f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x50, 0xfc, 0x00, 0x00, 0x0e, 0xc0, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x18, 0xf8, 0x00, 0x00, 0x0e, 0xc1, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x66, 0x81, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x1f, 0xc7, 0x80, 0x00, 0xf8, 0x00, 0x01, 0xe0, 0x00, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x1f, 0xc1, 0xe0, 0x01, 0xf8, 0x00, 0x03, 0xf0, 0x01, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0x1f, 0xc0, 0x3e, 0x03, 0xf0, 0x00, 0x00, 0xe0, 0x03, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x00, 0x1f, 0xe0, 0xe0, 0x03, 0xf2, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0x1f, 0xf0, 0x00, 0x07, 0xe6, 0x00, 0x00, 0xc0, 0x03, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0x00, 0x1f, 0xee, 0x00, 0x00, 0x80, 0x07, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xb8, 0x0f, 0xff, 0xf0, 0x3f, 0xdc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xbc, 0x0f, 0xff, 0xff, 0xff, 0xdc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x9e, 0x0f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x08, 0x0f, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x00, 0x0b, 0xff, 0xff, 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x00, 0x0b, 0xff, 0xff, 0xf9, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x3c, 0x09, 0xff, 0xff, 0xf1, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x1e, 0x08, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x1f, 0x08, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xce, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfe, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff
};

void setup()   
{                
	// initialize with the I2C addr 0x3C
	display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  

	// Clear the buffer.
	display.clearDisplay();

	// Display bitmap
	display.drawBitmap(0, 0,  MarilynMonroe, 128, 64, WHITE);
	display.display();

	// Invert Display
	//display.invertDisplay(1);
}

void loop() {}

This is how the output looks like.

Displaying Bitmap Image On OLED Dsiplay Module

To show bitmap image on the OLED display we need to call drawBitmap(X-coordinate, Y-coordinate, bitmap array, width, height, color) function. It takes six parameters viz. Top left corner X coordinate, top left corner Y coordinate, byte array of monochrome bitmap, width of bitmap in pixels, height of bitmap in pixels and Color.

In our example, the bitmap image is 128×64 in size. So, X & Y coordinates are set to 0 while width & height is set to 128 & 64.

// Display bitmap
display.drawBitmap(0, 0,  MarilynMonroe, 128, 64, WHITE);
display.display();

But, before we can call the drawBitmap() function, we first need an image to draw. Remember, the screen resolution of the OLED display is 128×64 pixels, so images larger than that will not display correctly. To get a correctly sized image, you can use your favorite drawing programs like Inkscape, Photoshop, Paint, etc., setting the canvas size to 128×64 pixels.

We took laughing Marilyn Monroe image as an example and converted into 128×64 pixels using Paint and saved as .bmp.

Marilyn Monroe
Marilyn Monroe 128x64

Once you have a bitmap, it’s time to convert it into an array that the SSD1306 OLED controller can understand. This can be done using two ways: Online method using image2cpp and Offline method using LCD Assistant.

Online Bitmap Array Generator – image2cpp

There’s an online application called image2cpp – http://javl.github.io/image2cpp/ which can convert your image into an array. Image2cpp is newer and much more powerful than LCD Assistant (later solution). It will allow you to:

  • Convert multiple images simultaneously.
  • Scale your image file – Stretch/Scale to fit/Original
  • Adjust the Brightness threshold between black and white.
  • Re-center the image vertically and / or horizontally.
  • Reverse image colors

This tool is so powerful that it can work offline as well. Simply save the page to your PC and open it in your browser. Thanks to Jasper van Loenen for his excellent contribution.

To begin with, open image2cpp in your browser and select any image you want to display on OLED screen.

Select Image - image2cpp Bitmap to Data Array Online Conversion Tool

The dimensions of your image will populate in Canvas size option under Image settings. If you have selected bigger image than 128×64, change it to 128×64 and select proper Scaling option. You can view the output in Preview section.

You can change the Background color or Invert image colors if necessary.

Finally, change the most important option – Brightness threshold as per your requirement. Setting threshold will make pixels above this level white and below black. In our case we have set it to 171 to get nice details of Marilyn Monroe.

Image Settings - image2cpp Bitmap to Data Array Online Conversion Tool

This little preview reflects whatever changes you make in your settings. You can change settings while keeping eye on it.

Image Preview - image2cpp Bitmap to Data Array Online Conversion Tool

Once you are satisfied with the outcome, you can proceed generating the data array. Simply select Code output format as Arduino Code and click on Generate code button.

Just for your information, there’s an option called Draw mode. It actually creates image according to the scanning patter of the display. If your image looks all messed up on your display, try changing the mode.

Generating Output - image2cpp Bitmap to Data Array Online Conversion Tool

That’s it. The byte array of your bitmap will be generated. You can use the output directly with our example code. Just be sure to name it appropriately. Then call your array inside the drawBitmap() function.

Arduino Code Output - image2cpp Bitmap to Data Array Online Conversion Tool

Offline Bitmap Array Generator – LCD Assistant

There’s another application called LCD assistant – http://en.radzio.dxp.pl/bitmap_converter/ which can convert your bitmap image into data array. It’s not as powerful as image2cpp but still popular among hobbyists.

To start with, you need to convert you image into 128×64 1-bit monochrome bitmap. You can use your favorite drawing programs like Inkscape, Photoshop, Paint, etc. to do it, just like we did in MS paint.

Open your file in MS Paint and resize it to 128×64.

Opening Image in Paint

Now, save your file as bitmap. While saving the file choose Save as type : Monochrome Bitmap(*.bmp;*.dib). This will generate 1-bit/binary bitmap image that has only two possible values for each pixel i.e. 0 (black) or 1 (white).

Saving 1-bit Monochrome Bitmap Image in MS Paint

The only downside here is that you cannot set brightness threshold level. It is set to 50% by default and cannot be changed.

Anyways now, download LCD assistant program. Open the executable and load your bitmap from File menu.

LCD Assistant Converts Bitmap Image to Data Array For LCD,OLED,Graphic Displays

There’s nothing much you can do with this tool. So, just go to File menu and click on Save output option. Save the file as text file.

Just for your information, there’s an option called Byte Orientation. It actually creates image according to the scanning patter of the display. If your image looks all messed up on your display, try changing the mode.

Save Output Of LCD Assistant

That’s it. With your array created, paste it into your code.

Bitmap to Data Array Conversion Output - LCD Assistant Application

Just be sure to name it appropriately. Then call your array inside the drawBitmap() function.