From 984833904d107b6a2b8fa15cb3a1c14748a92057 Mon Sep 17 00:00:00 2001 From: caternuson Date: Wed, 16 Jun 2021 09:01:13 -0700 Subject: [PATCH 1/4] major update --- Adafruit_MCP23017.cpp | 351 ------------------ Adafruit_MCP23017.h | 92 ----- README.md | 61 ++- examples/button/button.ino | 32 -- .../custom_frequency/custom_frequency.ino | 17 - examples/interrupt/.leonardo.test.only | 0 examples/interrupt/.mega2560.test.only | 0 examples/interrupt/.uno.test.only | 0 examples/interrupt/interrupt.ino | 128 ------- examples/mcp23xxx_blink/mcp23xxx_blink.ino | 40 ++ examples/mcp23xxx_button/mcp23xxx_button.ino | 41 ++ examples/mcp23xxx_combo/mcp23xxx_combo.ino | 41 ++ .../mcp23xxx_interrupt/mcp23xxx_interrupt.ino | 60 +++ examples/toggle/toggle.ino | 35 -- keywords.txt | 16 +- library.properties | 8 +- src/Adafruit_MCP23X08.cpp | 32 ++ src/Adafruit_MCP23X08.h | 20 + src/Adafruit_MCP23X17.cpp | 93 +++++ src/Adafruit_MCP23X17.h | 27 ++ src/Adafruit_MCP23XXX.cpp | 340 +++++++++++++++++ src/Adafruit_MCP23XXX.h | 77 ++++ 22 files changed, 817 insertions(+), 694 deletions(-) delete mode 100644 Adafruit_MCP23017.cpp delete mode 100644 Adafruit_MCP23017.h delete mode 100644 examples/button/button.ino delete mode 100644 examples/custom_frequency/custom_frequency.ino delete mode 100644 examples/interrupt/.leonardo.test.only delete mode 100644 examples/interrupt/.mega2560.test.only delete mode 100644 examples/interrupt/.uno.test.only delete mode 100644 examples/interrupt/interrupt.ino create mode 100644 examples/mcp23xxx_blink/mcp23xxx_blink.ino create mode 100644 examples/mcp23xxx_button/mcp23xxx_button.ino create mode 100644 examples/mcp23xxx_combo/mcp23xxx_combo.ino create mode 100644 examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino delete mode 100644 examples/toggle/toggle.ino create mode 100644 src/Adafruit_MCP23X08.cpp create mode 100644 src/Adafruit_MCP23X08.h create mode 100644 src/Adafruit_MCP23X17.cpp create mode 100644 src/Adafruit_MCP23X17.h create mode 100644 src/Adafruit_MCP23XXX.cpp create mode 100644 src/Adafruit_MCP23XXX.h diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp deleted file mode 100644 index 5e9d58e..0000000 --- a/Adafruit_MCP23017.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/*! - * @file Adafruit_MCP23017.cpp - * - * @mainpage Adafruit MCP23017 Library - * - * @section intro_sec Introduction - * - * This is a library for the MCP23017 i2c port expander - * - * These displays use I2C to communicate, 2 pins are required to - * interface - * Adafruit invests time and resources providing this open source code, - * please support Adafruit and open-source hardware by purchasing - * products from Adafruit! - * - * @section author Author - * - * Written by Limor Fried/Ladyada for Adafruit Industries. - * - * @section license License - * - * BSD license, all text above must be included in any redistribution - */ - -#ifdef __AVR -#include -#elif defined(ESP8266) -#include -#endif -#include "Adafruit_MCP23017.h" - -#if ARDUINO >= 100 -#include "Arduino.h" -#else -#include "WProgram.h" -#endif - -// minihelper to keep Arduino backward compatibility -static inline void wiresend(uint8_t x, TwoWire *theWire) { -#if ARDUINO >= 100 - theWire->write((uint8_t)x); -#else - theWire->send(x); -#endif -} - -static inline uint8_t wirerecv(TwoWire *theWire) { -#if ARDUINO >= 100 - return theWire->read(); -#else - return theWire->receive(); -#endif -} - -/** - * Bit number associated to a give Pin - */ -uint8_t Adafruit_MCP23017::bitForPin(uint8_t pin) { return pin % 8; } - -/** - * Register address, port dependent, for a given PIN - */ -uint8_t Adafruit_MCP23017::regForPin(uint8_t pin, uint8_t portAaddr, - uint8_t portBaddr) { - return (pin < 8) ? portAaddr : portBaddr; -} - -/** - * Reads a given register - */ -uint8_t Adafruit_MCP23017::readRegister(uint8_t addr) { - // read the current GPINTEN - _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(addr, _wire); - _wire->endTransmission(); - _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 1); - return wirerecv(_wire); -} - -/** - * Writes a given register - */ -void Adafruit_MCP23017::writeRegister(uint8_t regAddr, uint8_t regValue) { - // Write the register - _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(regAddr, _wire); - wiresend(regValue, _wire); - _wire->endTransmission(); -} - -/** - * Helper to update a single bit of an A/B register. - * - Reads the current register value - * - Writes the new register value - */ -void Adafruit_MCP23017::updateRegisterBit(uint8_t pin, uint8_t pValue, - uint8_t portAaddr, - uint8_t portBaddr) { - uint8_t regValue; - uint8_t regAddr = regForPin(pin, portAaddr, portBaddr); - uint8_t bit = bitForPin(pin); - regValue = readRegister(regAddr); - - // set the value for the particular bit - bitWrite(regValue, bit, pValue); - - writeRegister(regAddr, regValue); -} - -//////////////////////////////////////////////////////////////////////////////// - -/*! - * Initializes the MCP23017 given its HW selected address, see datasheet for - * Address selection. - * @param addr Selected address - * @param theWire the I2C object to use, defaults to &Wire - */ -void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { - if (addr > 7) { - addr = 7; - } - i2caddr = addr; - _wire = theWire; - - _wire->begin(); - - // set defaults! - // all inputs on port A and B - writeRegister(MCP23017_IODIRA, 0xff); - writeRegister(MCP23017_IODIRB, 0xff); - - // Turn off interrupt triggers - writeRegister(MCP23017_GPINTENA, 0x00); - writeRegister(MCP23017_GPINTENB, 0x00); - - // Turn off pull up resistors - writeRegister(MCP23017_GPPUA, 0x00); - writeRegister(MCP23017_GPPUB, 0x00); -} - -/** - * Initializes the default MCP23017, with 000 for the configurable part of the - * address - * @param theWire the I2C object to use, defaults to &Wire - */ -void Adafruit_MCP23017::begin(TwoWire *theWire) { begin(0, theWire); } - -/** - * Sets the pin mode to either INPUT or OUTPUT - * @param p Pin to set - * @param d Mode to set the pin - */ -void Adafruit_MCP23017::pinMode(uint8_t p, uint8_t d) { - updateRegisterBit(p, (d == INPUT), MCP23017_IODIRA, MCP23017_IODIRB); -} - -/** - * Reads all 16 pins (port A and B) into a single 16 bits variable. - * @return Returns the 16 bit variable representing all 16 pins - */ -uint16_t Adafruit_MCP23017::readGPIOAB() { - uint16_t ba = 0; - uint8_t a; - - // read the current GPIO output latches - _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(MCP23017_GPIOA, _wire); - _wire->endTransmission(); - - _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 2); - a = wirerecv(_wire); - ba = wirerecv(_wire); - ba <<= 8; - ba |= a; - - return ba; -} - -/** - * Read a single port, A or B, and return its current 8 bit value. - * @param b Decided what gpio to use. Should be 0 for GPIOA, and 1 for GPIOB. - * @return Returns the b bit value of the port - */ -uint8_t Adafruit_MCP23017::readGPIO(uint8_t b) { - - // read the current GPIO output latches - _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); - if (b == 0) - wiresend(MCP23017_GPIOA, _wire); - else { - wiresend(MCP23017_GPIOB, _wire); - } - _wire->endTransmission(); - - _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 1); - return wirerecv(_wire); -} - -/** - * Writes all the pins in one go. This method is very useful if you are - * implementing a multiplexed matrix and want to get a decent refresh rate. - */ -void Adafruit_MCP23017::writeGPIOAB(uint16_t ba) { - _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(MCP23017_GPIOA, _wire); - wiresend(ba & 0xFF, _wire); - wiresend(ba >> 8, _wire); - _wire->endTransmission(); -} - -/*! - * @brief Writes to a pin on the MCP23017 - * @param pin Pin to write to - * @param d What to write to the pin - */ -void Adafruit_MCP23017::digitalWrite(uint8_t pin, uint8_t d) { - uint8_t gpio; - uint8_t bit = bitForPin(pin); - - // read the current GPIO output latches - uint8_t regAddr = regForPin(pin, MCP23017_OLATA, MCP23017_OLATB); - gpio = readRegister(regAddr); - - // set the pin and direction - bitWrite(gpio, bit, d); - - // write the new GPIO - regAddr = regForPin(pin, MCP23017_GPIOA, MCP23017_GPIOB); - writeRegister(regAddr, gpio); -} - -/*! - * @brief Enables the pull-up resistor on the specified pin - * @param p Pin to set - * @param d Value to set the pin - */ -void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) { - updateRegisterBit(p, d, MCP23017_GPPUA, MCP23017_GPPUB); -} - -/*! - * @brief Reads the specified pin - * @param pin Pin to read - * @return Value of the pin - */ -uint8_t Adafruit_MCP23017::digitalRead(uint8_t pin) { - uint8_t bit = bitForPin(pin); - uint8_t regAddr = regForPin(pin, MCP23017_GPIOA, MCP23017_GPIOB); - return (readRegister(regAddr) >> bit) & 0x1; -} - -/** - * Configures the interrupt system. both port A and B are assigned the same - * configuration. - * @param mirroring Mirroring will OR both INTA and INTB pins. - * @param openDrain Opendrain will set the INT pin to value or open drain. - * @param polarity polarity will set LOW or HIGH on interrupt. - * Default values after Power On Reset are: (false, false, LOW) - * If you are connecting the INTA/B pin to arduino 2/3, you should configure the - * interupt handling as FALLING with the default configuration. - */ -void Adafruit_MCP23017::setupInterrupts(uint8_t mirroring, uint8_t openDrain, - uint8_t polarity) { - // configure the port A - uint8_t ioconfValue = readRegister(MCP23017_IOCONA); - bitWrite(ioconfValue, 6, mirroring); - bitWrite(ioconfValue, 2, openDrain); - bitWrite(ioconfValue, 1, polarity); - writeRegister(MCP23017_IOCONA, ioconfValue); - - // Configure the port B - ioconfValue = readRegister(MCP23017_IOCONB); - bitWrite(ioconfValue, 6, mirroring); - bitWrite(ioconfValue, 2, openDrain); - bitWrite(ioconfValue, 1, polarity); - writeRegister(MCP23017_IOCONB, ioconfValue); -} - -/** - * Set's up a pin for interrupt. uses arduino MODEs: CHANGE, FALLING, RISING. - * - * Note that the interrupt condition finishes when you read the information - * about the port / value that caused the interrupt or you read the port itself. - * Check the datasheet can be confusing. - * @param pin Pin to set - * @param mode Mode to set the pin - * - */ -void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) { - - // set the pin interrupt control (0 means change, 1 means compare against - // given value); - updateRegisterBit(pin, (mode != CHANGE), MCP23017_INTCONA, MCP23017_INTCONB); - // if the mode is not CHANGE, we need to set up a default value, different - // value triggers interrupt - - // In a RISING interrupt the default value is 0, interrupt is triggered when - // the pin goes to 1. In a FALLING interrupt the default value is 1, interrupt - // is triggered when pin goes to 0. - updateRegisterBit(pin, (mode == FALLING), MCP23017_DEFVALA, MCP23017_DEFVALB); - - // enable the pin for interrupt - updateRegisterBit(pin, HIGH, MCP23017_GPINTENA, MCP23017_GPINTENB); -} - -/** - * Disable a pin for interrupt. - * - * @param pin Pin to set - * - */ -void Adafruit_MCP23017::disableInterruptPin(uint8_t pin) { - // disable the pin for interrupt - updateRegisterBit(pin, LOW, MCP23017_GPINTENA, MCP23017_GPINTENB); -} - -/*! - * @brief Gets the last interrupt pin - * @return Returns the last interrupt pin - */ -uint8_t Adafruit_MCP23017::getLastInterruptPin() { - uint8_t intf; - - // try port A - intf = readRegister(MCP23017_INTFA); - for (int i = 0; i < 8; i++) - if (bitRead(intf, i)) - return i; - - // try port B - intf = readRegister(MCP23017_INTFB); - for (int i = 0; i < 8; i++) - if (bitRead(intf, i)) - return i + 8; - - return MCP23017_INT_ERR; -} -/*! - * @brief Gets the value of the last interrupt pin - * @return Returns the value of the last interrupt pin - */ -uint8_t Adafruit_MCP23017::getLastInterruptPinValue() { - uint8_t intPin = getLastInterruptPin(); - if (intPin != MCP23017_INT_ERR) { - uint8_t intcapreg = regForPin(intPin, MCP23017_INTCAPA, MCP23017_INTCAPB); - uint8_t bit = bitForPin(intPin); - return (readRegister(intcapreg) >> bit) & (0x01); - } - - return MCP23017_INT_ERR; -} diff --git a/Adafruit_MCP23017.h b/Adafruit_MCP23017.h deleted file mode 100644 index 6ed0f8d..0000000 --- a/Adafruit_MCP23017.h +++ /dev/null @@ -1,92 +0,0 @@ -/*! - * @file Adafruit_MCP23017.h - */ - -#ifndef _Adafruit_MCP23017_H_ -#define _Adafruit_MCP23017_H_ - -// Don't forget the Wire library -#ifndef ARDUINO_AVR_GEMMA -// TinyWireM is now part of -// Adafruit version of Wire Library, so this -// will work with Adafruit ATtiny85's -// But Arduino Gemma doesn't use that library -// We do NOT want to include Wire if it's an arduino Gemma -#include -#else -#include -#define Wire TinyWireM -#endif - -/*! - * @brief MCP23017 main class - */ -class Adafruit_MCP23017 { -public: - void begin(uint8_t addr, TwoWire *theWire = &Wire); - void begin(TwoWire *theWire = &Wire); - - void pinMode(uint8_t p, uint8_t d); - void digitalWrite(uint8_t p, uint8_t d); - void pullUp(uint8_t p, uint8_t d); - uint8_t digitalRead(uint8_t p); - - void writeGPIOAB(uint16_t); - uint16_t readGPIOAB(); - uint8_t readGPIO(uint8_t b); - - void setupInterrupts(uint8_t mirroring, uint8_t open, uint8_t polarity); - void setupInterruptPin(uint8_t pin, uint8_t mode); - void disableInterruptPin(uint8_t pin); - uint8_t getLastInterruptPin(); - uint8_t getLastInterruptPinValue(); - -private: - uint8_t i2caddr; - TwoWire *_wire; //!< pointer to a TwoWire object - - uint8_t bitForPin(uint8_t pin); - uint8_t regForPin(uint8_t pin, uint8_t portAaddr, uint8_t portBaddr); - - uint8_t readRegister(uint8_t addr); - void writeRegister(uint8_t addr, uint8_t value); - - /** - * Utility private method to update a register associated with a pin (whether - * port A/B) reads its value, updates the particular bit, and writes its - * value. - */ - void updateRegisterBit(uint8_t p, uint8_t pValue, uint8_t portAaddr, - uint8_t portBaddr); -}; - -#define MCP23017_ADDRESS 0x20 //!< MCP23017 Address - -// registers -#define MCP23017_IODIRA 0x00 //!< I/O direction register A -#define MCP23017_IPOLA 0x02 //!< Input polarity port register A -#define MCP23017_GPINTENA 0x04 //!< Interrupt-on-change pins A -#define MCP23017_DEFVALA 0x06 //!< Default value register A -#define MCP23017_INTCONA 0x08 //!< Interrupt-on-change control register A -#define MCP23017_IOCONA 0x0A //!< I/O expander configuration register A -#define MCP23017_GPPUA 0x0C //!< GPIO pull-up resistor register A -#define MCP23017_INTFA 0x0E //!< Interrupt flag register A -#define MCP23017_INTCAPA 0x10 //!< Interrupt captured value for port register A -#define MCP23017_GPIOA 0x12 //!< General purpose I/O port register A -#define MCP23017_OLATA 0x14 //!< Output latch register 0 A - -#define MCP23017_IODIRB 0x01 //!< I/O direction register B -#define MCP23017_IPOLB 0x03 //!< Input polarity port register B -#define MCP23017_GPINTENB 0x05 //!< Interrupt-on-change pins B -#define MCP23017_DEFVALB 0x07 //!< Default value register B -#define MCP23017_INTCONB 0x09 //!< Interrupt-on-change control register B -#define MCP23017_IOCONB 0x0B //!< I/O expander configuration register B -#define MCP23017_GPPUB 0x0D //!< GPIO pull-up resistor register B -#define MCP23017_INTFB 0x0F //!< Interrupt flag register B -#define MCP23017_INTCAPB 0x11 //!< Interrupt captured value for port register B -#define MCP23017_GPIOB 0x13 //!< General purpose I/O port register B -#define MCP23017_OLATB 0x15 //!< Output latch register 0 B - -#define MCP23017_INT_ERR 255 //!< Interrupt error - -#endif diff --git a/README.md b/README.md index f42bfc3..f4d48be 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,36 @@ # Adafruit MCP23017 Arduino Library [![Build Status](https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit-MCP23017-Arduino-Library/html/index.html) -This is a library for the MCP23017 I2c Port Expander - -These chips use I2C to communicate, 2 pins required to interface +This is a library for the MCP23008/17 I2C and MCP23S08/17 SPI Port Expanders. -Adafruit invests time and resources providing this open source code, -please support Adafruit and open-source hardware by purchasing +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing products from Adafruit! -Written by Limor Fried/Ladyada for Adafruit Industries. +Written by Carter Nelson for Adafruit Industries. BSD license, check license.txt for more information All text above must be included in any redistribution -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_MCP23017. Check that the Adafruit_MCP23017 folder contains Adafruit_MCP23017.cpp and Adafruit_MCP23017.h - -Place the Adafruit_MCP23017 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. - -Pin Addressing -============== - -When using single pin operations such as _pinMode(pinId, dir)_ or _digitalRead(pinId)_ or _digitalWrite(pinId, val)_ then the pins are addressed using the ID's below. For example, for set the mode of _GPB0_ then use _pinMode(8, ...)_. - -Physical Pin #| Pin Name | Pin ID -----|------|------------------------------ -21 | GPA0 | 0 -22 | GPA1 | 1 -23 | GPA2 | 2 -24 | GPA3 | 3 -25 | GPA4 | 4 -26 | GPA5 | 5 -27 | GPA6 | 6 -28 | GPA7 | 7 -1 | GPB0 | 8 -2 | GPB1 | 9 -3 | GPB2 | 10 -4 | GPB3 | 11 -5 | GPB4 | 12 -6 | GPB5 | 13 -7 | GPB6 | 14 -8 | GPB7 | 15 +To install, use the Arduino IDE Library Manager. + +# Pin Addressing + +When using single pin operations such as _pinMode(pinId, dir)_ or _digitalRead(pinId)_ or _digitalWrite(pinId, val)_ then the pins are addressed using the ID's below. For example, for set the mode of _GPB0_ then use _pinMode(8, ...)_. **NOTE** The MCP23008 and MCP23S08 only have _GPAx_ pins. + +MCP23x08 Pin # | MCP23x17 Pin # | Pin Name | Pin ID +:-------------:|:--------------:|:--------:|:-------: +10 | 21 | GPA0 | 0 +11 | 22 | GPA1 | 1 +12 | 23 | GPA2 | 2 +13 | 24 | GPA3 | 3 +14 | 25 | GPA4 | 4 +15 | 26 | GPA5 | 5 +16 | 27 | GPA6 | 6 +17 | 28 | GPA7 | 7 +-- | 1 | GPB0 | 8 +-- | 2 | GPB1 | 9 +-- | 3 | GPB2 | 10 +-- | 4 | GPB3 | 11 +-- | 5 | GPB4 | 12 +-- | 6 | GPB5 | 13 +-- | 7 | GPB6 | 14 +-- | 8 | GPB7 | 15 diff --git a/examples/button/button.ino b/examples/button/button.ino deleted file mode 100644 index 962b8c4..0000000 --- a/examples/button/button.ino +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include "Adafruit_MCP23017.h" - -// Basic pin reading and pullup test for the MCP23017 I/O expander -// public domain! - -// Connect pin #12 of the expander to Analog 5 (i2c clock) -// Connect pin #13 of the expander to Analog 4 (i2c data) -// Connect pins #15, 16 and 17 of the expander to ground (address selection) -// Connect pin #9 of the expander to 5V (power) -// Connect pin #10 of the expander to ground (common ground) -// Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low) - -// Input #0 is on pin 21 so connect a button or switch from there to ground - -Adafruit_MCP23017 mcp; - -void setup() { - mcp.begin(); // use default address 0 - - mcp.pinMode(0, INPUT); - mcp.pullUp(0, HIGH); // turn on a 100K pullup internally - - pinMode(13, OUTPUT); // use the p13 LED as debugging -} - - - -void loop() { - // The LED will 'echo' the button - digitalWrite(13, mcp.digitalRead(0)); -} \ No newline at end of file diff --git a/examples/custom_frequency/custom_frequency.ino b/examples/custom_frequency/custom_frequency.ino deleted file mode 100644 index a33729d..0000000 --- a/examples/custom_frequency/custom_frequency.ino +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include "Adafruit_MCP23017.h" - -// Sample for usage of two MCP23017 I/O expander with an ESP32 -// public domain! - -Adafruit_MCP23017 mcp; - -void setup() { - - Wire.setClock(1700000); // set frequency to 1.7mhz - - mcp.begin(&Wire); // use default address 0 -} - -void loop() { -} diff --git a/examples/interrupt/.leonardo.test.only b/examples/interrupt/.leonardo.test.only deleted file mode 100644 index e69de29..0000000 diff --git a/examples/interrupt/.mega2560.test.only b/examples/interrupt/.mega2560.test.only deleted file mode 100644 index e69de29..0000000 diff --git a/examples/interrupt/.uno.test.only b/examples/interrupt/.uno.test.only deleted file mode 100644 index e69de29..0000000 diff --git a/examples/interrupt/interrupt.ino b/examples/interrupt/interrupt.ino deleted file mode 100644 index 026db0e..0000000 --- a/examples/interrupt/interrupt.ino +++ /dev/null @@ -1,128 +0,0 @@ -// Install the LowPower library for optional sleeping support. -// See loop() function comments for details on usage. -//#include - -#include -#include - -Adafruit_MCP23017 mcp; - -byte ledPin=13; - -// Interrupts from the MCP will be handled by this PIN -byte arduinoIntPin=3; - -// ... and this interrupt vector -byte arduinoInterrupt=1; - -volatile boolean awakenByInterrupt = false; - -// Two pins at the MCP (Ports A/B where some buttons have been setup.) -// Buttons connect the pin to grond, and pins are pulled up. -byte mcpPinA=7; -byte mcpPinB=15; - -void setup(){ - - Serial.begin(9600); - Serial.println("MCP23007 Interrupt Test"); - - pinMode(arduinoIntPin,INPUT); - - mcp.begin(); // use default address 0 - - // We mirror INTA and INTB, so that only one line is required between MCP and Arduino for int reporting - // The INTA/B will not be Floating - // INTs will be signaled with a LOW - mcp.setupInterrupts(true,false,LOW); - - // configuration for a button on port A - // interrupt will triger when the pin is taken to ground by a pushbutton - mcp.pinMode(mcpPinA, INPUT); - mcp.pullUp(mcpPinA, HIGH); // turn on a 100K pullup internally - mcp.setupInterruptPin(mcpPinA,FALLING); - - // similar, but on port B. - mcp.pinMode(mcpPinB, INPUT); - mcp.pullUp(mcpPinB, HIGH); // turn on a 100K pullup internall - mcp.setupInterruptPin(mcpPinB,FALLING); - - // We will setup a pin for flashing from the int routine - pinMode(ledPin, OUTPUT); // use the p13 LED as debugging - -} - -// The int handler will just signal that the int has happen -// we will do the work from the main loop. -void intCallBack(){ - awakenByInterrupt=true; -} - -void handleInterrupt(){ - - // Get more information from the MCP from the INT - uint8_t pin=mcp.getLastInterruptPin(); - uint8_t val=mcp.getLastInterruptPinValue(); - - // We will flash the led 1 or 2 times depending on the PIN that triggered the Interrupt - // 3 and 4 flases are supposed to be impossible conditions... just for debugging. - uint8_t flashes=4; - if(pin==mcpPinA) flashes=1; - if(pin==mcpPinB) flashes=2; - if(val!=LOW) flashes=3; - - // simulate some output associated to this - for(int i=0;i +#include + +#define LED_PIN 0 // MCP23XXX pin LED is attached to + +// only used for SPI +#define CS_PIN 6 + +// uncomment appropriate line +Adafruit_MCP23X08 mcp; +//Adafruit_MCP23X17 mcp; + +void setup() { + Serial.begin(9600); + //while (!Serial); + Serial.println("MCP23xxx Blink Test!"); + + // uncomment appropriate mcp.begin + if (!mcp.begin_I2C()) { + //if (!mcp.begin_SPI(CS_PIN)) { + Serial.println("Error."); + while (1); + } + + // configure pin for output + mcp.pinMode(LED_PIN, OUTPUT); + + Serial.println("Looping..."); +} + +void loop() { + mcp.digitalWrite(LED_PIN, HIGH); + delay(500); + mcp.digitalWrite(LED_PIN, LOW); + delay(500); +} \ No newline at end of file diff --git a/examples/mcp23xxx_button/mcp23xxx_button.ino b/examples/mcp23xxx_button/mcp23xxx_button.ino new file mode 100644 index 0000000..9572e18 --- /dev/null +++ b/examples/mcp23xxx_button/mcp23xxx_button.ino @@ -0,0 +1,41 @@ +// Reads a button attached to a MCP23XXX pin. + +// ok to include only the one needed +// both included here to make things simple for example +#include +#include + +#define BUTTON_PIN 1 // MCP23XXX pin button is attached to + +// only used for SPI +#define CS_PIN 6 + +// uncomment appropriate line +Adafruit_MCP23X08 mcp; +//Adafruit_MCP23X17 mcp; + +void setup() { + Serial.begin(9600); + while (!Serial); + Serial.println("MCP23xxx Button Test!"); + + // uncomment appropriate mcp.begin + if (!mcp.begin_I2C()) { + //if (!mcp.begin_SPI(CS_PIN)) { + Serial.println("Error."); + while (1); + } + + // configure pin for input with pull up + mcp.pinMode(BUTTON_PIN, INPUT_PULLUP); + + Serial.println("Looping..."); +} + +void loop() { + // LOW = pressed, HIGH = not pressed + if (!mcp.digitalRead(BUTTON_PIN)) { + Serial.println("Button Pressed!"); + delay(250); + } +} \ No newline at end of file diff --git a/examples/mcp23xxx_combo/mcp23xxx_combo.ino b/examples/mcp23xxx_combo/mcp23xxx_combo.ino new file mode 100644 index 0000000..ff18e91 --- /dev/null +++ b/examples/mcp23xxx_combo/mcp23xxx_combo.ino @@ -0,0 +1,41 @@ +// Controls an LED via an attached button. + +// ok to include only the one needed +// both included here to make things simple for example +#include +#include + +#define LED_PIN 0 // MCP23XXX pin LED is attached to +#define BUTTON_PIN 1 // MCP23XXX pin button is attached to + +// only used for SPI +#define CS_PIN 6 + +// uncomment appropriate line +Adafruit_MCP23X08 mcp; +//Adafruit_MCP23X17 mcp; + +void setup() { + Serial.begin(9600); + //while (!Serial); + Serial.println("MCP23xxx Combo Test!"); + + // uncomment appropriate mcp.begin + if (!mcp.begin_I2C()) { + //if (!mcp.begin_SPI(CS_PIN)) { + Serial.println("Error."); + while (1); + } + + // configure LED pin for output + mcp.pinMode(LED_PIN, OUTPUT); + + // configure button pin for input with pull up + mcp.pinMode(BUTTON_PIN, INPUT_PULLUP); + + Serial.println("Looping..."); +} + +void loop() { + mcp.digitalWrite(LED_PIN, !mcp.digitalRead(BUTTON_PIN)); +} \ No newline at end of file diff --git a/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino b/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino new file mode 100644 index 0000000..e5fd747 --- /dev/null +++ b/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino @@ -0,0 +1,60 @@ +// NOTE: This is a simple example that only reads the INTA or INTB pin +// state. No actual interrupts are used on the host microcontroller. +// MCP23XXX supports the following interrupt modes: +// * CHANGE - interrupt occurs if pin changes to opposite state +// * LOW - interrupt occurs while pin state is LOW +// * HIGH - interrupt occurs while pin state is HIGH + +// ok to include only the one needed +// both included here to make things simple for example +#include +#include + +#define BUTTON_PIN 1 // MCP23XXX pin used for interrupt + +#define INT_PIN 7 // microcontroller pin attached to INTA/B + +// only used for SPI +#define CS_PIN 6 + +// uncomment appropriate line +Adafruit_MCP23X08 mcp; +//Adafruit_MCP23X17 mcp; + +void setup() { + Serial.begin(9600); + //while (!Serial); + Serial.println("MCP23xxx Interrupt Test!"); + + // uncomment appropriate mcp.begin + if (!mcp.begin_I2C()) { + //if (!mcp.begin_SPI(CS_PIN)) { + Serial.println("Error."); + while (1); + } + + // configure MCU pin that will read INTA/B state + pinMode(INT_PIN, INPUT); + + // OPTIONAL - call this to override defaults + // mirror INTA/B so only one wire required + // active drive so INTA/B will not be floating + // INTA/B will be signaled with a LOW + mcp.setupInterrupts(true, false, LOW); + + // configure button pin for input with pull up + mcp.pinMode(BUTTON_PIN, INPUT_PULLUP); + + // enable interrupt on button_pin + mcp.setupInterruptPin(BUTTON_PIN, LOW); + + Serial.println("Looping..."); +} + +void loop() { + if (!digitalRead(INT_PIN)) { + Serial.print("Interrupt detected on pin: "); + Serial.println(mcp.getLastInterruptPin()); + delay(250); // debounce + } +} \ No newline at end of file diff --git a/examples/toggle/toggle.ino b/examples/toggle/toggle.ino deleted file mode 100644 index e1e58dd..0000000 --- a/examples/toggle/toggle.ino +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "Adafruit_MCP23017.h" - -// Basic pin reading and pullup test for the MCP23017 I/O expander -// public domain! - -// Connect pin #12 of the expander to Analog 5 (i2c clock) -// Connect pin #13 of the expander to Analog 4 (i2c data) -// Connect pins #15, 16 and 17 of the expander to ground (address selection) -// Connect pin #9 of the expander to 5V (power) -// Connect pin #10 of the expander to ground (common ground) -// Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low) - -// Output #0 is on pin 21 so connect an LED or whatever from that to ground - -Adafruit_MCP23017 mcp; - -void setup() { - mcp.begin(); // use default address 0 - - mcp.pinMode(0, OUTPUT); -} - - -// flip the pin #0 up and down - -void loop() { - delay(100); - - mcp.digitalWrite(0, HIGH); - - delay(100); - - mcp.digitalWrite(0, LOW); -} \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index 9014299..9bfa7b7 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,13 +6,25 @@ # Datatypes (KEYWORD1) ####################################### -MCP23017 KEYWORD1 +Adafruit_MCP23X08 KEYWORD1 +Adafruit_MCP23X17 KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) ####################################### -pullUp KEYWORD2 +begin_I2C KEYWORD2 +begin_SPI KEYWORD2 +configureInterrupt KEYWORD2 +enableInterrupt KEYWORD2 +disableInterrupt KEYWORD2 +getLastInterruptPin KEYWORD2 +writeGPIO KEYWORD2 +readGPIO KEYWORD2 +writeGPIOA KEYWORD2 +readGPIOA KEYWORD2 +writeGPIOB KEYWORD2 +readGPIOB KEYWORD2 writeGPIOAB KEYWORD2 readGPIOAB KEYWORD2 diff --git a/library.properties b/library.properties index 7eef519..9275cd7 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ -name=Adafruit MCP23017 Arduino Library -version=1.3.0 +name=Adafruit MCP23X08/17 Arduino Library +version=2.0.0 author=Adafruit maintainer=Adafruit -sentence=Library for the MCP23017 I2C Port Expander -paragraph=Library for the MCP23017 I2C Port Expander +sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders +paragraph=Arduino Library for MCP23008, MCP23S08, MCP23017, and MCP23S17 I2C and SPI GPIO port expanders category=Signal Input/Output url=https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library architectures=* diff --git a/src/Adafruit_MCP23X08.cpp b/src/Adafruit_MCP23X08.cpp new file mode 100644 index 0000000..ab95b08 --- /dev/null +++ b/src/Adafruit_MCP23X08.cpp @@ -0,0 +1,32 @@ +/*! + * @file Adafruit_MCP23X08.cpp + * + * @mainpage Adafruit MCP23X08/17 Library + * + * @section intro_sec Introduction + * + * This is a library for the MCP23008/17 I2C and MCP23S08/17 SPI port + * expanders. + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section author Author + * + * Written by Carter Nelson for Adafruit Industries. + * + * @section license License + * + * BSD license, all text above must be included in any redistribution + */ + +#include "Adafruit_MCP23X08.h" + +/**************************************************************************/ +/*! + @brief default ctor. +*/ +/**************************************************************************/ +Adafruit_MCP23X08::Adafruit_MCP23X08() { + pinCount = 8; +} diff --git a/src/Adafruit_MCP23X08.h b/src/Adafruit_MCP23X08.h new file mode 100644 index 0000000..103ed6c --- /dev/null +++ b/src/Adafruit_MCP23X08.h @@ -0,0 +1,20 @@ +/*! + * @file Adafruit_MCP23X08.h + */ + +#ifndef __ADAFRUIT_MCP23X08_H__ +#define __ADAFRUIT_MCP23X08_H__ + +#include "Adafruit_MCP23XXX.h" + +/**************************************************************************/ +/*! + @brief Class for MCP23008 I2C and MCP23S08 SPI variants. +*/ +/**************************************************************************/ +class Adafruit_MCP23X08: public Adafruit_MCP23XXX { +public: + Adafruit_MCP23X08(); +}; + +#endif \ No newline at end of file diff --git a/src/Adafruit_MCP23X17.cpp b/src/Adafruit_MCP23X17.cpp new file mode 100644 index 0000000..1ca851a --- /dev/null +++ b/src/Adafruit_MCP23X17.cpp @@ -0,0 +1,93 @@ +/*! + * @file Adafruit_MCP23X17.cpp + * + * @mainpage Adafruit MCP23X08/17 Library + * + * @section intro_sec Introduction + * + * This is a library for the MCP23008/17 I2C and MCP23S08/17 SPI port + * expanders. + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section author Author + * + * Written by Carter Nelson for Adafruit Industries. + * + * @section license License + * + * BSD license, all text above must be included in any redistribution + */ + +#include "Adafruit_MCP23X17.h" + +/**************************************************************************/ +/*! + @brief default ctor. +*/ +/**************************************************************************/ +Adafruit_MCP23X17::Adafruit_MCP23X17() { + pinCount = 16; +} + +/**************************************************************************/ +/*! + @brief Bulk read all pins on Port A. + @returns current pin states of port as a uint8_t. +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23X17::readGPIOA() { + return readGPIO(0); +} + +/**************************************************************************/ +/*! + @brief Bulk write all pins on Port A. + @param value pin states to write as uint8_t. +*/ +/**************************************************************************/ +void Adafruit_MCP23X17::writeGPIOA(uint8_t value) { + writeGPIO(value, 0); +} + +/**************************************************************************/ +/*! + @brief Bulk read all pins on Port B. + @returns current pin states of port as a uint8_t. +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23X17::readGPIOB() { + return readGPIO(1); +} + +/**************************************************************************/ +/*! + @brief Bulk write all pins on Port B. + @param value pin states to write as uint8_t. +*/ +/**************************************************************************/ +void Adafruit_MCP23X17::writeGPIOB(uint8_t value) { + writeGPIO(value, 1); +} + +/**************************************************************************/ +/*! + @brief Bulk read all pins on Port A and B. + @returns current pin states of ports as a uint16_t. +*/ +/**************************************************************************/ +uint16_t Adafruit_MCP23X17::readGPIOAB() { + return readRegister16(getRegister(MCP23XXX_GPIO)); +} + +/**************************************************************************/ +/*! + @brief Bulk write all pins on Port A and Port B. + @param value pin states to write as uint16_t. +*/ +/**************************************************************************/ +void Adafruit_MCP23X17::writeGPIOAB(uint16_t value) { + writeRegister16(getRegister(MCP23XXX_GPIO), value); +} + diff --git a/src/Adafruit_MCP23X17.h b/src/Adafruit_MCP23X17.h new file mode 100644 index 0000000..3122421 --- /dev/null +++ b/src/Adafruit_MCP23X17.h @@ -0,0 +1,27 @@ +/*! + * @file Adafruit_MCP23X17.h + */ + +#ifndef __ADAFRUIT_MCP23X17_H__ +#define __ADAFRUIT_MCP23X17_H__ + +#include "Adafruit_MCP23XXX.h" + +/**************************************************************************/ +/*! + @brief Class for MCP23017 I2C and MCP23S17 SPI variants. +*/ +/**************************************************************************/ +class Adafruit_MCP23X17: public Adafruit_MCP23XXX { +public: + Adafruit_MCP23X17(); + + uint8_t readGPIOA(); + void writeGPIOA(uint8_t value); + uint8_t readGPIOB(); + void writeGPIOB(uint8_t value); + uint16_t readGPIOAB(); + void writeGPIOAB(uint16_t value); +}; + +#endif \ No newline at end of file diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp new file mode 100644 index 0000000..7a531ea --- /dev/null +++ b/src/Adafruit_MCP23XXX.cpp @@ -0,0 +1,340 @@ +/*! + * @file Adafruit_MCP23XXX.cpp + * + * @mainpage Adafruit MCP23X08/17 Library + * + * @section intro_sec Introduction + * + * This is a library for the MCP23008/17 I2C and MCP23S08/17 SPI port + * expanders. + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section author Author + * + * Written by Carter Nelson for Adafruit Industries. + * + * @section license License + * + * BSD license, all text above must be included in any redistribution + */ + +#include "Adafruit_MCP23XXX.h" + +/**************************************************************************/ +/*! + @brief Initialize MCP using I2C. + @param i2c_addr I2C address + @param wire Pointer to Wire instance + @return true if initialization successful, otherwise false. +*/ +/**************************************************************************/ +bool Adafruit_MCP23XXX::begin_I2C(uint8_t i2c_addr, TwoWire *wire) { + i2c_dev = new Adafruit_I2CDevice(i2c_addr, wire); + return i2c_dev->begin(); +} + +/**************************************************************************/ +/*! + @brief Initialize MCP using hardware SPI. + @param cs_pin Pin to use for SPI chip select + @param theSPI Pointer to SPI instance + @return true if initialization successful, otherwise false. +*/ +/**************************************************************************/ +bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) { + spi_dev = new Adafruit_SPIDevice(cs_pin, 1000000, SPI_BITORDER_MSBFIRST, SPI_MODE0, theSPI); + return spi_dev->begin(); +} + +/**************************************************************************/ +/*! + @brief Initialize MCP using software SPI. + @param cs_pin Pin to use for SPI chip select + @param sck_pin Pin to use for SPI clock + @param miso_pin Pin to use for SPI MISO + @param mosi_pin Pin to use for SPI MOSI + @return true if initialization successful, otherwise false. +*/ +/**************************************************************************/ +bool Adafruit_MCP23XXX::begin_SPI(int8_t cs_pin, int8_t sck_pin, int8_t miso_pin, + int8_t mosi_pin) { + spi_dev = new Adafruit_SPIDevice(cs_pin, sck_pin, miso_pin, mosi_pin); + return spi_dev->begin(); +} + +/**************************************************************************/ +/*! + @brief Configures the specified pin to behave either as an input or an output. + @param pin the Arduino pin number to set the mode of + @param mode INPUT, OUTPUT, or INPUT_PULLUP +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::pinMode(uint8_t pin, uint8_t mode) { + uint8_t iodir_reg = getRegister(MCP23XXX_IODIR, PORT(pin)); + uint8_t gppu_reg = getRegister(MCP23XXX_GPPU, PORT(pin)); + + uint8_t iodir = readRegister(iodir_reg); + + if (mode == OUTPUT) { + // clear for output + iodir &= ~MASK(pin); + } else { + // set for input + iodir |= MASK(pin); + // also configure internal pull-up + uint8_t gppu = readRegister(gppu_reg); + if (mode == INPUT_PULLUP) { + // set to enable + gppu |= MASK(pin); + } else { + // clear to disable + gppu &= ~MASK(pin); + } + writeRegister(gppu_reg, gppu); + } + writeRegister(iodir_reg, iodir); +} + +/**************************************************************************/ +/*! + @brief Reads the value from a specified digital pin, either HIGH or LOW. + @param pin the Arduino pin number you want to read + @returns HIGH or LOW +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23XXX::digitalRead(uint8_t pin) { + if (pin >= pinCount) return 0; + return ((readGPIO(PORT(pin)) & MASK(pin)) == 0) ? LOW : HIGH; +} + +/**************************************************************************/ +/*! + @brief Write a HIGH or a LOW value to a digital pin. + @param pin the Arduino pin number + @param value HIGH or LOW +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::digitalWrite(uint8_t pin, uint8_t value) { + uint8_t gpio = readGPIO(PORT(pin)); + if (value == HIGH) { + gpio |= MASK(pin); + } else { + gpio &= ~MASK(pin); + } + writeGPIO(gpio, PORT(pin)); +} + +/**************************************************************************/ +/*! + @brief Bulk read all pins on a port. + @param port 0 for Port A, 1 for Port B (MCP23X17 only). + @returns current pin states of port as a uint8_t. +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23XXX::readGPIO(uint8_t port) { + return readRegister(getRegister(MCP23XXX_GPIO, port)); +} + +/**************************************************************************/ +/*! + @brief Bulk write all pins on a port. + @param value pin states to write as a uint8_t. + @param port 0 for Port A, 1 for Port B (MCP23X17 only). +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { + writeRegister(getRegister(MCP23XXX_GPIO, port), value); +} + +/**************************************************************************/ +/*! + @brief Configure the interrupt system. + @param mirroring true to OR both INTA and INTB pins. + @param open true for open drain output, false for active drive output. + @param polarity HIGH or LOW +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity) { + uint8_t iocon = readRegister(getRegister(MCP23XXX_IOCON)); + if (mirroring) iocon |= 1 << 6; else iocon &= ~(1 << 6); + if (openDrain) iocon |= 1 << 2; else iocon &= ~(1 << 2); + if (polarity == HIGH) iocon |= 1 << 1; else iocon &= ~(1 << 1); + writeRegister(getRegister(MCP23XXX_IOCON), iocon); +} + +/**************************************************************************/ +/*! + @brief Enable interrupt and set mode for given pin. + @param pin Pin to enable. + @param mode CHANGE, LOW, HIGH +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::setupInterruptPin(uint8_t pin, uint8_t mode) { + // enable it + uint8_t reg = getRegister(MCP23XXX_GPINTEN, PORT(pin)); + uint8_t gpinten = readRegister(reg); + gpinten |= MASK(pin); + writeRegister(reg, gpinten); + // set mode + reg = getRegister(MCP23XXX_INTCON, PORT(pin)); + uint8_t intcon = readRegister(reg); + if (mode == CHANGE) { + // clear to compare to previous self (CHANGE) + intcon &= ~MASK(pin); + writeRegister(reg, intcon); + } else { + // set to compare to DEFVAL (LOW/HIGH) + intcon |= MASK(pin); + writeRegister(reg, intcon); + // set DEFVAL to 1=LOW or 0=HIGH + reg = getRegister(MCP23XXX_DEFVAL, PORT(pin)); + uint8_t defval = readRegister(reg); + if (mode == LOW) defval |= MASK(pin); else defval &= ~MASK(pin); + writeRegister(reg, defval); + } +} + +/**************************************************************************/ +/*! + @brief Disable interrupt for given pin. + @param pin Pin to disable. +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::disableInterruptPin(uint8_t pin) { + uint8_t reg = getRegister(MCP23XXX_GPINTEN, PORT(pin)); + uint8_t gpinten = readRegister(reg); + gpinten &= ~MASK(pin); + writeRegister(reg, gpinten); +} + +/**************************************************************************/ +/*! + @brief Gets the last interrupt pin. + @returns Pin that caused last interrupt. +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { + uint8_t intf = readRegister(getRegister(MCP23XXX_INTF)); + uint8_t intpin = 255; + // Port A + for (uint8_t pin = 0; pin < 8; pin++) { + if (intf & (1 << pin)) { + intpin = pin; + break; + } + } + // Port B + if ((pinCount > 8) && (intpin != 255)) { + intf = readRegister(getRegister(MCP23XXX_INTF, 1)); + for (uint8_t pin = 0; pin < 8; pin++) { + if (intf & (1 << pin)) { + intpin = pin + 8; + break; + } + } + } + // read INTCAP to clear + readRegister(getRegister(MCP23XXX_INTCAP)); + return intpin; +} + +/**************************************************************************/ +/*! + @brief read register + @param addr register address + @returns register value +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23XXX::readRegister(uint8_t addr) { + if (i2c_dev) { + buffer[0] = addr; + i2c_dev->write_then_read(buffer, 1, buffer, 1, false); + } else if (spi_dev) { + buffer[0] = MCP23XXX_SPI_READ; + buffer[1] = addr; + spi_dev->write_then_read(buffer, 2, buffer, 1); + } + return buffer[0]; +} + +/**************************************************************************/ +/*! + @brief write register + @param addr register address + @param value value to write +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::writeRegister(uint8_t addr, uint8_t value) { + if (i2c_dev) { + buffer[0] = addr; + buffer[1] = value; + i2c_dev->write(buffer, 2); + } else if (spi_dev) { + buffer[0] = MCP23XXX_SPI_WRITE; + buffer[1] = addr; + buffer[2] = value; + spi_dev->write(buffer, 3); + } +} + +/**************************************************************************/ +/*! + @brief read two consecutive registers + @param addr first register address + @returns register values, first register in lower byte +*/ +/**************************************************************************/ +uint16_t Adafruit_MCP23XXX::readRegister16(uint8_t addr) { + if (i2c_dev) { + buffer[0] = addr; + i2c_dev->write_then_read(buffer, 1, buffer, 2, false); + } else if (spi_dev) { + buffer[0] = MCP23XXX_SPI_READ; + buffer[1] = addr; + spi_dev->write_then_read(buffer, 2, buffer, 2); + } + return buffer[0] | (buffer[1] << 1); +} + +/**************************************************************************/ +/*! + @brief write two consecutive registers + @param addr first register address + @param value register values, first register in lower byte +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::writeRegister16(uint8_t addr, uint16_t value) { + if (i2c_dev) { + buffer[0] = addr; + buffer[1] = value & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + i2c_dev->write(buffer, 3); + } else if (spi_dev) { + buffer[0] = MCP23XXX_SPI_WRITE; + buffer[1] = addr; + buffer[2] = value & 0xFF; + buffer[3] = (value >> 8) & 0xFF; + spi_dev->write(buffer, 4); + } +} + +/**************************************************************************/ +/*! + @brief helper to get register address + @param baseAddress base register address + @param port 0 for A, 1 for B (MCP23X17 only) +*/ +/**************************************************************************/ +uint8_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { + // MCP23x08 + uint8_t reg = baseAddress; + // MCP23x17 BANK=0 + if (pinCount > 8) { + reg *= 2; + // Port B + if (port) reg++; + } + return reg; +} \ No newline at end of file diff --git a/src/Adafruit_MCP23XXX.h b/src/Adafruit_MCP23XXX.h new file mode 100644 index 0000000..f9e7845 --- /dev/null +++ b/src/Adafruit_MCP23XXX.h @@ -0,0 +1,77 @@ +/*! + * @file Adafruit_MCP23XXX.h + */ + +#ifndef __ADAFRUIT_MCP23XXX_H__ +#define __ADAFRUIT_MCP23XXX_H__ + +#include +#include +#include + + +// registers +#define MCP23XXX_IODIR 0x00 //!< I/O direction register +#define MCP23XXX_IPOL 0x01 //!< Input polarity register +#define MCP23XXX_GPINTEN 0x02 //!< Interrupt-on-change control register +#define MCP23XXX_DEFVAL \ + 0x03 //!< Default compare register for interrupt-on-change +#define MCP23XXX_INTCON 0x04 //!< Interrupt control register +#define MCP23XXX_IOCON 0x05 //!< Configuration register +#define MCP23XXX_GPPU 0x06 //!< Pull-up resistor configuration register +#define MCP23XXX_INTF 0x07 //!< Interrupt flag register +#define MCP23XXX_INTCAP 0x08 //!< Interrupt capture register +#define MCP23XXX_GPIO 0x09 //!< Port register +#define MCP23XXX_OLAT 0x0A //!< Output latch register + +#define MCP23XXX_ADDR 0x20 //!< Default I2C Address +#define MCP23XXX_SPI_WRITE 0x40 //!< Opcode for SPI write +#define MCP23XXX_SPI_READ 0x41 //!< Opcode for SPI read + +#define PORT(pin) ((pin < 8) ? 0 : 1) //!< Determine port from pin number +#define MASK(pin) (1 << (pin % 8)) //!< Determine mask from pin number + + +/**************************************************************************/ +/*! + @brief Base class for all MCP23XXX variants. +*/ +/**************************************************************************/ +class Adafruit_MCP23XXX { +public: + // init + bool begin_I2C(uint8_t i2c_addr = MCP23XXX_ADDR, TwoWire *wire = &Wire); + bool begin_SPI(uint8_t cs_pin, SPIClass *theSPI = &SPI); + bool begin_SPI(int8_t cs_pin, int8_t sck_pin, int8_t miso_pin, + int8_t mosi_pin); + + // main Arduino API methods + void pinMode(uint8_t pin, uint8_t mode); + uint8_t digitalRead(uint8_t pin); + void digitalWrite(uint8_t pin, uint8_t value); + + // bulk access + uint8_t readGPIO(uint8_t port=0); + void writeGPIO(uint8_t value, uint8_t port=0); + + // interrupts + void setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity); + void setupInterruptPin(uint8_t pin, uint8_t mode=CHANGE); + void disableInterruptPin(uint8_t pin); + uint8_t getLastInterruptPin(); + +protected: + Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface + Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface + uint8_t pinCount; ///< Total number of GPIO pins + uint8_t readRegister(uint8_t addr); + void writeRegister(uint8_t addr, uint8_t value); + uint16_t readRegister16(uint8_t addr); + void writeRegister16(uint8_t addr, uint16_t value); + uint8_t getRegister(uint8_t baseAddress, uint8_t port=0); + +private: + uint8_t buffer[4]; +}; + +#endif \ No newline at end of file From 10046a568e95ddd0fc26f43252761425a539190f Mon Sep 17 00:00:00 2001 From: caternuson Date: Wed, 16 Jun 2021 09:18:24 -0700 Subject: [PATCH 2/4] so much depends upon a red busio --- library.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/library.properties b/library.properties index 9275cd7..144aab2 100644 --- a/library.properties +++ b/library.properties @@ -7,3 +7,4 @@ paragraph=Arduino Library for MCP23008, MCP23S08, MCP23017, and MCP23S17 I2C and category=Signal Input/Output url=https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library architectures=* +depends=Adafruit BusIO \ No newline at end of file From 702c0f1c8c9c175353eda7973a442a065432ab5a Mon Sep 17 00:00:00 2001 From: caternuson Date: Wed, 16 Jun 2021 09:27:06 -0700 Subject: [PATCH 3/4] clang it up --- src/Adafruit_MCP23X08.cpp | 4 +--- src/Adafruit_MCP23X08.h | 2 +- src/Adafruit_MCP23X17.cpp | 21 +++++---------------- src/Adafruit_MCP23X17.h | 2 +- src/Adafruit_MCP23XXX.cpp | 36 ++++++++++++++++++++++++++---------- src/Adafruit_MCP23XXX.h | 24 +++++++++++------------- 6 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/Adafruit_MCP23X08.cpp b/src/Adafruit_MCP23X08.cpp index ab95b08..b9d7018 100644 --- a/src/Adafruit_MCP23X08.cpp +++ b/src/Adafruit_MCP23X08.cpp @@ -27,6 +27,4 @@ @brief default ctor. */ /**************************************************************************/ -Adafruit_MCP23X08::Adafruit_MCP23X08() { - pinCount = 8; -} +Adafruit_MCP23X08::Adafruit_MCP23X08() { pinCount = 8; } diff --git a/src/Adafruit_MCP23X08.h b/src/Adafruit_MCP23X08.h index 103ed6c..a238d38 100644 --- a/src/Adafruit_MCP23X08.h +++ b/src/Adafruit_MCP23X08.h @@ -12,7 +12,7 @@ @brief Class for MCP23008 I2C and MCP23S08 SPI variants. */ /**************************************************************************/ -class Adafruit_MCP23X08: public Adafruit_MCP23XXX { +class Adafruit_MCP23X08 : public Adafruit_MCP23XXX { public: Adafruit_MCP23X08(); }; diff --git a/src/Adafruit_MCP23X17.cpp b/src/Adafruit_MCP23X17.cpp index 1ca851a..dd7024f 100644 --- a/src/Adafruit_MCP23X17.cpp +++ b/src/Adafruit_MCP23X17.cpp @@ -27,9 +27,7 @@ @brief default ctor. */ /**************************************************************************/ -Adafruit_MCP23X17::Adafruit_MCP23X17() { - pinCount = 16; -} +Adafruit_MCP23X17::Adafruit_MCP23X17() { pinCount = 16; } /**************************************************************************/ /*! @@ -37,9 +35,7 @@ Adafruit_MCP23X17::Adafruit_MCP23X17() { @returns current pin states of port as a uint8_t. */ /**************************************************************************/ -uint8_t Adafruit_MCP23X17::readGPIOA() { - return readGPIO(0); -} +uint8_t Adafruit_MCP23X17::readGPIOA() { return readGPIO(0); } /**************************************************************************/ /*! @@ -47,9 +43,7 @@ uint8_t Adafruit_MCP23X17::readGPIOA() { @param value pin states to write as uint8_t. */ /**************************************************************************/ -void Adafruit_MCP23X17::writeGPIOA(uint8_t value) { - writeGPIO(value, 0); -} +void Adafruit_MCP23X17::writeGPIOA(uint8_t value) { writeGPIO(value, 0); } /**************************************************************************/ /*! @@ -57,9 +51,7 @@ void Adafruit_MCP23X17::writeGPIOA(uint8_t value) { @returns current pin states of port as a uint8_t. */ /**************************************************************************/ -uint8_t Adafruit_MCP23X17::readGPIOB() { - return readGPIO(1); -} +uint8_t Adafruit_MCP23X17::readGPIOB() { return readGPIO(1); } /**************************************************************************/ /*! @@ -67,9 +59,7 @@ uint8_t Adafruit_MCP23X17::readGPIOB() { @param value pin states to write as uint8_t. */ /**************************************************************************/ -void Adafruit_MCP23X17::writeGPIOB(uint8_t value) { - writeGPIO(value, 1); -} +void Adafruit_MCP23X17::writeGPIOB(uint8_t value) { writeGPIO(value, 1); } /**************************************************************************/ /*! @@ -90,4 +80,3 @@ uint16_t Adafruit_MCP23X17::readGPIOAB() { void Adafruit_MCP23X17::writeGPIOAB(uint16_t value) { writeRegister16(getRegister(MCP23XXX_GPIO), value); } - diff --git a/src/Adafruit_MCP23X17.h b/src/Adafruit_MCP23X17.h index 3122421..3aec5f8 100644 --- a/src/Adafruit_MCP23X17.h +++ b/src/Adafruit_MCP23X17.h @@ -12,7 +12,7 @@ @brief Class for MCP23017 I2C and MCP23S17 SPI variants. */ /**************************************************************************/ -class Adafruit_MCP23X17: public Adafruit_MCP23XXX { +class Adafruit_MCP23X17 : public Adafruit_MCP23XXX { public: Adafruit_MCP23X17(); diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 7a531ea..f12cd07 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -44,7 +44,8 @@ bool Adafruit_MCP23XXX::begin_I2C(uint8_t i2c_addr, TwoWire *wire) { */ /**************************************************************************/ bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) { - spi_dev = new Adafruit_SPIDevice(cs_pin, 1000000, SPI_BITORDER_MSBFIRST, SPI_MODE0, theSPI); + spi_dev = new Adafruit_SPIDevice(cs_pin, 1000000, SPI_BITORDER_MSBFIRST, + SPI_MODE0, theSPI); return spi_dev->begin(); } @@ -58,8 +59,8 @@ bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) { @return true if initialization successful, otherwise false. */ /**************************************************************************/ -bool Adafruit_MCP23XXX::begin_SPI(int8_t cs_pin, int8_t sck_pin, int8_t miso_pin, - int8_t mosi_pin) { +bool Adafruit_MCP23XXX::begin_SPI(int8_t cs_pin, int8_t sck_pin, + int8_t miso_pin, int8_t mosi_pin) { spi_dev = new Adafruit_SPIDevice(cs_pin, sck_pin, miso_pin, mosi_pin); return spi_dev->begin(); } @@ -105,7 +106,8 @@ void Adafruit_MCP23XXX::pinMode(uint8_t pin, uint8_t mode) { */ /**************************************************************************/ uint8_t Adafruit_MCP23XXX::digitalRead(uint8_t pin) { - if (pin >= pinCount) return 0; + if (pin >= pinCount) + return 0; return ((readGPIO(PORT(pin)) & MASK(pin)) == 0) ? LOW : HIGH; } @@ -156,11 +158,21 @@ void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { @param polarity HIGH or LOW */ /**************************************************************************/ -void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity) { +void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, + uint8_t polarity) { uint8_t iocon = readRegister(getRegister(MCP23XXX_IOCON)); - if (mirroring) iocon |= 1 << 6; else iocon &= ~(1 << 6); - if (openDrain) iocon |= 1 << 2; else iocon &= ~(1 << 2); - if (polarity == HIGH) iocon |= 1 << 1; else iocon &= ~(1 << 1); + if (mirroring) + iocon |= 1 << 6; + else + iocon &= ~(1 << 6); + if (openDrain) + iocon |= 1 << 2; + else + iocon &= ~(1 << 2); + if (polarity == HIGH) + iocon |= 1 << 1; + else + iocon &= ~(1 << 1); writeRegister(getRegister(MCP23XXX_IOCON), iocon); } @@ -191,7 +203,10 @@ void Adafruit_MCP23XXX::setupInterruptPin(uint8_t pin, uint8_t mode) { // set DEFVAL to 1=LOW or 0=HIGH reg = getRegister(MCP23XXX_DEFVAL, PORT(pin)); uint8_t defval = readRegister(reg); - if (mode == LOW) defval |= MASK(pin); else defval &= ~MASK(pin); + if (mode == LOW) + defval |= MASK(pin); + else + defval &= ~MASK(pin); writeRegister(reg, defval); } } @@ -334,7 +349,8 @@ uint8_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { if (pinCount > 8) { reg *= 2; // Port B - if (port) reg++; + if (port) + reg++; } return reg; } \ No newline at end of file diff --git a/src/Adafruit_MCP23XXX.h b/src/Adafruit_MCP23XXX.h index f9e7845..37fdbfa 100644 --- a/src/Adafruit_MCP23XXX.h +++ b/src/Adafruit_MCP23XXX.h @@ -5,10 +5,9 @@ #ifndef __ADAFRUIT_MCP23XXX_H__ #define __ADAFRUIT_MCP23XXX_H__ -#include #include #include - +#include // registers #define MCP23XXX_IODIR 0x00 //!< I/O direction register @@ -24,13 +23,12 @@ #define MCP23XXX_GPIO 0x09 //!< Port register #define MCP23XXX_OLAT 0x0A //!< Output latch register -#define MCP23XXX_ADDR 0x20 //!< Default I2C Address -#define MCP23XXX_SPI_WRITE 0x40 //!< Opcode for SPI write -#define MCP23XXX_SPI_READ 0x41 //!< Opcode for SPI read - -#define PORT(pin) ((pin < 8) ? 0 : 1) //!< Determine port from pin number -#define MASK(pin) (1 << (pin % 8)) //!< Determine mask from pin number +#define MCP23XXX_ADDR 0x20 //!< Default I2C Address +#define MCP23XXX_SPI_WRITE 0x40 //!< Opcode for SPI write +#define MCP23XXX_SPI_READ 0x41 //!< Opcode for SPI read +#define PORT(pin) ((pin < 8) ? 0 : 1) //!< Determine port from pin number +#define MASK(pin) (1 << (pin % 8)) //!< Determine mask from pin number /**************************************************************************/ /*! @@ -51,24 +49,24 @@ class Adafruit_MCP23XXX { void digitalWrite(uint8_t pin, uint8_t value); // bulk access - uint8_t readGPIO(uint8_t port=0); - void writeGPIO(uint8_t value, uint8_t port=0); + uint8_t readGPIO(uint8_t port = 0); + void writeGPIO(uint8_t value, uint8_t port = 0); // interrupts void setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity); - void setupInterruptPin(uint8_t pin, uint8_t mode=CHANGE); + void setupInterruptPin(uint8_t pin, uint8_t mode = CHANGE); void disableInterruptPin(uint8_t pin); uint8_t getLastInterruptPin(); protected: Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface - uint8_t pinCount; ///< Total number of GPIO pins + uint8_t pinCount; ///< Total number of GPIO pins uint8_t readRegister(uint8_t addr); void writeRegister(uint8_t addr, uint8_t value); uint16_t readRegister16(uint8_t addr); void writeRegister16(uint8_t addr, uint16_t value); - uint8_t getRegister(uint8_t baseAddress, uint8_t port=0); + uint8_t getRegister(uint8_t baseAddress, uint8_t port = 0); private: uint8_t buffer[4]; From 7d237995577410108edd8e60e5c6d4a464baf5d5 Mon Sep 17 00:00:00 2001 From: caternuson Date: Fri, 25 Jun 2021 10:05:41 -0700 Subject: [PATCH 4/4] use register --- examples/mcp23xxx_button/mcp23xxx_button.ino | 2 +- src/Adafruit_MCP23X08.cpp | 2 +- src/Adafruit_MCP23X17.cpp | 8 +- src/Adafruit_MCP23XXX.cpp | 238 ++++++------------- src/Adafruit_MCP23XXX.h | 16 +- 5 files changed, 87 insertions(+), 179 deletions(-) diff --git a/examples/mcp23xxx_button/mcp23xxx_button.ino b/examples/mcp23xxx_button/mcp23xxx_button.ino index 9572e18..fc48b33 100644 --- a/examples/mcp23xxx_button/mcp23xxx_button.ino +++ b/examples/mcp23xxx_button/mcp23xxx_button.ino @@ -16,7 +16,7 @@ Adafruit_MCP23X08 mcp; void setup() { Serial.begin(9600); - while (!Serial); + //while (!Serial); Serial.println("MCP23xxx Button Test!"); // uncomment appropriate mcp.begin diff --git a/src/Adafruit_MCP23X08.cpp b/src/Adafruit_MCP23X08.cpp index b9d7018..a4d2ebf 100644 --- a/src/Adafruit_MCP23X08.cpp +++ b/src/Adafruit_MCP23X08.cpp @@ -27,4 +27,4 @@ @brief default ctor. */ /**************************************************************************/ -Adafruit_MCP23X08::Adafruit_MCP23X08() { pinCount = 8; } +Adafruit_MCP23X08::Adafruit_MCP23X08() { pinCount = 8; } \ No newline at end of file diff --git a/src/Adafruit_MCP23X17.cpp b/src/Adafruit_MCP23X17.cpp index dd7024f..ed19b1f 100644 --- a/src/Adafruit_MCP23X17.cpp +++ b/src/Adafruit_MCP23X17.cpp @@ -68,7 +68,9 @@ void Adafruit_MCP23X17::writeGPIOB(uint8_t value) { writeGPIO(value, 1); } */ /**************************************************************************/ uint16_t Adafruit_MCP23X17::readGPIOAB() { - return readRegister16(getRegister(MCP23XXX_GPIO)); + Adafruit_BusIO_Register GPIO(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPIO, 0), 2); + return GPIO.read(); } /**************************************************************************/ @@ -78,5 +80,7 @@ uint16_t Adafruit_MCP23X17::readGPIOAB() { */ /**************************************************************************/ void Adafruit_MCP23X17::writeGPIOAB(uint16_t value) { - writeRegister16(getRegister(MCP23XXX_GPIO), value); + Adafruit_BusIO_Register GPIO(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPIO, 0), 2); + GPIO.write(value, 2); } diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index f12cd07..39724cb 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -73,29 +73,15 @@ bool Adafruit_MCP23XXX::begin_SPI(int8_t cs_pin, int8_t sck_pin, */ /**************************************************************************/ void Adafruit_MCP23XXX::pinMode(uint8_t pin, uint8_t mode) { - uint8_t iodir_reg = getRegister(MCP23XXX_IODIR, PORT(pin)); - uint8_t gppu_reg = getRegister(MCP23XXX_GPPU, PORT(pin)); + Adafruit_BusIO_Register IODIR(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_IODIR, MCP_PORT(pin))); + Adafruit_BusIO_Register GPPU(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPPU, MCP_PORT(pin))); + Adafruit_BusIO_RegisterBits dir_bit(&IODIR, 1, pin % 8); + Adafruit_BusIO_RegisterBits pullup_bit(&GPPU, 1, pin % 8); - uint8_t iodir = readRegister(iodir_reg); - - if (mode == OUTPUT) { - // clear for output - iodir &= ~MASK(pin); - } else { - // set for input - iodir |= MASK(pin); - // also configure internal pull-up - uint8_t gppu = readRegister(gppu_reg); - if (mode == INPUT_PULLUP) { - // set to enable - gppu |= MASK(pin); - } else { - // clear to disable - gppu &= ~MASK(pin); - } - writeRegister(gppu_reg, gppu); - } - writeRegister(iodir_reg, iodir); + dir_bit.write((mode == OUTPUT) ? 0 : 1); + pullup_bit.write((mode == INPUT_PULLUP) ? 1 : 0); } /**************************************************************************/ @@ -106,9 +92,11 @@ void Adafruit_MCP23XXX::pinMode(uint8_t pin, uint8_t mode) { */ /**************************************************************************/ uint8_t Adafruit_MCP23XXX::digitalRead(uint8_t pin) { - if (pin >= pinCount) - return 0; - return ((readGPIO(PORT(pin)) & MASK(pin)) == 0) ? LOW : HIGH; + Adafruit_BusIO_Register GPIO(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPIO, MCP_PORT(pin))); + Adafruit_BusIO_RegisterBits pin_bit(&GPIO, 1, pin % 8); + + return ((pin_bit.read() == 0) ? LOW : HIGH); } /**************************************************************************/ @@ -119,13 +107,11 @@ uint8_t Adafruit_MCP23XXX::digitalRead(uint8_t pin) { */ /**************************************************************************/ void Adafruit_MCP23XXX::digitalWrite(uint8_t pin, uint8_t value) { - uint8_t gpio = readGPIO(PORT(pin)); - if (value == HIGH) { - gpio |= MASK(pin); - } else { - gpio &= ~MASK(pin); - } - writeGPIO(gpio, PORT(pin)); + Adafruit_BusIO_Register GPIO(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPIO, MCP_PORT(pin))); + Adafruit_BusIO_RegisterBits pin_bit(&GPIO, 1, pin % 8); + + pin_bit.write((value == LOW) ? 0 : 1); } /**************************************************************************/ @@ -136,7 +122,9 @@ void Adafruit_MCP23XXX::digitalWrite(uint8_t pin, uint8_t value) { */ /**************************************************************************/ uint8_t Adafruit_MCP23XXX::readGPIO(uint8_t port) { - return readRegister(getRegister(MCP23XXX_GPIO, port)); + Adafruit_BusIO_Register GPIO(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPIO, port)); + return GPIO.read() & 0xFF; } /**************************************************************************/ @@ -147,7 +135,9 @@ uint8_t Adafruit_MCP23XXX::readGPIO(uint8_t port) { */ /**************************************************************************/ void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { - writeRegister(getRegister(MCP23XXX_GPIO, port), value); + Adafruit_BusIO_Register GPIO(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPIO, port)); + GPIO.write(value); } /**************************************************************************/ @@ -160,20 +150,15 @@ void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { /**************************************************************************/ void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity) { - uint8_t iocon = readRegister(getRegister(MCP23XXX_IOCON)); - if (mirroring) - iocon |= 1 << 6; - else - iocon &= ~(1 << 6); - if (openDrain) - iocon |= 1 << 2; - else - iocon &= ~(1 << 2); - if (polarity == HIGH) - iocon |= 1 << 1; - else - iocon &= ~(1 << 1); - writeRegister(getRegister(MCP23XXX_IOCON), iocon); + Adafruit_BusIO_Register GPINTEN(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_IOCON)); + Adafruit_BusIO_RegisterBits mirror_bit(&GPINTEN, 1, 6); + Adafruit_BusIO_RegisterBits openDrain_bit(&GPINTEN, 1, 2); + Adafruit_BusIO_RegisterBits polarity_bit(&GPINTEN, 1, 1); + + mirror_bit.write(mirroring ? 1 : 0); + openDrain_bit.write(openDrain ? 1 : 0); + polarity_bit.write((polarity == HIGH) ? 1 : 0); } /**************************************************************************/ @@ -184,31 +169,19 @@ void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, */ /**************************************************************************/ void Adafruit_MCP23XXX::setupInterruptPin(uint8_t pin, uint8_t mode) { - // enable it - uint8_t reg = getRegister(MCP23XXX_GPINTEN, PORT(pin)); - uint8_t gpinten = readRegister(reg); - gpinten |= MASK(pin); - writeRegister(reg, gpinten); - // set mode - reg = getRegister(MCP23XXX_INTCON, PORT(pin)); - uint8_t intcon = readRegister(reg); - if (mode == CHANGE) { - // clear to compare to previous self (CHANGE) - intcon &= ~MASK(pin); - writeRegister(reg, intcon); - } else { - // set to compare to DEFVAL (LOW/HIGH) - intcon |= MASK(pin); - writeRegister(reg, intcon); - // set DEFVAL to 1=LOW or 0=HIGH - reg = getRegister(MCP23XXX_DEFVAL, PORT(pin)); - uint8_t defval = readRegister(reg); - if (mode == LOW) - defval |= MASK(pin); - else - defval &= ~MASK(pin); - writeRegister(reg, defval); - } + Adafruit_BusIO_Register GPINTEN(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPINTEN, MCP_PORT(pin))); + Adafruit_BusIO_Register INTCON(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTCON, MCP_PORT(pin))); + Adafruit_BusIO_Register DEFVAL(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_DEFVAL, MCP_PORT(pin))); + Adafruit_BusIO_RegisterBits enable_bit(&GPINTEN, 1, pin % 8); + Adafruit_BusIO_RegisterBits config_bit(&INTCON, 1, pin % 8); + Adafruit_BusIO_RegisterBits defval_bit(&DEFVAL, 1, pin % 8); + + enable_bit.write(1); // enable it + config_bit.write((mode == CHANGE) ? 0 : 1); // set mode + defval_bit.write((mode == LOW) ? 1 : 0); // set defval } /**************************************************************************/ @@ -218,10 +191,11 @@ void Adafruit_MCP23XXX::setupInterruptPin(uint8_t pin, uint8_t mode) { */ /**************************************************************************/ void Adafruit_MCP23XXX::disableInterruptPin(uint8_t pin) { - uint8_t reg = getRegister(MCP23XXX_GPINTEN, PORT(pin)); - uint8_t gpinten = readRegister(reg); - gpinten &= ~MASK(pin); - writeRegister(reg, gpinten); + Adafruit_BusIO_Register GPINTEN(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_GPINTEN, MCP_PORT(pin))); + Adafruit_BusIO_RegisterBits enable_bit(&GPINTEN, 1, pin % 8); + + enable_bit.write(0); } /**************************************************************************/ @@ -231,18 +205,25 @@ void Adafruit_MCP23XXX::disableInterruptPin(uint8_t pin) { */ /**************************************************************************/ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { - uint8_t intf = readRegister(getRegister(MCP23XXX_INTF)); uint8_t intpin = 255; + uint8_t intf; + // Port A + Adafruit_BusIO_Register INTFA(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTF)); + INTFA.read(&intf); for (uint8_t pin = 0; pin < 8; pin++) { if (intf & (1 << pin)) { intpin = pin; break; } } - // Port B - if ((pinCount > 8) && (intpin != 255)) { - intf = readRegister(getRegister(MCP23XXX_INTF, 1)); + + // Port B and still not found? + if ((pinCount > 8) && (intpin == 255)) { + Adafruit_BusIO_Register INTFB(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTF), 1); + INTFB.read(&intf); for (uint8_t pin = 0; pin < 8; pin++) { if (intf & (1 << pin)) { intpin = pin + 8; @@ -250,89 +231,15 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { } } } - // read INTCAP to clear - readRegister(getRegister(MCP23XXX_INTCAP)); - return intpin; -} - -/**************************************************************************/ -/*! - @brief read register - @param addr register address - @returns register value -*/ -/**************************************************************************/ -uint8_t Adafruit_MCP23XXX::readRegister(uint8_t addr) { - if (i2c_dev) { - buffer[0] = addr; - i2c_dev->write_then_read(buffer, 1, buffer, 1, false); - } else if (spi_dev) { - buffer[0] = MCP23XXX_SPI_READ; - buffer[1] = addr; - spi_dev->write_then_read(buffer, 2, buffer, 1); - } - return buffer[0]; -} - -/**************************************************************************/ -/*! - @brief write register - @param addr register address - @param value value to write -*/ -/**************************************************************************/ -void Adafruit_MCP23XXX::writeRegister(uint8_t addr, uint8_t value) { - if (i2c_dev) { - buffer[0] = addr; - buffer[1] = value; - i2c_dev->write(buffer, 2); - } else if (spi_dev) { - buffer[0] = MCP23XXX_SPI_WRITE; - buffer[1] = addr; - buffer[2] = value; - spi_dev->write(buffer, 3); - } -} -/**************************************************************************/ -/*! - @brief read two consecutive registers - @param addr first register address - @returns register values, first register in lower byte -*/ -/**************************************************************************/ -uint16_t Adafruit_MCP23XXX::readRegister16(uint8_t addr) { - if (i2c_dev) { - buffer[0] = addr; - i2c_dev->write_then_read(buffer, 1, buffer, 2, false); - } else if (spi_dev) { - buffer[0] = MCP23XXX_SPI_READ; - buffer[1] = addr; - spi_dev->write_then_read(buffer, 2, buffer, 2); + // clear if found + if (intpin != 255) { + Adafruit_BusIO_Register INTCAP(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTCAP)); + INTCAP.read(); } - return buffer[0] | (buffer[1] << 1); -} -/**************************************************************************/ -/*! - @brief write two consecutive registers - @param addr first register address - @param value register values, first register in lower byte -*/ -/**************************************************************************/ -void Adafruit_MCP23XXX::writeRegister16(uint8_t addr, uint16_t value) { - if (i2c_dev) { - buffer[0] = addr; - buffer[1] = value & 0xFF; - buffer[2] = (value >> 8) & 0xFF; - i2c_dev->write(buffer, 3); - } else if (spi_dev) { - buffer[0] = MCP23XXX_SPI_WRITE; - buffer[1] = addr; - buffer[2] = value & 0xFF; - buffer[3] = (value >> 8) & 0xFF; - spi_dev->write(buffer, 4); - } + return intpin; } /**************************************************************************/ @@ -342,9 +249,9 @@ void Adafruit_MCP23XXX::writeRegister16(uint8_t addr, uint16_t value) { @param port 0 for A, 1 for B (MCP23X17 only) */ /**************************************************************************/ -uint8_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { +uint16_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { // MCP23x08 - uint8_t reg = baseAddress; + uint16_t reg = baseAddress; // MCP23x17 BANK=0 if (pinCount > 8) { reg *= 2; @@ -352,5 +259,6 @@ uint8_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { if (port) reg++; } - return reg; -} \ No newline at end of file + // for SPI, add opcode as high byte + return (spi_dev) ? (0x4000 | reg) : reg; +} diff --git a/src/Adafruit_MCP23XXX.h b/src/Adafruit_MCP23XXX.h index 37fdbfa..98975f4 100644 --- a/src/Adafruit_MCP23XXX.h +++ b/src/Adafruit_MCP23XXX.h @@ -5,6 +5,7 @@ #ifndef __ADAFRUIT_MCP23XXX_H__ #define __ADAFRUIT_MCP23XXX_H__ +#include #include #include #include @@ -23,12 +24,11 @@ #define MCP23XXX_GPIO 0x09 //!< Port register #define MCP23XXX_OLAT 0x0A //!< Output latch register -#define MCP23XXX_ADDR 0x20 //!< Default I2C Address -#define MCP23XXX_SPI_WRITE 0x40 //!< Opcode for SPI write -#define MCP23XXX_SPI_READ 0x41 //!< Opcode for SPI read +#define MCP23XXX_ADDR 0x20 //!< Default I2C Address +#define MCP23XXX_SPIREG \ + ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE //!< SPI register type -#define PORT(pin) ((pin < 8) ? 0 : 1) //!< Determine port from pin number -#define MASK(pin) (1 << (pin % 8)) //!< Determine mask from pin number +#define MCP_PORT(pin) ((pin < 8) ? 0 : 1) //!< Determine port from pin number /**************************************************************************/ /*! @@ -62,11 +62,7 @@ class Adafruit_MCP23XXX { Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface uint8_t pinCount; ///< Total number of GPIO pins - uint8_t readRegister(uint8_t addr); - void writeRegister(uint8_t addr, uint8_t value); - uint16_t readRegister16(uint8_t addr); - void writeRegister16(uint8_t addr, uint16_t value); - uint8_t getRegister(uint8_t baseAddress, uint8_t port = 0); + uint16_t getRegister(uint8_t baseAddress, uint8_t port = 0); private: uint8_t buffer[4];