Library for 128 by 64 OLED I2C Display

Status
Not open for further replies.

GregM

Active member
I am looking for an Arduino library that works with Teensy 3.1 and the common 128 by 64 OLED display. The display uses the SSD1306 controller. The I2C address for the display is 0x3C. I am using the Adruino 1.6.4 version IDE. I would like to use the display as part of a clock that is updated by NTP.

I have tried the U8GLIB library "Hello World" example with Teensy 3.1, but it does not work. However, the same example with the U8GLIB library works with a NANO processor. I tried the Adafruit libraries with its example. It sort of works with a display of something, but, is generally unreadable.

I have tried several other libraries that I found with either searching the Arduino forum or a General Google search. So far no luck. What is a known good library for use with OLED displays?

Thank you in advance for any suggested libraries to use.

Enjoy life, GregM
Live Well, Laugh Often, Love Much
 
Thank you, tenkai for the information. I have tried that library, which also needs the Adafruit GFX library. When I run the the ssd1306_128x64_i2C.ino example, all the displayed information is shown in only one quarter of the screen. The library seems to be written for an Adafruit display. In the library code, it resets the ssd1306 via a reset pin. My display does not have the reset pin, but, the Adafruit display does. The reset may be needed to set a standard initial state. My display is never set to that state and the transmitted data is not process correctly. I will have to keep looking for a library that works, or else get an Adafruit display. Thanks again.

Enjoy life, GregM
Live Well, Laugh Often, Love Much.
 
I came to Teensy with generic I2C 1306 OLED's and the library code worked well right off when wired to a breadboard. @tenkai - I saw on your other thread you got I2C to work - interesting to know what you found with the speed. I was seeing good update speed on an UNO and AtTiny over I2C given it is MONO and low pixel count.
 
When I run the the ssd1306_128x64_i2C.ino example, all the displayed information is shown in only one quarter of the screen.

where did you get the display? or are you sure it's ssd1306? sometimes the stuff you get on ebay etc turns out to be SH1106; in this case u8glib is your friend.

edit: oh, sorry, missed this piece of information: "the same example with the U8GLIB library works with a NANO processor", so SH1106 is ruled out. if it works w/ atmega, it should work with teensy, i'd say. u8glib is pretty solid and portable in my experience (though i only ever used SPI oleds). so maybe something i2c related?
 
Last edited:
Thank you, mxxx for the information. I have been search the web for more information. I am finding that many people seem to have problems with these devices. In general the u8glib seems to be good. I am starting to think the device may have a problem. I have another display on order from a different supplier. Hopefully, that one will work better. It seems like a device reset is needed, so maybe the Adafruit device is a better choice.

Enjoy Life, GregM
Live Well, Laugh Often, Love Much.
 
To all, thank you for the help. I got the another display today. The display I was using before either has a problem, is non-standard or both.

The new display unit is more common 0.96 inch size. The new display using a Nano works properly will all the libraries I found. No problems at all.

With a Teensy 3.1, the Adafruit library works perfectly fine with the I2C interface. The ug8lib has a problem. When I compile a sketch, there are a bunch of complier warnings about the I2C initialization. The display does not start up with Teensy 3.1 and ug8lib. The Adafruit library will do for now.

I did find this web site, that has a very good explanation of SSD1306 display controller and its commands:
http://robotcantalk.blogspot.com/2015/03/interfacing-arduino-with-ssd1306-driven.html

It really helps to understand what is being done. There is some test code that would be help if you wanted to do some fancy graphics. It appears to be faster than Adafruit library.

Thanks again to all. I hope this helps someone else.

Enjoy life, GregM
Live Well, Laugh Often, Love Much
 
@GregM good to hear. I think the SSD1306 needs a reset pin AT LEAST (in addition to SDA and SCL).

@defragster I swapped the Wire library with the i2c_t3 library and bumped up the speed to I2C_RATE_2000 (2000 hz? 2000 khz? not sure) any higher and I would get graphical anomolies. Increasing the I2C rate definitely made the display refresh much faster.

Compared to SPI, it did refresh slower, but not by much. It was only incrementally faster. Depending on how saturated my SPI line ends up being, I might use this for my project in the end. I wonder if I could make it any faster by using ug8lib over Adafruit GFX (never used ug8).
 
i've recently got hold of one of these i2c oleds, too (ie the one without the reset pin, SH1106) and indeed it's not working with teensy 3.1 and u8glib. the simple reason seems to be that u8glib doesn't support i2c for non-AVR mcus (edit: that should read non-Arduino, as due is supported).

anyways, i figured it couldn't be that tricky to get this working à la the way this would be done for SPI/ARM (and which works). ie come up with a "com" function for i2c. so i've added two files -- u8g_i2c.h and u8g_i2c.cpp -- to u8glib, which contain said "com" function: uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)

edit: see next post
being fairly unfamiliar with i2c (i only ever used SPI), i can't get it to work though. it looks as if teensy freezes up as soon as the com function calls Wire.begin(...) (both i2c_t3 and the regular Wire library do that). i know the hardware/display works in principle with teensy, as it responds to simple i2c commands and displays simple stuff (hello world etc).

