Multiple SSD1306 OLED Displays

Hey all! I'm moderately new to Arduino coding and attempting to measure the CO2 concentration, temperature, and humidity of a controlled environment for a project. I've been reading the forums regarding the U8glib by Oliver to control the two OLED screens separately, but I keep getting the following error: "undefined reference to `I2C_SLA' collect2.exe: error: ld returned 1 exit status." I've tried uninstalling Arduino, the other used libraries, and even tried testing the code on a different laptop that has never had Arduino installed, and I get the same error message. I tested the code from post #7 on this forum on the new laptop before installing any other libraries and get the same error.

Here is the code I am attempting to use for the project:

#include <Adafruit_SCD30.h>
#include <Adafruit_SSD1306.h>
#include <U8glib.h>

Adafruit_SCD30  scd30;
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);
U8GLIB_SSD1306_128X32 u8g1(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
U8GLIB_SSD1306_128X64 u8g3(U8G_I2C_OPT_NO_ACK);

extern uint8_t I2C_SLA;

float str;

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10);

  Serial.println("Adafruit SCD30 test!");

  // Try to initialize!
  if (!scd30.begin()) {
    Serial.println("Failed to find SCD30 chip");
    while (1) { delay(10); }
  }
  Serial.println("SCD30 Found!");

  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  if (!scd30.setMeasurementInterval(2)){
    Serial.println("Failed to set measurement interval");
    while(1){ delay(10);}
  }
  Serial.print("Measurement Interval: "); 
  Serial.print(scd30.getMeasurementInterval()); 
  Serial.println(" seconds");

  display.display();
  delay(500); // Pause for half second

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setRotation(0);

  //I2C_SLA = 0x07A;
  //u8g3.begin();
  u8g1.begin();
  I2C_SLA = 0x03c;

}

void loop() {
  if (scd30.dataReady()){
    display.clearDisplay();
    display.setCursor(0,0);
    display.setTextSize(1);
    
    Serial.println("Data available!");

    if (!scd30.read()){ 
      Serial.println("Error reading sensor data");
      display.println("READ ERR");
      display.display();
      return;
      }

    Serial.print("Temperature: ");
    Serial.print(scd30.temperature);
    Serial.println(" degrees C");
    
    Serial.print("Relative Humidity: ");
    Serial.print(scd30.relative_humidity);
    Serial.println(" %");
    
    Serial.print("CO2:   ");
    Serial.print(scd30.CO2, 3);
    Serial.println(" ppm");
    Serial.println("");
    
    display.print("CO2:   ");
    display.print(scd30.CO2, 0);
    
    display.println(" ppm");

    display.print("TEMP:  ");
    display.print(scd30.temperature, 2);
    display.println(" C");

    display.print("HUMID: ");
    display.print(scd30.relative_humidity, 2);
    display.println("%");
    
    display.display();
  } 

  delay(100);
}

Hi @techjunkie3,

you have declared I2C_SLA as an extern variable ...

Do you know in which library it is used? I found a #define I2C_SLA 0x3c in https://github.com/olikraus/u8glib/blob/master/csrc/u8g_com_i2c.c

You may try to remove (or comment) the two lines

// extern uint8_t I2C_SLA;  // make this a comment
// and later
// I2C_SLA = 0x03c;             // make this a comment

as they seem not to be required in your sketch ....

Update: I looked up the thread you referred to in post #1 and found this

I guess you did not change the line in the U8glib library on your computer from #define to uint8_t as described in post #7 of that thread. This seems to be necessary to be able to address different I2C-Slaves ... No idea if that really works as I2C_SLA is only used in the library part for RaspberryPi ...

Do you really want three SSD1306 displays ?
i.e. 128x32, 128x32, 128x64.

Which Arduino are you using?

Life would be much simpler if you used the same library for all three displays.

David.

I suspect the OLED's have the same I2C address.

Without a special circuit all the I2C devices need their own address, else you cannot tell which one you are writing to.

You can only have 0x3C and 0x3D. i.e. two displays.
The third display needs to be on a separate bus or you use some external electronics.

Thank you for noticing that! I've been trying to fix this for three weeks and that worked wonders!

Well not very special. Wire each of the display's address select pins to a separate output pin. Then have them all set low. When you want to address a specific display put that display's address select pin high, write to the high address and when you have finished put that pin low again.

This will work for any number of devices that have at least one address select pin.

Yes, that is a perfectly good technique. Use one global display object e.g. 0x3C.
When printing to a screen set the address to 0x3C. When finished set back to 0x3D.

This requires SDA, SCL and CS1, CS2, CS3 i.e. 5 GPIO pins.
You would need an extra CS4 pin if you wanted 4 slaves.

Using two buses you don't need to hack any displays.
Requires SDA0, SCL0, SDA1, SCL1. i.e. 4 GPIO pins for up to 4 slaves.

Both approaches are easy to implement. Clearly it gets silly for extra displays. In which case you might consider an I2C multiplexer chip.
e.g. https://www.ebay.co.uk/itm/313603433690

David.

Or perhaps use a port expander to address all those address select lines. It could even be an I2C port expander so the total number of Arduino pins used is still two.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.