U8G2 with Two SSD1306 OLED Displays

Hi, I need some quick help. I'm trying to connect two SSD1306 OLED displays with Arduino Uno, but don't know how to address them separately. I searched many forums and most of them have tried to it with hardware address hack on the display module itself but with U8G. The modules I have possess no such capability. I read in many forums that U8G2 specifically addresses the issues of multiple displays, but did not find any documentation oh how to integrate them. There is one thread regarding SPI displays, but not the I2C OLED that I’m working with.

This is the display in use:

A typical code like the following works only with one OLED module. How to address two such modules?

#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

void setup(void) {
u8g2.begin();
}

void loop(void) {
  u8g2.firstPage();
  do {
 //Do something
       }
  
    while ( u8g2.nextPage() );
    delay(100);
}

Please help. Thanks.

Take a look at post #89 of this thread....

http://forum.arduino.cc/index.php?topic=219419.75

borland:
Take a look at post #89 of this thread....

Problem with SSD1306 LCD and U8glib - Displays - Arduino Forum

Thanks borland for the reply. Seems like the method is suggested for an OLED module with selectable address. Unfortunately the modules I have do not have such an option. I read U8G2 FAQs and the following code is suggested alongwith authorial comments:

Q: How can I use multiple SPI Displays?
A: For each additional display, separate CS (Chip select) and RST (Reset) lines are required.

// Setup display1 and display2
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI display1(U8G2_R0, /*CLK*/ 18, /*MOSI*/ 23, /*CS*/ 16,
                                                /*DC*/ 17, /*RS*/ 4);
U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI display2(U8G2_R0, /*CLK*/ 18, /*MOSI*/ 23, /*CS*/ 15,
                                            /*DC*/ 17, /*RS*/ 4);    
```
Ensure that the buffer is sent after printing with each display as follows.

```C++
    display1.begin();
    display2.begin();
    
    display1.setCursor(64, 32);
    display1.print("DISPLAY 1");
    display1.sendBuffer();
    
    display2.setCursor(64, 32);
    display2.print("DISPLAY 2");
    display2.sendBuffer();

I'm not well versed in display technology and related protocols, but seems like I need a different module with additional two pins namely, CS and RST. Does that mean I can opt for either of the following modules?


or

Thanks.

You could probably remove one of the resistors on the back to change the I2C address which would be specified in the manufacturer's datasheet for that display module. It's probably only available in Chinese language.

I've seen some SPI/I2C displays that have a key silkscreened on the back giving enough info for you be able to change the I2C address or set usage between SPI or I2C serial communications via jumpers or remove/place resistors. Before making another purchase, best to just look at all the available display module options on supplier web pages (like Adafruit.com or SparkFun.com) or on eBay.

According to the SSD1306 datasheet, the I2C address can be set between two different addresses by the D/C pin. Your module's header pins do not provide the D/C pin, but you could look at the SSD1306 datasheet and figure out how/if your module is wired (hint: trace the foil pinouts that are directly soldered to the PCB). Pin D/C may be pulled high or low with a resistor to ground or Vcc.

Here's a copy of the SSD1306 datasheet someone has posted:

borland:
According to the SSD1306 datasheet, the I2C address can be set between two different addresses by the D/C pin. Your module's header pins do not provide the D/C pin, but you could look at the SSD1306 datasheet and figure out how/if your module is wired (hint: trace the foil pinouts that are directly soldered to the PCB). Pin D/C may be pulled high or low with a resistor to ground or Vcc.

Here's a copy of the SSD1306 datasheet someone has posted:

http://www.buydisplay.com/download/ic/SSD1306.pdf

Thanks for digging the web! I tried to assimilate the datasheet, but I still don't understand how to identify the D/C pin. In principle, if we need is a Chip Selection pin connected to Arduino derived from either pulling up or down the D/C pin on the OLED module, then is it possible that the OLED modules with standard CS pin would work? I'm asking this question because I can still return the modules and replace them with the ones compatible. For that, I need to know if they would work as intended, along with a code that I still don't understand how to implement for two I2C displays. This is still hypothetical to me so I need some clarity of thought.

Thanks.

No, hard wire the D/C pins on each module PCB.

The SSD1306 is the actual OLED part mounted on the module's PCB. The SSD1306 datasheet identifies the ribbon/foil pins of the OLED part. The datasheet is technically written for engineers that need to incorporate the part in their designs (like the designer's of an OLED module).

Easiest is to buy two SPI display modules. If you require I2C, many modules offer option of hard wiring an alternate I2C address.

