OLED Display with SSD1308 Driver

Background

Seeed Studios and mbed made some free modules available. I signed up for the OLED display (128x64 pixels, monochrome black/white) and got it! Thanks! The datasheet for the module and for its displaydriver (Solomon Tech SSD1308) can be found here.

/media/uploads/wim/_scaled_400px-toled128642.jpg

This notebook page shows how to interface the display to mbed. The hardware interface requires powersupply (5V, GND) and an I2C controlbus.

Code Port to mbed

There are some I2C libraries for the SSD1308 available on the internet. This software was originally developed for arduino. The SSD1308 code is by Andrew Schamp and was submitted as a part of Jeff Rowberg's I2Cdevlib library. I have ported that code to mbed and optimised it in several areas. Currently the basic methods to access registers and initialise the controlller have been completed. The displaymemory can be cleared and filled with patterns, bitmaps or textstrings. The display can be scrolled, mirrored left-right and top-bottom or shown in reverse (black pixels on white background). Some missing features like brightness control will be added. A disadvantage of the display is that you can not read back data from the displayed image. Pixels are also not individually addressable, but grouped in one byte for 8 (vertical) pixels. These limitations make graphic routines more difficult to implement since you often need to perform read-modify-write operations when drawing lines etc. There are some work-arounds possible and we will see how far I will go..

This is a sneakpreview of what to expect:

/media/uploads/wim/_scaled_img_2461.jpg

The image was made by loading a bitmap with the mbed logo and then writing a string on top of that. The data for a bitmap display can be created with a special softwaretool that converts an image into a 'C' header file containing a constant char array. See LCDAssistant.

Some example code:

/* mbed Seeed 128x64 OLED Test
 *
 */
#include "mbed.h"
#include "mbed_logo.h"
#include "SSD1308.h"

//Pin Defines for I2C Bus
#define D_SDA                  p28
#define D_SCL                  p27
I2C i2c(D_SDA, D_SCL);

// Host PC Communication channels
Serial pc(USBTX, USBRX); // tx, rx

// Instantiate OLED
SSD1308 oled = SSD1308(&i2c, SSD1308_SA0);  // NEW, modified the lib to fix the 'non copyable' problem with recent mbed libs

int main() {
  pc.printf("OLED test start\r");  
  
  oled.writeString(0, 0, "Hello World !");
  wait(3);
    
  oled.fillDisplay(0xAA);
  wait(3);

  oled.setDisplayOff();
  wait(0.5);

  oled.setDisplayOn();
  wait(0.5);  

  oled.clearDisplay();
  wait(0.5);

  oled.setDisplayInverse();
  wait(0.5);

  oled.setDisplayNormal();                                         
  wait(0.5);

  oled.writeBitmap((PAGES*COLUMNS), (uint8_t*) mbed_logo);

  pc.printf("OLED test done\r\n");  
}

Hardware Hints

The display driver is a 3V3 device. However, the Seeed module has been designed for a 5V supply and 5V I2C controlsignals. I have used a Sparkfun 3V3-5V level converter between mbed's I2C signals (SDA, SCL) and the display. The display comes with a colour coded wire.

  • Red = 5V, connect to mbed VU (Pin 39)
  • Black = GND, connect to mbed GND (Pin 0)
  • Yellow = SCL, connect to mbed SCL (Pin 10 or Pin 27), using level converter
  • White = SDA, connect to mbed SDA (Pin 9 or Pin 28), using level converter

Note that the levelconverter has internal pull-up R's for the I2C bus.

The powerconsumption of the display depends on the selected contrastvalue and the number of active pixels. On average expect 10-15mA when all pixels are active.

The testsetup is shown here:

/media/uploads/wim/_scaled_img_2465.jpg

Note how small the display really is. It is however surprisingly readable due to the sharp image that OLEDs provide. The levelconverter is the small red pcb on the left.

References

The mbed version is here. An example programme is here.

Have fun !


5 comments on OLED Display with SSD1308 Driver:

11 Jul 2013

Hello, and thank-you for this code. I am working on a project with Crius 128x64 OLED and the code seems to work pretty well. However;

I can't get the oled.writeString(0, 0, "xx"); function to work. writeBitmap works but no printf function for the OLED. any thoughts?

11 Jul 2013

Nicholas Farrell wrote:

Hello, and thank-you for this code. I am working on a project with Crius 128x64 OLED and the code seems to work pretty well. However;

I can't get the oled.writeString(0, 0, "xx"); function to work. writeBitmap works but no printf function for the OLED. any thoughts?