anyone familiar with i2c / u8glib to see what might be going on?


this is my u8g_i2c.cpp :

Code:
#include <Arduino.h>
#include <u8glib.h>
#include <i2c_t3.h>

const uint16_t SLAVE_ADR = 0x3C;    // == 0x78
const uint16_t DATA_MODE = 0x40;    // i2c data command
const uint16_t COMMAND_MODE = 0x00; // i2c command command; 0x80 -- either seems to work

uint16_t CTRL_CMD = 0; 

uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
  switch(msg)
  {
    case U8G_COM_MSG_STOP:
      //STOP THE DEVICE
    break;

    case U8G_COM_MSG_INIT:

      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_3000);
		
    break;

    case U8G_COM_MSG_ADDRESS:  
      //SWITCH FROM DATA TO COMMAND MODE (arg_val == 0) for command mode
    if (arg_val == 0)
      {
    	  CTRL_CMD = COMMAND_MODE;
      }
      else
      {
    	  CTRL_CMD = DATA_MODE;
      }
    break;

    case U8G_COM_MSG_RESET:
      // there's no reset pin .. ~ U8G_I2C_OPT_NO_ACK 
    break;

    case U8G_COM_MSG_WRITE_BYTE:
      //WRITE BYTE TO DEVICE
    
      Wire.beginTransmission(SLAVE_ADR);    // slave addr
      Wire.write(CTRL_CMD);                 // cmd
      Wire.write(arg_val);                  // data
      Wire.endTransmission();  
     
    break;

    case U8G_COM_MSG_WRITE_SEQ:
    case U8G_COM_MSG_WRITE_SEQ_P:
	 {
    //WRITE A SEQUENCE OF BYTES TO THE DEVICE
    register uint8_t *ptr = static_cast<uint8_t *>(arg_ptr);
    
    Wire.beginTransmission(SLAVE_ADR);
    Wire.write(CTRL_CMD); 
    while(arg_val > 0){
		    Wire.write(*ptr++);
		    arg_val--;
      }
    Wire.endTransmission();
  }
    break;

  }
  return 1;
}

and this is u8g_i2c.h :

Code:
#ifndef _U8G_ARM_H
#define _U8G_ARM_H
 
#include <u8glib.h>

// the com function:
uint8_t u8g_com_hw_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr);
 
#endif

the simple test code should just print a number (works with a SPI oled):

Code:
#include <i2c_t3.h>
#include <u8g_i2c.h>
//#include <spi4teensy3_14.h> // spi4teeensy w/ SCK = 14
//#include <u8g_teensy_14.h> // SPI equivalent which works. 

U8GLIB u8g(&u8g_dev_sh1106_128x64_i2c, u8g_com_hw_i2c_fn);   // this doesn't work
//U8GLIB u8g(&u8g_dev_sh1106_128x64_2x_hw_spi, u8g_com_hw_spi_fn); // this works 

uint16_t xxx = 0; // some number to print

void draw(void) {
  xxx = millis()/1000;
  u8g.setFont(u8g_font_unifont);
  u8g.setPrintPos(0, 10);
  u8g.print(xxx);
}

void setup(void) {
  delay(1000);
  Serial.println(".... ? ");
  pinMode(13, OUTPUT); 
}

void loop(void) {
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );
  delay(100);
  Serial.println(xxx);
}
 
Last edited:
ok, fwiw: after playing around with this a little more, i just bypassed the C++ wrapper*, and the above "com" function started to work right away**. so you'd just have to drop those two files next to u8glib.h/cpp; it's a little less nice to deal with, especially there's no "print"; but it seems to work up to I2C_RATE_3000 (at 120MHz). here's a/the little test program:

Code:
#include <i2c_t3.h>
#include <u8g_i2c.h>

u8g_t u8g;

void display_something() 
{
  uint16_t y = 0x08+random(55);
  u8g_FirstPage(&u8g);
  do {
    u8g_DrawStr(&u8g, 10, y, "hello etc");
  } while(u8g_NextPage(&u8g)); 
} 

void setup(void) 
{  
  delay(100);
  // init display:
  u8g_InitComFn(&u8g, &u8g_dev_sh1106_128x64_i2c, u8g_com_hw_i2c_fn);
  // font , color 
  u8g_SetFont(&u8g, u8g_font_6x12);
  u8g_SetColorIndex(&u8g, 1);
}


uint32_t _time;

void loop(void) 
{  
  _time = micros();
  display_something();
  Serial.println(micros()-_time);
  delay(250);
}


* as of u8glib 1.18 it supports arduino due/i2c, so i guess a suitable #if defined(__MK20DX256__) could be added there, too; ie to "U8glib for Arduino" and u8g_com_i2c.c

** trying to initialize i2c_t3 with I2C_OP_MODE_DMA fails after a few seconds.
 
