From a4136bedc395067809bb999ed552e802fc171040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fiedler?= Date: Mon, 10 Aug 2020 00:50:04 +0200 Subject: [PATCH 01/49] add possibility to pass in a Wire instance This adds the possibility to pass in a Wire instance to be able to configure the clock speed / frequency and also the used IO pins. --- Adafruit_MCP23017.cpp | 71 ++++++++++--------- Adafruit_MCP23017.h | 5 +- .../custom_frequency/custom_frequency.ino | 19 +++++ examples/use_two_i2c/use_two_i2c.ino | 23 ++++++ 4 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 examples/custom_frequency/custom_frequency.ino create mode 100644 examples/use_two_i2c/use_two_i2c.ino diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index abf13c3..c90c7ee 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -36,19 +36,19 @@ #endif // minihelper to keep Arduino backward compatibility -static inline void wiresend(uint8_t x) { +static inline void wiresend(uint8_t x, TwoWire *theWire) { #if ARDUINO >= 100 - Wire.write((uint8_t)x); + theWire->write((uint8_t)x); #else - Wire.send(x); + theWire->send(x); #endif } -static inline uint8_t wirerecv(void) { +static inline uint8_t wirerecv(TwoWire *theWire) { #if ARDUINO >= 100 - return Wire.read(); + return theWire->read(); #else - return Wire.receive(); + return theWire->receive(); #endif } @@ -70,11 +70,11 @@ uint8_t Adafruit_MCP23017::regForPin(uint8_t pin, uint8_t portAaddr, */ uint8_t Adafruit_MCP23017::readRegister(uint8_t addr) { // read the current GPINTEN - Wire.beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(addr); - Wire.endTransmission(); - Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1); - return wirerecv(); + _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); + wiresend(addr, _wire); + _wire->endTransmission(); + _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 1); + return wirerecv(_wire); } /** @@ -82,10 +82,10 @@ uint8_t Adafruit_MCP23017::readRegister(uint8_t addr) { */ void Adafruit_MCP23017::writeRegister(uint8_t regAddr, uint8_t regValue) { // Write the register - Wire.beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(regAddr); - wiresend(regValue); - Wire.endTransmission(); + _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); + wiresend(regAddr, _wire); + wiresend(regValue, _wire); + _wire->endTransmission(); } /** @@ -114,13 +114,14 @@ void Adafruit_MCP23017::updateRegisterBit(uint8_t pin, uint8_t pValue, * Address selection. * @param addr Selected address */ -void Adafruit_MCP23017::begin(uint8_t addr) { +void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { if (addr > 7) { addr = 7; } i2caddr = addr; + _wire = theWire; - Wire.begin(); + _wire->begin(); // set defaults! // all inputs on port A and B @@ -132,7 +133,7 @@ void Adafruit_MCP23017::begin(uint8_t addr) { * Initializes the default MCP23017, with 000 for the configurable part of the * address */ -void Adafruit_MCP23017::begin(void) { begin(0); } +void Adafruit_MCP23017::begin(TwoWire *theWire) { begin(0, theWire); } /** * Sets the pin mode to either INPUT or OUTPUT @@ -152,13 +153,13 @@ uint16_t Adafruit_MCP23017::readGPIOAB() { uint8_t a; // read the current GPIO output latches - Wire.beginTransmission(MCP23017_ADDRESS | i2caddr); - wiresend(MCP23017_GPIOA); - Wire.endTransmission(); + _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); + wiresend(MCP23017_GPIOA, _wire); + _wire->endTransmission(); - Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 2); - a = wirerecv(); - ba = wirerecv(); + _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 2); + a = wirerecv(_wire); + ba = wirerecv(_wire); ba <<= 8; ba |= a; @@ -173,16 +174,16 @@ uint16_t Adafruit_MCP23017::readGPIOAB() { uint8_t Adafruit_MCP23017::readGPIO(uint8_t b) { // read the current GPIO output latches - Wire.beginTransmission(MCP23017_ADDRESS | i2caddr); + _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); if (b == 0) - wiresend(MCP23017_GPIOA); + wiresend(MCP23017_GPIOA, _wire); else { - wiresend(MCP23017_GPIOB); + wiresend(MCP23017_GPIOB, _wire); } - Wire.endTransmission(); + _wire->endTransmission(); - Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1); - return wirerecv(); + _wire->requestFrom(MCP23017_ADDRESS | i2caddr, 1); + return wirerecv(_wire); } /** @@ -190,11 +191,11 @@ uint8_t Adafruit_MCP23017::readGPIO(uint8_t b) { * 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); - wiresend(ba & 0xFF); - wiresend(ba >> 8); - Wire.endTransmission(); + _wire->beginTransmission(MCP23017_ADDRESS | i2caddr); + wiresend(MCP23017_GPIOA, _wire); + wiresend(ba & 0xFF, _wire); + wiresend(ba >> 8, _wire); + _wire->endTransmission(); } /*! diff --git a/Adafruit_MCP23017.h b/Adafruit_MCP23017.h index 69083f5..dde203c 100644 --- a/Adafruit_MCP23017.h +++ b/Adafruit_MCP23017.h @@ -23,8 +23,8 @@ */ class Adafruit_MCP23017 { public: - void begin(uint8_t addr); - void begin(void); + 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); @@ -42,6 +42,7 @@ class Adafruit_MCP23017 { 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); diff --git a/examples/custom_frequency/custom_frequency.ino b/examples/custom_frequency/custom_frequency.ino new file mode 100644 index 0000000..d6de63d --- /dev/null +++ b/examples/custom_frequency/custom_frequency.ino @@ -0,0 +1,19 @@ +#include +#include "Adafruit_MCP23017.h" + +// Sample for usage of two MCP23017 I/O expander with an ESP32 +// public domain! + +TwoWire myWire = TwoWire(0); + +Adafruit_MCP23017 mcp; + +void setup() { + + myWire.setClock(1700000); // set frequency to 1.7mhz + + mcp.begin(&myWire); // use default address 0 +} + +void loop() { +} diff --git a/examples/use_two_i2c/use_two_i2c.ino b/examples/use_two_i2c/use_two_i2c.ino new file mode 100644 index 0000000..4d81f27 --- /dev/null +++ b/examples/use_two_i2c/use_two_i2c.ino @@ -0,0 +1,23 @@ +#include +#include "Adafruit_MCP23017.h" + +// Sample for usage of two MCP23017 I/O expander with an ESP32 +// public domain! + +TwoWire firstWire = TwoWire(0); +TwoWire secondWire = TwoWire(1); + +Adafruit_MCP23017 firstMcp; +Adafruit_MCP23017 secondMcp; + +void setup() { + + firstWire.begin(21, 22); + secondWire.begin(19, 23); + + firstMcp.begin(&firstWire); // use default address 0 for I2C #1 + secondMcp.begin(&secondWire); // use default address 0 for I2C #2 +} + +void loop() { +} From 47b97e9666a226519f2edb1aad5eec16d315d940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fiedler?= Date: Mon, 10 Aug 2020 01:06:43 +0200 Subject: [PATCH 02/49] simplification --- examples/custom_frequency/custom_frequency.ino | 6 ++---- examples/use_two_i2c/use_two_i2c.ino | 11 ++++------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/examples/custom_frequency/custom_frequency.ino b/examples/custom_frequency/custom_frequency.ino index d6de63d..a33729d 100644 --- a/examples/custom_frequency/custom_frequency.ino +++ b/examples/custom_frequency/custom_frequency.ino @@ -4,15 +4,13 @@ // Sample for usage of two MCP23017 I/O expander with an ESP32 // public domain! -TwoWire myWire = TwoWire(0); - Adafruit_MCP23017 mcp; void setup() { - myWire.setClock(1700000); // set frequency to 1.7mhz + Wire.setClock(1700000); // set frequency to 1.7mhz - mcp.begin(&myWire); // use default address 0 + mcp.begin(&Wire); // use default address 0 } void loop() { diff --git a/examples/use_two_i2c/use_two_i2c.ino b/examples/use_two_i2c/use_two_i2c.ino index 4d81f27..fc44838 100644 --- a/examples/use_two_i2c/use_two_i2c.ino +++ b/examples/use_two_i2c/use_two_i2c.ino @@ -4,19 +4,16 @@ // Sample for usage of two MCP23017 I/O expander with an ESP32 // public domain! -TwoWire firstWire = TwoWire(0); -TwoWire secondWire = TwoWire(1); - Adafruit_MCP23017 firstMcp; Adafruit_MCP23017 secondMcp; void setup() { - firstWire.begin(21, 22); - secondWire.begin(19, 23); + Wire.begin(21, 22); + Wire1.begin(4, 5); - firstMcp.begin(&firstWire); // use default address 0 for I2C #1 - secondMcp.begin(&secondWire); // use default address 0 for I2C #2 + firstMcp.begin(&Wire); // use default address 0 for I2C #1 + secondMcp.begin(&Wire1); // use default address 0 for I2C #2 } void loop() { From d8a6ec09c80d9b749e46cd81c68fca946142d6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fiedler?= Date: Mon, 10 Aug 2020 01:16:05 +0200 Subject: [PATCH 03/49] remove not working example --- examples/use_two_i2c/use_two_i2c.ino | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 examples/use_two_i2c/use_two_i2c.ino diff --git a/examples/use_two_i2c/use_two_i2c.ino b/examples/use_two_i2c/use_two_i2c.ino deleted file mode 100644 index fc44838..0000000 --- a/examples/use_two_i2c/use_two_i2c.ino +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "Adafruit_MCP23017.h" - -// Sample for usage of two MCP23017 I/O expander with an ESP32 -// public domain! - -Adafruit_MCP23017 firstMcp; -Adafruit_MCP23017 secondMcp; - -void setup() { - - Wire.begin(21, 22); - Wire1.begin(4, 5); - - firstMcp.begin(&Wire); // use default address 0 for I2C #1 - secondMcp.begin(&Wire1); // use default address 0 for I2C #2 -} - -void loop() { -} From 4d065c4feed0afc3fc4c9bb4e0978e175d30c0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fiedler?= Date: Mon, 10 Aug 2020 01:23:28 +0200 Subject: [PATCH 04/49] fix doxygen issue --- Adafruit_MCP23017.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index c90c7ee..79d193c 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -113,6 +113,7 @@ void Adafruit_MCP23017::updateRegisterBit(uint8_t pin, uint8_t pValue, * 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) { @@ -132,6 +133,7 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { /** * 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); } From f37ca2a6b98b5970c3a5a0ab6ef9903eb3e53f2c Mon Sep 17 00:00:00 2001 From: Ross Date: Sun, 16 Aug 2020 17:48:55 -0400 Subject: [PATCH 05/49] 'physial' -> 'physical' update. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bc7e1f..f42bfc3 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ 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, ...)_. -Physial Pin #| Pin Name | Pin ID +Physical Pin #| Pin Name | Pin ID ----|------|------------------------------ 21 | GPA0 | 0 22 | GPA1 | 1 From 32cc4ebd85bd5db571473534d90a1d305ebadc6d Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 17 Aug 2020 15:19:48 -0700 Subject: [PATCH 06/49] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 3328d38..5d182ce 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=1.1.0 +version=1.2.0 author=Adafruit maintainer=Adafruit sentence=Library for the MCP23017 I2C Port Expander From 2f0597b426c015a864ada60b91d22649020b69ab Mon Sep 17 00:00:00 2001 From: PsuFan Date: Mon, 8 Feb 2021 14:27:24 -0500 Subject: [PATCH 07/49] Add disableInterruptPin --- Adafruit_MCP23017.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index 79d193c..97ce9cf 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -295,6 +295,17 @@ void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) { 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 From d64be8c16eed3405d119b48ac5ed362bc270777d Mon Sep 17 00:00:00 2001 From: PsuFan Date: Mon, 8 Feb 2021 14:29:15 -0500 Subject: [PATCH 08/49] Add disableInterruptPin() --- Adafruit_MCP23017.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Adafruit_MCP23017.h b/Adafruit_MCP23017.h index dde203c..6ed0f8d 100644 --- a/Adafruit_MCP23017.h +++ b/Adafruit_MCP23017.h @@ -36,7 +36,8 @@ class Adafruit_MCP23017 { uint8_t readGPIO(uint8_t b); void setupInterrupts(uint8_t mirroring, uint8_t open, uint8_t polarity); - void setupInterruptPin(uint8_t p, uint8_t mode); + void setupInterruptPin(uint8_t pin, uint8_t mode); + void disableInterruptPin(uint8_t pin); uint8_t getLastInterruptPin(); uint8_t getLastInterruptPinValue(); From 067a072ea92db40199140c97a47af1c28335a7a0 Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 13:20:44 -0500 Subject: [PATCH 09/49] Turn off Interrupt Triggers and Pull Up Resistors on begin() --- Adafruit_MCP23017.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index 97ce9cf..d0595c9 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -128,6 +128,14 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { // 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); } /** From 1c8e61174be3305a2f0872b4274c7588d140e55c Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 13:42:10 -0500 Subject: [PATCH 10/49] Reset Interrupt Register If Trigger Came Before Ready If an interrupt comes before the board is ready, the interrupt pin does not get reset until a read is made from A/B (if mirrored). --- examples/interrupt/interrupt.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/interrupt/interrupt.ino b/examples/interrupt/interrupt.ino index 15247c5..f2aeade 100644 --- a/examples/interrupt/interrupt.ino +++ b/examples/interrupt/interrupt.ino @@ -103,6 +103,11 @@ void cleanInterrupts(){ * and you can wait for interrupts while waiting. */ void loop(){ + // Clear Previous Interrupts + if (digitalRead(arduinoIntPin) == LOW) { + MCP.digitalRead(0); + MCP.digitalRead(7); + } // enable interrupts before going to sleep/wait // And we setup a callback for the arduino INT handler. From a8effb63684d44007ff9442b75275a1acee2066b Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 14:14:22 -0500 Subject: [PATCH 11/49] Reset Interrupt Register If Trigger Came Before Ready --- examples/interrupt/interrupt.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/interrupt/interrupt.ino b/examples/interrupt/interrupt.ino index f2aeade..026db0e 100644 --- a/examples/interrupt/interrupt.ino +++ b/examples/interrupt/interrupt.ino @@ -105,8 +105,8 @@ void cleanInterrupts(){ void loop(){ // Clear Previous Interrupts if (digitalRead(arduinoIntPin) == LOW) { - MCP.digitalRead(0); - MCP.digitalRead(7); + mcp.digitalRead(0); + mcp.digitalRead(7); } // enable interrupts before going to sleep/wait From 6ac4db4ec6515c2831d3ac710a76872125feb726 Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 14:45:15 -0500 Subject: [PATCH 12/49] Attempt Clang Format Fix --- Adafruit_MCP23017.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index d0595c9..929831f 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -135,7 +135,7 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { // Turn off pull up resistors writeRegister(MCP23017_GPPUA, 0x00); - writeRegister(MCP23017_GPPUB, 0x00); + writeRegister(MCP23017_GPPUB, 0x00); } /** From 2a939fce4921738693f13d112eaf9b712417d08c Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 14:51:40 -0500 Subject: [PATCH 13/49] Update Adafruit_MCP23017.cpp --- Adafruit_MCP23017.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index 929831f..ee9b928 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -130,12 +130,12 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { writeRegister(MCP23017_IODIRB, 0xff); // Turn off interrupt triggers - writeRegister(MCP23017_GPINTENA, 0x00); - writeRegister(MCP23017_GPINTENB, 0x00); + writeRegister(MCP23017_GPINTENA, 0x0); + writeRegister(MCP23017_GPINTENB, 0x0); // Turn off pull up resistors - writeRegister(MCP23017_GPPUA, 0x00); - writeRegister(MCP23017_GPPUB, 0x00); + writeRegister(MCP23017_GPPUA, 0x0); + writeRegister(MCP23017_GPPUB, 0x0); } /** From e876ca9bfff38f65e83da6bdaac8bacbe1e79a53 Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 15:01:27 -0500 Subject: [PATCH 14/49] Update Adafruit_MCP23017.cpp --- Adafruit_MCP23017.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index ee9b928..929831f 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -130,12 +130,12 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { writeRegister(MCP23017_IODIRB, 0xff); // Turn off interrupt triggers - writeRegister(MCP23017_GPINTENA, 0x0); - writeRegister(MCP23017_GPINTENB, 0x0); + writeRegister(MCP23017_GPINTENA, 0x00); + writeRegister(MCP23017_GPINTENB, 0x00); // Turn off pull up resistors - writeRegister(MCP23017_GPPUA, 0x0); - writeRegister(MCP23017_GPPUB, 0x0); + writeRegister(MCP23017_GPPUA, 0x00); + writeRegister(MCP23017_GPPUB, 0x00); } /** From da518c93edd12a4a4cc643fbed561cb577456ff2 Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 15:22:58 -0500 Subject: [PATCH 15/49] Update Adafruit_MCP23017.cpp --- Adafruit_MCP23017.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index 929831f..d0595c9 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -135,7 +135,7 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { // Turn off pull up resistors writeRegister(MCP23017_GPPUA, 0x00); - writeRegister(MCP23017_GPPUB, 0x00); + writeRegister(MCP23017_GPPUB, 0x00); } /** From 8716cd0081ff06b18606f7b614a8cc4064a2cd4a Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 15:29:09 -0500 Subject: [PATCH 16/49] Update Adafruit_MCP23017.cpp --- Adafruit_MCP23017.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index d0595c9..e184d76 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -124,15 +124,17 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { _wire->begin(); + _wire->setClock(400000); + // 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); @@ -303,12 +305,6 @@ void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) { 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); From 488152908866510572fc68d1d4c124e29f1b9735 Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 15:43:05 -0500 Subject: [PATCH 17/49] Update Adafruit_MCP23017.cpp --- Adafruit_MCP23017.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index e184d76..c169d29 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -305,6 +305,12 @@ void Adafruit_MCP23017::setupInterruptPin(uint8_t pin, uint8_t mode) { 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); From ffc8a645a94a78dae124ef7e71c45c2eea8988d4 Mon Sep 17 00:00:00 2001 From: PsuFan Date: Tue, 9 Feb 2021 16:00:47 -0500 Subject: [PATCH 18/49] Update Adafruit_MCP23017.cpp --- Adafruit_MCP23017.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Adafruit_MCP23017.cpp b/Adafruit_MCP23017.cpp index c169d29..5e9d58e 100644 --- a/Adafruit_MCP23017.cpp +++ b/Adafruit_MCP23017.cpp @@ -124,8 +124,6 @@ void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) { _wire->begin(); - _wire->setClock(400000); - // set defaults! // all inputs on port A and B writeRegister(MCP23017_IODIRA, 0xff); From 65438e94ef5cdeb73d7a79d37b8ca46ee9331cd2 Mon Sep 17 00:00:00 2001 From: Dylan Herrada <33632497+dherrada@users.noreply.github.com> Date: Tue, 9 Feb 2021 16:33:49 -0500 Subject: [PATCH 19/49] Bump to 1.3.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 5d182ce..7eef519 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=1.2.0 +version=1.3.0 author=Adafruit maintainer=Adafruit sentence=Library for the MCP23017 I2C Port Expander From 984833904d107b6a2b8fa15cb3a1c14748a92057 Mon Sep 17 00:00:00 2001 From: caternuson Date: Wed, 16 Jun 2021 09:01:13 -0700 Subject: [PATCH 20/49] 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 21/49] 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 22/49] 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 23/49] 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]; From 344654b6e676453bb8dd381ae842550514f466fd Mon Sep 17 00:00:00 2001 From: Donkie Date: Sun, 4 Jul 2021 13:25:41 +0200 Subject: [PATCH 24/49] Fixed interrupt pins on port B not being able to be read --- src/Adafruit_MCP23XXX.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 39724cb..d23c9af 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -210,7 +210,7 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { // Port A Adafruit_BusIO_Register INTFA(i2c_dev, spi_dev, MCP23XXX_SPIREG, - getRegister(MCP23XXX_INTF)); + getRegister(MCP23XXX_INTF, 0)); INTFA.read(&intf); for (uint8_t pin = 0; pin < 8; pin++) { if (intf & (1 << pin)) { @@ -222,7 +222,7 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { // 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); + getRegister(MCP23XXX_INTF, 1)); INTFB.read(&intf); for (uint8_t pin = 0; pin < 8; pin++) { if (intf & (1 << pin)) { From 3f1755ef18d386281f0592975d197d85a9c639a2 Mon Sep 17 00:00:00 2001 From: Donkie Date: Sun, 4 Jul 2021 13:26:00 +0200 Subject: [PATCH 25/49] Fixed interrupts on port B not being cleared --- src/Adafruit_MCP23XXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index d23c9af..921158d 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -235,7 +235,7 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { // clear if found if (intpin != 255) { Adafruit_BusIO_Register INTCAP(i2c_dev, spi_dev, MCP23XXX_SPIREG, - getRegister(MCP23XXX_INTCAP)); + getRegister(MCP23XXX_INTCAP, MCP_PORT(intpin))); INTCAP.read(); } From 1a1983b27d1c4cfe8322e550eb8de2ee59629198 Mon Sep 17 00:00:00 2001 From: Daniel Hultgren Date: Sat, 17 Jul 2021 23:05:24 +0200 Subject: [PATCH 26/49] Formatted document --- src/Adafruit_MCP23XXX.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 921158d..7bb97d3 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -234,8 +234,9 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { // clear if found if (intpin != 255) { - Adafruit_BusIO_Register INTCAP(i2c_dev, spi_dev, MCP23XXX_SPIREG, - getRegister(MCP23XXX_INTCAP, MCP_PORT(intpin))); + Adafruit_BusIO_Register INTCAP( + i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTCAP, MCP_PORT(intpin))); INTCAP.read(); } From 410ae8137aa10d3606370fdd44aa6a9695d3a7b5 Mon Sep 17 00:00:00 2001 From: Daniel Hultgren Date: Sun, 18 Jul 2021 00:19:52 +0200 Subject: [PATCH 27/49] Fixed doxygen --- .github/workflows/githubci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 9145985..c457fbc 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -15,6 +15,9 @@ jobs: with: repository: adafruit/ci-arduino path: ci + + - name: move src contents to root + run: mv -v src/* . - name: pre-install run: bash ci/actions_install.sh From bb679b5fb5f10c7b0fe5a709bfc141dcc29196da Mon Sep 17 00:00:00 2001 From: Daniel Hultgren Date: Sun, 18 Jul 2021 00:56:18 +0200 Subject: [PATCH 28/49] Split into multiple jobs --- .github/workflows/githubci.yml | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index c457fbc..849c5af 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -16,20 +16,46 @@ jobs: repository: adafruit/ci-arduino path: ci - - name: move src contents to root - run: mv -v src/* . - - name: pre-install run: bash ci/actions_install.sh - name: test platforms run: python3 ci/build_platform.py main_platforms + clang-format: + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: adafruit/ci-arduino + path: ci + + - name: pre-install + run: bash ci/actions_install.sh - name: clang run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . + doxygen: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: adafruit/ci-arduino + path: ci + + # The Adafruit doxygen setup is configured to only look for files in the root directory + - name: move src contents to root + run: mv -v src/* . - name: doxygen env: GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} PRETTYNAME : "Adafruit MCP23017 Library" run: bash ci/doxy_gen_and_deploy.sh + From 4644d27aa7c612d231c087f1b7c9a842660a95c5 Mon Sep 17 00:00:00 2001 From: Daniel Hultgren Date: Sun, 18 Jul 2021 00:48:26 +0200 Subject: [PATCH 29/49] Made it comply with Doxygen rules --- src/Adafruit_MCP23X08.cpp | 18 ------------------ src/Adafruit_MCP23X17.cpp | 18 ------------------ src/Adafruit_MCP23XXX.cpp | 3 ++- 3 files changed, 2 insertions(+), 37 deletions(-) diff --git a/src/Adafruit_MCP23X08.cpp b/src/Adafruit_MCP23X08.cpp index a4d2ebf..eed7f57 100644 --- a/src/Adafruit_MCP23X08.cpp +++ b/src/Adafruit_MCP23X08.cpp @@ -1,23 +1,5 @@ /*! * @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" diff --git a/src/Adafruit_MCP23X17.cpp b/src/Adafruit_MCP23X17.cpp index ed19b1f..cbf8c17 100644 --- a/src/Adafruit_MCP23X17.cpp +++ b/src/Adafruit_MCP23X17.cpp @@ -1,23 +1,5 @@ /*! * @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" diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 39724cb..3c1d7e3 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -144,7 +144,7 @@ void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { /*! @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 openDrain true for open drain output, false for active drive output. @param polarity HIGH or LOW */ /**************************************************************************/ @@ -247,6 +247,7 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { @brief helper to get register address @param baseAddress base register address @param port 0 for A, 1 for B (MCP23X17 only) + @returns calculated register address */ /**************************************************************************/ uint16_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { From a80a8405e5da47e0a593a2fcc867a3c3a4fdb0bf Mon Sep 17 00:00:00 2001 From: c0redumb Date: Sat, 17 Jul 2021 21:53:43 -0700 Subject: [PATCH 30/49] Used wrong variable name for IOCON --- src/Adafruit_MCP23XXX.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 39724cb..9771785 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -150,11 +150,11 @@ void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { /**************************************************************************/ void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity) { - Adafruit_BusIO_Register GPINTEN(i2c_dev, spi_dev, MCP23XXX_SPIREG, + Adafruit_BusIO_Register IOCON(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); + Adafruit_BusIO_RegisterBits mirror_bit(&IOCON, 1, 6); + Adafruit_BusIO_RegisterBits openDrain_bit(&IOCON, 1, 2); + Adafruit_BusIO_RegisterBits polarity_bit(&IOCON, 1, 1); mirror_bit.write(mirroring ? 1 : 0); openDrain_bit.write(openDrain ? 1 : 0); From de3350ec4e9cac2fb9b36d7ef5687033f34236da Mon Sep 17 00:00:00 2001 From: c0redumb Date: Sun, 18 Jul 2021 09:16:06 -0700 Subject: [PATCH 31/49] It seems that clang formatter does not like the extra spaces --- src/Adafruit_MCP23XXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 9771785..f9c8759 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -151,7 +151,7 @@ void Adafruit_MCP23XXX::writeGPIO(uint8_t value, uint8_t port) { void Adafruit_MCP23XXX::setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity) { Adafruit_BusIO_Register IOCON(i2c_dev, spi_dev, MCP23XXX_SPIREG, - getRegister(MCP23XXX_IOCON)); + getRegister(MCP23XXX_IOCON)); Adafruit_BusIO_RegisterBits mirror_bit(&IOCON, 1, 6); Adafruit_BusIO_RegisterBits openDrain_bit(&IOCON, 1, 2); Adafruit_BusIO_RegisterBits polarity_bit(&IOCON, 1, 1); From 8636f117dcda592c4174e430e9d2d83ad3cabd38 Mon Sep 17 00:00:00 2001 From: Dylan Herrada <33632497+dherrada@users.noreply.github.com> Date: Thu, 22 Jul 2021 11:40:38 -0400 Subject: [PATCH 32/49] Bump to 2.0.1 --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 144aab2..26c1f08 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23X08/17 Arduino Library -version=2.0.0 +version=2.0.1 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders @@ -7,4 +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 +depends=Adafruit BusIO From 00f90585d3c722f7ff5be113fac4b1b04f8a8927 Mon Sep 17 00:00:00 2001 From: caternuson Date: Sun, 1 Aug 2021 16:15:35 -0700 Subject: [PATCH 33/49] revert lib name --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 26c1f08..b6b29e6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ -name=Adafruit MCP23X08/17 Arduino Library -version=2.0.1 +name=Adafruit MCP23017 Arduino Library +version=2.0.2 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders From ff4ccc35c10ecbf6b17a8ea0d494ff01205411c2 Mon Sep 17 00:00:00 2001 From: Mateusz Juzwiak Date: Tue, 7 Dec 2021 00:09:35 +0100 Subject: [PATCH 34/49] HW Address pins support --- README.md | 14 ++++++++++++++ src/Adafruit_MCP23X17.cpp | 32 ++++++++++++++++++++++++++++++++ src/Adafruit_MCP23X17.h | 1 + src/Adafruit_MCP23XXX.cpp | 15 +++++++++++---- src/Adafruit_MCP23XXX.h | 6 ++++-- 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f4d48be..da90771 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,17 @@ MCP23x08 Pin # | MCP23x17 Pin # | Pin Name | Pin ID -- | 6 | GPB5 | 13 -- | 7 | GPB6 | 14 -- | 8 | GPB7 | 15 + +# Use of HW address pins for SPI device + +Library supports MCP23Sxx HW pin addressing (A2, A1, A0 for S17 and A1, A0 for S08) +To use it provide HW address to begin_SPI(CS, SPI, HW_ADDR) function, and as a result each SPI message will contain correct chip address. + +Example: +mcp.begin_SPI(10, &SPI, 0b101); + +MCP23S08 uses addr pins by default. For MCP23S17 address recognition must be enabled by enableAddrPins() function. **NOTE** Calling enableAddrPins() will enable IOCON.HAEN bit for all active (CS low) devices on SPI bus. +**NOTE** +There is hardware bug in the MCP23S17 chip, see "MCP23S17 Rev. A Silicon Errata". +As a result, if using device with A2 = high, and not using addressing, hw address must be set to 0b1XX +In such case, even if not using addressing, initalize your MCP23S17 chip with 0b1XX address, eg: mcp.begin_SPI(10, &SPI, 0b100);. diff --git a/src/Adafruit_MCP23X17.cpp b/src/Adafruit_MCP23X17.cpp index cbf8c17..1479845 100644 --- a/src/Adafruit_MCP23X17.cpp +++ b/src/Adafruit_MCP23X17.cpp @@ -66,3 +66,35 @@ void Adafruit_MCP23X17::writeGPIOAB(uint16_t value) { getRegister(MCP23XXX_GPIO, 0), 2); GPIO.write(value, 2); } + +/**************************************************************************/ +/*! + @brief Enable usage of HW address pins (A0, A1, A2) on MCP23S17 + + Send this message as first message after chip init, as it will + set bits in IOCON register to default (except HAEN) + By default pins are not used and disabled (see README for details) + This message is sent to all devices on bus (no hw_addr is added to msg + as it's not enabled yet) + Due to HW bug in the chip message must be sent twice (to addr 0b000 and + 0b1xx) +*/ +/**************************************************************************/ +void Adafruit_MCP23X17::enableAddrPins() { + if (!spi_dev) // I2C dev always use addr, only makes sense for SPI dev + return; + + Adafruit_BusIO_Register GPIOAddr(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_IOCON, 0), 2); + + // Send message to address 0b000 regardless of chip addr, + // Because addressing is not yet enabled + uint8_t tmp = this->hw_addr; + this->hw_addr = 0; // Temporary set hw addr to 0 + Adafruit_BusIO_Register GPIONoAddr(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_IOCON, 0), 2); + this->hw_addr = tmp; + + GPIONoAddr.write((1 << 3), 1); // Bit3: HAEN, devices with A2 = 0 + GPIOAddr.write((1 << 3), 1); // Devices with A2 = 1 (if any) +} \ No newline at end of file diff --git a/src/Adafruit_MCP23X17.h b/src/Adafruit_MCP23X17.h index 3aec5f8..49f35ac 100644 --- a/src/Adafruit_MCP23X17.h +++ b/src/Adafruit_MCP23X17.h @@ -22,6 +22,7 @@ class Adafruit_MCP23X17 : public Adafruit_MCP23XXX { void writeGPIOB(uint8_t value); uint16_t readGPIOAB(); void writeGPIOAB(uint16_t value); + void enableAddrPins(); }; #endif \ No newline at end of file diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 4e23e91..d1f06d9 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -40,10 +40,13 @@ bool Adafruit_MCP23XXX::begin_I2C(uint8_t i2c_addr, TwoWire *wire) { @brief Initialize MCP using hardware SPI. @param cs_pin Pin to use for SPI chip select @param theSPI Pointer to SPI instance + @param _hw_addr Hardware address (pins A2, A1, A0) @return true if initialization successful, otherwise false. */ /**************************************************************************/ -bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) { +bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI, + uint8_t _hw_addr) { + this->hw_addr = _hw_addr; spi_dev = new Adafruit_SPIDevice(cs_pin, 1000000, SPI_BITORDER_MSBFIRST, SPI_MODE0, theSPI); return spi_dev->begin(); @@ -56,18 +59,22 @@ bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) { @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 + @param _hw_addr Hardware address (pins A2, A1, A0) @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) { + int8_t miso_pin, int8_t mosi_pin, + uint8_t _hw_addr) { + this->hw_addr = _hw_addr; 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. + @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 */ @@ -262,5 +269,5 @@ uint16_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { reg++; } // for SPI, add opcode as high byte - return (spi_dev) ? (0x4000 | reg) : reg; + return (spi_dev) ? (0x4000 | (hw_addr << 9) | reg) : reg; } diff --git a/src/Adafruit_MCP23XXX.h b/src/Adafruit_MCP23XXX.h index 98975f4..39f880e 100644 --- a/src/Adafruit_MCP23XXX.h +++ b/src/Adafruit_MCP23XXX.h @@ -39,9 +39,10 @@ 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(uint8_t cs_pin, SPIClass *theSPI = &SPI, + uint8_t _hw_addr = 0x00); bool begin_SPI(int8_t cs_pin, int8_t sck_pin, int8_t miso_pin, - int8_t mosi_pin); + int8_t mosi_pin, uint8_t _hw_addr = 0x00); // main Arduino API methods void pinMode(uint8_t pin, uint8_t mode); @@ -62,6 +63,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 hw_addr; ///< HW address matching A2/A1/A0 pins uint16_t getRegister(uint8_t baseAddress, uint8_t port = 0); private: From aa391dcdd7f2f94954fe07b10724da0af843110e Mon Sep 17 00:00:00 2001 From: caternuson Date: Wed, 23 Feb 2022 12:48:01 -0800 Subject: [PATCH 35/49] readme update --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index f4d48be..13a0cd8 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,8 @@ MCP23x08 Pin # | MCP23x17 Pin # | Pin Name | Pin ID -- | 6 | GPB5 | 13 -- | 7 | GPB6 | 14 -- | 8 | GPB7 | 15 + +# Warning + +Some people have reported an undocumented bug that can potentially corrupt the I2C bus. +It occurs if an MCP230XX input pin state changes during I2C readout. **This should be very rare.** For more information, see this [forum post](https://www.microchip.com/forums/m646539.aspx) and this [knowledge base article](https://microchipsupport.force.com/s/article/On-MCP23008-MCP23017-SDA-line-change-when-GPIO7-input-change>). From 667cd738ef0badafd6e4c67423a0eaea745449a3 Mon Sep 17 00:00:00 2001 From: Eva Herrada <33632497+evaherrada@users.noreply.github.com> Date: Tue, 1 Mar 2022 14:09:11 -0500 Subject: [PATCH 36/49] Bump to 2.0.3 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index b6b29e6..2fab73c 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.0.2 +version=2.0.3 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders From 7238c95d6cbf427c1f934fbd62547841ff90515f Mon Sep 17 00:00:00 2001 From: Carter Nelson Date: Wed, 2 Mar 2022 08:36:06 -0800 Subject: [PATCH 37/49] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index da90771..40cee90 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,8 @@ MCP23S08 uses addr pins by default. For MCP23S17 address recognition must be ena There is hardware bug in the MCP23S17 chip, see "MCP23S17 Rev. A Silicon Errata". As a result, if using device with A2 = high, and not using addressing, hw address must be set to 0b1XX In such case, even if not using addressing, initalize your MCP23S17 chip with 0b1XX address, eg: mcp.begin_SPI(10, &SPI, 0b100);. + +# Warning + +Some people have reported an undocumented bug that can potentially corrupt the I2C bus. +It occurs if an MCP230XX input pin state changes during I2C readout. **This should be very rare.** For more information, see this [forum post](https://www.microchip.com/forums/m646539.aspx) and this [knowledge base article](https://microchipsupport.force.com/s/article/On-MCP23008-MCP23017-SDA-line-change-when-GPIO7-input-change>). From 0e82c8d873037ff2522b9167ac20433ac23ef0d4 Mon Sep 17 00:00:00 2001 From: Carter Nelson Date: Wed, 2 Mar 2022 08:56:08 -0800 Subject: [PATCH 38/49] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 2fab73c..30528a2 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.0.3 +version=2.1.0 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders From 93afb632344a1f34f42e79fd8c117cc18977e4b9 Mon Sep 17 00:00:00 2001 From: Alexandre Maurer Date: Mon, 25 Jul 2022 14:01:01 +0200 Subject: [PATCH 39/49] Add enableAddrPins() for MCP23X08 --- README.md | 38 +++++++++++++++++++------------------- library.properties | 2 +- src/Adafruit_MCP23X08.cpp | 22 +++++++++++++++++++++- src/Adafruit_MCP23X08.h | 4 +++- 4 files changed, 44 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 40cee90..1ae6be9 100644 --- a/README.md +++ b/README.md @@ -16,24 +16,24 @@ To install, use the Arduino IDE Library Manager. 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 +| 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 | # Use of HW address pins for SPI device @@ -43,7 +43,7 @@ To use it provide HW address to begin_SPI(CS, SPI, HW_ADDR) function, and as a r Example: mcp.begin_SPI(10, &SPI, 0b101); -MCP23S08 uses addr pins by default. For MCP23S17 address recognition must be enabled by enableAddrPins() function. **NOTE** Calling enableAddrPins() will enable IOCON.HAEN bit for all active (CS low) devices on SPI bus. +HW Address recognition must be enabled by enableAddrPins() function. **NOTE** Calling enableAddrPins() will enable IOCON.HAEN bit for all active (CS low) devices on SPI bus. **NOTE** There is hardware bug in the MCP23S17 chip, see "MCP23S17 Rev. A Silicon Errata". As a result, if using device with A2 = high, and not using addressing, hw address must be set to 0b1XX diff --git a/library.properties b/library.properties index 30528a2..9366c51 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.1.0 +version=2.1.1 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders diff --git a/src/Adafruit_MCP23X08.cpp b/src/Adafruit_MCP23X08.cpp index eed7f57..62c5bb4 100644 --- a/src/Adafruit_MCP23X08.cpp +++ b/src/Adafruit_MCP23X08.cpp @@ -9,4 +9,24 @@ @brief default ctor. */ /**************************************************************************/ -Adafruit_MCP23X08::Adafruit_MCP23X08() { pinCount = 8; } \ No newline at end of file +Adafruit_MCP23X08::Adafruit_MCP23X08() { pinCount = 8; } + +/**************************************************************************/ +/*! + @brief Enable usage of HW address pins (A0, A1) on MCP23S08 + + Send this message as first message after chip init. + + By default HW address pins are disabled. + (Register IOCON, bit HAEN = 0 on chip reset) +*/ +/**************************************************************************/ +void Adafruit_MCP23X08::enableAddrPins() { + if (!spi_dev) // I2C dev always use addr, only makes sense for SPI dev + return; + + Adafruit_BusIO_Register GPIOAddr(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_IOCON, 0), 2); + + GPIOAddr.write((1 << 3), 1); +} \ No newline at end of file diff --git a/src/Adafruit_MCP23X08.h b/src/Adafruit_MCP23X08.h index a238d38..37f2ae6 100644 --- a/src/Adafruit_MCP23X08.h +++ b/src/Adafruit_MCP23X08.h @@ -13,8 +13,10 @@ */ /**************************************************************************/ class Adafruit_MCP23X08 : public Adafruit_MCP23XXX { -public: + public: Adafruit_MCP23X08(); + + void enableAddrPins(); }; #endif \ No newline at end of file From 6f92c72afa71e7b47eef2227580c7c3f30bffc26 Mon Sep 17 00:00:00 2001 From: caternuson Date: Tue, 2 Aug 2022 13:35:33 -0700 Subject: [PATCH 40/49] add INTCAP support --- .../mcp23xxx_interrupt/mcp23xxx_interrupt.ino | 8 ++- src/Adafruit_MCP23XXX.cpp | 54 +++++++++++++++---- src/Adafruit_MCP23XXX.h | 4 ++ 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino b/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino index e5fd747..1b0e4fd 100644 --- a/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino +++ b/examples/mcp23xxx_interrupt/mcp23xxx_interrupt.ino @@ -55,6 +55,12 @@ void loop() { if (!digitalRead(INT_PIN)) { Serial.print("Interrupt detected on pin: "); Serial.println(mcp.getLastInterruptPin()); - delay(250); // debounce + Serial.print("Pin states at time of interrupt: 0b"); + Serial.println(mcp.getCapturedInterrupt(), 2); + delay(250); // debounce + // NOTE: If using DEFVAL, INT clears only if interrupt + // condition does not exist. + // See Fig 1-7 in datasheet. + mcp.clearInterrupts(); // clear } } \ No newline at end of file diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index d1f06d9..8b073ae 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -207,12 +207,25 @@ void Adafruit_MCP23XXX::disableInterruptPin(uint8_t pin) { /**************************************************************************/ /*! - @brief Gets the last interrupt pin. - @returns Pin that caused last interrupt. + @brief Clear interrupts. NOTE:If using DEFVAL, INT clears only if interrupt + condition does not exist. See Fig 1-7 in datasheet. +*/ +/**************************************************************************/ +void Adafruit_MCP23XXX::clearInterrupts() { + // reading INTCAP register(s) clears interrupts + // just call this and ignore return + getCapturedInterrupt(); +} + +/**************************************************************************/ +/*! + @brief Gets the pin that caused the latest interrupt, from INTF, without + clearing any interrupt flags. + @returns Pin that caused lastest interrupt. */ /**************************************************************************/ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { - uint8_t intpin = 255; + uint8_t intpin = MCP23XXX_INT_ERR; uint8_t intf; // Port A @@ -227,7 +240,7 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { } // Port B and still not found? - if ((pinCount > 8) && (intpin == 255)) { + if ((pinCount > 8) && (intpin == MCP23XXX_INT_ERR)) { Adafruit_BusIO_Register INTFB(i2c_dev, spi_dev, MCP23XXX_SPIREG, getRegister(MCP23XXX_INTF, 1)); INTFB.read(&intf); @@ -239,15 +252,34 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { } } - // clear if found - if (intpin != 255) { - Adafruit_BusIO_Register INTCAP( - i2c_dev, spi_dev, MCP23XXX_SPIREG, - getRegister(MCP23XXX_INTCAP, MCP_PORT(intpin))); - INTCAP.read(); + return intpin; +} + +/**************************************************************************/ +/*! + @brief Get pin states captured at time of interrupt. + @returns Mutli-bit value representing pin states. +*/ +/**************************************************************************/ +uint16_t Adafruit_MCP23XXX::getCapturedInterrupt() { + uint16_t intcap; + uint8_t intf; + + // Port A + Adafruit_BusIO_Register INTCAPA(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTCAP, 0)); + INTCAPA.read(&intf); + intcap = intf; + + // Port B ? + if (pinCount > 8) { + Adafruit_BusIO_Register INTCAPB(i2c_dev, spi_dev, MCP23XXX_SPIREG, + getRegister(MCP23XXX_INTCAP, 1)); + INTCAPB.read(&intf); + intcap |= (uint16_t)intf << 8; } - return intpin; + return intcap; } /**************************************************************************/ diff --git a/src/Adafruit_MCP23XXX.h b/src/Adafruit_MCP23XXX.h index 39f880e..5cfc907 100644 --- a/src/Adafruit_MCP23XXX.h +++ b/src/Adafruit_MCP23XXX.h @@ -30,6 +30,8 @@ #define MCP_PORT(pin) ((pin < 8) ? 0 : 1) //!< Determine port from pin number +#define MCP23XXX_INT_ERR 255 //!< Interrupt error + /**************************************************************************/ /*! @brief Base class for all MCP23XXX variants. @@ -57,7 +59,9 @@ class Adafruit_MCP23XXX { void setupInterrupts(bool mirroring, bool openDrain, uint8_t polarity); void setupInterruptPin(uint8_t pin, uint8_t mode = CHANGE); void disableInterruptPin(uint8_t pin); + void clearInterrupts(); uint8_t getLastInterruptPin(); + uint16_t getCapturedInterrupt(); protected: Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface From bf7eddb2fe1a739b7d13f856090e2a27c5ad0568 Mon Sep 17 00:00:00 2001 From: Eva Herrada <33632497+evaherrada@users.noreply.github.com> Date: Tue, 25 Oct 2022 17:25:31 -0400 Subject: [PATCH 41/49] Bump to 2.2.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 30528a2..36cfcb8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.1.0 +version=2.2.0 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders From ff57aa4e9c8d78baff0b8125a4468397669a1669 Mon Sep 17 00:00:00 2001 From: Jesus Vaquerizo <32816191+jvaque@users.noreply.github.com> Date: Wed, 7 Dec 2022 23:30:35 +0000 Subject: [PATCH 42/49] Replace NULL with nullptr --- src/Adafruit_MCP23XXX.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Adafruit_MCP23XXX.h b/src/Adafruit_MCP23XXX.h index 5cfc907..8f330a5 100644 --- a/src/Adafruit_MCP23XXX.h +++ b/src/Adafruit_MCP23XXX.h @@ -64,10 +64,10 @@ class Adafruit_MCP23XXX { uint16_t getCapturedInterrupt(); 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 hw_addr; ///< HW address matching A2/A1/A0 pins + Adafruit_I2CDevice *i2c_dev = nullptr; ///< Pointer to I2C bus interface + Adafruit_SPIDevice *spi_dev = nullptr; ///< Pointer to SPI bus interface + uint8_t pinCount; ///< Total number of GPIO pins + uint8_t hw_addr; ///< HW address matching A2/A1/A0 pins uint16_t getRegister(uint8_t baseAddress, uint8_t port = 0); private: From 540acfcf99819d2a1a4381db4f05b4aead641fd7 Mon Sep 17 00:00:00 2001 From: Jesus Vaquerizo <32816191+jvaque@users.noreply.github.com> Date: Wed, 7 Dec 2022 23:51:37 +0000 Subject: [PATCH 43/49] Refactor getLastInterruptPin() by returning early Changed function logic more in line to how it was first implemented in v1.3.0 by @PsuFan --- src/Adafruit_MCP23XXX.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 8b073ae..7f29378 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -225,7 +225,6 @@ void Adafruit_MCP23XXX::clearInterrupts() { */ /**************************************************************************/ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { - uint8_t intpin = MCP23XXX_INT_ERR; uint8_t intf; // Port A @@ -234,25 +233,23 @@ uint8_t Adafruit_MCP23XXX::getLastInterruptPin() { INTFA.read(&intf); for (uint8_t pin = 0; pin < 8; pin++) { if (intf & (1 << pin)) { - intpin = pin; - break; + return pin; } } - // Port B and still not found? - if ((pinCount > 8) && (intpin == MCP23XXX_INT_ERR)) { + // Port B ? + if (pinCount > 8) { 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; - break; + return pin + 8; } } } - return intpin; + return MCP23XXX_INT_ERR; } /**************************************************************************/ From 4be95a4e34134ac7e84da801f3d12cf8921e39fc Mon Sep 17 00:00:00 2001 From: Jesus Vaquerizo <32816191+jvaque@users.noreply.github.com> Date: Thu, 8 Dec 2022 00:54:37 +0000 Subject: [PATCH 44/49] Refactor bit manipulation in getRegister() function Obtain the same outcome by using bitwise operations --- src/Adafruit_MCP23XXX.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Adafruit_MCP23XXX.cpp b/src/Adafruit_MCP23XXX.cpp index 7f29378..7328c44 100644 --- a/src/Adafruit_MCP23XXX.cpp +++ b/src/Adafruit_MCP23XXX.cpp @@ -292,10 +292,8 @@ uint16_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) { uint16_t reg = baseAddress; // MCP23x17 BANK=0 if (pinCount > 8) { - reg *= 2; - // Port B - if (port) - reg++; + reg <<= 1; + reg |= port; } // for SPI, add opcode as high byte return (spi_dev) ? (0x4000 | (hw_addr << 9) | reg) : reg; From 5124fdc5f47d23187afaed224a7d6fb5ac4d8877 Mon Sep 17 00:00:00 2001 From: Alexandre Maurer Date: Mon, 12 Dec 2022 22:33:13 +0100 Subject: [PATCH 45/49] remove change --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 9366c51..36cfcb8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.1.1 +version=2.2.0 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders From 25ae252adcac44222b61b72519c3577722b00a62 Mon Sep 17 00:00:00 2001 From: Alexandre Maurer Date: Mon, 12 Dec 2022 22:42:47 +0100 Subject: [PATCH 46/49] clang-format on file --- src/Adafruit_MCP23X08.cpp | 2 +- src/Adafruit_MCP23X08.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Adafruit_MCP23X08.cpp b/src/Adafruit_MCP23X08.cpp index 62c5bb4..209bdaa 100644 --- a/src/Adafruit_MCP23X08.cpp +++ b/src/Adafruit_MCP23X08.cpp @@ -22,7 +22,7 @@ Adafruit_MCP23X08::Adafruit_MCP23X08() { pinCount = 8; } */ /**************************************************************************/ void Adafruit_MCP23X08::enableAddrPins() { - if (!spi_dev) // I2C dev always use addr, only makes sense for SPI dev + if (!spi_dev) // I2C dev always use addr, only makes sense for SPI dev return; Adafruit_BusIO_Register GPIOAddr(i2c_dev, spi_dev, MCP23XXX_SPIREG, diff --git a/src/Adafruit_MCP23X08.h b/src/Adafruit_MCP23X08.h index 37f2ae6..3a55320 100644 --- a/src/Adafruit_MCP23X08.h +++ b/src/Adafruit_MCP23X08.h @@ -13,7 +13,7 @@ */ /**************************************************************************/ class Adafruit_MCP23X08 : public Adafruit_MCP23XXX { - public: +public: Adafruit_MCP23X08(); void enableAddrPins(); From 1aa25ca344bbf64cc8d74f25942d37eb534fd5d6 Mon Sep 17 00:00:00 2001 From: Eva Herrada <33632497+evaherrada@users.noreply.github.com> Date: Tue, 27 Dec 2022 15:11:01 -0500 Subject: [PATCH 47/49] Bump to 2.3.0 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 36cfcb8..59919a8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.2.0 +version=2.3.0 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders From 011d817e684c1d910be5301dc4a24bdb2c8d2ca7 Mon Sep 17 00:00:00 2001 From: dherrada Date: Fri, 12 May 2023 11:23:54 -0400 Subject: [PATCH 48/49] Update CI action versions --- .github/workflows/githubci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 849c5af..86f9f88 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -7,11 +7,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: python-version: '3.x' - - uses: actions/checkout@v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: repository: adafruit/ci-arduino path: ci @@ -25,11 +25,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: python-version: '3.x' - - uses: actions/checkout@v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: repository: adafruit/ci-arduino path: ci @@ -43,8 +43,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: repository: adafruit/ci-arduino path: ci From 91b5f457365139b1f92dde0545828f327ccc2434 Mon Sep 17 00:00:00 2001 From: Tyeth Gundry Date: Tue, 14 Nov 2023 20:16:34 +0000 Subject: [PATCH 49/49] Bump version number to 2.3.2 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 59919a8..bc8faa8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit MCP23017 Arduino Library -version=2.3.0 +version=2.3.2 author=Adafruit maintainer=Adafruit sentence=Arduino Library for MCP23XXX I2C and SPI GPIO port expanders