MCP23017 inverted output

Hi,
my experience is very low and I can`t fix the following issue:

There is a MCP23017 expander connected to an arduino mega2560. The connections are as required. The MCP is adressed correctly.
8 LEDs are connected to both the mega and the mcp. The led are controlled by buttons and should light up the same on the mega and on the mcp. This works during operation correctly. But after a restart, the led on the mcp light up inversely. I have already tried pull-up, reset, delay, and various other things. I also set the pins to a specific level at startup. Unfortunately without success.

Has anyone an idea?
Thanks a lot.

You need to post your code and a wiring diagram of how you have everything connected.

Thanks for your help. It is my first time here. So I`ll try.

The purpose of the sketch is to control points on a model railway. The points have two coils, one for straight ahead, the other for branching. Now I want to see the position of the points with the LEDs. The sketch works perfectly in normal operation. The LEDs on the Arduino and on the MCP are correctly controlled. The error occurs when restarting. After a restart, the LEDs on the Arduino light up correctly according to the data stored in the EEPROM. The LEDs on the MCP light up inversely.

#include <EEPROM.h> // Bibliothek für EEPROM-Speicherung
#include <Wire.h>  // I²C Bibliothek
#include <Adafruit_MCP23X17.h>   // Bibliothek für MCP23017

// MCP23017 Instanz erstellen
Adafruit_MCP23X17 mcp1;  // Erstes Modul (Adresse 0x20)
Adafruit_MCP23X17 mcp2;  // Zweites Modul (Adresse 0x21)
Adafruit_MCP23X17 mcp3;  // Drittes Modul (Adresse 0x22)
Adafruit_MCP23X17 mcp4;  // Viertes Modul (Adresse 0x23)

// Definition der Taster-Eingänge für den Arduino Mega
#define TASTER1 22  // Taster für Einfahrt
#define TASTER2 23  // Taster für Bahnsteig 1
#define TASTER3 24  // Taster für Bahnsteig 2
#define TASTER4 25  // Taster für Bahnsteig 3
#define TASTER5 26  // Taster für Ausfahrt

// Definition der Spulen für die Weichensteuerung
#define SPULE_WEICHE1_Li_GERADE 30  // Weiche1_li gerade
#define SPULE_WEICHE1_Li_ABZWEIG 31  // Weiche1_li abzweig
#define SPULE_WEICHE2_Li_GERADE 32  // Weiche2_li gerade
#define SPULE_WEICHE2_Li_ABZWEIG 33  // Weiche2_li abzweig
#define SPULE_WEICHE1_RE_GERADE 34  // Weiche1_re gerade
#define SPULE_WEICHE1_RE_ABZWEIG 35  // Weiche1_re abzweig
#define SPULE_WEICHE2_RE_GERADE 36  // Weiche2_re gerade
#define SPULE_WEICHE2_RE_ABZWEIG 37  // Weiche2_re abzweig

// LED Pins auf dem Arduino Mega
#define LED1_W1l_ger_Mega 40 //Led für Weiche 1 links gerade
#define LED2_W1l_abzw_Mega 41 //Led für Weiche 1 links abzweig
#define LED3_W2l_ger_Mega 42 //Led für Weiche 2 links gerade
#define LED4_W2l_abzw_Mega 43 //Led für Weiche 2 links abzweig
#define LED5_W3r_ger_Mega 44 //Led für Weiche 3 rechts gerade
#define LED6_W3r_abzw_Mega 45 //Led für Weiche 3 rechts abzweig
#define LED7_W4r_ger_Mega 46 //Led für Weiche 4 rechts gerade
#define LED8_W4r_abzw_Mega 47 //Led für Weiche 4 rechts abzweig

// LED Pins auf dem ersten MCP23017
#define LED1_W1l_ger_MCP1 0 //Led für Weiche 1 links gerade
#define LED2_W1l_abzw_MCP1 1 //Led für Weiche 1 links abzweig
#define LED3_W2l_ger_MCP1 2 //Led für Weiche 2 links gerade
#define LED4_W2l_abzw_MCP1 3 //Led für Weiche 2 links abzweig
#define LED5_W3r_ger_MCP1 4 //Led für Weiche 3 rechts gerade
#define LED6_W3r_abzw_MCP1 5 //Led für Weiche 3 rechts abzweig
#define LED7_W4r_ger_MCP1 6 //Led für Weiche 4 rechts gerade
#define LED8_W4r_abzw_MCP1 7 //Led für Weiche 4 rechts abzweig


// Globale Variablen zur Speicherung der Start- und Zielpunkte
int start = -1;
int ziel = -1;

// Globale Variable für die Entprell-Zeit
unsigned long lastTasterZeit = 0;
unsigned long startTime = 0;

// Globale Variable für die nummer des zuletzt gedrückten Tasters
int lastTaster = -1;

// Konstante Werte zur Steuerung des Programms
const unsigned long debounceDelay = 50;  // 50 Millisekunden Entprell-Zeit
const int switchTime = 200; // Dauer des Schaltimpulses für die Weichen
const int timeout = 5000; // Maximale Zeit für die Eingabe von Start und Ziel
const int delayBetweenOperations = 500; // Verzögerung zwischen den Weichenstellungen
const int delayBetweenWeichen = 200; // Verzögerung zwischen einzelnen Weichenschaltungen

bool mcp1_ok = false;  // Variable vor der Nutzung deklarieren
bool mcp2_ok = false;  // Variable vor der Nutzung deklarieren
bool mcp3_ok = false;  // Variable vor der Nutzung deklarieren
bool mcp4_ok = false;  // Variable vor der Nutzung deklarieren

// Funktionsprototypen
void schalteWeiche(int weiche, bool gerade, bool speichern = true);

void speichereWeichenstellung(int weiche, bool gerade) { // EEPROM-Funktion: Weichenstellung speichern
    EEPROM.update(weiche - 1, gerade ? 1 : 0);
    Serial.println("Speicherung Weiche " + String(weiche) + ": " + (gerade ? "gerade" : "abzweig"));
}

void resetEEPROM() { // EEPROM zurücksetzen (wieder löschen, nach Fertigstellung)
    Serial.println("⚠️ EEPROM wird zurückgesetzt...");
    for (int i = 0; i < 4; i++) {
        EEPROM.update(i, 0);
    }
    Serial.println("✅ EEPROM wurde erfolgreich zurückgesetzt.");
}

void initialisiereEEPROM() { //Überprüft, ob die ersten 4 Speicherzellen des EEPROM bereits gültige Werte (0 oder 1) enthalten.
    bool eepromLeer = true;

    for (int i = 0; i < 4; i++) { // 4 Weichen
        int wert = EEPROM.read(i);
        if (wert == 0 || wert == 1) {
            eepromLeer = false; // Mindestens ein gültiger Wert gefunden
            break;
        }
    }
    
    if (eepromLeer) { // Falls EEPROM leer oder ungültig, Standardwerte setzen
        Serial.println("EEPROM uninitialisiert, setze Standardwerte...");
        for (int i = 0; i < 4; i++) {
            EEPROM.update(i, 0); // Standard: alle Weichen auf "gerade"
        }
        Serial.println("EEPROM-Initialisierung abgeschlossen.");
    } else {
        Serial.println("EEPROM bereits initialisiert.");
    }
}

bool ladeWeichenstellung(int weiche) { // EEPROM-Funktion: Weichenstellung laden
    int wert = EEPROM.read(weiche - 1);
    Serial.println("Geladene Stellung Weiche " + String(weiche) + ": " + (wert == 1 ? "gerade" : "abzweig"));
    return (wert == 1);
}

String tasterZuText(int taster) { // Funktion zur Umwandlung der Tastennummer in Klartext
    switch (taster) {
        case 1: return "Einfahrt";
        case 2: return "Bahnsteig 1";
        case 3: return "Bahnsteig 2";
        case 4: return "Bahnsteig 3";
        case 5: return "Ausfahrt";
        default: return "Unbekannt";
    }
}

