0.91″ SSD1306

Preamble

I bought this, 0.91″128×32 IIC I2C White DIY OLED LCD Display Module 3.3V Fr PIC Arduino Hot im and connected it to an Arduino Mega, SDA/SCL/GND and connected to 5V and thought that I had broken it…

It turns out that I hadn’t, and only the very first versions of this display are 3V3 sensitive. However, finding a library to work was a bit of a task, and a small library, that doesn’t gobble up all of the Arduino’s memory, is even harder to find.

See also

Links

First, I tried the Adafruit SSD1306 library, /Adafruit_SSD1306, running the ssd1306_128x32_i2c.ino example gave no joy.  I have 4 pins and not 5 (no reset)

Then I read this: Does someone got this OLED working? –> 128×64 Display Module SSD1306, says that I2C doesn’t work, but SPI does, however it is the wrong display as it is for the 0.96″, not 0.91″. It also mentions:

Software: U8glib supports SSD1306…

From OLED I2c Display With Arduino use the i2c_scanner to get the I2C address, no address returned…

Then SSD1306 OLED driver, looks good (SPI and I2C)

Then this video, D054 – OLED 0.91 I2C 128×32 White (SSD1306), and associated blog, OLED 0.91 I2C 128×32 White (SSD1306) [D054]

Finally, Julian IlettArduino Anxiety – Uno, 128×32 OLED and u8g2lib – note the usage of “U8G2LIB”

As Julian points out, the display board, even though it is advertised as 3.3V, the IC U2 is a 3.3V regulator, so 5V is probably OK:

SSD1306 - U2 3.3 V voltage regulator
SSD1306 – U2 3.3 V voltage regulator

I connected the display to an Uno, and wired as per Julian’s video. I used the U8glib, not version 2, on Arduino IDE 1.8.3, ran the “Hello World” example and it worked fine, using the I2C HW, SDA and SCL pins:

U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / TWI U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE); // I2C / TWI

Perfect?

Re-running the I2CScanner now gives the address 0x3C.

After reconnecting to the Arduino Mega, I realised that I had not actually powered the display at all, as the breadboard power rails were not linked and so the… well, it is obvious really.

So, now re-running the Adafruit example, ssd1306_128x32_i2c.ino, on the Arduino Mega, even though I have no reset pin connected, or available, it works fine. However, a lower portion of the display seems to be missing:

 

See also Update: u8g2lib and the 128×32 OLED, for a less panicky video:

Using u8g2, the same half screen effect:

Missing lower third of screen
Missing lower third of screen

Additional Libraries

I located a lightweight collection of functions, SSD1306_OLED_HW_I2C library/code via this discussion, New minimalistic library for 128×64 I2C OLED displays. One of the comments, quite rightly, states that Adafruit’s SSD1306 library is too heavyweight. I had also found that the U8g2 library to be way to large for my GhettoVaper project – fine if using an Arduino Mega2560, but running it on a Nano, or Uno even, left little space for the actual sketch.

This minimal library can be found here, ssd1306_oled_hw_i2c, and is derived from SSD1306xLED. Unfortunately it is for a 128×64 0.96″ display, but can be made to work with some modification. It is not like a typical Arduino library, as there are no objects. It has 6×8 and 8×16 fonts.

However, the demo would not display correctly, straight out of the box. The characters were distorted and the top and bottom horizontal lines would not display, and the text had the top and bottom row of pixels missing.

The datasheet for the SSD1306: PDF link, SSD1306. Of most relevance were the Offset (0xD3) and the Multiplexor (0xAB) settings.

The simplest test was to change the MUX to 0x1F (32) en lieu of 0x3F (64). However, this did not help much. Setting the MUX back to 64, I then experimented with the offset. After playing around with the offsets for a bit, I found that an offset of 0x3F displayed the box (the horizontal top and bottom lines) and the text correctly, or at least centred. Note that I had to reduce the bottom horizontal line positioning from 63, to 62 to get it to display. This seemed odd as for a 64 line display 0 and 63 should be the upper and lower limits.

Once I was happy with the offset settings, I then made a demo/test sketch and playing around, I realised that only even numbered lines would print.

See also Any MSP430 OLED display code examples for SSD1306 driver?

SSD1306_SETMULTIPLEX changed from 0x3F to 0x1F (from 64 to 32)

SSD1306_SETCOMPINS changed from 0x12 to 0x02

This made me realise that the odd numbered lines were not printing, maybe because I still was using the MUX set to 64. However, as before setting MUX to 0x1F (32) and using an offset of 0x1F (32), did not help much as the odd numbered lines still would not print. However, changing the com pin settings (0xDA) from 0x12 to 0x02, and changing the offset back to 0x00, made the screen print as expected.

The correct settings for the 0.91″ display are as follows:

// Display initialization sequence
const uint8_t init_sequence [] PROGMEM = {
	0xAE,			// Display OFF (sleep mode)
	0x20, 0b00,		// Set Memory Addressing Mode
					// 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode;
					// 10=Page Addressing Mode (RESET); 11=Invalid
	0xB0,			// Set Page Start Address for Page Addressing Mode, 0-7
	0xC8,			// Set COM Output Scan Direction
	0x00,			// ---set low column address
	0x10,			// ---set high column address
//	0x00,			// ---set start line address (this does not change height)
	0x40,			// ---set start line address
	0x81, 0x00,		// Set contrast control register
	0xA1,			// Set Segment Re-map. A0=address mapped; A1=address 127 mapped. 
	0xA6,			// Set display mode. A6=Normal; A7=Inverse
	0xA8, 0x1F,		// Set multiplex ratio(1 to 32)
//	0xA8, 0x3F,		// Set multiplex ratio(1 to 64)
	0xA4,			// Output RAM to Display
					// 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content
	0xD3, 0x00,		// Set display offset. 00 = no offset (prints full screen, correctly offset but top line truncated - corrupted characters)
//	0xD3, 0x01,		// Set display offset. 01 = offset (prints full screen, correctly offset but top line truncated - non corrupted characters)
//	0xD3, 0x0F,		// Set display offset. 0F = offset (prints full screen, offset up by under third - non corrupted characters)
//	0xD3, 0x10,		// Set display offset. 10 = offset (prints full screen, offset up by third - corrupted characters)
//	0xD3, 0x11,		// Set display offset. 11 = offset (prints full screen, offset up by over third - non corrupted characters)
//	0xD3, 0x1F,		// Set display offset. 1F = offset (prints full screen, offset by under half - non corrupted characters)
//	0xD3, 0x20,		// Set display offset. 20 = offset (prints full screen, offset by half - corrupted characters)
//	0xD3, 0x21,		// Set display offset. 21 = offset (prints full screen, offset by over half - non corrupted characters)
//	0xD3, 0x2F,		// Set display offset. 2F = offset (prints full screen, offset down by third - non corrupted characters)
//	0xD3, 0x30,		// Set display offset. 30 = offset (prints full screen, offset down by third - corrupted characters)
//	0xD3, 0x31,		// Set display offset. 31 = offset (prints full screen, offset down by third - non corrupted characters)
//	0xD3, 0x3F,		// Set display offset. 3F = offset (prints full screen, correctly offset but bottom line truncated - non corrupted characters)
//	0xD3, 0x40,		// Set display offset. 40 = offset (prints full screen, correctly offset but top line truncated - corrupted characters)
//	0xD3, 0x41,		// Set display offset. 41 = offset (prints full screen, correctly offset but top line truncated - non corrupted characters)
	0xD5,			// --set display clock divide ratio/oscillator frequency
	0xF0,			// --set divide ratio
	0xD9, 0x22,		// Set pre-charge period
//	0xDA, 0x12,		// Set com pins hardware configuration 64 lines		
	0xDA, 0x02,		// Set com pins hardware configuration 32 lines		
	0xDB,			// --set vcomh
	0x20,			// 0x20,0.77xVcc
	0x8D, 0x14,		// Set DC-DC enable
	0xAF			// Display ON in normal mode
};

The characters print below the cursor point.

Creating libraries (initial attempt)

I turned this SSD1306_OLED_HW_I2C library/code into a bone fide Arduino library, SSD1306_OLED_HW_I2C_LIB. However, this will not handle strings stored in EEPROM, using F(), and handling the various floats, longs, that can be passed to print became rather cumbersome, see SSD1306_OLED_HW_I2C_LIB_FULL. So an object correctly/properly derived from the Arduino Print library is required

Then I created a Print object derived class, SSD1306_OLED_HW_I2C_LIB_PRINT. The characters ° and Ω are not defined, so I had to create and add my own 6×8 character bitmaps. However, the characters where a little too small for my liking. Note that SSD1306_OLED_HW_I2C_LIB_PRINT reproduces/contains the code from SSD1306_OLED_HW_I2C_LIB. It would be better for SSD1306_OLED_HW_I2C_LIB_PRINT class to be derived from both the Arduino Print class and SSD1306_OLED_HW_I2C_LIB to remove duplication (this is where SSD1306_OLED_HW_LIB2, and its derivatives, comes into play – see also my blog about SSD1306_OLED_HW_LIB2).

Then, from SSD1306_OLED_HW_I2C_LIB_PRINT, I derived a further class and I added the larger characters (from tinusaur’s SSD1306xLED), SSD1306_OLED_HW_I2C_LIB_PRINT_8X16. Again, the characters ° and Ω are not defined, so I had to create and add my own 8×16 character bitmaps.

From these three classes (SSD1306_OLED_HW_I2C_LIB, SSD1306_OLED_HW_I2C_LIB_PRINT and SSD1306_OLED_HW_I2C_LIB_PRINT_8X16) I derived the more Arduino friendly classes, which include begin(), clear(), setCursor(), etc, as well as cursor mode control and character size selection:

  • Small_SSD1306
  • Small_SSD1306_Print
  • Small_SSD1306_Print_8x16

Note that I have not published any of the libraries listed above, due to their experimental, and duplicative, nature. Instead, I have made a much more manageable series of classes, available on Github, see SSD1306_OLED_HW_LIB2 and the blog SSD1306_OLED_HW_LIB2.

Notes

The following issues were encountered:

  1. If write() does not return 1, or the return statement/value is omitted completely, then only the first character of a string is printed, see Re: 5V IIC/I2C/TWI LCD Module Adapter For Arduino from eBay (which is linked to from Re: I2C LCD only prints first character of the string)

Other minor issues:

  1. Character cursor placement, of the SSD1306_OLED_HW_I2C code, in the Y axis is already in character mode (due to the memory pages of the SSD1306), i.e. in multiples of 8 pixels, whereas the X axis is single pixel based
  2. Design of the ° and Ω characters – non UTF8 values for the character codes are used
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s