What's the difference between Adafruit SSD1306 and SH1106?

Hey all! I've scoured some pretty sketchy sites in search of this, and haven't found anything concrete. I have a need to use Adafruit's SSD1306 library for my OLED displays. The problem? I'm using these cheap ones which only support SH1106: Amazon.com

I hear that there isn't much difference between the two libraries, but there's enough to cause me problems. Does anyone know what I ought to do to modify SSD1306 so that it works with my displays?

I know it's a long shot, but I'd appreciate any help!

I have here one cheap OLED screen like that and I'm using the library from Adafruit too, and without problems. I saw this:

video too, and it seems like yours, an he are using that library too.

Hi luisilva, thanks for responding. That was a handy video! Unfortunately, I can't get my display to work in the same way that the guy in the video did. The reason being that I'm actually using a Spark Core (www.spark.io) to run the display, which has a much more limited library selection than the Arduino. I don't mean to derail an arduino forum, however, which is why I was specifically asking about the differences between the SSD1306 and SH1106 libraries.

At present, using SSD1306 yields the very same issu as this person's: Support for 132x64 display · Issue #14 · adafruit/Adafruit_SSD1306 · GitHub That's the only place I've been able to find somebody else with the same issue of the screen being filled with junk, btw. However, that person's issues were solved by simply switching to the u8glib. I'd love to do just that, but u8glib isn't compatible with Spark. Hence me trying to figure out a way to modify the existing SSD1306 library to be compatible with my display.

Thanks again for any insight!

OK. Now I understand. From this discussion:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=1150108

They point out this library:

There is only one small difference between SSD1306 and SH1106: The SH1106 controller has an internal RAM of 132x64 pixel. The SSD1306 only has 128x64 pixel.

First problem for standard 128x64 OLEDs with SH1106 controller is: How is the 128x64 window mapped into the 132x64 RAM?
It seems, that the 128x64 OLED is centered in most cases within the 132x64 area, that means pixel (2,0) in ram is pixel (0,0) on the display.

For u8glib, the update for the SH1106 was very small. I just had to shift the display by 2 pixel. This is more complicated with the Adafruit lib. Mainly the procedure "Adafruit_SSD1306::display(void)" depends very much on the hardware architecture and assumes, that the width of the RAM area is 128 (which is wrong for the SH1106). I think the procedure Adafruit_SSD1306::display(void) needs to be rewritten completly (including the commands, which are sent).

Oliver

Hey Oliver,

Thanks for the response! That's a super helpful starting point, something I never would have guessed. I'll have a look at Adafruit's display() method this evening, and see if I can't get something hacked together.

And luisilva, I did see that thread a day or two ago, but I haven't had time to test/tinker with multiLCD yet. Looks like we were on the same track though!

So, I've done a bit of hacking at the SSD1306 library, but so far haven't had any improvement (or even change) in results. The screen is still filled primarily (about 80% of it) with junk.

