Coder Social home page Coder Social logo

arduino-mcp23017's Introduction

MCP23017

Build Status License

This library provides full control over the Microchip's MCP23017, including interrupt support.

Features

  • Individual pins read & write
  • Ports read & write
  • Registers read & write
  • Full interrupt support

Usage

Unlike most Arduino library, no default instance is created when the library is included. It's up to you to create one using the appropriate I2C address based on MCP23017 A0, A1 and A2 pins wirings. Available addresses go from 0x20 to 0x27, allowing up to 8 MCP23017 on the same I2C bus.

#include <Arduino.h>
#include <MCP23017.h>

MCP23017 mcp = MCP23017(0x24);

Additionaly, you can specify the Wire instance to use as a second argument. For instance MCP23017(0x24, Wire1).
See included examples for further usage.

Warning about GPA7 & GPB7

GPA7 or GPB7 should not be used as inputs despite what the configuration registers allow. As stated by Microchip, it can lead to SDA signal corruption or even malfunction in the host bus under some conditions.

Breaking changes in v2.0.0

Major renames have been performed in v2.0.0 to improve compatibility with a variety of platforms. Existing code will break when you update from version v1.x.

Name in v1.x Name in v2.x
MCP23017_PORT MCP23017Port
MCP23017_REGISTER MCP23017Register
MCP23017_INTMODE MCP23017InterruptMode

In addition to this, every member of the MCP23017Register enum were renamed to avoid possible conflicts with macro definitions. GPIOA was renamed to GPIO_A, INTCAPA to INTCAP_A and so on...

arduino-mcp23017's People

Contributors

blemasle avatar cwverhey avatar dok-net avatar muman613 avatar p4rk avatar rolgordijn avatar trycoon avatar yanzixiang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

arduino-mcp23017's Issues

Init method should not enable pull-up by default

The init() method enables the pull-up resistors by default.
this means that there is 5V on each pin. Even if I then configure the pins as output, there will be a very short time that a weak 5V is present at the output.

This is really undesirable.

In my case, my Arduino board is powered with 16V AC.
This is then converted to DC, and from that DC voltage, I make 9 volts with a step-down converter and 5 volts with a linear regulator to power my circuit. I'm controlling solenoids from that stabilized DC voltage. These are activated with a transistor connected to the MCP23017 with an appropriate base resistor.

At power-on, the pull-ups are activated, activating all 16 solenoids. They draw to much current, causing the DC voltage to drop and this causes a brown-out reset. (and the cycle starts again. Arduino starts, executes init() method, activates all solenoids, brown out reset, ....)

Problem with readPort

I am using two mux (for the moment) to read a keyboard matrix, one mux uses all pins of both ports as outputs, the other one only 7 of port A as inputs (there is a diode from col to row on each key). The MCU is a teensy 4.1.

I am using a Serial.println(mcpRows.readPort(MCP23017Port::A), BIN); to check the activated rows but I am getting some weird output, at first it seems to shows the 8 pins, then when I start pressing a key it shows 6 digits, then maybe only one, 4, etc. any ideas what can be the issue ?

Code:

#include <Arduino.h>
#include <Wire.h>
#include <MCP23017.h>

MCP23017 mcpCols = MCP23017(KBD_COL_MUX_ADDR, Wire1);
MCP23017 mcpRows = MCP23017(KBD_ROW_MUX_ADDR, Wire1);

const int muxPorts[] = {
  0b00000001,
  0b00000010,
  0b00000100,
  0b00001000,
  0b00010000,
  0b00100000,
  0b01000000,
  0b10000000,
};

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

  // Setup I2c (default ports)
  Wire.begin();
  // Setup I2c (second port)
  Wire1.begin();

  mcpCols.init();
  mcpCols.portMode(MCP23017Port::A, 0); // Port A output
  mcpCols.portMode(MCP23017Port::B, 0); // Port B output

  mcpCols.writeRegister(MCP23017Register::GPIO_A, 0x00);
  mcpCols.writeRegister(MCP23017Register::GPIO_B, 0x00);

  mcpRows.init();
  mcpRows.portMode(MCP23017Port::A, 0b11111111, 0b00000000, 0x00); // Port A input,no  pull up, ipolb

  mcpRows.writeRegister(MCP23017Register::GPIO_A, 0x00);
}

