MCP23018 I2C IO expander

Hi
I bought a new MCP23018 IO expander. But underestimated the difficulty of what I started.
I’m able to get a connection without having any errors and detected it on address 20:

Wire.begin();
Wire.beginTransmission(20);
int error = Wire.endTransmission();

But I don’t know how to get a led to blink. (Totally useless)
It’s an Arduino Uno rev3 with 2 pull-up resistors of 10Kohm for the i2c communication.
I can’t find any clear tutorial and don’t know where to start. (The datasheet is also not self-explaining :D)
It would be nice if you could give me one working example.
Greeting from The Netherlands.

Hi philippe

This may help: Interfacing MCP23018 io expander via Arduino. - Interfacing - Arduino Forum

Also: [solved]mcp23018 not working - LEDs and Multiplexing - Arduino Forum

Regards

Ray

Thanks a lot for responding!
I already read those 2 posts, but by trying again because of yours motivation I am able to get a led blink. (Link 1)
But I have 2 questions.
I don’t understand the first 10 lines in the setup. Is it really needed, or is there a shorter way if I just want a led to blink. (Without libraries)
Second (less important), my led blinks very weak (with 220ohm resistor). Is there already an internal resistor and could I omit it, or is this just the maximum output current?
Again thanks!

I think there are problems with the code in the original post in link 1 thread.

The code in reply #2 of that thread may be a better starting point.

Looks like the absolute minimum you require in setup() for your application is to set the IODIRA direction register so that the pins are outputs, not inputs.

For this, you need to write 0x00 to IODIRA.

#define IODIRA 0x00
#define GPIOA 0x12
#define I2C_ADDRESS 0x20
void setup()
{
  Wire.begin();
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(IODIRA);
  Wire.send(0x00); 
  Wire.endTransmission();
}

With the default IOCON settings, GPIOA is register 0x12.

void loop()
{
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(GPIOA);
  Wire.send(0xFF); 
  Wire.endTransmission();
  delay(1000);
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.send(GPIOA);
  Wire.send(0x00); 
  Wire.endTransmission();
  delay(1000);
}

Note: I don't have an MCP23018 so can't test this, I'm afraid.

About your LED, how do you have it and the series resistor connected?

Hi
Sorry, but your code doesn’t work. I have to set 2 more configurations. I finally understand the datasheet and think this is the minimum:

#include <Wire.h>

#define IODIRA 0x00
#define GPPUA 0x06
#define GPIOA 0x09
#define OLATA 0x0a
#define I2C_ADDRESS 0x20

void setup()
{
  Wire.begin();
  Wire.beginTransmission(I2C_ADDRESS);//set all pins to output
  Wire.write(IODIRA);
  Wire.write(0x00);
  Wire.endTransmission();
  
  //*FIRST
  Wire.beginTransmission(I2C_ADDRESS);//use output latch???
  Wire.write(OLATA);
  Wire.write(0xFF);
  Wire.endTransmission();
  
  //*SECOND
  Wire.beginTransmission(I2C_ADDRESS);//use internal pull-up resistors (250 µA)
  Wire.write(GPPUA);
  Wire.write(0xFF);
  Wire.endTransmission();
}

void loop()
{
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(GPIOA);
  Wire.write(0x01); 
  Wire.endTransmission();
  delay(100);
  
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(GPIOA);
  Wire.write(0x00); 
  Wire.endTransmission();
  delay(100);
}

Note: you should first set the latch, then the pull-up resistor: WEIRD?? Otherwise it doesn’t work.
Something else: it’s very unstable. When I try to connect a cable just on one side to any point in the breadboard, it stops.

Connection of my led:
GPA0 (pin 20) --> led --> 220ohm resistor --> ground of Arduino
With an external pull-up resistor (10Kohm), the LED is a little bit brighter, but not as bright as connecting it directly of the 5 volt with 220ohm.

Connection of my led:
GPA0 (pin 20) --> led --> 220ohm resistor --> ground of Arduino

The MCP23018 outputs are open drain. Your LED and series resistor will work better if connected to +5V. When the output goes LOW, the LED should come on.

This will avoid the need to use the internal pull-up resistors.

#define OLATA 0x0a

When the MCP23018 powers up, IOCON contains 0x00. This means bit 7 (BANK) is 0, so the register addresses in datasheet Table 1-5 apply.

From this table, 0x0A is the address of IOCON, not OLATA.

 //*FIRST
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(OLATA); 
  Wire.write(0xFF);
  Wire.endTransmission();

This code therefore writes 0xFF into IOCON, which sets BANK = 1, so now the addresses in Table 1-4 apply.

From that table, GPPUA is 0x06 and GPIOA is 0x09, which match the #defines in your code.

THANKS THANKS THANKS!!!!
It works how you predicted the first time!! But now I also understand what went wrong. I didn’t realize that the register address changed in comparison to the state of this chip.
By the way my LED blinks like a sun! :smiley:
My new working code:

#include <Wire.h>

#define IODIRA 0x00
#define GPIOA 0x12
#define I2C_ADDRESS 0x20

void setup()
{
  Wire.begin();
  Wire.beginTransmission(I2C_ADDRESS);//set all pins to output
  Wire.write(IODIRA);
  Wire.write(0x00);
  Wire.endTransmission();
}

void loop()
{
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(GPIOA);
  Wire.write(0x01); 
  Wire.endTransmission();
  delay(500);
  
  Wire.beginTransmission(I2C_ADDRESS);
  Wire.write(GPIOA);
  Wire.write(0x00); 
  Wire.endTransmission();
  delay(500);
}

Best wishes for a happy New Year!

1 Like