MCP23017 freezes randomly

Hi, I am using the 16bit GPIO Expander MCP23017.
My project is actually only at the beginning, but a serious error is already occurring. I use a W5500 Ethernet board for the connection to my MQTT Broker. At the moment the procedure is simple, if it is necessary to turn on the heating, a message is sent via the MQTT callback. Besides the current temperature is also sent away via MQTT. Normally this procedure works very well, but if it ran for one or two days and switched several times, the MCP23017 freezes and stays permanently on LOW at the output. If you do a softreset, the output is permanently HIGH. Only by switching off the power supply will it be possible to get the process working again properly.
Is the MCP23017 not suitable for 24/7 continuous operation or is there still an error on my part?

Here is my code:

#include <Ethernet2.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include "Adafruit_MCP23017.h"

#define ONE_WIRE_BUS 15 // 1-Wire Pin

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress Temp_PCB { 0x28, 0xEE, 0x01, 0x2D, 0x23, 0x16, 0x01, 0x6C };
DeviceAddress Temp_oben { 0x28, 0xFF, 0xFC, 0xEF, 0xB2, 0x17, 0x04, 0x0C };
DeviceAddress Temp_unten { 0x28, 0xFF, 0xDA, 0xBD, 0xB2, 0x17, 0x04, 0xB7 };

Adafruit_MCP23017 mcp1;            //Expander mit standard Adresse

#define RST_PIN         1          // NFC RST PIN
#define CS1_PIN         5          // NFC1 Haustuer


byte mac[] = {...};
const char* mqttServer = "...";
const int mqttPort = ...;

EthernetClient ethClient;
PubSubClient client(ethClient);

unsigned long Temperaturabfrage_letzter_Zeitstempel = 0;
int Temperaturabfrage_Zeitintervall = 60000;              // Zeitintervall Temperaturupdate

unsigned long Temperaturabfrage_Gewaechshaus_letzter_Zeitstempel = 0;
int Temperaturabfrage_Gewaechshaus_Zeitintervall = 60000;              // Zeitintervall Temperaturupdate für Heizung

void reconnect() {
  while (!client.connected()) {
    Serial.print("Verbindung zum MQTT Broker wird wiederhergestellt");
    if (client.connect("Keller")) {
      Serial.println("Mit MQTT Broker verbunden");
      client.subscribe("/Werte/Keller/Temperaturabfrage");
      client.subscribe("/Werte/Keller/Temperaturabfrage_Gewaechshausheizung");
      client.subscribe("/Werte/Keller/Restart");
      client.subscribe("/Werte/Keller/Gewaechshaus_Heizung");
      client.publish("/Werte/Keller/Update", "1");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" Warte 2 Sekunden");
      delay(2000);
    }
  }
}
void setup() {
  Serial.begin(115200);    // Initialize serial communications with the PC
  while (!Serial);    // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
  Serial.println("Verbindung zum Netzwerk herstellen");
  // You can use Ethernet.init(pin) to configure the CS pin
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for (;;)
      ;
  }
  // print your local IP address:
  Serial.print("Aktuelle IP-Adresse: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);

  while (!client.connected()) {
    Serial.println("Verbindung zu MQTT Broker herstellen");

    if (client.connect("Keller")) {

      Serial.println("Mit MQTT Broker verbunden");
      client.subscribe("/Werte/Keller/Temperaturabfrage");
      client.subscribe("/Werte/Keller/Temperaturabfrage_Gewaechshausheizung");
      client.subscribe("/Werte/Keller/Restart");
      client.subscribe("/Werte/Keller/Gewaechshaus_Heizung");
      client.publish("/Werte/Keller/Update", "1");
    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

    }
  }
  delay(200);
  sensors.begin();
  sensors.setResolution(Temp_PCB, 9);
  sensors.setResolution(Temp_unten, 9);
  sensors.setResolution(Temp_oben, 9);
  sensors.requestTemperatures();
  Serial.print("Temperatur PCB: ");
  Serial.println(sensors.getTempC(Temp_PCB));
  Serial.print("Temperatur Gewächshaus unten: ");
  Serial.println(sensors.getTempC(Temp_unten));
  Serial.print("Temperatur Gewächshaus oben: ");
  Serial.println(sensors.getTempC(Temp_oben));
  Serial.println("Temperatursensor OK");
  delay(200);
  mcp1.begin(0);
  mcp1.pinMode(0, OUTPUT);
  mcp1.digitalWrite(0, LOW);
  Serial.println("Expander OK");
  Serial.println("Start");
}
void callback(char* topic, byte* payload, unsigned int length) {
  if (strcmp(topic, "/Werte/Keller/Temperaturabfrage") == 0) {
    Temperaturabfrage_Zeitintervall = 0;
    for (int i = 0; i < length; i++) {
      char c = payload[i];
      if (c >= '0' && c <= '9')
        Temperaturabfrage_Zeitintervall = Temperaturabfrage_Zeitintervall * 10 + c - '0';
    }
    Serial.print("UPDATE Zeitintervall Temperaturabfrage: ");
    Serial.println(Temperaturabfrage_Zeitintervall);
  }
  if (strcmp(topic, "/Werte/Keller/Temperaturabfrage_Gewaechshausheizung") == 0) {
    Temperaturabfrage_Gewaechshaus_Zeitintervall = 0;
    for (int i = 0; i < length; i++) {
      char c = payload[i];
      if (c >= '0' && c <= '9')
        Temperaturabfrage_Gewaechshaus_Zeitintervall = Temperaturabfrage_Gewaechshaus_Zeitintervall * 10 + c - '0';
    }
    Serial.print("UPDATE Zeitintervall Temperaturabfrage für Heizung: ");
    Serial.println(Temperaturabfrage_Gewaechshaus_Zeitintervall);
  }
  if (strcmp(topic, "/Werte/Keller/Restart") == 0) {
    if (payload[0] == '1') {
      Serial.println("Restart");
      ESP.restart();
    }
  }
  if (strcmp(topic, "/Werte/Keller/Gewaechshaus_Heizung") == 0) {
    if (payload[0] == '1') {
      Serial.println("Gewächshaus Heizung: ON");
      mcp1.digitalWrite(0, HIGH);
    }
    if (payload[0] == '0') {
      Serial.println("Gewächshaus Heizung: OFF");
      mcp1.digitalWrite(0, LOW);
    }
  }
}

void loop() {
  unsigned long currentMillis = millis();
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  ///////////////////////////////TEMPUPDATE/////////////////////////////////////////
  if (currentMillis - Temperaturabfrage_letzter_Zeitstempel >= Temperaturabfrage_Zeitintervall) {
    Temperaturabfrage_letzter_Zeitstempel = currentMillis;
    sensors.requestTemperatures();
    Serial.print("Temperatur PCB: ");
    float temp0 = sensors.getTempC(Temp_PCB);
    temp0 = ((int)(temp0*10)) / 10.0;
    Serial.println(temp0);
    client.publish("/Temperatur/Keller/PCB", String(temp0).c_str());
    Serial.print("Temperatur Gewächshaus oben: ");
    float temp1 = sensors.getTempC(Temp_oben);
    temp1 = ((int)(temp1*10)) / 10.0;
    Serial.println(temp1);
    client.publish("/Temperatur/Keller/Gewaechshaus_oben", String(temp1).c_str());
    Serial.print("Temperatur Gewächshaus unten: ");
    float temp2 = sensors.getTempC(Temp_unten);
    temp2 = ((int)(temp2*10)) / 10.0;
    Serial.println(temp2);
    client.publish("/Temperatur/Keller/Gewaechshaus_unten", String(temp2).c_str());
  }

  if (currentMillis - Temperaturabfrage_Gewaechshaus_letzter_Zeitstempel >= Temperaturabfrage_Gewaechshaus_Zeitintervall) {
    Temperaturabfrage_Gewaechshaus_letzter_Zeitstempel = currentMillis;
    sensors.requestTemperatures();
    Serial.print("Temperatur Gewächshaus oben für Heizung: ");
    float temp_oben_heizung = sensors.getTempC(Temp_oben);
    temp_oben_heizung = ((int)(temp_oben_heizung*10)) / 10.0;
    Serial.println(temp_oben_heizung);
    client.publish("/Temperatur/Keller/Heizung/Gewaechshaus_oben", String(temp_oben_heizung).c_str());
    Serial.print("Temperatur Gewächshaus unten für Heizung: ");
    float temp_unten_heizung = sensors.getTempC(Temp_unten);
    temp_unten_heizung = ((int)(temp_unten_heizung*10)) / 10.0;
    Serial.println(temp_unten_heizung);
    client.publish("/Temperatur/Keller/Heizung/Gewaechshaus_unten", String(temp_unten_heizung).c_str());
  }
}

doorstep:
Is the MCP23017 not suitable for 24/7 continuous operation or is there still an error on my part?

Microchip is not in the business of building chips that only work for a day. They sell hundreds of million microcontrollers every year that work 24/7. The MCP23017 is basically a PICmicro.

A few things I notes about your code.

  • in callback you could use else if to stop comparing when you found the topic
  • in callback you work directly on the interval variable, when the payload is wrong your interval could become zero
  • your variable naming seems a bit of a mess, have a look at the Arduino naming convention and use one language, makes life easier in the long run
  • you do a lot of stuff in callback that does require more than variables (print, MCP I/O, ESP.restart) I would try to reduce that, set some flags and handle everything in loop

Is this with a ESP8266 board ? then why do you need a W5500 shield ?
Is this with a Arduino Uno ? how did you get all those libraries in it ?
Is this with a Arduino Mega ? how did you get the ESP.restart() function accepted by the compiler ?

Tell us about your I2C bus.
Is it with 3.3V devices or 5V or both ? Are there pullup resistors ? Are the wires longer than 50cm ?

Sorry for the missing information. I use an ESP8266 with the Ethernet module w5500. The ethernet module is in using, because there is no WLAN available at this place.
So I should only save the message in a variable and work with it in the loop?

The MCP23017 works with 3.3V and switches optocouplers, which then trigger a relay.
I have a simple setup for testing, because I want to build a customized board later. So at the moment the cable lengths are not longer than 10cm.

doorstep:
So I should only save the message in a variable and work with it in the loop?

Because you do not know when and how often the callback is executed it is good practice to keep it short and avoid side effects.

Your MQTT message topics seem a bit long. With the amount of characters, you could encode more message topics than Youtube can encode video links. :slight_smile:

doorstep:
I have a simple setup for testing, because I want to build a customized board later.

Can you provide a schematic? Hand drawn; photo taken with smart phone is OK.