int getTaster() { // Funktion zur Ermittlung, welcher Taster gedrückt wurde
    if (digitalRead(TASTER1) == LOW) { delay(10); return 1; }
    if (digitalRead(TASTER2) == LOW) { delay(10); return 2; }
    if (digitalRead(TASTER3) == LOW) { delay(10); return 3; }
    if (digitalRead(TASTER4) == LOW) { delay(10); return 4; }
    if (digitalRead(TASTER5) == LOW) { delay(10); return 5; }
    return -1;
}
// Initialisierung der Ein- und Ausgänge
void setup() {
    Serial.begin(9600);
    Serial.println(F("🚦 Modellbahnsteuerung startet..."));
    Serial.println(F("🔍 Prüfe EEPROM..."));

    initialisiereEEPROM(); // EEPROM beim ersten Start prüfen und ggf. initialisieren    

    // I²C starten
    Wire.begin();
    mcp1.begin_I2C(0x20);

    // Überprüfung der Verbindung
    if (!mcp1_ok) Serial.println("⚠️ Fehler: MCP23017 (0x20) nicht erkannt!");    
    if (!mcp2_ok) Serial.println("⚠️ Fehler: MCP23017 (0x21) nicht erkannt!");
    if (!mcp3_ok) Serial.println("⚠️ Fehler: MCP23017 (0x22) nicht erkannt!");   
    if (!mcp4_ok) Serial.println("⚠️ Fehler: MCP23017 (0x23) nicht erkannt!");  

    // Erst die Pins setzen, wenn MCP erfolgreich initialisiert wurde
    
    if (mcp1_ok) {
        for (int i = 0; i < 8; i++) {
            mcp1.pinMode(i, OUTPUT);
            mcp1.digitalWrite(i, LOW); // Oder HIGH, je nach gewünschtem Startzustand            
        }
    }

    // Taster als Eingänge setzen
    for (int i = 22; i <= 26; i++) {
        pinMode(i, INPUT_PULLUP);
    }
    
     // Weichensteuerung als Ausgänge setzen
    for (int i = 30; i <= 37; i++) {
        pinMode(i, OUTPUT);
    }

    // LED-Pins am Arduino Mega als Ausgänge setzen
    for (int i = 40; i < 48; i++) {
        pinMode(i, OUTPUT);
        digitalWrite(i, LOW); // Setzt die LEDs initial aus
    }

    // Weichenstellungen aus EEPROM laden und setzen
    for (int w = 1; w <= 4; w++) {
        bool gespeicherteStellung = ladeWeichenstellung(w);
        Serial.println("Setze Weiche " + String(w) + " nach Neustart auf " + (gespeicherteStellung ? "gerade" : "abzweig"));

        int gerPin, abzPin;

        switch (w) {
            case 1: gerPin = SPULE_WEICHE1_Li_GERADE; abzPin = SPULE_WEICHE1_Li_ABZWEIG; break;
            case 2: gerPin = SPULE_WEICHE2_Li_GERADE; abzPin = SPULE_WEICHE2_Li_ABZWEIG; break;
            case 3: gerPin = SPULE_WEICHE1_RE_GERADE; abzPin = SPULE_WEICHE1_RE_ABZWEIG; break;
            case 4: gerPin = SPULE_WEICHE2_RE_GERADE; abzPin = SPULE_WEICHE2_RE_ABZWEIG; break;
            default: 
                Serial.println("❌ Fehler: Ungültige Weichennummer!");
                break;
        }

        // Weiche korrekt einstellen
        digitalWrite(gespeicherteStellung ? gerPin : abzPin, HIGH);
        delay(200);
        digitalWrite(gespeicherteStellung ? gerPin : abzPin, LOW);
    }

    // LED Status nach Initialisierung setzen (EEPROM-Adressen beachten!)
    Serial.println("LED Status nach Initialisierung:");
    for (int l = 1; l <= 4; l++) { // Jetzt von 1-4, weil nur 4 Weichen gespeichert werden
        bool gespeicherteStellung = ladeWeichenstellung(l);        

        // LED-Pins setzen (Arduino Mega)
        digitalWrite(40 + (l - 1) * 2, gespeicherteStellung ? HIGH : LOW);
        digitalWrite(41 + (l - 1) * 2, gespeicherteStellung ? LOW : HIGH);

        // MCP1-Pins setzen
        mcp1.digitalWrite((l - 1) * 2, gespeicherteStellung ? HIGH : LOW);
        delay(500); //kurze Verzögerung um die MCP-Pegel zu stabiliaieren

        mcp1.digitalWrite((l - 1) * 2 + 1, gespeicherteStellung ? LOW : HIGH);
        delay(500); //kurze Verzögerung um die MCP-Pegel zu stabiliaieren


        // LEDs am MCP1 gemäß Weichenstellung setzen
        switch (l) {
            case 1: mcp1.digitalWrite(LED1_W1l_ger_MCP1, gespeicherteStellung ? HIGH : LOW);
                    mcp1.digitalWrite(LED2_W1l_abzw_MCP1, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 2: mcp1.digitalWrite(LED3_W2l_ger_MCP1, gespeicherteStellung ? HIGH : LOW);
                    mcp1.digitalWrite(LED4_W2l_abzw_MCP1, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 3: mcp1.digitalWrite(LED5_W3r_ger_MCP1, gespeicherteStellung ? HIGH : LOW);
                    mcp1.digitalWrite(LED6_W3r_abzw_MCP1, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 4: mcp1.digitalWrite(LED7_W4r_ger_MCP1, gespeicherteStellung ? HIGH : LOW);
                    mcp1.digitalWrite(LED8_W4r_abzw_MCP1, gespeicherteStellung ? LOW : HIGH);
                    break;
        }

        delay(500); //kurze Verzögerung um die MCP-Pegel zu stabiliaieren

        // LEDs am Arduino Mega gemäß Weichenstellung setzen
        switch (l) {
            case 1: digitalWrite(LED1_W1l_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED2_W1l_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 2: digitalWrite(LED3_W2l_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED4_W2l_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 3: digitalWrite(LED5_W3r_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED6_W3r_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 4: digitalWrite(LED7_W4r_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED8_W4r_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
        }   
    }

    Serial.println("Erweiterung 1 initialisiert");
    delay(1000);
    Serial.println("System bereit. Bitte Start und Ziel eingeben."); 

}



// Funktion zur Steuerung der Weichen mit EEPROM-Speicherung
// weiche: Nummer der Weiche (1-4)
// gerade: true für gerade, false für abzweig
void schalteWeiche(int weiche, bool gerade, bool speichern = true) {
    int gerPin, abzPin, ledGerade, ledAbzweig;
    
    // Prüfen, ob die Weiche bereits in der gewünschten Stellung ist
    Serial.print("Weiche ");
    Serial.print(weiche);
    Serial.print(" schalten auf ");
    Serial.println(gerade ? "gerade" : "abzweig");

    if (ladeWeichenstellung(weiche) == gerade) {
        Serial.println("Weiche bereits in dieser Stellung, keine Schaltung nötig.");
        return;
    }

    switch (weiche) {
        case 1: gerPin = SPULE_WEICHE1_Li_GERADE; abzPin = SPULE_WEICHE1_Li_ABZWEIG; ledGerade = LED1_W1l_ger_Mega; ledAbzweig = LED2_W1l_abzw_Mega; break;
        case 2: gerPin = SPULE_WEICHE2_Li_GERADE; abzPin = SPULE_WEICHE2_Li_ABZWEIG; ledGerade = LED3_W2l_ger_Mega; ledAbzweig = LED4_W2l_abzw_Mega; break;
        case 3: gerPin = SPULE_WEICHE1_RE_GERADE; abzPin = SPULE_WEICHE1_RE_ABZWEIG; ledGerade = LED5_W3r_ger_Mega; ledAbzweig = LED6_W3r_abzw_Mega; break;
        case 4: gerPin = SPULE_WEICHE2_RE_GERADE; abzPin = SPULE_WEICHE2_RE_ABZWEIG; ledGerade = LED7_W4r_ger_Mega; ledAbzweig = LED8_W4r_abzw_Mega; break;
        default: return;
    }
    
    // Weiche nur umschalten, wenn sich die Stellung ändert
    Serial.println("Schaltbefehl gesendet!");
    digitalWrite(gerade ? gerPin : abzPin, HIGH);
    delay(200);
    digitalWrite(gerade ? gerPin : abzPin, LOW); 

     // LEDs am Mega aktualisieren
    digitalWrite(ledGerade, gerade ? HIGH : LOW);
    digitalWrite(ledAbzweig, gerade ? LOW : HIGH);

    // LEDs am MCP aktualisieren
    mcp1.digitalWrite((weiche - 1) * 2, gerade ? HIGH : LOW);
    mcp1.digitalWrite((weiche - 1) * 2 + 1, gerade ? LOW : HIGH); 
    
    // Neue Stellung speichern, falls erforderlich
    if (speichern) speichereWeichenstellung(weiche, gerade);  
}

// Hauptprogramm
void loop() {
    int taster = getTaster();

    if (taster != -1 && taster != lastTaster) {  // Prüfen, ob die Taste wirklich neu ist
        unsigned long aktuelleZeit = millis();
        
        // Entprellung mit millis(), nur reagieren, wenn genügend Zeit vergangen ist
        if (aktuelleZeit - lastTasterZeit > debounceDelay) {
            lastTasterZeit = aktuelleZeit;  // Zeit aktualisieren
            lastTaster = taster;  // Merken, welche Taste zuletzt gedrückt wurde
        }

        if (start == -1) {
            start = taster;
            startTime = millis();
            Serial.print("Start gesetzt: ");
            Serial.println(tasterZuText(start));
        } else {
            if (millis() - startTime > timeout) {
                Serial.println("Zeitüberschreitung, bitte Start und Ziel erneut eingeben");
                start = -1;
                return;
            } 

            ziel = taster;
            Serial.print("Ziel gesetzt: ");
            Serial.println(tasterZuText(ziel));
            
            // Weichen- und LED-Schaltung gemäß den definierten Routen
            if ((start == 1 && ziel == 2) || (start == 2 && ziel == 1)) { schalteWeiche(2, false); schalteWeiche(1, true); mcp1.digitalWrite(0, LOW); mcp1.digitalWrite(1, HIGH); mcp1.digitalWrite(2, HIGH);mcp1.digitalWrite(3, LOW); }
            else if ((start == 1 && ziel == 3) || (start == 3 && ziel == 1)) { schalteWeiche(2, true); schalteWeiche(1, true); mcp1.digitalWrite(0, LOW); mcp1.digitalWrite(1, HIGH); mcp1.digitalWrite(2, LOW);mcp1.digitalWrite(3, HIGH); }
            else if ((start == 1 && ziel == 4) || (start == 4 && ziel == 1)) { schalteWeiche(1, false); mcp1.digitalWrite(0, HIGH); mcp1.digitalWrite(1, LOW); }
            else if ((start == 2 && ziel == 5) || (start == 5 && ziel == 2)) { schalteWeiche(3, true); schalteWeiche(4, false); mcp1.digitalWrite(4, LOW); mcp1.digitalWrite(5, HIGH); mcp1.digitalWrite(6, HIGH);mcp1.digitalWrite(7, LOW); }
            else if ((start == 3 && ziel == 5) || (start == 5 && ziel == 3)) { schalteWeiche(3, false); schalteWeiche(4, false); mcp1.digitalWrite(4, HIGH); mcp1.digitalWrite(5, LOW); mcp1.digitalWrite(6, HIGH);mcp1.digitalWrite(7, LOW); }
            else if ((start == 4 && ziel == 5) || (start == 5 && ziel == 4)) { schalteWeiche(4, true); mcp1.digitalWrite(6, LOW);mcp1.digitalWrite(7, HIGH); }         
            else {
                Serial.println("Fehler: Ungültige Route");
                start = -1;
                ziel = -1;
            }
            
            start = -1;
            ziel = -1;
        }
      } 
      // Timeout-Überprüfung 
      if (start != -1 && millis() - startTime > timeout) {
        Serial.println("Zeitüberschreitung, bitte neue Eingabe.");
        start = -1;
      }
    }       
   
     
    

You could try connecting the RST pin of the MCP to the Mega's RESET pin.

Thanks for your suggestion. I would like to be careful because I read that this is not the recommended variant and could lead to the destruction of the MCP.

Unfortunately also an updated version is not showing the right LED combination after a restart.

// I²C starten
    pinMode(MCP_RESET_PIN, OUTPUT);
    digitalWrite(MCP_RESET_PIN, LOW);  
    delay(10);  // Mindestens 1 µs laut Datenblatt
    digitalWrite(MCP_RESET_PIN, HIGH);
    
    
    Wire.begin();
    mcp1.begin_I2C();
    mcp1_ok = mcp1.begin_I2C(0x20);
    mcp2_ok = mcp2.begin_I2C(0x21);
    mcp3_ok = mcp3.begin_I2C(0x22);
    mcp4_ok = mcp4.begin_I2C(0x23);

    // Überprüfung der Verbindung
    if (!mcp1_ok) Serial.println("⚠️ Fehler: MCP23017 (0x20) nicht erkannt!");    

OK guys, I've figured it out. In the part of the programme I'm showing you here, I had to write the LOW and HIGH settings on the MCP inversely to the Arduino. But I still don't know why it has to be like this.

 // LEDs am MCP1 gemäß Weichenstellung setzen
        switch (l) {
            case 1: mcp1.digitalWrite(LED1_W1l_ger_MCP1, gespeicherteStellung ? LOW : HIGH);
                    mcp1.digitalWrite(LED2_W1l_abzw_MCP1, gespeicherteStellung ? HIGH : LOW);
                    break;
            case 2: mcp1.digitalWrite(LED3_W2l_ger_MCP1, gespeicherteStellung ? LOW : HIGH);
                    mcp1.digitalWrite(LED4_W2l_abzw_MCP1, gespeicherteStellung ? HIGH : LOW);
                    break;
            case 3: mcp1.digitalWrite(LED5_W3r_ger_MCP1, gespeicherteStellung ? LOW : HIGH);
                    mcp1.digitalWrite(LED6_W3r_abzw_MCP1, gespeicherteStellung ? HIGH : LOW);
                    break;
            case 4: mcp1.digitalWrite(LED7_W4r_ger_MCP1, gespeicherteStellung ? LOW : HIGH);
                    mcp1.digitalWrite(LED8_W4r_abzw_MCP1, gespeicherteStellung ? HIGH : LOW);
                    break;
        }

        delay(500); //kurze Verzögerung um die MCP-Pegel zu stabiliaieren

        // LEDs am Arduino Mega gemäß Weichenstellung setzen
        switch (l) {
            case 1: digitalWrite(LED1_W1l_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED2_W1l_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 2: digitalWrite(LED3_W2l_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED4_W2l_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 3: digitalWrite(LED5_W3r_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED6_W3r_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
            case 4: digitalWrite(LED7_W4r_ger_Mega, gespeicherteStellung ? HIGH : LOW);
                    digitalWrite(LED8_W4r_abzw_Mega, gespeicherteStellung ? LOW : HIGH);
                    break;
        }   

Thanks for your help.

Please post a link so I can read that too.

That won't work, because

so if you invert them, they will work correctly after a restart but not before.

With this code the LED work as they should. They switch after I switched a point and they light up correctly after a restart.

Unfortunately I can't recall where I read it. Sorry.

The way you have connected the LEDS is active low on the MCP23017, but active high on the Arduino. So you need to invert the state when writing to the MCP23017.

Thanks for your explanation. Someone told me that the power consumption is not so high if I use an 'open drain' structure. I'm a bit unsure which way is more stable: a) to connect against gnd or to connect against to Vcc. Do you have a recommendation?

I don't think it changes the power consumption, however the MCP23017 might be able to provide more current with active low outputs (haven't checked the datasheet). You should make sure the LEDs draw less current than the spec (I think around 7mA per LED, and less than 125mA in total for the MCP23017).

I would probably keep it wired the way you have and handle it in software.

I do.
Most semiconductor devices can sink more current than they can source, so it is prefered to use the open drain or totem pole output with the LED cathode connected to the IC/device or "connect against gnd" as you call it.

Also the source of the current is external to the IC/device.

Thanks a lot for your comment and recommendation.

Thanks for sharing your experience.

You are welcome

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