Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Two Displays with non-default I2C-Pins at ESP32S3 #2206

Open
ams-hh opened this issue Jun 20, 2023 · 8 comments
Open

Two Displays with non-default I2C-Pins at ESP32S3 #2206

ams-hh opened this issue Jun 20, 2023 · 8 comments

Comments

@ams-hh
Copy link

ams-hh commented Jun 20, 2023

Dear Olikraus
at first: Thank you for this magnificant library and the work you had with it!

I have the following issue:
On a custom board with ESP32-WROOM-32 support two OLED-Display
128x64, SH1106, Ic2-Address 0x3d
128x34, SH1306, Ic2-Address 0x3c

Until now I used the default-Pins SDA:21, SCL:22 for this Microcontroller and everything works as
expected.

Now I've made a PCB rebuild and use ESP32S3-WROOM-1.
Every documatentation said: "You can use every Pins for I2C"
So I did SDA:2, SCL:4
And in the construcor I used the 3rd and 4. Parameter for the GPIO.

And now the trouble started.
The first Line -Output on the first display is working.
When for the second Display the u8g2.begin() is executed, the system hangs until a timeout.
(You call in begin() init_display(). There it hangs.)
And when after the timeout I try to write a second line on the first Display, it does hang as well.

The #defines SDA and SCL are predefined somewhere. When compiled and loaded into an
ESP32-WROOM-32 they show 21/22.
I now learned, when compiled and loaded into an ESP32S3-WROOM-1 they show 8/9.

With my development-system I've made the following tests with the program see below:

**** ES32-WROOM_32: ****
One Display, default-Pins, Constructor without I2C-Pin-Parameter >>> works
One Display, non-default-Pins, Constructor WITH I2C-Pin-Parameter >>> works
Two Displays, default-Pins, Constructor without I2C-Pin-Parameter >>> works
Two Displays, non-default-Pins, Constructor WITH I2C-Pin-Parameter >>> works

**** ES32S3-WROOM-1: ****
One Display, default-Pins, Constructor without I2C-Pin-Parameter >>> works
One Display, default-Pins, Constructor WITH I2C-Pin-Parameter >>> works

Two Displays, default-Pins, Constructor without I2C-Pin-Parameter >>> works
Two Displays, default-Pins, Constructor WITH I2C-Pin-Parameter >>> hangs at Second Display begin()
Two Displays, non-default-Pins, Constructor WITH I2C-Pin-Parameter >>> hangs at Second Display begin()

So it seems to be dependend form the use of the constructor parameters for SCL/SDA GPIO.

I could now redesign the PCB once again and use 8/9.
Or do you have an idea how to solve this other way?
Thank you in advance and regards from Hamburg
Andree


Test-Program.
Use #define (un)commenting for the Test cases.

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


#define TWODISPLAYS
#define INIT_WITH_SCL_SDA

//ESP32-WROOM32 Default
//#define         I2C_SDA                     21
//#define         I2C_SCL                     22

//ESP32S3-WROOM-1 Default
//#define         I2C_SDA                     8
//#define         I2C_SCL                     9


//Test-Pins ESP32-WROOM-32
//#define         I2C_SDA                     17
//#define         I2C_SCL                     18

//Test-Pins ESP32-S3-WROOM-1
#define         I2C_SDA                     2
#define         I2C_SCL                     4


#define     OLED_SYSMON_I2CADDR             0x3d // !!7-Bit-Address
#define     OLED_GPIOMON_I2CADDR            0x3c // !!7-Bit-Address


#ifdef INIT_WITH_SCL_SDA
    U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2A(U8G2_R2      ,
                                             U8X8_PIN_NONE,  // Reset
                                             I2C_SCL      ,  // SCL
                                             I2C_SDA      ); // SDA
#else
    U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2A(U8G2_R2      ,
                                             U8X8_PIN_NONE); // Reset
#endif

#ifdef TWODISPLAYS
    #ifdef INIT_WITH_SCL_SDA
        U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2B(U8G2_R2                 ,
                                                     U8X8_PIN_NONE,  // Reset
                                                     I2C_SCL      ,  // SCL
                                                     I2C_SDA      ); // SDA
    #else
        U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2B(U8G2_R2      ,
                                                     U8X8_PIN_NONE);
    #endif