The code in post #89 is in C++ object oriented language which Arduino uses for it's complier. The code declare two instances of the C++ library, simplifying programming two I2C displays.

Thanks Borland! Considering my programming skills, it would be better if I stay with I2C modules since they are easier to integrate and communicate with. I have a few doubts regarding these display modules. Why are the displays sold as SPI/IIC devices (example)? Are these protocols interchangeable? Is there a practical difference between 6 pin and 7 pin modules? And for my project, can I use this module and simply change the address by swapping the resistor to the adjacent location?

Thanks again for all your efforts!

Yes, that module offers hard wiring, providing option for one alternate I2C address. You may have difficulty un-solder and re-solder the option, as those resistors are very small.

Since your using a display library, both SPI and I2C are easy to implement. I2C has fewer hookup wires, but SPI is a much faster display. I2C termination can be problematic when using multiple I2C devices; you may after experimentation, need to provide additional pull up resistor.

eBay prices can be very low, but be careful buying displays or other Arduino modules, as most Asian sellers are selling items without any knowledge of the product, and photos or descriptions can be inaccurate. Since eBay buyer protection can get you a refund without actually returning the item (seller pays return shipping for damaged or "not as described" items), long shipping times and wrong item shipped can be frustrating or not worth the trouble.

I think most of the questions are answered. I just want to point out one more solution: If speed is not an issue, you can use U8g2 software emulated I2C to control two displays with the same address. Just connect your two displays with two different pairs of pin. For example connect one display to pins 2 (SCL) and 3 (SDA) and the other display to 4 (SCL) and 5 (SDA).

U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2_a(U8G2_R0, /* clock=*/ 2, /* data=*/ 3, /* reset=*/ U8X8_PIN_NONE);
U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2_b(U8G2_R0, /* clock=*/ 4, /* data=*/ 5, /* reset=*/ U8X8_PIN_NONE);

After this, you can use u8g2_a and u8g2_b to write to the two displays.

Of course you could also use hardware I2C with one of the displays.

Different I2C addresses are only required if you want to connect two displays at the same pair of pins.

Oliver

Yes, that module offers hard wiring, providing option for one alternate I2C address. You may have difficulty un-solder and re-solder the option, as those resistors are very small.

Since your using a display library, both SPI and I2C are easy to implement. I2C has fewer hookup wires, but SPI is a much faster display. I2C termination can be problematic when using multiple I2C devices; you may after experimentation, need to provide additional pull up resistor.

eBay prices can be very low, but be careful buying displays or other Arduino modules, as most Asian sellers are selling items without any knowledge of the product, and photos or descriptions can be inaccurate. Since eBay buyer protection can get you a refund without actually returning the item (seller pays return shipping for damaged or "not as described" items), long shipping times and wrong item shipped can be frustrating or not worth the trouble.

Thanks Borland, as you suggested, seems like SPI is a better option out of the two. I understand the technical ambiguity that surrounds devices sold on ebay. Unfortunately, Amazon lacks diversity that ebay offers. As for the choice of protocol itslef, please also confirm that if I apply SPI modules, I won't have to change the address on the module itself since as I read (2nd post), an SPI display could be addressed individually through the CS pin. If I have hypothesized this correctly, then the following code from this thread should work.

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8);      // pin 10 has nothing attached since the module is always selected
U8GLIB_SSD1306_128X64 u8g2(5, 4, 7, 3, 2);      // pin 7 has nothing attached since the module is always selected
void setup() {
  // put your setup code here, to run once:
  if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);       // pixel on
  }
}
void draw(void) {
  // graphic commands to redraw the complete screen should be placed here
  u8g.setFont(u8g_font_unifont);
  //u8g.setFont(u8g_font_osb21);
  u8g.drawStr( 0, 22, "Hello");
}
void draw2(void) {
  u8g2.setFont(u8g_font_unifont);
  u8g2.drawStr( 0, 22, "World");
}
void loop(void) {
  // put your main code here, to run repeatedly:
  u8g.firstPage();
  do {
    draw();
  }
  
  while ( u8g.nextPage() );
  u8g2.firstPage();
  do {
    draw2();
  }
  
  while ( u8g2.nextPage() );
  delay(100);
}

}

Under these assumptions, should I go ahead and make a purchase for this OLED module?

I think most of the questions are answered. I just want to point out one more solution: If speed is not an issue, you can use U8g2 software emulated I2C to control two displays with the same address. Just connect your two displays with two different pairs of pin. For example connect one display to pins 2 (SCL) and 3 (SDA) and the other display to 4 (SCL) and 5 (SDA).