Last edited:
i have one of those cheap SH1106 I2c, and it works flawless with arduino but as you mention seems not to be working with Teensy. i've give a quick test to your hack but i got a compile error:
I've put the 2 files in the same folder of ug8lib but it seems that is not the right location.
i'm sure is a silly problem but i can't figure it how to solve it.

sketch_jul22a.ino:2:21: fatal error: u8g_i2c.h: No such file or directory
compilation terminated.
 
sketch_jul22a.ino:2:21: fatal error: u8g_i2c.h: No such file or directory
compilation terminated.


mmh, you've restarted the IDE etc i suppose? this is how the library folder looks here:

u8g_teensy_i2c /
u8g_i2c.cpp
u8g_i2c.h
u8glib.cpp
u8glib.h
utilities/

here's the thing in full: https://github.com/mxmxmx/eurotrash/tree/master/mkII/u8g_teensy_i2c , if that's of any help. it really should work:

19216964093_21b9041f78_c.jpg
 
mmh, you've restarted the IDE etc i suppose? this is how the library folder looks here:

u8g_teensy_i2c /
u8g_i2c.cpp
u8g_i2c.h
u8glib.cpp
u8glib.h
utilities/

here's the thing in full: https://github.com/mxmxmx/eurotrash/tree/master/mkII/u8g_teensy_i2c , if that's of any help. it really should work:

View attachment 4731

I messed up the files, now it compiles but i have no output on the disp, i've hooked display SCL to teensy pin 19 and SDA to pin 18 (powered at 3.3 from the teensy).
The same display works fine on arduino, i'm using a teensy with audio shield soldered (but not used right now).
 
mmh, maybe try with a more conservative i2c rate? I was running at 120mhz F_cpu / 3000khz.
 
2015-07-22 16.33.39.jpgi've compiled with the teensy at 24mhz but no changes unfortunately.
with arduino uno the display works fine with both

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // I2C / TWI
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI
 
Last edited:
A common issue with i2c on Teensy is that the Teensy needs pull-up resistors on the two i2c pins, while the Arduino does not. If you don't have two separate pull-up resistors between each of A4/A5 and the 3.3v pin (4.7K is the default recommendation), try adding them.

Another common issue is whether the device can run at 3.3v or if it needs 5v. Assuming the device can run at 3.3v, be sure to connect the device's power to the 3.3v pin and not VIN (i.e. 5v). Some things will not respond correctly if you have 3.3v signalling and 5v power.

If your device needs 5v power, then you will need to do a level conversion from 3.3v to 5v. I've used https://www.pololu.com/product/2595 for level shifting i2c devices. I've also used http://dsscircuits.com/sale/product/dssc0105. Note, I don't really stress the i2c work, and generally I use the default Wire library instead of t3_i2c.
 
I just bought the LC and have an eBay OLED i2c that uses the SH1106 library. I found this thread when the display did not work with the LC- like the other member here it worked fine with my Arduino Uno. It did work on 3.3V when I tried it with the Uno.

I copied the code above and created new cpp and h files, then placed them in the existing u8g library. The Github page with the i2c library is dead:
https://github.com/mxmxmx/eurotrash/tree/master/mkII/u8g_teensy_i2c

I added two 4.7K resistors between the SCL on teensy pin 19 and SDA on pin 18 from each pin to 3.3V.

I tried both my gauge sensor sketch and the example sketch above and still no display.

EDIT
I found there was a missing reference in one file to a library called i2c_t3.h. A google search found it here:
https://github.com/nox771/i2c_t3

Installing it made no difference, display still blank.

Here's the example code:

Code:
#include <i2c_t3.h>
#include <u8g_i2c.h>
//#include <spi4teensy3_14.h> // spi4teeensy w/ SCK = 14
//#include <u8g_teensy_14.h> // SPI equivalent which works. 

U8GLIB u8g(&u8g_dev_sh1106_128x64_i2c, u8g_com_hw_i2c_fn);   // this doesn't work
//U8GLIB u8g(&u8g_dev_sh1106_128x64_2x_hw_spi, u8g_com_hw_spi_fn); // this works 

uint16_t xxx = 0; // some number to print

void draw(void) {
  xxx = millis()/1000;
  u8g.setFont(u8g_font_unifont);
  u8g.setPrintPos(0, 10);
  u8g.print(xxx);
}

void setup(void) {
  delay(1000);
  Serial.println(".... ? ");
  pinMode(13, OUTPUT); 
}

void loop(void) {
  u8g.firstPage();  
  do {
    draw();
  } while( u8g.nextPage() );
  delay(100);
  Serial.println(xxx);
}
 
Last edited:
Dear All,

I have a (possibly) SH1106, working under u8glib, but i need to shrink the HEX.
What is the Reset used for? There is no such pin on my OLED, and as i see it's only used at the very beginning of the init stage in SSD1106 library.
Maybe it is safe to communicate with the SH1106 without reset, using code from SSD1106?
 
Status
Not open for further replies.
Back
Top