void loop() {
  /* Matrix buttons handling */
  for (int col = 0; col < 15; col++) {
    if (col < 8) {
      // Clear bank B
      mcpCols.writePort(MCP23017Port::B, 0x00000000);

      // Bank A
      mcpCols.writePort(MCP23017Port::A, muxPorts[col]);
      if (VERBOSE) {
        Serial.printf("COLA %d\t", col);
      }
    } else {
      // Clear bank A
      mcpCols.writePort(MCP23017Port::A, 0x00000000);

      // Bank B
      // Remove 8 to start from 0 on the second bank
      mcpCols.writePort(MCP23017Port::B, muxPorts[col-8]);
      if (VERBOSE) {
        Serial.printf("COLB %d\t", col);
      }
    }

    // Get rows status
    // byte rowStatus = mcpRows.readPort(MCP23017Port::A);
    if (VERBOSE) {
      Serial.println(mcpRows.readPort(MCP23017Port::A), BIN);
    }

    // For debugging purposes
    delay(10);
  }

}

example output:

COLA 0  10011000
COLA 1  10011000
COLA 2  10011000
COLA 3  10011000
COLA 4  10011100
COLA 5  10011100
COLA 6  11100
COLA 7  11000
COLB 8  11000
COLB 9  11000
COLB 10 11000
...
COLB 13 11001
COLB 14 11001
COLA 0  11001
COLA 1  11001
COLA 2  11001
COLA 3  11001
...
COLB 14 1000
COLA 0  1000
COLA 1  1000
COLA 2  1000
COLA 3  1001000
COLA 4  1001000
COLA 5  1001000
COLA 6  0
COLA 7  0
COLB 8  0
COLB 9  0
COLB 10 0
COLB 11 0
...
COLA 5  0
COLA 6  0
COLA 7  0
COLB 8  0
COLB 9  0
COLB 10 0
COLB 11 0
COLB 12 0
COLB 13 0
COLB 14 0
COLA 0  0
COLA 1  0
COLA 2  1000000
COLA 3  1000000
COLA 4  1000000
COLA 5  0
COLA 6  0
COLA 7  0
COLB 8  0
COLB 9  0

Compile error, multiple default-values specified

Compiling .pio/build/nodemcuv2/libf5a/MCP23017_ID6001/MCP23017.cpp.o
.pio/libdeps/nodemcuv2/MCP23017_ID6001/src/MCP23017.cpp:3:56: error: default argument given for parameter 2 of 'MCP23017::MCP23017(uint8_t, TwoWire&)' [-fpermissive]
MCP23017::MCP23017(uint8_t address, TwoWire& bus = Wire) {
^
In file included from .pio/libdeps/nodemcuv2/MCP23017_ID6001/src/MCP23017.cpp:1:0:
.pio/libdeps/nodemcuv2/MCP23017_ID6001/src/MCP23017.h:67:2: note: previous specification in 'MCP23017::MCP23017(uint8_t, TwoWire&)' here
MCP23017(uint8_t address, TwoWire& bus = Wire);

Default parameter has been specified both here https://github.com/blemasle/arduino-mcp23017/blob/master/src/MCP23017.cpp#L3 and here https://github.com/blemasle/arduino-mcp23017/blob/master/src/MCP23017.h#L67
It should only be set in header-file!

Encoders

Hi, thanks very much for the library. Does it support rotary encoders? I can't figure out how to get a proper reading.

Interrupts aren't open drain by default

In the init for the MCP23017 the comments say that setting IOCON.ODR (bit 2) to 0 sets the interrupts to be open-drain.
This in fact sets the output to use the active drivers and the IOCON.INTPOL for active high and active low.

Created a PR to update the comments on the init function here #25

Thank you for the library.

Multiple boards on 1 bus

EDIT:
I've realized: YES, this library CAN handle up to 8 of the MCP23017 panels, each with different address.

The Readme.md could be enhanced a tiny bit more to make that clear:

Usage

Unlike most Arduino library, no default instance is created when the library is included.
It's up to you to create one with the appropriate chip I2C address.
Maximum 8 boards can be attached to one I2C bus. Address goes from (hexa) 0x20 - 0x27

#include <Arduino.h>
#include <MCP23017.h>

MCP23017 mcp1 = MCP23017(0x20);
// ...
MCP23017 mcp8 = MCP23017(0x27);

INPUT-OUTPUT-Definition

In MCP23017.cpp line 41 setting of OUTPUT is:
iodir = readRegister(iodirreg);
if(mode == OUTPUT) iodir |= _BV(pin);
else iodir &= ~_BV(pin);

but from datasheet:
3.5.1 I/O DIRECTION REGISTER
Controls the direction of the data I/O.
When a bit is set, the corresponding pin becomes an input.
When a bit is clear, the corresponding pin becomes an output.

So please correct
Thanks

Understanding Example PortCopyOnInterrupt

It seems that I miss something in the PortCoypOnInterrupt Example.
My setup uses an Arduino MEGA in conjunction with the MCP23017

I attached buttons to port B (input port) that connect the MCP pins on port B to ground when pressed.
Port A pins serve as outputs for LEDs.

When I run the example and I press any of the buttons the corresponding pin on portA turns on.
The interrupt routine has been called and the interrupt has been handled.

However, after the first interrupt no further interrupts occur anymore, neither on the same pin nor on any other input pin.

As I understand the default input mode is with pull up, so after releasing the button (disconnecting ground) the input pin should return to high.

Any idea why subsequent interrupts are ignored or don't get through?

Not able to initiate the class in an array

I have a number of MCP23017 and rather than initialising each individually I attempted to use the following:

  MCP23017 mcpi[4];
  int address = 0x20;
  for( int j = 0; j < 4; j++)
  {
    mcpi[j].MCP23017(address)
    address++;
  }

but get the error "no matching function for call to 'MCP23017::MCP23017()'

Are you able to confirm thus can be done and if so what am I doing wrong.

add support to use wire1?

the library use WRIE default ?
but some board have two i2c-bus or more,
how to use another i2c-bus?

delay time for a bounce switch

On the 23017 Arduino Library, I changed the delay statement for the switch bounce to checking the io pin according to the timimg on the data sheet instead of waiting the 200 milliseconds. For me the I2C is slow enough without waiting 200ms every time a switch is pressed

Problem with digitalRead

Hi!

program code

#include <Wire.h>
#include <MCP23017.h>
#define i2c_mcp23017_ADDR_000 0x20
MCP23017 mcp23017_0x20 = MCP23017(i2c_mcp23017_ADDR_000);

void setup() {
  Serial.begin(9600);
  Wire.begin();
  mcp23017_0x20.init();
  for (uint8_t i = 0; i < 16; i++) mcp23017_0x20.pinMode(i, INPUT);
  Wire.beginTransmission(i2c_mcp23017_ADDR_000);
  Wire.write(0x02);
  Wire.write(0xFF);
  Wire.endTransmission();
  Wire.beginTransmission(i2c_mcp23017_ADDR_000);
  Wire.write(0x03);
  Wire.write(0xFF);
  Wire.endTransmission();
}

void loop() {
  if (mcp23017_0x20.digitalRead(2)) {
    Serial.println("pin2 = HIGH");
  }
  else {
    Serial.println("pin2 = LOW");
  }
  Serial.println(mcp23017_0x20.readPort(MCP23017_PORT::A), BIN);
  Serial.println(mcp23017_0x20.readPort(MCP23017_PORT::B), BIN);
  delay(1000);
}

COM port monitor

pin2 = LOW
10000000
10000000
pin2 = LOW
10000100
10000000
pin2 = LOW
10000100
10000100
pin2 = HIGH
10000101
10000100
pin2 = LOW
10000100
10000100

When inverted ports with any choice of pin (0-7 / 8-15), the condition is triggered when a signal is applied to 0 or 8, respectively.
Help me!

Pavel

Datasheet Change Due To Issue Discovered In MCP23017 Chip

I found out today that Microchip discovered an issue in their MCP23017 chip where under certain circumstances the I2C SDA signal may become corrupted when the chip’s GPA7 and/or GPB7 pins are used as inputs. For this reason, they updated the datasheet to reflect that those pins should only be used as outputs.

I'm hopeful that a silicon revision is in the works, but I wanted to alert the library maintainer in case they were unaware of the issue.

Problem in dual configuration

Hi,
so I'm experiencing a weird problem, that I can't identify correctly.

In the Arduino (I'm using an Arduino Uno, 2.2K pull-ups on I²C-bus) setup function I do the following configuration:

#define i2c_address_ioe_address 0x27
#define i2c_address_ioe_data_misc 0x20
MCP23017 mcp_address = MCP23017(i2c_address_ioe_address), mcp_data_misc = MCP23017(i2c_address_ioe_data_misc);
mcp_address.init();
mcp_data_misc.init();
mcp_address.portMode(MCP23017Port::A, 0); //Port A as output
mcp_address.portMode(MCP23017Port::B, 0); //Port B as output
mcp_data_misc.portMode(MCP23017Port::A, 0); //Port A as output
mcp_data_misc.portMode(MCP23017Port::B, 0b11110000); //Port A partly as output

In the loop, I have a test program, which turns each pin on individually (all others 0, the tested pin to one; I'm ignoring the ones that are configured as input ofc) to test if the output is working. I monitor the pin states with a 28 pin logic analyzer and therefore see which pin is working. To set the pin states I use the below functions.

uint16_t address = some_value;
mcp_address.write(address);
gpio->mcp_data_misc.writePort(MCP23017Port::A, data);
mcp_data_misc.digitalWrite(singlePin, 0);
mcp_data_misc.digitalWrite(singlePin, 1);

My issue is that if I write any pin to the mcp_address-module, pin 10 of the mcp_data_misc-module is not changing its state anymore.

Obviously, I thought this might be a PCB issue (schematic and layout of the PCB for reference). However, I tried 2 copies of the PCB and the issue persists.

One of those PCBs I already tested months ago with the MCP23017-library of WiringPi (obv. on a Raspberry Pi; I had level conversion there for 3.3V RPi GPIO to 5V MCP23017 levels) and back then all pins were working in a similar test.

So my question: Is there anything one has to keep in mind when working with multiple MCP23017? Has anybody experienced a similar issue? Is my configuration or the functions I use wrong?

TY for any help in advance.

Interrupt behaviour on multiple MCP23017

Hi,

I'm stuck with an interrupt issue and hoping to get some guidance.

I'm using 2 MCP23017 with an Arduino Mega on different interrupts and a couple of push buttons. MCPs are initialised in the same way, and the code to read them is the same, however the behaviour is slightly different.

Here's the outuput after pressing and releasing 2 push buttons, one connected to each MCP:

20:00:10.626 -> MCP1 Interrupted
20:00:10.626 -> Port A -> 11111101
20:00:10.626 -> Port B -> 11111111

20:00:13.056 -> MCP4 Interrupted
20:00:13.056 -> Port A -> 11111101
20:00:13.056 -> Port B -> 11111111
20:00:13.148 -> MCP4 Interrupted
20:00:13.148 -> Port A -> 11111111
20:00:13.148 -> Port B -> 11111111

So looks like MCP1 is only catching when I push down the button, but not the release. Any idea what could be causing this difference in behaviour?

Here's my initialisation code:

    mcp1.init();
    mcp1.portMode(MCP23017Port::A, 0xFF);          
    mcp1.portMode(MCP23017Port::B, 0xFF); //Port B as input

    mcp1.interruptMode(MCP23017InterruptMode::Or);      
    mcp1.interrupt(MCP23017Port::A, FALLING);
    mcp1.interrupt(MCP23017Port::B, FALLING);
    

    mcp1.writeRegister(MCP23017Register::IPOL_A, 0x00);
    mcp1.writeRegister(MCP23017Register::IPOL_B, 0x00);

    mcp1.writeRegister(MCP23017Register::GPIO_A, 0x00);
    mcp1.writeRegister(MCP23017Register::GPIO_B, 0x00);

    mcp1.clearInterrupts();

     pinMode(MCP1_INT_PIN, INPUT_PULLUP);

    attachInterrupt(digitalPinToInterrupt(MCP1_INT_PIN), MCP1_int, FALLING);

And here's how I read the values:

    if(MCP1_interrupted) 
    {
      Serial.println("MCP1 Interrupted");

     MCP1_interrupted = false;
      mcp1.interruptedBy(a, b);
      mcp1.clearInterrupts(captureA, captureB);     


      currentA = mcp1.readPort(MCP23017Port::A);
      currentB = mcp1.readPort(MCP23017Port::B);

      Serial.print("Port A -> ");
      Serial.println(currentA,BIN);
      Serial.print("Port B -> ");
      Serial.println(currentB,BIN);
      mcp1.clearInterrupts();
    }

Cheers,

Bruno

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.