Thank you Olikraus for the valuable input. I shall keep this in mind should the need arise for two I2C displays to be run without hardware modification. I intend to stay with one approach for integrating multiple displays with Arduino, it saves me the time to deal with different hardware setups which otherwise would eventually affect the objective. I tend to repurpose existing ones, so its more convenient and economical if less hardware requires modification. In this case, I may require better refresh rate, so would have to eventually replace the modules to begin with. I hope that an SPI display would eliminate the need of hardware modification and is addressable uniquely through the code.

Thanks.

Any suggestion would be of great help!

Antrix:
Any suggestion would be of great help!

Suggestion for what? Your four pin OLED will work and the refered 7 pin OLED will also work in a two display configuration.

Olvier

Thanks Oliver and Borland for your help and all memebers who have contributed to this forum. Finally, the two SPI OLED displays worked with a little tweaking to the code discussed in this thread. Below is the minimalistic code in case someone requires it:

/*
   U8G2 TWO OLED SPI DISPLAY (MINIMALISTIC)
   HARDWARE: ARDUINO UNO, SSD1306 SPI (7PIN) MODULES
   Updated on 11/22/17
   ARDUINO OLED INTERFACE:
   1st OLED
   13 - D0
   11 - D1
   10 - CS
   9 - DC
   8 - RES
   2nd OLED
   13 - D0
   11 - D1
   7 - CS
   6 - DC
   5 - RES

   The Random number generator is merely to differentiate the two displays and ensure that they are working in HW mode.
   PIN-13 and PIN-11 are common for both OLED modules. No seperate power lines are necessary.
*/

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
long randNumber1;
long randNumber2;

U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI OLED1(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI OLED2(U8G2_R0, /* cs=*/ 7, /* dc=*/ 6, /* reset=*/ 5);
void setup() {
  OLED1.begin();
  OLED2.begin();
  // put your setup code here, to run once:

}
void draw(void) {

  OLED1.setFont(u8g_font_unifont);
  OLED1.drawStr( 0, 22, "DISPLAY 1");
  OLED1.setFont(u8g2_font_7x14B_mr);
  OLED1.setCursor(1, 40);
  OLED1.print(randNumber1);
}
void draw2(void) {
  OLED2.setFont(u8g_font_unifont);
  OLED2.drawStr( 0, 22, "DISPLAY 2");
  OLED2.setFont(u8g2_font_7x14B_mr);
  OLED2.setCursor(1, 40);
  OLED2.print(randNumber2);
}
void loop(void) {
  // put your main code here, to run repeatedly:

  randNumber1 = random(0, 255);
  randNumber2 = random(0, 255);
  
  OLED1.firstPage();
  do {
    draw();
  } while ( OLED1.nextPage() );
  OLED2.firstPage();
  do {
    draw2();
  } while ( OLED2.nextPage() );
  delay(100);
}

Thanks again!

Thanks for the feedback.

Oliver

Hi,

is there and easy way how to add SPI displays to array? I will have more of them and it will be easier to handle them.
I tried this

U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI u8g[]={  U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI(12, 11, 8, 9, 10),
                                               U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI(12, 11, 6, 9, 10)};

And I reaceive error/warning

display_SPI_arrayv2\display_SPI_arrayv2.ino:5:102: warning: invalid conversion from 'int' to 'const u8g2_cb_t* {aka const u8g2_cb_struct*}' [-fpermissive]
U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI u8g[]={ U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI(12, 11, 8, 9, 10),
In file included from display_SPI_arrayv2.ino:1:0:
\Arduino\libraries\U8g2\src/U8g2lib.h:1166:11: note: initializing argument 1 of 'U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI::U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI(const u8g2_cb_t*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t)'public: U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI(const u8g2_cb_t rotation, uint8_t clock, uint8_t data, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE) : U8G2() {
\Arduino\display_SPI_arrayv2\display_SPI_arrayv2.ino:6:103: warning: invalid conversion from 'int' to 'const u8g2_cb_t
{aka const u8g2_cb_struct*}' [-fpermissive] U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI(12, 11, 6, 9, 10)};

Thanks

You can do something like this

U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI u8g2_1(U8G2_R0, 12, 11, 8, 9, 10);
U8G2_SH1106_128X64_NONAME_1_4W_SW_SPI u8g2_2(U8G2_R0, 12, 11, 8, 9, 10);

U8G2 *u8g2_array[] =  {&u8g2_1, &u8g2_2};

But then you need to use "->" instead of ".", like u8g2_array[0]->print().

Oliver