The CRIUS seems to use the SSD1306. There are some differences (chargepump). I need to compare the datasheets in more detail. There are some hints here that the SSD1306 has an internal chargepump that needs to be activated. Your images will be too faint otherwise. Is that the case?

When bitmaps show the problem must be minor. Maybe the font table (font8x8.h) is somehow empty. Did you include the SSD1308 lib or did you include the source files and recompile with your own code.Have you tried writeChar() to display a single 8x8 character. Have you tried writeBigChar() to display a single large 16x24 digit. You may have seen my example program. That has a simple menu to test different functions.

11 Jul 2013

I dont suspect the chargpump to be a problem, I can see images on the oled. I will however check out that link.

I imported your example ("An example programme is here") and I am using the same files. I checked to see if the 8x8.h was bad. First I created a new font8x8.h but nothing. Then I wanted to test if the 8x8 was in fact bad. So I changed the writeBigChar() to use the 8x8font. That worked fine. option 'E' displayed in 8x8 just fine.

It seems to me that the writeString() function is the problem. I am investigating the code but to be honest, I am new to OLED/GUI. The most display work I have done has been in 16x2 & 20x4 text.

I wrote a simple 'for loop' to increment the row/column portion. I was thinking maybe the cursor position was wrong, but nothing.

for loop

     
     while (1) {

     for(x = 0; x< 128; x++){
          writeString(x, y, "Hello World");
          pc.printf("cursor = (%d,%d)\n", x, y);
          }
     if(y<64); {
          x = 0;
          y++;
          }
     else
          pc.printf("end test");
}

I also wrote a simple main program with only the writeString(0, 0, "Hello World"); function.. no display

I will try writeChar() and also investigate the SSD1306

Thanks for your help, hopefully its something simple, I want to get the writeString() function working.

20 Jul 2013

Hi Nicolas, just wondering if you had found the problem with the SSD1306. Looks like the difference between the SSD1308 and SSD1306 is that SSD1306 has an onboard chargepump. However, both devices can work with an external powersupply also and you should not activate the chargepump for the SSD1306 in that case.

There is one other issue that you may run into when using the I2C interface. The SSD1306 has separate pins for SDAin and SDAout. The SDAin is used to receive commands and data. The SDAout pin is used to Acknowledge the I2C commands or data to the host CPU (in this case mbed). The reasons for using separate pins are technical and I wont go into that here. Normally both pins are connected. However, in some cases the SDAout is NOT connected. That means the device will not acknowledge I2C traffic. The problem is now that the mbed I2C libs for blockwrite operations will abort when the I2C messages dont get an acknowledge. I my lib I use blockwrites for displaying a character. This happens in _sendData().

/** @brief Write databyte to display
 *  @brief Start at current cursor location
 *  @param uint8_t data databyte to write
*/
void SSD1308::_sendData(uint8_t data){

  char databytes[2];
    
  databytes[0] = DATA_MODE;
  databytes[1] = data;    
  _i2c.write(_writeOpcode, databytes, 2);    // Write Data   
  
}

So you may want to try replacing the blockwrite by separate I2C write operations. They still dont get acknowledged, but they will continue just the same.

Try this:

/** @brief Write databyte to display
 *  @brief Start at current cursor location
 *  @param uint8_t data databyte to write
*/

void SSD1308::_sendData(uint8_t data){

#if(0)
//I2C Blockwrite versions dont seem to work ?
//That may be related to fact that the SSD1306 does NOT return an acknowledge: blockwrite may abort the operation
//Noted for mbed lib v63 on 20/7/13 
  char databytes[2];
    
  databytes[0] = DATA_MODE;
  databytes[1] = data;    
  _i2c.write(_writeOpcode, databytes, 2);    // Write Data   

#else
  _i2c.start();
  _i2c.write(_writeOpcode);
  _i2c.write(DATA_MODE);  
  _i2c.write(data); 
  _i2c.stop();  
#endif
 
}

I dont see the Ack problem for my SSD1308, but that may be because it is wired differently. In my case both blockwrite and single writes work fine.

18 Dec 2017

The latest mbed libs have made some changes that resulted in a "NoneCopyable" problem for the i2c bus parameter. The issue should be fixed in the new release of the SSD1308 lib. I have used the same method as in some of my other libs. You now need to instantiate the display as follows:

...
//Pin Defines for I2C Bus
#define D_SDA                  p28
#define D_SCL                  p27
I2C i2c(D_SDA, D_SCL);

// Instantiate OLED
SSD1308 oled = SSD1308(&i2c, SSD1308_SA0);

...

Please log in to post comments.