Adafruit SSD1306 multiple instances issue?

Status
Not open for further replies.

Sandro

Well-known member
Hi all,
In my project, with the amazing Teensy 3.6, I'm using #2 I2C OLED displays 32x128, cause I'm not able to make this guy work:
IMG_20181203_210236-min.jpg

One display has its original I2C address 3C, the other 3D (obtained by changing the position of a 4.7K resistor on the small board).

I'm facing an issue even with this super simple configuration... :confused:
Does anyone know why using in this test code:

Code:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET 4

Adafruit_SSD1306 display_R(OLED_RESET); // Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display_L(OLED_RESET); // Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

void setup()
{
  display_L.begin(SSD1306_SWITCHCAPVCC, 0x3D);  // I2C address 0x3D for LEFT display
  display_R.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // I2C address 0x3C for RIGHT display
  display_L.clearDisplay(); // clears Adafruit logo 
  display_R.clearDisplay(); // clears Adafruit logo
  display_L.display(); // empty screen
  display_R.display(); // empty screen
  
  display_R.setTextSize(1);
  display_R.setTextColor(WHITE);
  display_R.setCursor(0, 30);
  display_R.print("RIGHT DISPLAY"); 
  display_R.display();
  delay(2000);
  display_L.display();
}

void loop()
{
}

after 2 seconds both displays demand to be the only "RIGHT DISPLAY"?
IMG_20181203_210301-min.jpg

I'm supposing that ONLY .begin and .display functions are "address sensitive"... Is it possible?
Thank you!
 
I've not looked at the code for very long but I see a potential issue. Both displayed are using the same reset pin? I don't know when the reset pin is asserted (I've not looked at the library code), but let's say it's in the begin() member function of the corresponding display objects. That means the following sequence happens:

1. display_L.begin() is called.
1.1 reset pin is pulsed, but since both displayed are connected to the same pin, both displays are reset.
1.2 the rest of display_L is initialized
2. display_R.begin() is called.
2.1 reset pin is pulsed, but since both displayed are connected to the same pin, both displays are reset.
2.2 the rest of display_R is initialized.

Note that the display_L hardware is reset twice. Once before and once after the code initializes the display_L object. This is surely not what the library author intended.

Suggestion: Use separate pins to allow each display to be reset individually.

I don't know if that is the cause of the issue you are seeing, but I might be.
 
I too was seeing similar issues when using two displays using the SPI interface. Thanks to markonian, using separate reset and chip select pins seems to have fixed the issue. I have not done extensive testing but both displays now I am able to display different text with no issues to two displays.
 
I think markonian figured it out. Generally the reset pin is not absolutely needed, so for a quick try you could set OLED_RESET to -1, the library then will not use the reset pin.
 
I tried with OLED_RESET = -1:
Code:
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1

Adafruit_SSD1306 display_R(OLED_RESET); // Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display_L(OLED_RESET); // Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

void setup()
{
  display_L.begin(SSD1306_SWITCHCAPVCC, 0x3D);  // I2C address 0x3D for LEFT display
  display_R.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // I2C address 0x3C for RIGHT display
  display_L.clearDisplay(); // clears Adafruit logo 
  display_R.clearDisplay(); // clears Adafruit logo
  display_L.display(); // empty screen
  display_R.display(); // empty screen
  
  display_R.setTextSize(1);
  display_R.setTextColor(WHITE);
  display_R.setCursor(0, 30);
  display_R.print("RIGHT DISPLAY"); 
  display_R.display();
  delay(2000);
  display_L.display();
}

void loop()
{
}

And with two (random) values:
Code:
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Adafruit_SSD1306 display_R(1); // Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display_L(2); // Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

void setup()
{
  display_L.begin(SSD1306_SWITCHCAPVCC, 0x3D);  // I2C address 0x3D for LEFT display
  display_R.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // I2C address 0x3C for RIGHT display
  display_L.clearDisplay(); // clears Adafruit logo 
  display_R.clearDisplay(); // clears Adafruit logo
  display_L.display(); // empty screen
  display_R.display(); // empty screen
  
  display_R.setTextSize(1);
  display_R.setTextColor(WHITE);
  display_R.setCursor(0, 30);
  display_R.print("RIGHT DISPLAY"); 
  display_R.display();
  delay(2000);
  display_L.display();
}

void loop()
{
}

but the behave remains the same...:confused:
 
Note that the display_L hardware is reset twice. Once before and once after the code initializes the display_L object. This is surely not what the library author intended.

Hi markonian,
I belive that this cannot be avoided, otherwise the Adafuit logo remains on the screen.
 
It might be that it's not a reset problem, but rather that the SSD1306 library is not instance safe, defining the write buffer as static. That would mean that every time you use .write("something"), it would go into the same buffer without distinguishing if you did .write() on the right or the left OLED. As soon as you call .display() for either OLED, it would display the content of the common write buffer. To work around that without deep hacking the library, the strategy would be:

right.write("...");
right.display("...");
left.write("..."); // eventually find a way to clear the write buffer before
left.display();
...and so on.

I'm at work now, can't look at the library's source code.
 
Found it. It's not in the SSD1306 library. It's in the Wire library which is used to handle the I2C communication between the SSD1306 lib and the OLEDs. There is (as I suspected) only one buffer. That means left.write() and right.write() will go into the same buffer. As soon as you call left.display() or right.display(). The content of the (common) buffer will be sent to the corresponding display.

That must not be a problem, you'll have just to do another write("something") after each .display() to re-initialize the buffer, so that the previous content does not land on the second display.
 
It might be that it's not a reset problem, but rather that the SSD1306 library is not instance safe, defining the write buffer as static. That would mean that every time you use .write("something"), it would go into the same buffer without distinguishing if you did .write() on the right or the left OLED. As soon as you call .display() for either OLED, it would display the content of the common write buffer. To work around that without deep hacking the library, the strategy would be:

right.write("...");
right.display("...");
left.write("..."); // eventually find a way to clear the write buffer before
left.display();
...and so on.

I'm at work now, can't look at the library's source code.

Hi Theremingenieur, yes this workaround is exactly what I'm doing to overcome the issue, and works perfectly ;)
 
Found it. It's not in the SSD1306 library. It's in the Wire library which is used to handle the I2C communication between the SSD1306 lib and the OLEDs. There is (as I suspected) only one buffer. That means left.write() and right.write() will go into the same buffer. As soon as you call left.display() or right.display(). The content of the (common) buffer will be sent to the corresponding display.

Good that the issue is addressed!

That must not be a problem, you'll have just to do another write("something") after each .display() to re-initialize the buffer, so that the previous content does not land on the second display.
Yes I agree this is a perfect workaround.
Thank you!
 
Status
Not open for further replies.
Back
Top