#endif


void setup()
{
    Serial.begin(115200);

    #ifdef TWODISPLAYS
        Serial.println(" >>>>>>>>> Startet TWO-Display-Test");
    #else
        Serial.println(" >>>>>>>>> Startet ONE-Display-Test");
    #endif
    #ifdef INIT_WITH_SCL_SDA
        Serial.println("Construct U8G2-Object with SDA/SCL  >>> Use #defined I2C_SCL/I2C_SDA");
    #else
        Serial.println("Construct U8G2-Object WITHOUT SDA/SCL  >>> Use Default");
    #endif


    Serial.printf("Default SDA/SCL: %d/%d\n", SDA, SCL);
    #ifdef INIT_WITH_SCL_SDA
        #if (SDA!= I2C_SDA)
            Serial.printf("Defined SDA/SCL: %d/%d\n", I2C_SDA, I2C_SCL);
        #endif
    #endif


    Serial.println("First Display, First Line");

    Serial.println(">>> 1a");
    u8g2A.setI2CAddress(OLED_SYSMON_I2CADDR << 1);
    Serial.println(">>> 1b");
    u8g2A.begin();
    Serial.println(">>> 1c");
    u8g2A.clearBuffer();

    Serial.println(">>> 2");
    u8g2A.setFont(u8g2_font_ncenB08_tr);	// choose a suitable font
    Serial.println(">>> 3");
    u8g2A.drawStr(0,10,"Hello World-1-1!");	// write something to the internal memory
    Serial.println(">>> 4");
    u8g2A.sendBuffer();					// transfer internal memory to the display
    Serial.println(">>> 5");
    delay(1000);


#ifdef TWODISPLAYS
    Serial.println("Second Display, First Line");

    Serial.println(">>> 1a");
    u8g2B.setI2CAddress(OLED_GPIOMON_I2CADDR << 1);
    Serial.println(">>> 1b");
    u8g2B.begin();
    Serial.println(">>> 1c");
    u8g2B.clearBuffer();

    Serial.println(">>> 2");
    u8g2B.setFont(u8g2_font_ncenB08_tr);	// choose a suitable font
    Serial.println(">>> 3");
    u8g2B.drawStr(0,10,"Hello World-2-1");	// write something to the internal memory
    Serial.println(">>> 4");
    u8g2B.sendBuffer();					// transfer internal memory to the display
    Serial.println(">>> 5");
    delay(1000);
#endif


    Serial.println("First Display, 2nd Line");
    Serial.println(">>> 6");
    u8g2A.drawStr(0,20,"Hello World-1-2!");	// write something to the internal memory
    Serial.println(">>> 7");
    u8g2A.sendBuffer();					// transfer internal memory to the display
    delay(1000);


#ifdef TWODISPLAYS
    Serial.println("Second Display, 2nd Line");

    Serial.println(">>> 6");
    u8g2B.drawStr(0,20,"Hello World-2-2!");	// write something to the internal memory
    Serial.println(">>> 7");
    u8g2B.sendBuffer();					// transfer internal memory to the display
    delay(1000);
#endif



}

void loop(void)
{
}

@olikraus
Copy link
Owner

U8g2 just passes the arguments to the (none-standard) wire function of the ESP32 board software:

u8g2/cppsrc/U8x8lib.cpp

Lines 1343 to 1354 in 74e379c

#if defined(ESP8266) || defined(ARDUINO_ARCH_ESP8266) || defined(ESP_PLATFORM) || defined(ARDUINO_ARCH_ESP32)
/* for ESP8266/ESP32, Wire.begin has two more arguments: clock and data */
if ( u8x8->pins[U8X8_PIN_I2C_CLOCK] != U8X8_PIN_NONE && u8x8->pins[U8X8_PIN_I2C_DATA] != U8X8_PIN_NONE )
{
// second argument for the wire lib is the clock pin. In u8g2, the first argument of the clock pin in the clock/data pair
Wire.begin((int)u8x8->pins[U8X8_PIN_I2C_DATA] , u8x8->pins[U8X8_PIN_I2C_CLOCK]);
}
else
{
Wire.begin();
}
#else

