Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 11 of 11

Thread: Adafruit SSD1306 multiple instances issue?

  1. #1
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    115

    Adafruit SSD1306 multiple instances issue?

    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:
    Click image for larger version. 

Name:	IMG_20181203_210236-min.jpg 
Views:	58 
Size:	56.4 KB 
ID:	15278

    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...
    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"?
    Click image for larger version. 

Name:	IMG_20181203_210301-min.jpg 
Views:	79 
Size:	114.3 KB 
ID:	15279

    I'm supposing that ONLY .begin and .display functions are "address sensitive"... Is it possible?
    Thank you!

  2. #2
    Senior Member
    Join Date
    Jan 2013
    Posts
    184
    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.

  3. #3
    Junior Member
    Join Date
    Mar 2017
    Location
    Colorado Springs, CO
    Posts
    12
    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.

  4. #4
    Junior Member
    Join Date
    Mar 2017
    Location
    Germany
    Posts
    18
    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.

  5. #5
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    115
    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...

  6. #6
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    115
    Quote Originally Posted by markonian View Post
    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.

  7. #7
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,590
    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.

  8. #8
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,590
    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.

  9. #9
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    115
    Quote Originally Posted by Theremingenieur View Post
    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

  10. #10
    Senior Member Sandro's Avatar
    Join Date
    Nov 2016
    Location
    Rimini - Italy
    Posts
    115
    Quote Originally Posted by Theremingenieur View Post
    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!

    Quote Originally Posted by Theremingenieur View Post
    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!

  11. #11
    Senior Member+ Theremingenieur's Avatar
    Join Date
    Feb 2014
    Location
    Colmar, France
    Posts
    2,590
    Glad that I could help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •