[SOLVED] MCP23017 Not working properly

I'm making a remote control for an rc car that I'm going to make. When it was on the breadboard, the MCP23017 was working fine, but now that I've soldered all together, the code stops here:

if (!mcp.begin_I2C(0x20, &I2C_1)) { // Inicializa com o endereço 0x20
    Serial.println("Erro ao iniciar MCP23017.");
    while (1); // Pare o programa se o MCP23017 não puder ser inicializado
}

Also is there a way to print the current mcp address?

Here's the full code:

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_MCP23X17.h"
#include "U8g2lib.h"
#include "nRF24L01.h"
#include "RF24.h"

#define LCDWidth u8g2.getDisplayWidth()
#define ALIGN_CENTER(t) ((LCDWidth - (u8g2.getUTF8Width(t))) / 2)
#define ALIGN_RIGHT(t) (LCDWidth - u8g2.getUTF8Width(t))
#define ALIGN_LEFT 0

#define SDA1 14
#define SCL1 13

TwoWire I2C_1 = TwoWire(1);
Adafruit_MCP23X17 mcp;

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);  // All Boards without Reset of the Display

// 'Max', 20x10px
const unsigned char maxbat[] PROGMEM = {
  0xfc, 0xff, 0x0f, 0x04, 0x00, 0x08, 0xf7, 0xde, 0x0b, 0xf1, 0xde, 0x0b, 0xf1, 0xde, 0x0b, 0xf1,
  0xde, 0x0b, 0xf1, 0xde, 0x0b, 0xf7, 0xde, 0x0b, 0x04, 0x00, 0x08, 0xfc, 0xff, 0x0f
};
// 'Medium', 20x10px
const unsigned char medbat[] PROGMEM = {
  0xfc, 0xff, 0x0f, 0x04, 0x00, 0x08, 0x07, 0xde, 0x0b, 0x01, 0xde, 0x0b, 0x01, 0xde, 0x0b, 0x01,
  0xde, 0x0b, 0x01, 0xde, 0x0b, 0x07, 0xde, 0x0b, 0x04, 0x00, 0x08, 0xfc, 0xff, 0x0f
};
// 'Low', 20x10px
const unsigned char lowbat[] PROGMEM = {
  0xfc, 0xff, 0x0f, 0x04, 0x00, 0x08, 0x07, 0xc0, 0x0b, 0x01, 0xc0, 0x0b, 0x01, 0xc0, 0x0b, 0x01,
  0xc0, 0x0b, 0x01, 0xc0, 0x0b, 0x07, 0xc0, 0x0b, 0x04, 0x00, 0x08, 0xfc, 0xff, 0x0f
};

// 'ConfigIcon', 13x13px
const unsigned char configIcon[] PROGMEM = {
  0x00, 0x00, 0x4e, 0x04, 0x4a, 0x04, 0x4e, 0x04, 0x44, 0x0e, 0x44, 0x0a, 0x44, 0x0e, 0x44, 0x04,
  0xe4, 0x04, 0xa4, 0x04, 0xe4, 0x04, 0x44, 0x04, 0x00, 0x00
};

// 'JogosIcon', 10x10px
const unsigned char JogosIcon[] PROGMEM = {
  0x02, 0x01, 0xfd, 0x02, 0x01, 0x02, 0xcd, 0x02, 0x45, 0x02, 0x01, 0x02, 0x79, 0x02, 0x85, 0x02,
  0x85, 0x02, 0x02, 0x01
};

// 'VoltarIcon', 10x10px
const unsigned char VoltarIcon[] PROGMEM = {
  0x30, 0x00, 0x18, 0x00, 0x0c, 0x00, 0xfe, 0x00, 0x0c, 0x01, 0x18, 0x02, 0x30, 0x02, 0x00, 0x01,
  0xfc, 0x00, 0x00, 0x00
};

// 'JoysticksIcon', 10x10px
const unsigned char JoysticksIcon[] PROGMEM = {
  0x30, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x30, 0x00, 0x78, 0x00,
  0xfe, 0x01, 0xff, 0x03
};

// 'PowerSavingIcon', 10x10px
const unsigned char PowerSavingIcon[] PROGMEM = {
  0x30, 0x00, 0xfc, 0x00, 0x84, 0x00, 0x94, 0x00, 0xa4, 0x00, 0x94, 0x00, 0xa4, 0x00, 0x94, 0x00,
  0x84, 0x00, 0xfc, 0x00
};

// 'ControlesIcon', 10x10px
const unsigned char ControlesIcon[] PROGMEM = {
  0x78, 0x00, 0x86, 0x01, 0x32, 0x01, 0x49, 0x02, 0x49, 0x02, 0x79, 0x02, 0x49, 0x02, 0x4a, 0x01,
  0x86, 0x01, 0x78, 0x00
};

const uint8_t *bitmaps[] = { VoltarIcon, ControlesIcon, PowerSavingIcon, JogosIcon, JoysticksIcon, VoltarIcon, VoltarIcon };
// ============================================================ //

RF24 radio(4, 5);

int MidpointEsqX = 119;
int MidpointEsqY = 119;
int MidpointDirX = 119;
int MidpointDirY = 119;
uint8_t Tolerance = 5;

uint8_t joyAX; // Joystick Esquerdo X (0-255) (Midpoint: 119)
uint8_t joyAY; // Joystick Esquerdo Y (0-255) (Midpoint: 119)
uint8_t joyBX; // Joystick Direito X (0-255) (Midpoint: 119)
uint8_t joyBY; // Joystick Direito Y (0-255) (Midpoint: 119)
uint8_t pot1;
uint8_t pot2;
uint8_t pot3;
uint8_t pot4;

struct MeuControleRemoto {
  boolean BotEsqCim = 0;
  boolean BotEsqEsq = 0;
  boolean BotEsqDir = 0;
  boolean BotEsqBai = 0;
  boolean BotDirCim = 0;
  boolean BotDirEsq = 0;
  boolean BotDirDir = 0;
  boolean BotDirBai = 0;
  boolean Mts1 = 0;
  boolean Mts2 = 0;
  boolean Mts3 = 0;
  boolean Mts4 = 0;
  byte Pot1 = 0;
  byte Pot2 = 0;
  byte Pot3 = 0;
  byte Pot4 = 0;
  byte JoyDireitaX = 127;
  byte JoyDireitaY = 127;
  byte JoyEsquerdaX = 127;
  byte JoyEsquerdaY = 127;
  byte rcBattery = 50; // 3.7v -> 5v (dividir por 10)
};

MeuControleRemoto ControleRemoto;

// Os 2 Joysticks + 4 Potenciometros
byte joyAXp = 27; 
byte joyAYp = 26; 
byte joyBXp = 25;
byte joyBYp = 33;
byte pot1p = 35;
byte pot2p = 34;
byte pot3p = 2;
byte pot4p = 15;

// #define joyAXp = 0; 
// #define joyAYp = 0; 
// #define joyBXp = 0;
// #define joyBYp = 0;

// No esp
#define Mts1Pin 16
#define Mts2Pin 17
#define Mts3Pin 32

// No MCP
#define BotEsqCimPin 0 // GPA0
#define BotEsqDirPin 1 // GPA1
#define BotEsqBaiPin 2 // GPA2
#define BotEsqEsqPin 3 // GPA3
#define BotDirCimPin 4 // GPA4
#define BotDirDirPin 5 // GPA5
#define BotDirBaiPin 6 // GPA6
#define BotDirEsqPin 7 // GPA7
#define Mts4Pin 8 // GPB0

const int numReadings = 10;  // Número de leituras para calcular a média
const int numJoysticks = 8;  // Número de entradas de joystick

// Pinos dos joysticks
const int joystickPins[numJoysticks] = {joyAXp, joyAYp, joyBXp, joyBYp, pot1p, pot2p, pot3p, pot4p};

struct Joystick {
  int pin;
  int readings[numReadings];
  int readIndex;
  long total;
  int count;
};

Joystick joysticks[numJoysticks];

int getSmoothedJoystickValue(Joystick &joystick) {
  joystick.total -= joystick.readings[joystick.readIndex];
  int newValue = analogRead(joystick.pin);
  joystick.readings[joystick.readIndex] = newValue;
  joystick.total += newValue;
  joystick.readIndex = (joystick.readIndex + 1) % numReadings;
  if (joystick.count < numReadings) {
    joystick.count++;
  }
  return joystick.total / joystick.count;
}

const unsigned char *batLevel;
const unsigned char *RCbatLevel;
char *rcName = "TESTE";
int canal = 123;
bool botaoPressionado = false;

uint8_t lastRcBattery = ControleRemoto.rcBattery;
uint8_t remoteBattery = 45;
uint8_t lastRemoteBattery = 45; // ficticia

unsigned long startMillis;  // Millis para os loops em geral
unsigned long currentMillis;  // Millis para os loops em geral
const int period = 5000;  //the value is a number of milliseconds

bool menuAtivo = false;
int selected;  // Para os menus

bool rodou = 0; // Para o display saber se ja atualizou a tela

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

  startMillis = millis();  //initial start time


  
  for (int i = 0; i < numJoysticks; i++) {
    joysticks[i] = {joystickPins[i], {0}, 0, 0, 0};
    pinMode(joysticks[i].pin, INPUT);
  }
  

  if (radio.isChipConnected())
    Serial.println("\n\nTransmitter NF24 connected to SPI");
  else Serial.println("\n\nNF24 is NOT connected to SPI");

  // Inicialize o segundo barramento I2C
  I2C_1.begin(SDA1, SCL1, 100000); // 100kHz é a frequência do I2C

  // Inicialize o MCP23017 com o barramento I2C1
  if (!mcp.begin_I2C(0x20, &I2C_1)) { // Inicializa com o endereço 0x20
    Serial.println("Erro ao iniciar MCP23017.");
    while (1); // Pare o programa se o MCP23017 não puder ser inicializado
  }

  for (int i = 0; i < 9; i++) {mcp.pinMode(i, INPUT_PULLUP);}

  // Configure o pino 0 como entrada com pull-up interno ativado
  radio.begin();                          // Inicializando o MÓDULO RF24l01 para comunicação.
  radio.setAutoAck(false);                // Desativando pacotes ACK (Pacote de Confirmação de Recebimento de Mensagem)
  radio.setChannel(100);                  // Configurando Módulo para operar no canal número 1 (você pode escolher um canal de 0 a 127) (Canal Padrão é o 76)
  radio.setDataRate(RF24_250KBPS);        // Configurando Módulo para operar em uma taxa de 250kbps (Menor taxa de dados possível para um maior alcance do rádio)
  radio.setPALevel(RF24_PA_HIGH);         // Configurando Módulo para transmitir em potência máxima
  radio.powerUp();                        // Ativando Módulo, caso entre em estado de baixo consumo.
  radio.openWritingPipe(0xE8E8F0F0E1LL);  // Abrindo o meio de comunicação entre transmissor e receptor e configurando endereço de comunicação (0xE8E8F0F0E1LL)
  radio.stopListening();                  // Interrompendo mecanismos de recepção "escuta" do Módulo
  pinMode(16, INPUT);
}

// int x = 0;

void loop() 
{
  /*
  if (menuAtivo) {
    menu();
    return;
  }
  */

  joyAX = map(getSmoothedJoystickValue(joysticks[0]), 0, 4095, 0, 255);
  joyAY = map(getSmoothedJoystickValue(joysticks[1]), 0, 4095, 0, 255);
  joyBX = map(getSmoothedJoystickValue(joysticks[2]), 0, 4095, 0, 255);
  joyBY = map(getSmoothedJoystickValue(joysticks[3]), 0, 4095, 0, 255);
  pot1 =  map(getSmoothedJoystickValue(joysticks[4]), 0, 4095, 0, 255);
  pot2 =  map(getSmoothedJoystickValue(joysticks[5]), 0, 4095, 0, 255);
  pot3 =  map(getSmoothedJoystickValue(joysticks[6]), 0, 4095, 0, 255);
  pot4 =  map(getSmoothedJoystickValue(joysticks[7]), 0, 4095, 0, 255);

  if ((joyAX != ControleRemoto.JoyEsquerdaX) || (joyAY != ControleRemoto.JoyEsquerdaY) ||
      (joyBX != ControleRemoto.JoyDireitaX) || (joyBY != ControleRemoto.JoyDireitaY)) {
    
    if ((joyAX > (MidpointEsqX + Tolerance)) || ((joyAX < (MidpointEsqX - Tolerance)))) {
      ControleRemoto.JoyEsquerdaX = joyAX;
    }
    
    if ((joyAY > (MidpointEsqY + Tolerance)) || ((joyAY < (MidpointEsqY - Tolerance)))) {
      ControleRemoto.JoyEsquerdaY = joyAY;
    }

    if ((joyBX > (MidpointDirX + Tolerance)) || ((joyBX < (MidpointDirX - Tolerance)))) {
      ControleRemoto.JoyDireitaX = joyBX;
    }
    
    if ((joyBY > (MidpointDirY + Tolerance)) || ((joyBY < (MidpointDirY - Tolerance)))) {
      ControleRemoto.JoyDireitaY = joyBY;
    }

    
    /*
    Serial.print("joyAX: ");
    Serial.print(joyAX);
    Serial.print(" joyAY: ");
    Serial.print(joyAY);
    Serial.print(" | ");
    Serial.print("joyBX: ");
    Serial.print(joyBX);
    Serial.print(" joyBY: ");
    Serial.println(joyBY);
    */
  }

  ControleRemoto.Pot1 = pot1;
  ControleRemoto.Pot2 = pot2;
  ControleRemoto.Pot3 = pot3;
  ControleRemoto.Pot4 = pot4;

  ControleRemoto.BotEsqCim = mcp.digitalRead(0);
  ControleRemoto.BotEsqDir = mcp.digitalRead(1);
  ControleRemoto.BotEsqBai = mcp.digitalRead(2);
  ControleRemoto.BotEsqEsq = mcp.digitalRead(3);
  ControleRemoto.BotDirCim = mcp.digitalRead(4);
  ControleRemoto.BotDirDir = mcp.digitalRead(5);
  ControleRemoto.BotDirBai = mcp.digitalRead(6);
  ControleRemoto.BotDirEsq = mcp.digitalRead(7);

  Serial.print(ControleRemoto.Mts4);
  Serial.print(" | ");
  Serial.println(ControleRemoto.BotDirDir);

  ControleRemoto.Mts1 = digitalRead(34);
  ControleRemoto.Mts2 = digitalRead(35);
  ControleRemoto.Mts3 = digitalRead(32);
  ControleRemoto.Mts4 = mcp.digitalRead(8);


  
  if ((ControleRemoto.rcBattery != lastRcBattery || remoteBattery != lastRemoteBattery)/* && (rodou == 0)*/)
  {
    rodou = 1;
    Serial.println("Atualizou");
    u8g2.clearBuffer();  // clear the internal memory
    bateria();
    u8g2.setFont(u8g2_font_amstrad_cpc_extended_8u);
    u8g2.setCursor(1, 13);
    u8g2.print(F("CANAL: "));
    u8g2.setCursor(55, 13);
    u8g2.print(canal);

    u8g2.setFont(u8g2_font_t0_11_mr);
    u8g2.setCursor(ALIGN_CENTER(rcName), 30);
    u8g2.print(rcName);

    // Ícones
    u8g2.drawXBMP(107, 3, 20, 10, batLevel);
    u8g2.drawXBMP(107, 52, 20, 10, RCbatLevel);
    u8g2.drawXBMP(1, 50, 13, 13, configIcon);

    u8g2.drawHLine(0, 15, 128);
    u8g2.drawHLine(0, 47, 128);

    u8g2.sendBuffer();  // transfer internal memory to the display

    //u8g2.setPowerSave(1);
    //delay(5000);
    //u8g2.setPowerSave(0);
    //x += 1;
  }
  

  /*
  if (x == 5) {
    menuAtivo = true;
  }
  */

  for (int i = 0; i < 5; i++) {
    radio.write(&ControleRemoto, sizeof(ControleRemoto));
    // Serial.println(ControleRemoto.JoyDireitaX);
  }
}

void Controles() {}

void PowerSaving() {}

void Jogos() {}

void Debug() {}

// =========MENU========= //
typedef void (*FuncPtr)();

/*
void menu() 
{
  const char *options[5] = {
    " Voltar",
    " Controles",
    " Power Saving",
    " Jogos",
    " Debug"
  };

  FuncPtr funcoesMenu[5] = {
    loop,
    Controles,
    PowerSaving,
    Jogos,
    Debug
  };

  const int menuLength = sizeof(options) / sizeof(options[0]);
  const unsigned long period = 20;  // Intervalo em milissegundos
  int start = 0;
  selected = 0;  // Começa no item "Voltar"

  bool last12State = HIGH; // Invertido por causa do INPUT_PULLUP
  bool last13State = HIGH;
  bool last14State = HIGH;

  while (menuAtivo) {

    if (digitalRead(14) != last14State) {

      if (digitalRead(14) == LOW) {
        last14State = LOW;
        botaoPressionado = true;

        selected += 1;

        if (selected >= menuLength) {
          selected = 0;  // Volta para o primeiro item
          start = 0;
        }

        if (selected >= start + 3) {
          start += 1;  // Ajuste o início para rolar para baixo
        }
      }
      delay(100);
    }

    last14State = digitalRead(14);

// Atualiza o estado anterior do botão

    if (digitalRead(12) == LOW) {
      botaoPressionado = true;
      
      if (selected == 0) {
        selected = menuLength - 1;  // Volta para o último item
        start = menuLength - 3;     // Ajuste o início para mostrar os últimos itens
      } else {
        selected -= 1;
      }

      if (selected < start) {
        start -= 1;  // Ajuste o início para rolar para cima
      }
    }

    if (digitalRead(13) == LOW) {
      botaoPressionado = true;
      
      if (selected == 0) {
        menuAtivo = false;
        return;
      }

      funcoesMenu[selected]();  // Chame a função correspondente ao item selecionado
    }

    if (botaoPressionado) {
      botaoPressionado = false;

      u8g2.clearBuffer();
      u8g2.setCursor(ALIGN_CENTER("MENU"), 13);
      u8g2.print(F("MENU"));
      u8g2.drawHLine(0, 15, 128);

      for (int i = start; i < start + 5 && i < menuLength; i++) {
        int yPos = 15 + (i - start) * 12;
        if (i == selected) {
          u8g2.setDrawColor(1);
          u8g2.drawBox(0, yPos + 6, 128, 10);
          u8g2.setDrawColor(0);
        } else {
          u8g2.setDrawColor(1);
        }
        u8g2.drawXBMP(0, yPos + 6, 10, 10, bitmaps[i]);
        u8g2.setCursor(14, yPos + 15);
        u8g2.print(options[i]);
      }

      u8g2.sendBuffer();
    }
  }
}

*/

void bateria() 
{
  // Lê a V. bateria
  int x = 44;  // V. Ficticia (Controle)
  int y = ControleRemoto.rcBattery;  // V. Ficticia (Carrinho)

  if (x >= 50) {
    batLevel = maxbat;
  } else if (x > 43) {
    batLevel = medbat;
  } else {
    batLevel = lowbat;
  }

  if (y >= 50) {
    RCbatLevel = maxbat;
  } else if (y > 43) {
    RCbatLevel = medbat;
  } else {
    RCbatLevel = lowbat;
  }
}

And here's the diagram:

How did you solder the address pins ?

I just added the diagram

Did you check with multimeter if the address pins are correctly grounded, and there is no solder bridges anywhere ?

Try I2C scanner

Maybe the device was damaged during soldering

I don't know if this is normal, but on my two esp32s EVERY pin is "shorted". For example, if I put my multimeter on the continuity scale and then test GND and 3V3, they are shorted. But even so, both always worked well.

No, not normal. The continuity check is either not working correctly, or you are using it incorrectly. Make sure that the MCU is not powered when testing continuity.

I tried one and it says this:

Scanning...
I2C device found at address 0x3C  !
done

.

I changed the MCP and it still don't work

Also, I'm not using any resistors in SDA and SCL. Could this be the problem?
And if it is, which ones should I use?

UPDATE: Tried it one more time and it was working 'till I restarted the esp32... Don't know why. It's so strange, it works only when it wants

Hi, @joneox

Can you please post some images of your project?

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Not a Fritzy cut and paste image.
Sorry but your Fritzy makes no sense electrically.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

@joneox
He means the address pins on the MCP23017 not the ESP.

Yes this is normal because the voltage out of the continuity tester sends out a small voltage and this breaks down the chip's static protection diodes so it looks like a short.

Try this experiment, using the continuity tester test an LED. You should see the LED light up very very dimly. If you do not see anything then swap the leads over. This illustrates how useless testing the continuity of a chip is.

SDA and SCL are open collector drivers. You need pull-up resistors to ensure proper functioning. 4.7K or 5K to 3.3V is typical.

No bypass capacitor for the MCP.

Sometimes the stray capacitance of a breadboard can be enough that the circuit works without a bypass cap. But every bare chip in your circuit needs one, 0.1uF as close as possible to the Vcc & Gnd pins of each chip.

It might not fix the problem, but you should always add bypass caps, and it's very simple, so not much point looking for other reasons until you have eliminated that one.

Could be dangerous.

Do your 18650 cells have built-in over-discharge protection? Most to not. The ones that do have a metal strip running the length of the battery and are slightly longer than 65mm because of the tiny protection circuit board.

Without those, the batteries can be damaged, and then there is a risk of them exploding or catching fire when you recharge them.

The AMS1117-33 claims to be "low drop-out" but I would not describe them like that. There are much lower drop-out regulators available such as MCP1700 and HT7333. With AMS1117, the battery life will be shortened because of its higher voltage drop.

Your AMS1117 will probably not work reliably, or at all, because you haven't added the recommended smoothing capacitors on its input and output pins.

Your ESP board may already have an AMS1117 onboard anyway. I'm not sure why you connected an external one also. None of your other components appear to need high currents.

Why are you using NRF2401? It's range is similar to the ESP's WiFi. There is also ESPnow if you want to communicate between ESP boards without actually using WiFi.

First of all, thanks for all of you guys help



I know, it's a mess, and you can barely understand what's happening, but I ensure you that there's no wires shorted

I don't know if this is what you are asking for, but everything is on the image I uploaded in the first post

Thanks!

I will search how to do this

Actually, I forgot to add them on the schematics, but they're here. 100uf on the input and 10uf on the output


That white thing is hot glue to prevent shorting

Yes, it has. But I couldn't find any information about it and I don't know how much mA it can provide

It's because my rc car uses arduino

Hi, @joneox
It would have been better for you to use strip or Vero board for your project.
image

Can you please post a copy of your updated circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

What do you mean

You are missing connection for the reset pin of MCP, have to stay high for working.

Ciao, Ale.

1 Like

Thanks, solved my problem.

Thanks to everyone who helped me


The circled wire arrangements.
What wire goes to what terminal on the 1117 for example, what are the terminals named?
The MTS, two of them only have ONE connection and in all cases you have wires over top of other wires.
None of the 23017 pins is labelled.

Sorry but this would have been noticed earlier with a concise schematic.

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Thanks.. Tom... :smiley: :+1: :coffee: :australia:

My bad. It's because I made this scheme just for myself, I didn't plan on showing it to anyone else.

Unbelievable.

We can only know what you tell us and we didn't stand a chance did we?

For your information your whole circuit is riddled with errors you have been told about and done nothing to correct this. We can tell this from your actual photographs.

One wonders why you ask questions only to ignore answers.