@ams-hh
Copy link
Author

ams-hh commented Jun 20, 2023

So it seems there is no chance to solve it and the only solution is to redesign the PCB ...

Your code calls Wire.begin() in any case, either with or without SDA/SCL.
I will at least make a test and manipulate the lib so that in the second u8g2.begin() NO Wire.begin is executed,
because Wire.begin has always be done in the first u8g2.begin(). Maybe this helps ...?

Thanks!

@ams-hh
Copy link
Author

ams-hh commented Jun 21, 2023

Got it!
When the FIRST Construtor is called WITH SDA/SCL and the SECOND one is called WITHOUT SDA/SCL then you call in u8x8_byte_arduino_hw_i2c in the second case Wire.begin() without SDA/SCL.
And then it works.
(But I am unsure why. I don't want to dig now into the Wire Code to see what happens then. No way ... it works)

@olikraus
Copy link
Owner

It also sounds strange to me, but I am happy you found a solution :-)

@ams-hh
Copy link
Author

ams-hh commented Jun 21, 2023

Yes.... but maybe its a fluke only ...
So... I think the better way for more than one Display on the same I2C-Bus should be the possibility to announce to u8g2.begin() with a a parameter that the Wire-Interface is already initialized (maybe by a u8g2.begin() before or by an "outside" Wire.begin?) and then insideu8x8_byte_arduino_hw_i2c has not to call Wire.begin() (again).

@olikraus
Copy link
Owner

Yes, i know... that might be better. However the code impact would be huge and I don't have time to change this at the moment.

@FriqueNFraque
Copy link

@ams-hh, Ihave landed on this same issue. using i2c 64x32 OLEDs, with no address pin breakout. Using esp32s1 with dual i2c buses. i have been fighting this issue for years off and on as a hobbyist and assumed i wasn't using the libraries correctly. would you mind posting your code? if the solution is possibly just in the order of operations, would be invaluable to see code that is working. thanks!

@ams-hh
Copy link
Author

ams-hh commented Jan 7, 2024

Hello FriqueNFraque,
at first: You write "with dual I2C". This is for me (as a not native english speaker) ambiguous. Does it mean

  • Two Displays on two pairs of GPIO SDA/SCL? (with identically or different I2C addresses does no matter then ...) or
  • Two Displays WITH two different I2C addresses on ONE pair of GPIO SDA/SCL?

I fought with the second issue.
(No idea if Oli Kraus changed something in the meantime)
As written, I encountered a problem of the Wire Class, when it is called twice with the same SDA/SCL GPIO. The constructor of u8g2 calls Wire internally WHEN THE THIRD and FOURTH parameter is used. So I then called the first constructor for Display A WITH theses parameters and the for DISPLAY B WITHOUT.

                //OLED 128x32 als GPIO-Monitor
                U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C 
                                                u8g2GPIOMon(U8G2_R2      ,
                                                            U8X8_PIN_NONE, /* reset=*/ 
                                                            I2C_SCL      , /* clock=*/ 
                                                            I2C_SDA      );/* data =*/ 

                //OLED 128x64 als Systemmonitor //V07.04.a
                U8G2_SH1106_128X64_NONAME_F_HW_I2C 
                                                u8g2SysMon(U8G2_R2      ,
                                                           U8X8_PIN_NONE); /* reset=*/ 

And after that, start work with:

            u8g2GPIOMon.setI2CAddress(OLED_GPIOMON_I2CADDR << 1);
            u8g2GPIOMon.begin();

and

            u8g2SysMon.setI2CAddress(OLED_SYSMON_I2CADDR << 1);
            u8g2SysMon.begin();

The defines in these examples are:

    #define         I2C_SDA                     42
    #define         I2C_SCL                     2

and

    #define     OLED_SYSMON_I2CADDR           0x3d //ACHTUNG! Echte Adresse wird auf obere 7 Bit abgebildet = 0x7A
    #define     OLED_GPIOMON_I2CADDR          0x3c //ACHTUNG! Echte Adresse wird auf obere 7 Bit abgebildet = 0x78

After that, everything works.
Regards from Hamburg
A.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants