tttapa / Control-Surface

Arduino library for creating MIDI controllers and other MIDI devices.
GNU General Public License v3.0
1.24k stars 139 forks source link

Does the library support multiplexers for the OLED modules? #158

Open d1One opened 4 years ago

d1One commented 4 years ago

Hello, sorry if this is not the right place to ask but I am wondering if the library supports multiplexers for the screens. Such as a TCA9548A, basically to be able to use 4 SSD1306 OLED screens instead of 2 as used in the example.

tttapa commented 4 years ago

Displays are managed through DisplayInterfaces. You can easily change how the data is actually written to the display by overriding the display method:

https://github.com/tttapa/Control-Surface/blob/6ef0fc9e3cf15830989c2f0f75880261be74cfb7/src/Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp#L20

For example (incomplete and untested)

#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>

class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
 public:
  MySSD1306_DisplayInterface(Adafruit_SSD1306 &display, uint8_t muxCh)
    : SSD1306_DisplayInterface(display), muxCh(muxCh) {}

  void begin() override {
    selectMux();
    // Initialize the Adafruit_SSD1306 display
    if (!disp.begin())
      FATAL_ERROR(F("SSD1306 allocation failed."), 0x1306);

    // If you override the begin method, remember to call the super class method
    SSD1306_DisplayInterface::begin();
  }

  void display() override {
    selectMux();
    SSD1306_DisplayInterface::display();
  }

  void drawBackground() override { disp.drawLine(1, 8, 126, 8, WHITE); }

 private:
  uint8_t muxCh;

  void selectMux() {
    // Implement this, use I2C to select the right multiplexer channel
    Wire.write(...);
    Wire.write(muxCh);
  }
} display = ssd1306Display;

In theory, only the begin and display methods communicate with the display over I2C, so these are the only methods that you have to override and add selectMux() to.

anikhossain285 commented 4 years ago

I tried the above solution but nothing shows on display. I have tried adding Serial.print() to see whether it's selecting mux or not. But nothing works. Even tried differently initialisation

#include <Control_Surface.h> // Include the Control Surface library
// Include the display interface you'd like to use
#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>
#include <Wire.h>
// ----------------------------- MIDI Interface ----------------------------- //
USBMIDI_Interface midi;

// ----------------------------- Display setup ------------------------------ //
constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 64;
constexpr int8_t OLED_RESET = -1; // Use the external RC circuit for reset
Adafruit_SSD1306 ssd1306Display_L(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 ssd1306Display_R(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 ssd1306Display_R2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //3rd screen
Adafruit_SSD1306 ssd1306Display_R3(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //4th screen

// --------------------------- Display interface ---------------------------- //
constexpr int8_t muxCh_L = 0; // multiplexer channel for Left Screen
constexpr int8_t muxCh_R = 1; // multiplexer channel for Right Screen
constexpr int8_t muxCh_R2 = 2; //3rd screen
constexpr int8_t muxCh_R3 = 3; //4th screen

class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
  public:
    MySSD1306_DisplayInterface(Adafruit_SSD1306 &display, uint8_t muxCh)
      : SSD1306_DisplayInterface(display), muxCh(muxCh) {}

    void begin() override {
      selectMux();
      // Initialize the Adafruit_SSD1306 display
      if (!disp.begin())
        FATAL_ERROR(F("SSD1306 allocation failed."), 0x3C);

      SSD1306_DisplayInterface::begin();
      //SSD1306_DisplayInterface::begin(SSD1306_SWITCHCAPVCC, 0x3C);
    }

    void display() override {
      selectMux();
      SSD1306_DisplayInterface::display();
    }

    void drawBackground() override {
      selectMux();
      disp.drawLine(1, 8, 126, 8, WHITE);
    }

  private:
    uint8_t muxCh;
    //how the heck do i make this work :(
    void selectMux() {
      Wire.beginTransmission(0x70);
      Wire.write(1 << muxCh);
      Wire.endTransmission();
      Serial.print("Selected mux:");
      Serial.print(muxCh);
    }
} display_L = {ssd1306Display_L, muxCh_L}, display_R = {ssd1306Display_R, muxCh_R}, display_R2 = {ssd1306Display_R2, muxCh_R2}, display_R3 = {ssd1306Display_R3, muxCh_R3};

// ------------------------------- Bank setup ------------------------------- //
// ========================================================================== //

Bank<2> bank(4); // Create a new bank with four tracks per bank

// Create a new bank selector to control the bank using a push button
IncrementSelector<2> bankselector = {bank, 5};

// -------------------------- MIDI Input Elements --------------------------- //
// ========================================================================== //

// Main MCU LCD screen, used to get track names
MCU::LCD<> lcd = {};

// Time display_L keeps track of the bar counter
MCU::TimeDisplay timedisplay = {};

// Play / Record
NoteValue play = {MCU::PLAY};
NoteValue record = {MCU::RECORD};

// Mute
Bankable::NoteValue<2> mute[] = {
  {bank, MCU::MUTE_1},
  {bank, MCU::MUTE_2},
  {bank, MCU::MUTE_3},
  {bank, MCU::MUTE_4},
};

// Solo
Bankable::NoteValue<2> solo[] = {
  {bank, MCU::SOLO_1},
  {bank, MCU::SOLO_2},
  {bank, MCU::SOLO_3},
  {bank, MCU::SOLO_4},
};

NoteValue rudeSolo = {MCU::RUDE_SOLO};

// Record arm / ready
Bankable::NoteValue<2> recrdy[] = {
  {bank, MCU::REC_RDY_1},
  {bank, MCU::REC_RDY_2},
  {bank, MCU::REC_RDY_3},
  {bank, MCU::REC_RDY_4},
};

// VU meters
MCU::Bankable::VU<2> vu[] = {
  {bank, 1, MCU::VUDecay::Hold},
  {bank, 2, MCU::VUDecay::Hold},
  {bank, 3, MCU::VUDecay::Hold},
  {bank, 4, MCU::VUDecay::Hold},
};

// VPot rings
MCU::Bankable::VPotRing<2> vpot[] = {
  {bank, 1},
  {bank, 2},
  {bank, 3},
  {bank, 4},
};

// ---------------------------- Display Elements ---------------------------- //
// ========================================================================== //

// Track names
MCU::LCDDisplay lcddisps[] = {
  // track (1), position (0, 40), font size (1)
  {display_L, lcd, bank, 1, {0, 40}, 1, WHITE},
  {display_L, lcd, bank, 2, {64, 40}, 1, WHITE},
  {display_R, lcd, bank, 3, {0, 40}, 1, WHITE},
  {display_R, lcd, bank, 4, {64, 40}, 1, WHITE},
};

// Time display
MCU::TimeDisplayDisplay timedisplaydisplay = {
  // position (0, 0), font size (1)
  display_L, timedisplay, {0, 0}, 1, WHITE,
};

// Play / Record
NoteBitmapDisplay playDisp = {
  display_L, play, XBM::play_7, {16 + 64, 0}, WHITE,
};
NoteBitmapDisplay recordDisp = {
  display_L, record, XBM::record_7, {26 + 64, 0}, WHITE,
};

// Mute
NoteBitmapDisplay muteDisp[] = {
  {display_L, mute[0], XBM::mute_10B, {14, 50}, WHITE},
  {display_L, mute[1], XBM::mute_10B, {14 + 64, 50}, WHITE},
  {display_R, mute[2], XBM::mute_10B, {14, 50}, WHITE},
  {display_R, mute[3], XBM::mute_10B, {14 + 64, 50}, WHITE},
};

// Solo
NoteBitmapDisplay soloDisp[] = {
  {display_L, solo[0], XBM::solo_10B, {14, 50}, WHITE},
  {display_L, solo[1], XBM::solo_10B, {14 + 64, 50}, WHITE},
  {display_R, solo[2], XBM::solo_10B, {14, 50}, WHITE},
  {display_R, solo[3], XBM::solo_10B, {14 + 64, 50}, WHITE},
};

NoteBitmapDisplay rudeSoloDisp = {
  display_L, rudeSolo, XBM::solo_7, {36 + 64, 0}, WHITE
};

// Record arm / ready
NoteBitmapDisplay recrdyDisp[] = {
  {display_L, recrdy[0], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
  {display_L, recrdy[1], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
  {display_R, recrdy[2], XBM::rec_rdy_10B, {14 + 14, 50}, WHITE},
  {display_R, recrdy[3], XBM::rec_rdy_10B, {14 + 14 + 64, 50}, WHITE},
};

// VU meters
MCU::VUDisplay vuDisp[] = {
  // position (32+11, 60), width (16), bar height (3) px, bar spacing (1) px
  {display_L, vu[0], {32 + 11, 60}, 16, 3, 1, WHITE},
  {display_L, vu[1], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
  {display_R, vu[2], {32 + 11, 60}, 16, 3, 1, WHITE},
  {display_R, vu[3], {32 + 11 + 64, 60}, 16, 3, 1, WHITE},
};

// VPot rings
MCU::VPotDisplay vpotDisp[] = {
  // position (0, 10), outer radius (14) px, inner radius (12) px
  {display_L, vpot[0], {0, 10}, 14, 12, WHITE},
  {display_L, vpot[1], {64, 10}, 14, 12, WHITE},
  {display_R, vpot[2], {0, 10}, 14, 12, WHITE},
  {display_R, vpot[3], {64, 10}, 14, 12, WHITE},
};

// Bank seting
BankDisplay bankDisp[] = {
  // first track of the bank (1), position (0, 50), font size (2)
  {display_L, bank, 1, {0, 50}, 2, WHITE},
  {display_L, bank, 2, {64, 50}, 2, WHITE},
  //{display_R, bank, 3, {0, 50}, 2, WHITE},
  //{display_R, bank, 4, {64, 50}, 2, WHITE},
  {display_R2, bank, 3, {0, 50}, 2, WHITE},
  {display_R3, bank, 4, {64, 50}, 2, WHITE},
};

// --------------------------------- Setup ---------------------------------- //
// ========================================================================== //
void initializeDisplay() {
  // Initialize with the display with I²C address 0x3C
  select_chnl(0);
  ssd1306Display_L.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  //Wire.setClock(3400000); // Set the I²C clock to 1.8 MHz for faster refresh / 1800000 was the default, changed to 3400000 not sure if this even works this fast.
  ssd1306Display_L.setRotation(0); // Normal screen orientation.
  select_chnl(1);
  ssd1306Display_R.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  //Wire.setClock(3400000); // Set the I²C clock to 1.8 MHz for faster refresh / 1800000 was the default, changed to 3400000 not sure if this even works this fast.
  ssd1306Display_R.setRotation(0); // Normal screen orientation.
  select_chnl(2);
  ssd1306Display_R2.begin(SSD1306_SWITCHCAPVCC, 0x3C);
 // Wire.setClock(3400000); // Set the I²C clock to 1.8 MHz for faster refresh / 1800000 was the default, changed to 3400000 not sure if this even works this fast.
  ssd1306Display_R2.setRotation(0); // Normal screen orientation.
  select_chnl(3);
 // Wire.setClock(3400000); // Set the I²C clock to 1.8 MHz for faster refresh / 1800000 was the default, changed to 3400000 not sure if this even works this fast.
  ssd1306Display_R3.setRotation(0); // Normal screen orientation.
}
void select_chnl(int ch)
{
  Wire.beginTransmission(0x70);
  Wire.write(1 << ch);
  Wire.endTransmission();
  Serial.print("Selected mux:");
  Serial.print(ch);
}
void setup() {
  Serial.begin(9600);
  initializeDisplay();     // Start the OLED display
  Control_Surface.begin(); // Initialize Control Surface
}

// ---------------------------------- Loop ---------------------------------- //
// ========================================================================== //

void loop() {
  Control_Surface.loop(); // Refresh all elements
}
tttapa commented 4 years ago

I don't have the necessary hardware to help you debugging, I only have a single I2C display, I always use SPI OLED displays for my projects.

That being said, the first step should be to get this working without the Control Surface library. Use just the Adafruit library directly and maybe a library that controls the mux if it requires one, and do something extremely simple, like printing "1" to the first display, "2" to the second, etc., just enough to show that it's working.

Once that's working, I can show you how to do the same thing using the Control Surface library.

You might want to try using IO pins to drive the reset lines of the displays instead of using an RC circuit, it seems to be more reliable if you have multiple displays. First try a separate IO pin for the reset line of each OLED.

The code you posted tries to initialize the displays twice, once in the MySSD1306_DisplayInterface::begin() method, and once in the initializeDisplay() function. You don't need the initializeDisplay() function, by calling Control_Surface.begin(), you're already implicitly calling the MySSD1306_DisplayInterface::begin() method.
Initializing the displays multiple times will probably do more harm than good.

Good luck!

anikhossain285 commented 4 years ago

I have tried single initialisation too. I will remove initializeDisplay() I will try separate reset pin too. I will let you know the update. I have been successful in using the mux for the four displays. I got it to work for a single display without mux using control surface library. The only problem occurs when I try to use multiple displays in control surface library. Maybe I am doing something wrong in Display interface.

Code for working display with mux

//#include <SPI.h>
#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 -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define TCAADDR 0x70 // Define address for TCA

// Create an object for each OLED display
Adafruit_SSD1306 display0(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display2(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 display3(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void TCA9548A(uint8_t bus)
{
  Wire.beginTransmission(TCAADDR); //TCA9548A address is 0x70
  Wire.write(1 << bus);         // send byte to select bus
  Serial.println("TCA Loop "); Serial.println(bus);
  Wire.endTransmission();
}

void setup() {
  Serial.begin(9600);
//  Serial.println(("Start"));

  // start wire library for I2C
  Wire.begin();

//initialize OLED at ox3C (set multiplexer to channel 1 and initialize OLED-0 with I2C addr 0x3C
    TCA9548A(0);
    display0.begin(SSD1306_SWITCHCAPVCC, 0x3C);
//    Serial.println(("Initialize 0"));

    TCA9548A(1);
    display1.begin(SSD1306_SWITCHCAPVCC, 0x3C);
//    Serial.println(("Initialize 1"));

    TCA9548A(2);
    display1.begin(SSD1306_SWITCHCAPVCC, 0x3C);
//    Serial.println(("Initialize 2"));

    TCA9548A(3);
    display1.begin(SSD1306_SWITCHCAPVCC, 0x3C);
//    Serial.println(("Initialize 3"));
}

void oled1() {
TCA9548A(0);
display0.clearDisplay();//clear display
display0.setTextColor(WHITE);//set color (always white)
display0.setTextSize(2);//set font size
display0.setCursor(0,0);//set the cursor coordinates
display0.print("disp 1");
display0.display();
//Serial.println(("Write Display One"));
delay(1000);}

void oled2() {
TCA9548A(1);
display1.clearDisplay();
display1.setTextColor(WHITE);//set color (always white)
display1.setTextSize(2);//set font size
display1.setCursor(0,0);//set the cursor coordinates
display1.print("disp 3");
display1.display();
//Serial.println(("Write Display Two"));
delay(1000);}

void oled3() {
TCA9548A(2);
display1.clearDisplay();
display1.setTextColor(WHITE);//set color (always white)
display1.setTextSize(2);//set font size
display1.setCursor(0,0);//set the cursor coordinates
display1.print("disp 3");
display1.display();
//Serial.println(("Write Display Three"));
delay(1000);}

void oled4() {
TCA9548A(3);
display1.clearDisplay();
display1.setTextColor(WHITE);//set color (always white)
display1.setTextSize(2);//set font size
display1.setCursor(0,0);//set the cursor coordinates
display1.print("disp 4");
display1.display();
//Serial.println(("Write Display Four"));
delay(1000);}
void loop() {
oled1();
oled2();
oled3();
oled4();
}

Sode for single display without a mux

#include <Encoder.h> // Include the Encoder library.
// This must be done before the Control Surface library.
#include <Control_Surface.h> // Include the Control Surface library
// Include the display interface you'd like to use
#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>
#include <Wire.h> // Include the I²C library for the display

// ----------------------------- MIDI Interface ----------------------------- //

USBMIDI_Interface midi;
// USBDebugMIDI_Interface midi(115200);

// ----------------------------- Display setup ------------------------------ //

constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 64;
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 ssd1306Display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void initializeDisplay() {
    // Initialize with the display with I²C address 0x3C
    ssd1306Display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    Wire.setClock(3400000); // Set the I²C clock to 1.8 MHz for faster refresh / 1800000 was the default, changed to 3400000 not sure if this even works this fast.
    ssd1306Display.setRotation(0); // Normal screen orientation.
}

// --------------------------- Display interface ---------------------------- //

class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
  public:
    MySSD1306_DisplayInterface(Adafruit_SSD1306 &display)
        : SSD1306_DisplayInterface(display) {}

    void drawBackground() override { disp.drawLine(1, 8, 126, 8, WHITE); } //remove this later
} display = ssd1306Display;

// -------------------------- MIDI Input Elements --------------------------- //

//constexpr unsigned int decay = MCU::VUDecay::Hold;
// Try this option if your DAW doesn't decay the VU meters automatically
constexpr unsigned int decay = 85; // milliseconds to decay one block

// VU meters
MCU::VU VUMeters[8] = {
  {1, decay}, // The VU meter for the first track, decay time as specified above
  {2, decay}, {3, decay}, {4, decay}, {5, decay},
  {6, decay}, {7, decay}, {8, decay},
};

// ---------------------------- Display Elements ---------------------------- //

MCU::VUDisplay vuDisp[8] = {
  // Draw the first VU meter to the display, at position (2, 50),
  // (12) pixels wide, blocks of (3) pixels high, a spacing between
  // blocks of (1) pixel, and draw in white.
  {display, VUMeters[0], {2 + 16 * 0, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[1], {2 + 16 * 1, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[2], {2 + 16 * 2, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[3], {2 + 16 * 3, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[4], {2 + 16 * 4, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[5], {2 + 16 * 5, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[6], {2 + 16 * 6, 50}, 12, 3, 1, WHITE},
  {display, VUMeters[7], {2 + 16 * 7, 50}, 12, 3, 1, WHITE},
};

// --------------------------------- Setup ---------------------------------- //

void setup() {
    initializeDisplay();     // Start the OLED display
    Control_Surface.begin(); // Initialize Control Surface
}

// ---------------------------------- Loop ---------------------------------- //

void loop() {
    Control_Surface.loop(); // Refresh all elements
}
tttapa commented 4 years ago

In your code without Control Surface, you're calling

    display0.begin(SSD1306_SWITCHCAPVCC, 0x3C);

But in your Control Surface code, you're calling it without any arguments:

    void begin() override {
      selectMux();
      // Initialize the Adafruit_SSD1306 display
      if (!disp.begin()) //                                                ← No arguments here 
        FATAL_ERROR(F("SSD1306 allocation failed."), 0x3C);

      SSD1306_DisplayInterface::begin();
      //SSD1306_DisplayInterface::begin(SSD1306_SWITCHCAPVCC, 0x3C);
    }
anikhossain285 commented 4 years ago

I tried this too. I am not sure it's a correct format or not.

void begin() override {
      selectMux();
      // Initialize the Adafruit_SSD1306 display
      if (!disp.begin(SSD1306_SWITCHCAPVCC,0x3C))
        FATAL_ERROR(F("SSD1306 allocation failed."), 0x3C);

      SSD1306_DisplayInterface::begin();
      //SSD1306_DisplayInterface::begin(SSD1306_SWITCHCAPVCC, 0x3C);
    }
tttapa commented 4 years ago

I think the problem is that you forgot to call Wire.begin() before setting the mux channel. If you only use a single display, the Adafruit_SSD1306::begin() method will call Wire.begin() internally, but since you're talking I2C to the mux before initializing the display, you have to initialize the I2C interface first, manually.

The following works for me (without a mux, both displays in the code draw to the same physical display):

#include <Control_Surface.h> // Include the Control Surface library
// Include the display interface you'd like to use
#include <Display/DisplayInterfaces/DisplayInterfaceSSD1306.hpp>

// ----------------------------- MIDI Interface ----------------------------- //

USBMIDI_Interface midi;

// ----------------------------- Display setup ------------------------------ //

constexpr uint8_t SCREEN_WIDTH = 128;
constexpr uint8_t SCREEN_HEIGHT = 64;

constexpr int8_t OLED_reset = -1; // Use the external RC circuit for reset

// Instantiate the displays
Adafruit_SSD1306 ssd1306Display_L = {
  SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_reset,
};
Adafruit_SSD1306 ssd1306Display_R = {
  SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_reset,
};

constexpr uint8_t muxCh_L = 0; // multiplexer channel for Left Screen
constexpr uint8_t muxCh_R = 1; // multiplexer channel for Right Screen

// --------------------------- Display interface ---------------------------- //

class MySSD1306_DisplayInterface : public SSD1306_DisplayInterface {
  public:
    MySSD1306_DisplayInterface(Adafruit_SSD1306 &display, uint8_t muxCh)
      : SSD1306_DisplayInterface(display), muxCh(muxCh) {}

    void begin() override {
      selectMux();

      // Initialize the Adafruit_SSD1306 display
      if (!disp.begin(SSD1306_SWITCHCAPVCC, 0x3C))
        FATAL_ERROR(F("SSD1306 allocation failed."), 0x1306);

      SSD1306_DisplayInterface::begin();

      disp.setTextColor(WHITE);
      disp.setTextSize(2);
    }

    void display() override {
      selectMux();
      SSD1306_DisplayInterface::display();
      delay(2000); // slow down, easier to debug
    }

    void drawBackground() override {}

  private:
    uint8_t muxCh;

    void selectMux() {
      Wire.beginTransmission(0x70);
      Wire.write(1 << muxCh);
      Wire.endTransmission();
      Serial.print("Selected mux:");
      Serial.println(muxCh);
    }
} display_L = {ssd1306Display_L, muxCh_L},
  display_R = {ssd1306Display_R, muxCh_R};

// ---------------------------- Display Elements ---------------------------- //

// Simple display element that just prints some text
struct TestDisplayElement : DisplayElement {
  TestDisplayElement(DisplayInterface &display, const char *message)
   : DisplayElement(display), message(message) {}

  void draw() override {
    getDisplay().setCursor(8, 8);
    getDisplay().print(message);
  }

  const char *message;
} dispElem_L = {display_L, "LEFT"}, 
  dispElem_R = {display_R, "RIGHT"};

// --------------------------------- Setup ---------------------------------- //

void setup() {
  Serial.begin(115200);
  Wire.begin(); // This is important! Otherwise, you can't select the mux channel
  Control_Surface.begin(); // Initialize Control Surface
}

// ---------------------------------- Loop ---------------------------------- //

void loop() {
  Control_Surface.loop(); // Refresh all elements
}
anikhossain285 commented 4 years ago

I knew it, it would be something small like that. Thank you so much. It's working now.