The main thing I tried was expanding buffer[] to 1056 elements from 1024 elements (that's 132 * 64 / 8, rather than 128 * 64 / 8 ). From there, I tried different combinations of changing SSD1306_LCDWIDTH to 132, keeping it the same but making the for loops in display() and clearDisplay() loop through 1056 times rather than 1024 times, as in the lines that say:

for (uint16_t i=0; i<(SSD1306LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {

However, I completely forgot to mess with the command() calls at the top of display(). Whoops! I'll do that as well once I get home this evening - trying command(0) and command(131), as opposed to command(127), would make sense, no?

I'm still in the process of studying the library/learning how it all works, so forgive me if I sound like a complete newbie. Is there anything else/any other areas of the code that I should play around with?

In fact I do not much about the Adafriut library. But what i have seen the commands might need to be adjusted. Best is to study the commands, which are sent by the Adafruit lib and update them according to the display. It also seems that some internal drawing area is defined. This usually is not required if this is the case.
I also think that it is better to draw each page (128x8 pixel area) individually instead of writing all the 128x64 pixel at once. That means i think it is better to use two nested loops instead of one loop. This would also allow you to send commands at the begin of the page:

for( page = 0; page < 8; page ++ ) {
  // send commands to place cursor at the correct page start position
  for( i = 0; i < 128; i++ ) {
    // write page
  }
}

Oliver

Now I really understand your question, because I had the same issue. I simply change my library from Adafruit to u8glib. Do you get to something? Do you want to share your result?

Hi,

For those who're interested, I've just update my port of Adafruit Library to be able to run with SH1106. I started with the one dedicated to Raspberry PI
you can check out here

I did not forked the Arduino one, but you can get into the source code, the modified part are only the begin and display methods of SSD1306 class to add SH1106 compatibility.

Does anybody already did Adafruit lib fork working with 132x64 SH1106 ?

I know I'm reviving an old thread with such a late reply, but I stumbled upon this today after trying to get my Taiwan-manufactured, Amazon-bought OLED to work. It's a 1.3" B&W OLED display with a SH1106 driver with 4 pins—SCL, SDA, VCC (+5V), and GND. The problem I had was that only about the top eighth of the screen "worked" while the rest just displayed jumbled, stationary white noise.

After doing the tiniest bit of Googling, I found a solution by a Github user called wonho-maker:

Download that library and place it in the correct directory and your OLED should work. It's a modified version of Adafruit's SSD1306 library and works in tandem with Adafruit's GFX library.

I hope this response helps future users that may run into the same problem! :slight_smile:

cosined:
I hope this response helps future users that may run into the same problem! :slight_smile:

hiya!

thanks!

i tried that - but get - fatal error: avr/pgmspace.h: No such file or directory?

i tried that - but get - fatal error: avr/pgmspace.h: No such file or directory?

Since you only posted part of the error messages, I'll only post part of the answer.

You need to

Is that enough?

1 Like

PaulS:
Since you only posted part of the error messages, I'll only post part of the answer.

You need to

Is that enough?

yes, you are correct.

the other part of the error is:

Adafruit_SH1106.cpp:29:26:

EDIT - so i edited the Adafruit_SH1106.cpp file to remove the avr/ path and now it needs a delay.h file:

Adafruit_SH1106.cpp:31:25: fatal error: util/delay.h: No such file or directory

 #include <util/delay.h>

now i'm hunting down a delay.h to include...

EDIT - so i edited teh lines in SH1106.cpp from:

#ifndef __SAM3X8E__
#include <util/delay.h>
#endif

to:

#ifdef __avr__
 #include <util/delay.h>
#endif

and now it is saying this:

Arduino: 1.8.4 (Windows 10), Board: "Generic ESP8266 Module, 80 MHz, 40MHz, DIO, 115200, 4M (1M SPIFFS), ck, Disabled, None"

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp: In member function 'void Adafruit_SH1106::begin(uint8_t, uint8_t, bool)':

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp:182:17: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'PortReg* {aka volatile unsigned char*}' in assignment

    csport      = portOutputRegister(digitalPinToPort(cs));

                ^

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp:184:17: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'PortReg* {aka volatile unsigned char*}' in assignment

    dcport      = portOutputRegister(digitalPinToPort(dc));

                ^

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp:190:19: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'PortReg* {aka volatile unsigned char*}' in assignment

      clkport     = portOutputRegister(digitalPinToPort(sclk));

                  ^

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp:192:19: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'PortReg* {aka volatile unsigned char*}' in assignment

      mosiport    = portOutputRegister(digitalPinToPort(sid));

                  ^

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp: In member function 'void Adafruit_SH1106::display()':

C:\Users\Toshi2\Documents\Arduino\libraries\Adafruit_SH1106-master\Adafruit_SH1106.cpp:554:28: error: 'TWBR' was not declared in this scope

      uint8_t twbrbackup = TWBR;

                           ^

exit status 1
Error compiling for board Generic ESP8266 Module.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

OK - so i have found u8g2 :slight_smile:

compile errors once again are a blessing in disguise...

olikraus:
There is only one small difference between SSD1306 and SH1106: The SH1106 controller has an internal RAM of 132x64 pixel. The SSD1306 only has 128x64 pixel.

Ok, I know this thread is ancient, but I've not seen this answered succinctly, so here it is.

The SSD1306 has an expanded command set over the SH1106.
The SH1106 only supports page addressing mode
The SSD1306 added special horizontal and vertical addressing modes.
The SSD1306 also has capability for automatic scrolling.

If you (or your library) uses page addressing mode, it will work with either of the contollers (with the difference of line length, 128 vs. 132).
If you (or your library) uses horizontal or vertical addressing mode it will only work on the SSD1306.

Just a heads up if you are using multiple of those displays:

They have FIXED I2C addresses that are all the same (0x3C I believe) , so if you are using multiple, you will need to find an I2C multiplexer to interface them so they don't all get the exact same instruction.

Good luck with your project!

amarotica:
They have FIXED I2C addresses that are all the same (0x3C I believe)

You can select between 0x3C and 0x3D or use SPI on the SSD1306.