From 2e46b2274742fed767fd2cbbef3ad218e54d64fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Tue, 25 Feb 2020 01:17:54 +0100 Subject: [PATCH 01/15] Added inverted input mode --- src/MCP23017.cpp | 255 +++++++++++++++++++++++++++++++++++++++++++++-- src/MCP23017.h | 221 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 468 insertions(+), 8 deletions(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 293675d..5175b36 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -1,197 +1,440 @@ #include "MCP23017.h" + + MCP23017::MCP23017(uint8_t address, TwoWire& bus) { + _deviceAddr = address; + _bus = &bus; + } + + MCP23017::~MCP23017() {} + + void MCP23017::init() + { + //BANK = 0 : sequential register addresses + //MIRROR = 0 : use configureInterrupt + //SEQOP = 1 : sequential operation disabled, address pointer does not increment + //DISSLW = 0 : slew rate enabled + //HAEN = 0 : hardware address pin is always enabled on 23017 + //ODR = 0 : open drain output + //INTPOL = 0 : interrupt active low + writeRegister(MCP23017_REGISTER::IOCON, 0b00100000); + + //enable all pull up resistors (will be effective for input pins only) + writeRegister(MCP23017_REGISTER::GPPUA, 0xFF, 0xFF); + } -void MCP23017::portMode(MCP23017_PORT port, uint8_t value) + + +void MCP23017::portMode(MCP23017_PORT port, uint8_t value, bool inverted) + { + writeRegister(MCP23017_REGISTER::IODIRA + port, value); + + if( inverted ){ + + writeRegister(MCP23017_REGISTER::IPOLA + port, value); + + } + } -void MCP23017::pinMode(uint8_t pin, uint8_t mode) + + +void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) + { + MCP23017_REGISTER iodirreg = MCP23017_REGISTER::IODIRA; + uint8_t iodir; - if(pin > 7) + + if( pin > 7 ) + { + iodirreg = MCP23017_REGISTER::IODIRB; + pin -= 8; + + } + + + + if( inverted && mode == INPUT ){ + + + + MCP23017_REGISTER reg; + + uint8_t pol; + + + + if( pin < 8 ) { + + pol = readRegister(MCP23017_REGISTER::IPOLA); + + } else { + + pol = readRegister(MCP23017_REGISTER::IPOLB); + } + + + pol = readRegister(reg); + + pol |= _BV(pin); + + writeRegister( reg, pol ); + + } + + + iodir = readRegister(iodirreg); - if(mode == OUTPUT) iodir &= ~_BV(pin); - else iodir |= _BV(pin); - writeRegister(iodirreg, iodir); + if(mode == OUTPUT) { + + iodir &= ~_BV(pin); + + } else{ + + iodir |= _BV(pin); + + } + + + + writeRegister( iodirreg, iodir ); + + + } + + void MCP23017::digitalWrite(uint8_t pin, uint8_t state) + { + MCP23017_REGISTER gpioreg = MCP23017_REGISTER::GPIOA; + uint8_t gpio; + if(pin > 7) + { + gpioreg = MCP23017_REGISTER::GPIOB; + pin -= 8; + } + + gpio = readRegister(gpioreg); + if(state == HIGH) gpio |= _BV(pin); + else gpio &= ~_BV(pin); + + writeRegister(gpioreg, gpio); + } + + uint8_t MCP23017::digitalRead(uint8_t pin) + { + MCP23017_REGISTER gpioreg = MCP23017_REGISTER::GPIOA; + uint8_t gpio; + if(pin > 7) + { + gpioreg = MCP23017_REGISTER::GPIOB; + pin -=8; + } + + gpio = readRegister(gpioreg); + if((gpio & _BV(pin)) == _BV(pin)) return HIGH; + return LOW; + } + + void MCP23017::writePort(MCP23017_PORT port, uint8_t value) + { + writeRegister(MCP23017_REGISTER::GPIOA + port, value); + } + + void MCP23017::write(uint16_t value) + { + writeRegister(MCP23017_REGISTER::GPIOA, lowByte(value), highByte(value)); + } + + uint8_t MCP23017::readPort(MCP23017_PORT port) + { + return readRegister(MCP23017_REGISTER::GPIOA + port); + } + + uint16_t MCP23017::read() + { + uint8_t a = readPort(MCP23017_PORT::A); + uint8_t b = readPort(MCP23017_PORT::B); + + return a | b << 8; + } + + void MCP23017::writeRegister(MCP23017_REGISTER reg, uint8_t value) + { + _bus->beginTransmission(_deviceAddr); + _bus->write(static_cast(reg)); + _bus->write(value); + _bus->endTransmission(); + } + + void MCP23017::writeRegister(MCP23017_REGISTER reg, uint8_t portA, uint8_t portB) + { + _bus->beginTransmission(_deviceAddr); + _bus->write(static_cast(reg)); + _bus->write(portA); + _bus->write(portB); + _bus->endTransmission(); + } + + + uint8_t MCP23017::readRegister(MCP23017_REGISTER reg) + { + _bus->beginTransmission(_deviceAddr); + _bus->write(static_cast(reg)); + _bus->endTransmission(); + _bus->requestFrom(_deviceAddr, (uint8_t)1); + return _bus->read(); + } + + void MCP23017::readRegister(MCP23017_REGISTER reg, uint8_t& portA, uint8_t& portB) + { + _bus->beginTransmission(_deviceAddr); + _bus->write(static_cast(reg)); + _bus->endTransmission(); + _bus->requestFrom(_deviceAddr, (uint8_t)2); + portA = _bus->read(); + portB = _bus->read(); + } + + #ifdef _MCP23017_INTERRUPT_SUPPORT_ + + void MCP23017::interruptMode(MCP23017_INTMODE intMode) + { + uint8_t iocon = readRegister(MCP23017_REGISTER::IOCON); + if(intMode == MCP23017_INTMODE::OR) iocon |= static_cast(MCP23017_INTMODE::OR); + else iocon &= ~(static_cast(MCP23017_INTMODE::OR)); + + writeRegister(MCP23017_REGISTER::IOCON, iocon); + } + + void MCP23017::interrupt(MCP23017_PORT port, uint8_t mode) + { + MCP23017_REGISTER defvalreg = MCP23017_REGISTER::DEFVALA + port; + MCP23017_REGISTER intconreg = MCP23017_REGISTER::INTCONA + port; + + //enable interrupt for port + writeRegister(MCP23017_REGISTER::GPINTENA + port, 0xFF); + switch(mode) + { + case CHANGE: + //interrupt on change + writeRegister(intconreg, 0); + break; + case FALLING: + //interrupt falling : compared against defval, 0xff + writeRegister(intconreg, 0xFF); + writeRegister(defvalreg, 0xFF); + break; + case RISING: + //interrupt falling : compared against defval, 0x00 + writeRegister(intconreg, 0xFF); + writeRegister(defvalreg, 0x00); + break; + } + } + + void MCP23017::interruptedBy(uint8_t& portA, uint8_t& portB) + { + readRegister(MCP23017_REGISTER::INTFA, portA, portB); + } + + void MCP23017::disableInterrupt(MCP23017_PORT port) + { + writeRegister(MCP23017_REGISTER::GPINTENA + port, 0x00); + } + + void MCP23017::clearInterrupts() + { + uint8_t a, b; + clearInterrupts(a, b); + } + + void MCP23017::clearInterrupts(uint8_t& portA, uint8_t& portB) + { + readRegister(MCP23017_REGISTER::INTCAPA, portA, portB); + } + + #endif + diff --git a/src/MCP23017.h b/src/MCP23017.h index d467567..4d23052 100644 --- a/src/MCP23017.h +++ b/src/MCP23017.h @@ -1,218 +1,435 @@ #pragma once + + #include + #include + + #define _MCP23017_INTERRUPT_SUPPORT_ ///< Enables support for MCP23017 interrupts. + + enum class MCP23017_PORT : uint8_t + { + A = 0, + B = 1 + }; + + /** + * Controls if the two interrupt pins mirror each other. + * See "3.6 Interrupt Logic". + */ + enum class MCP23017_INTMODE : uint8_t + { + SEPARATED = 0, ///< Interrupt pins are kept independent + OR = 0b01000000 ///< Interrupt pins are mirrored + }; + + /** + * Registers addresses. + * The library use addresses for IOCON.BANK = 0. + * See "3.2.1 Byte mode and Sequential mode". + */ + enum class MCP23017_REGISTER : uint8_t + { + IODIRA = 0x00, ///< Controls the direction of the data I/O for port A. + IODIRB = 0x01, ///< Controls the direction of the data I/O for port B. + IPOLA = 0x02, ///< Configures the polarity on the corresponding GPIO port bits for port A. + IPOLB = 0x03, ///< Configures the polarity on the corresponding GPIO port bits for port B. + GPINTENA = 0x04, ///< Controls the interrupt-on-change for each pin of port A. + GPINTENB = 0x05, ///< Controls the interrupt-on-change for each pin of port B. + DEFVALA = 0x06, ///< Controls the default comparaison value for interrupt-on-change for port A. + DEFVALB = 0x07, ///< Controls the default comparaison value for interrupt-on-change for port B. + INTCONA = 0x08, ///< Controls how the associated pin value is compared for the interrupt-on-change for port A. + INTCONB = 0x09, ///< Controls how the associated pin value is compared for the interrupt-on-change for port B. + IOCON = 0x0A, ///< Controls the device. + GPPUA = 0x0C, ///< Controls the pull-up resistors for the port A pins. + GPPUB = 0x0D, ///< Controls the pull-up resistors for the port B pins. + INTFA = 0x0E, ///< Reflects the interrupt condition on the port A pins. + INTFB = 0x0F, ///< Reflects the interrupt condition on the port B pins. + INTCAPA = 0x10, ///< Captures the port A value at the time the interrupt occured. + INTCAPB = 0x11, ///< Captures the port B value at the time the interrupt occured. + GPIOA = 0x12, ///< Reflects the value on the port A. + GPIOB = 0x13, ///< Reflects the value on the port B. + OLATA = 0x14, ///< Provides access to the port A output latches. + OLATB = 0x15, ///< Provides access to the port B output latches. + }; + + inline MCP23017_REGISTER operator+(MCP23017_REGISTER a, MCP23017_PORT b) { + return static_cast(static_cast(a) + static_cast(b)); + }; + + class MCP23017 + { + private: + TwoWire* _bus; + uint8_t _deviceAddr; + public: + /** + * Instantiates a new instance to interact with a MCP23017 at the specified address. + */ + MCP23017(uint8_t address, TwoWire& bus = Wire); + ~MCP23017(); + #ifdef _DEBUG + void debug(); + #endif + /** + * Initializes the chip with the default configuration. + * Enables Byte mode (IOCON.BANK = 0 and IOCON.SEQOP = 1). + * Enables pull-up resistors for all pins. This will only be effective for input pins. + * + * See "3.2.1 Byte mode and Sequential mode". + */ + void init(); + /** + * Controls the pins direction on a whole port at once. + * + * 1 = Pin is configured as an input. + * 0 = Pin is configured as an output. + * + * See "3.5.1 I/O Direction register". + */ - void portMode(MCP23017_PORT port, uint8_t value); + + void portMode(MCP23017_PORT port, uint8_t value, bool inverted=false); + /** + * Controls a single pin direction. + * Pin 0-7 for port A, 8-15 fo port B. + * + * 1 = Pin is configured as an input. + * 0 = Pin is configured as an output. + * + * See "3.5.1 I/O Direction register". + */ - void pinMode(uint8_t pin, uint8_t mode); + + void pinMode(uint8_t pin, uint8_t mode, bool inverted=false); + + /** + * Writes a single pin state. + * Pin 0-7 for port A, 8-15 for port B. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ + void digitalWrite(uint8_t pin, uint8_t state); + /** + * Reads a single pin state. + * Pin 0-7 for port A, 8-15 for port B. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ + uint8_t digitalRead(uint8_t pin); + + /** + * Writes pins state to a whole port. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ + void writePort(MCP23017_PORT port, uint8_t value); + /** + * Writes pins state to both ports. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ + void write(uint16_t value); + + /** + * Reads pins state for a whole port. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ + uint8_t readPort(MCP23017_PORT port); + /** + * Reads pins state for both ports. + * + * 1 = Logic-high + * 0 = Logic-low + * + * See "3.5.10 Port register". + */ + uint16_t read(); + + /** + * Writes a single register value. + */ + void writeRegister(MCP23017_REGISTER reg, uint8_t value); + /** + * Writes values to a register pair. + * + * For portA and portB variable to effectively match the desired port, + * you have to supply a portA register address to reg. Otherwise, values + * will be reversed due to the way the MCP23017 works in Byte mode. + */ + void writeRegister(MCP23017_REGISTER reg, uint8_t portA, uint8_t portB); + /** + * Reads a single register value. + */ + uint8_t readRegister(MCP23017_REGISTER reg); + /** + * Reads the values from a register pair. + * + * For portA and portB variable to effectively match the desired port, + * you have to supply a portA register address to reg. Otherwise, values + * will be reversed due to the way the MCP23017 works in Byte mode. + */ + void readRegister(MCP23017_REGISTER reg, uint8_t& portA, uint8_t& portB); + + #ifdef _MCP23017_INTERRUPT_SUPPORT_ + + /** + * Controls how the interrupt pins act with each other. + * If intMode is SEPARATED, interrupt conditions on a port will cause its respective INT pin to active. + * If intMode is OR, interrupt pins are OR'ed so an interrupt on one of the port will cause both pints to active. + * + * Controls the IOCON.MIRROR bit. + * See "3.5.6 Configuration register". + */ + void interruptMode(MCP23017_INTMODE intMode); + /** + * Configures interrupt registers using an Arduino-like API. + * mode can be one of CHANGE, FALLING or RISING. + */ + void interrupt(MCP23017_PORT port, uint8_t mode); + /** + * Disable interrupts for the specified port. + */ + void disableInterrupt(MCP23017_PORT port); + /** + * Reads which pin caused the interrupt. + */ + void interruptedBy(uint8_t& portA, uint8_t& portB); + /** + * Clears interrupts on both ports. + */ + void clearInterrupts(); + /** + * Clear interrupts on both ports. Returns port values at the time the interrupt occured. + */ + void clearInterrupts(uint8_t& portA, uint8_t& portB); + + #endif + }; \ No newline at end of file From 1b75617af74a931c95a6e02017be9a7dc99eb96e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Tue, 25 Feb 2020 01:40:38 +0100 Subject: [PATCH 02/15] removed blank lines --- src/MCP23017.cpp | 227 +---------------------------------------------- src/MCP23017.h | 217 -------------------------------------------- 2 files changed, 4 insertions(+), 440 deletions(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 5175b36..cf0b825 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -1,440 +1,221 @@ #include "MCP23017.h" - - MCP23017::MCP23017(uint8_t address, TwoWire& bus) { - _deviceAddr = address; - _bus = &bus; - } - - MCP23017::~MCP23017() {} - - void MCP23017::init() - { - //BANK = 0 : sequential register addresses - //MIRROR = 0 : use configureInterrupt - //SEQOP = 1 : sequential operation disabled, address pointer does not increment - //DISSLW = 0 : slew rate enabled - //HAEN = 0 : hardware address pin is always enabled on 23017 - //ODR = 0 : open drain output - //INTPOL = 0 : interrupt active low - writeRegister(MCP23017_REGISTER::IOCON, 0b00100000); - - //enable all pull up resistors (will be effective for input pins only) - writeRegister(MCP23017_REGISTER::GPPUA, 0xFF, 0xFF); - } - - void MCP23017::portMode(MCP23017_PORT port, uint8_t value, bool inverted) - { - writeRegister(MCP23017_REGISTER::IODIRA + port, value); if( inverted ){ - writeRegister(MCP23017_REGISTER::IPOLA + port, value); - } - } - - -void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) - +void MCP23017::pinMode(uint8_t pin, uint8_t mode) { - MCP23017_REGISTER iodirreg = MCP23017_REGISTER::IODIRA; - uint8_t iodir; - - if( pin > 7 ) - + if(pin > 7) { - iodirreg = MCP23017_REGISTER::IODIRB; - pin -= 8; - } - - - if( inverted && mode == INPUT ){ - - MCP23017_REGISTER reg; - uint8_t pol; - - if( pin < 8 ) { - pol = readRegister(MCP23017_REGISTER::IPOLA); - } else { - pol = readRegister(MCP23017_REGISTER::IPOLB); - } - - - pol = readRegister(reg); - pol |= _BV(pin); - + writeRegister( reg, pol ); - - } +} iodir = readRegister(iodirreg); - if(mode == OUTPUT) { - iodir &= ~_BV(pin); - } else{ - iodir |= _BV(pin); - } - - writeRegister( iodirreg, iodir ); - - - } - - void MCP23017::digitalWrite(uint8_t pin, uint8_t state) - { - MCP23017_REGISTER gpioreg = MCP23017_REGISTER::GPIOA; - uint8_t gpio; - if(pin > 7) - { - gpioreg = MCP23017_REGISTER::GPIOB; - pin -= 8; - } - - gpio = readRegister(gpioreg); - if(state == HIGH) gpio |= _BV(pin); - else gpio &= ~_BV(pin); - - writeRegister(gpioreg, gpio); - } - - uint8_t MCP23017::digitalRead(uint8_t pin) - { - MCP23017_REGISTER gpioreg = MCP23017_REGISTER::GPIOA; - uint8_t gpio; - if(pin > 7) - { - gpioreg = MCP23017_REGISTER::GPIOB; - pin -=8; - } - - gpio = readRegister(gpioreg); - if((gpio & _BV(pin)) == _BV(pin)) return HIGH; - return LOW; - } - - void MCP23017::writePort(MCP23017_PORT port, uint8_t value) - { - writeRegister(MCP23017_REGISTER::GPIOA + port, value); - } - - void MCP23017::write(uint16_t value) - { - writeRegister(MCP23017_REGISTER::GPIOA, lowByte(value), highByte(value)); - } - - uint8_t MCP23017::readPort(MCP23017_PORT port) - { - return readRegister(MCP23017_REGISTER::GPIOA + port); - } - - uint16_t MCP23017::read() - { - uint8_t a = readPort(MCP23017_PORT::A); - uint8_t b = readPort(MCP23017_PORT::B); - - return a | b << 8; - } - - void MCP23017::writeRegister(MCP23017_REGISTER reg, uint8_t value) - { - _bus->beginTransmission(_deviceAddr); - _bus->write(static_cast(reg)); - _bus->write(value); - _bus->endTransmission(); - } - - void MCP23017::writeRegister(MCP23017_REGISTER reg, uint8_t portA, uint8_t portB) - { - _bus->beginTransmission(_deviceAddr); - _bus->write(static_cast(reg)); - _bus->write(portA); - _bus->write(portB); - _bus->endTransmission(); - } - - - uint8_t MCP23017::readRegister(MCP23017_REGISTER reg) - { - _bus->beginTransmission(_deviceAddr); - _bus->write(static_cast(reg)); - _bus->endTransmission(); - _bus->requestFrom(_deviceAddr, (uint8_t)1); - return _bus->read(); - } - - void MCP23017::readRegister(MCP23017_REGISTER reg, uint8_t& portA, uint8_t& portB) - { - _bus->beginTransmission(_deviceAddr); - _bus->write(static_cast(reg)); - _bus->endTransmission(); - _bus->requestFrom(_deviceAddr, (uint8_t)2); - portA = _bus->read(); - portB = _bus->read(); - } - - #ifdef _MCP23017_INTERRUPT_SUPPORT_ - - void MCP23017::interruptMode(MCP23017_INTMODE intMode) - { - uint8_t iocon = readRegister(MCP23017_REGISTER::IOCON); - if(intMode == MCP23017_INTMODE::OR) iocon |= static_cast(MCP23017_INTMODE::OR); - else iocon &= ~(static_cast(MCP23017_INTMODE::OR)); - - writeRegister(MCP23017_REGISTER::IOCON, iocon); - } - - void MCP23017::interrupt(MCP23017_PORT port, uint8_t mode) - { - MCP23017_REGISTER defvalreg = MCP23017_REGISTER::DEFVALA + port; - MCP23017_REGISTER intconreg = MCP23017_REGISTER::INTCONA + port; - - //enable interrupt for port - writeRegister(MCP23017_REGISTER::GPINTENA + port, 0xFF); - switch(mode) - { - case CHANGE: - //interrupt on change - writeRegister(intconreg, 0); - break; - case FALLING: - //interrupt falling : compared against defval, 0xff - writeRegister(intconreg, 0xFF); - writeRegister(defvalreg, 0xFF); - break; - case RISING: - //interrupt falling : compared against defval, 0x00 - writeRegister(intconreg, 0xFF); - writeRegister(defvalreg, 0x00); - break; - } - } - - void MCP23017::interruptedBy(uint8_t& portA, uint8_t& portB) - { - readRegister(MCP23017_REGISTER::INTFA, portA, portB); - } - - void MCP23017::disableInterrupt(MCP23017_PORT port) - { - writeRegister(MCP23017_REGISTER::GPINTENA + port, 0x00); - } - - void MCP23017::clearInterrupts() - { - uint8_t a, b; - clearInterrupts(a, b); - } - - void MCP23017::clearInterrupts(uint8_t& portA, uint8_t& portB) - { - readRegister(MCP23017_REGISTER::INTCAPA, portA, portB); - } - - #endif - diff --git a/src/MCP23017.h b/src/MCP23017.h index 4d23052..4cd5a43 100644 --- a/src/MCP23017.h +++ b/src/MCP23017.h @@ -1,435 +1,218 @@ #pragma once - - #include - #include - - #define _MCP23017_INTERRUPT_SUPPORT_ ///< Enables support for MCP23017 interrupts. - - enum class MCP23017_PORT : uint8_t - { - A = 0, - B = 1 - }; - - /** - * Controls if the two interrupt pins mirror each other. - * See "3.6 Interrupt Logic". - */ - enum class MCP23017_INTMODE : uint8_t - { - SEPARATED = 0, ///< Interrupt pins are kept independent - OR = 0b01000000 ///< Interrupt pins are mirrored - }; - - /** - * Registers addresses. - * The library use addresses for IOCON.BANK = 0. - * See "3.2.1 Byte mode and Sequential mode". - */ - enum class MCP23017_REGISTER : uint8_t - { - IODIRA = 0x00, ///< Controls the direction of the data I/O for port A. - IODIRB = 0x01, ///< Controls the direction of the data I/O for port B. - IPOLA = 0x02, ///< Configures the polarity on the corresponding GPIO port bits for port A. - IPOLB = 0x03, ///< Configures the polarity on the corresponding GPIO port bits for port B. - GPINTENA = 0x04, ///< Controls the interrupt-on-change for each pin of port A. - GPINTENB = 0x05, ///< Controls the interrupt-on-change for each pin of port B. - DEFVALA = 0x06, ///< Controls the default comparaison value for interrupt-on-change for port A. - DEFVALB = 0x07, ///< Controls the default comparaison value for interrupt-on-change for port B. - INTCONA = 0x08, ///< Controls how the associated pin value is compared for the interrupt-on-change for port A. - INTCONB = 0x09, ///< Controls how the associated pin value is compared for the interrupt-on-change for port B. - IOCON = 0x0A, ///< Controls the device. - GPPUA = 0x0C, ///< Controls the pull-up resistors for the port A pins. - GPPUB = 0x0D, ///< Controls the pull-up resistors for the port B pins. - INTFA = 0x0E, ///< Reflects the interrupt condition on the port A pins. - INTFB = 0x0F, ///< Reflects the interrupt condition on the port B pins. - INTCAPA = 0x10, ///< Captures the port A value at the time the interrupt occured. - INTCAPB = 0x11, ///< Captures the port B value at the time the interrupt occured. - GPIOA = 0x12, ///< Reflects the value on the port A. - GPIOB = 0x13, ///< Reflects the value on the port B. - OLATA = 0x14, ///< Provides access to the port A output latches. - OLATB = 0x15, ///< Provides access to the port B output latches. - }; - - inline MCP23017_REGISTER operator+(MCP23017_REGISTER a, MCP23017_PORT b) { - return static_cast(static_cast(a) + static_cast(b)); - }; - - class MCP23017 - { - private: - TwoWire* _bus; - uint8_t _deviceAddr; - public: - /** - * Instantiates a new instance to interact with a MCP23017 at the specified address. - */ - MCP23017(uint8_t address, TwoWire& bus = Wire); - ~MCP23017(); - #ifdef _DEBUG - void debug(); - #endif - /** - * Initializes the chip with the default configuration. - * Enables Byte mode (IOCON.BANK = 0 and IOCON.SEQOP = 1). - * Enables pull-up resistors for all pins. This will only be effective for input pins. - * - * See "3.2.1 Byte mode and Sequential mode". - */ - void init(); - /** - * Controls the pins direction on a whole port at once. - * - * 1 = Pin is configured as an input. - * 0 = Pin is configured as an output. - * - * See "3.5.1 I/O Direction register". - */ - void portMode(MCP23017_PORT port, uint8_t value, bool inverted=false); - /** - * Controls a single pin direction. - * Pin 0-7 for port A, 8-15 fo port B. - * - * 1 = Pin is configured as an input. - * 0 = Pin is configured as an output. - * - * See "3.5.1 I/O Direction register". - */ - void pinMode(uint8_t pin, uint8_t mode, bool inverted=false); - - /** - * Writes a single pin state. - * Pin 0-7 for port A, 8-15 for port B. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ - void digitalWrite(uint8_t pin, uint8_t state); - /** - * Reads a single pin state. - * Pin 0-7 for port A, 8-15 for port B. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ - uint8_t digitalRead(uint8_t pin); - - /** - * Writes pins state to a whole port. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ - void writePort(MCP23017_PORT port, uint8_t value); - /** - * Writes pins state to both ports. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ - void write(uint16_t value); - - /** - * Reads pins state for a whole port. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ - uint8_t readPort(MCP23017_PORT port); - /** - * Reads pins state for both ports. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". - */ - uint16_t read(); - - /** - * Writes a single register value. - */ - void writeRegister(MCP23017_REGISTER reg, uint8_t value); - /** - * Writes values to a register pair. - * - * For portA and portB variable to effectively match the desired port, - * you have to supply a portA register address to reg. Otherwise, values - * will be reversed due to the way the MCP23017 works in Byte mode. - */ - void writeRegister(MCP23017_REGISTER reg, uint8_t portA, uint8_t portB); - /** - * Reads a single register value. - */ - uint8_t readRegister(MCP23017_REGISTER reg); - /** - * Reads the values from a register pair. - * - * For portA and portB variable to effectively match the desired port, - * you have to supply a portA register address to reg. Otherwise, values - * will be reversed due to the way the MCP23017 works in Byte mode. - */ - void readRegister(MCP23017_REGISTER reg, uint8_t& portA, uint8_t& portB); - - #ifdef _MCP23017_INTERRUPT_SUPPORT_ - - /** - * Controls how the interrupt pins act with each other. - * If intMode is SEPARATED, interrupt conditions on a port will cause its respective INT pin to active. - * If intMode is OR, interrupt pins are OR'ed so an interrupt on one of the port will cause both pints to active. - * - * Controls the IOCON.MIRROR bit. - * See "3.5.6 Configuration register". - */ - void interruptMode(MCP23017_INTMODE intMode); - /** - * Configures interrupt registers using an Arduino-like API. - * mode can be one of CHANGE, FALLING or RISING. - */ - void interrupt(MCP23017_PORT port, uint8_t mode); - /** - * Disable interrupts for the specified port. - */ - void disableInterrupt(MCP23017_PORT port); - /** - * Reads which pin caused the interrupt. - */ - void interruptedBy(uint8_t& portA, uint8_t& portB); - /** - * Clears interrupts on both ports. - */ - void clearInterrupts(); - /** - * Clear interrupts on both ports. Returns port values at the time the interrupt occured. - */ - void clearInterrupts(uint8_t& portA, uint8_t& portB); - - #endif - }; \ No newline at end of file From da9eed46cbeba544925a1a9bdc7293cb91cff619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Tue, 25 Feb 2020 01:43:02 +0100 Subject: [PATCH 03/15] . --- src/MCP23017.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index cf0b825..aace7e5 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -31,7 +31,7 @@ void MCP23017::portMode(MCP23017_PORT port, uint8_t value, bool inverted) } } -void MCP23017::pinMode(uint8_t pin, uint8_t mode) +void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) { MCP23017_REGISTER iodirreg = MCP23017_REGISTER::IODIRA; uint8_t iodir; @@ -52,7 +52,7 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode) } pol = readRegister(reg); pol |= _BV(pin); - + writeRegister( reg, pol ); } From dba31dcc29d538d08eec2ec613ce3d9eedc6b525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 17:44:51 +0100 Subject: [PATCH 04/15] Update src/MCP23017.cpp That is quite more efficient! Co-Authored-By: Bertrand Lemasle --- src/MCP23017.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index aace7e5..578f625 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -22,13 +22,10 @@ void MCP23017::init() writeRegister(MCP23017_REGISTER::GPPUA, 0xFF, 0xFF); } -void MCP23017::portMode(MCP23017_PORT port, uint8_t value, bool inverted) +void MCP23017::portMode(MCP23017_PORT port, uint8_t dir, uint8_t inverted) { - writeRegister(MCP23017_REGISTER::IODIRA + port, value); - - if( inverted ){ - writeRegister(MCP23017_REGISTER::IPOLA + port, value); - } + writeRegister(MCP23017_REGISTER::IODIRA + port, dir); + writeRegister(MCP23017_REGISTER::IPOLA + port, inverted); } void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) From 1d75401f0de9be5d58a866f4825529a10e5ce303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 17:54:03 +0100 Subject: [PATCH 05/15] Update src/MCP23017.h See above. Co-Authored-By: Bertrand Lemasle --- src/MCP23017.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MCP23017.h b/src/MCP23017.h index 4cd5a43..cb47cff 100644 --- a/src/MCP23017.h +++ b/src/MCP23017.h @@ -85,7 +85,7 @@ class MCP23017 * * See "3.5.1 I/O Direction register". */ - void portMode(MCP23017_PORT port, uint8_t value, bool inverted=false); + void portMode(MCP23017_PORT port, uint8_t dir, uint8_t inverted=0x00); /** * Controls a single pin direction. * Pin 0-7 for port A, 8-15 fo port B. @@ -215,4 +215,4 @@ class MCP23017 void clearInterrupts(uint8_t& portA, uint8_t& portB); #endif -}; \ No newline at end of file +}; From 7b369a90ed1ed5582304294f3b059ae9b81ce79e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 18:22:13 +0100 Subject: [PATCH 06/15] Update src/MCP23017.cpp Co-Authored-By: Bertrand Lemasle --- src/MCP23017.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 578f625..e9bc8f7 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -62,7 +62,8 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) iodir |= _BV(pin); } - writeRegister( iodirreg, iodir ); + writeRegister(iodirreg, iodir); + writeRegister(polreg, pol); } void MCP23017::digitalWrite(uint8_t pin, uint8_t state) From b048c19f172b433c23c4d48c780790fb290ca955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 18:22:24 +0100 Subject: [PATCH 07/15] Update src/MCP23017.cpp Co-Authored-By: Bertrand Lemasle --- src/MCP23017.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index e9bc8f7..25d7307 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -59,7 +59,10 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) if(mode == OUTPUT) { iodir &= ~_BV(pin); } else{ - iodir |= _BV(pin); + iodir |= _BV(pin); + + if(inverted) pol |= _BV(pin); + else pol &= ~_BV(pin); } writeRegister(iodirreg, iodir); From 8bd158e955ff70e6172606b05c3f2c98e29efcfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 18:22:34 +0100 Subject: [PATCH 08/15] Update src/MCP23017.cpp Co-Authored-By: Bertrand Lemasle --- src/MCP23017.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 25d7307..70ff192 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -56,6 +56,7 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) iodir = readRegister(iodirreg); + pol = readRegister(polreg); if(mode == OUTPUT) { iodir &= ~_BV(pin); } else{ From 76a6ede191474ee366c708171f59bf94c77cbf65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 18:23:00 +0100 Subject: [PATCH 09/15] Update src/MCP23017.cpp You are right. Co-Authored-By: Bertrand Lemasle --- src/MCP23017.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 70ff192..07a2ab0 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -37,23 +37,6 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) iodirreg = MCP23017_REGISTER::IODIRB; pin -= 8; } - if( inverted && mode == INPUT ){ - - MCP23017_REGISTER reg; - uint8_t pol; - - if( pin < 8 ) { - pol = readRegister(MCP23017_REGISTER::IPOLA); - } else { - pol = readRegister(MCP23017_REGISTER::IPOLB); - } - pol = readRegister(reg); - pol |= _BV(pin); - - writeRegister( reg, pol ); -} - - iodir = readRegister(iodirreg); pol = readRegister(polreg); From 5892189de48d58f968e06610743309dc9b9d4eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Fri, 28 Feb 2020 22:17:17 +0100 Subject: [PATCH 10/15] Added examples/InvertedInput/InvertedInputs.ino --- examples/InvertedInput/InvertedInputs.ino | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 examples/InvertedInput/InvertedInputs.ino diff --git a/examples/InvertedInput/InvertedInputs.ino b/examples/InvertedInput/InvertedInputs.ino new file mode 100644 index 0000000..8ba2459 --- /dev/null +++ b/examples/InvertedInput/InvertedInputs.ino @@ -0,0 +1,53 @@ +#include +#include + +/** + * Please connect: + * + * A0 => B0 + * A1 => B1 + * A2 => B2 + * A3 => B3 + * A4 => B4 + * A5 => B5 + * A6 => B6 + * A7 => B7 + */ + +MCP23017 mcp = MCP23017(); + +void setup() { + Wire.begin(); + mcp.init(); + + Serial.begin(115200); + + // All pins on Port A are inverted inputs + mp.portMode( MCP23017_PORT::A, INPUT, 0b11111111 ); + mp.portMode( MCP23017_PORT::B, OUTPUT ); + + for ( int i=8; i<16 ;i++ ){ + mp.digitalWrite( i, HIGH ); + if ( mp.digitalRead(i) == mp.digitalRead(i-8) ){ + Serial.writeln( "Your connections are wrong, please check for it." ); + } + } + + for ( int i=0; i<16; i++ ){ + + if ( i< 8 ) + mp.pinMode( i, INPUT, true ); + else + mp.pinMode( i, OUTPUT ); + } + + for ( int i=0; i<8 ;i++ ){ + mp.digitalWrite( i, HIGH ); + if ( mp.digitalRead(i) == mp.digitalRead(i+8) ){ + Serial.writeln( "Your connections are wrong, please check for it." ); + } + } + +} + +void loop() {} \ No newline at end of file From 4c9b31db893c46510edfa6ea2eb0b545f86e20c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Sun, 1 Mar 2020 17:23:59 +0100 Subject: [PATCH 11/15] - Added examples/InvertedInput/InvertedInputs.ino - modified documentation --- examples/InvertedInput/InvertedInputs.ino | 53 ------- examples/InvertedInputs/InvertedInputs.ino | 105 +++++++++++++ src/MCP23017.cpp | 63 +++++--- src/MCP23017.h | 162 +++++++++++++-------- 4 files changed, 247 insertions(+), 136 deletions(-) delete mode 100644 examples/InvertedInput/InvertedInputs.ino create mode 100644 examples/InvertedInputs/InvertedInputs.ino diff --git a/examples/InvertedInput/InvertedInputs.ino b/examples/InvertedInput/InvertedInputs.ino deleted file mode 100644 index 8ba2459..0000000 --- a/examples/InvertedInput/InvertedInputs.ino +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include - -/** - * Please connect: - * - * A0 => B0 - * A1 => B1 - * A2 => B2 - * A3 => B3 - * A4 => B4 - * A5 => B5 - * A6 => B6 - * A7 => B7 - */ - -MCP23017 mcp = MCP23017(); - -void setup() { - Wire.begin(); - mcp.init(); - - Serial.begin(115200); - - // All pins on Port A are inverted inputs - mp.portMode( MCP23017_PORT::A, INPUT, 0b11111111 ); - mp.portMode( MCP23017_PORT::B, OUTPUT ); - - for ( int i=8; i<16 ;i++ ){ - mp.digitalWrite( i, HIGH ); - if ( mp.digitalRead(i) == mp.digitalRead(i-8) ){ - Serial.writeln( "Your connections are wrong, please check for it." ); - } - } - - for ( int i=0; i<16; i++ ){ - - if ( i< 8 ) - mp.pinMode( i, INPUT, true ); - else - mp.pinMode( i, OUTPUT ); - } - - for ( int i=0; i<8 ;i++ ){ - mp.digitalWrite( i, HIGH ); - if ( mp.digitalRead(i) == mp.digitalRead(i+8) ){ - Serial.writeln( "Your connections are wrong, please check for it." ); - } - } - -} - -void loop() {} \ No newline at end of file diff --git a/examples/InvertedInputs/InvertedInputs.ino b/examples/InvertedInputs/InvertedInputs.ino new file mode 100644 index 0000000..1eb0e37 --- /dev/null +++ b/examples/InvertedInputs/InvertedInputs.ino @@ -0,0 +1,105 @@ +#include +#include + +/** + * Please connect: + * A5 => SCL (ON UNO R3) + * A4 => SDA (ON UNO R3) + * A3 => RST (ON UNO R3) + * A0 => B0 + * A1 => B1 + * A2 => B2 + * A3 => B3 + * A4 => B4 + * A5 => B5 + * A6 => B6 + * A7 => B7 + */ + +#define MCP23017_ADDR 0x20 + +MCP23017 mcp = MCP23017(MCP23017_ADDR); + +void setup() { + + Serial.begin(115200); + delay(200); + //Serial.write(27); Serial.print("[2J"); // CLRSCR + //Serial.write(27); Serial.print("[H"); // HOME + + pinMode( A3, OUTPUT ); + + digitalWrite( A3, LOW ); + delay(50); + digitalWrite( A3, HIGH ); + delay(50); + + Wire.begin(); + mcp.init(); + + bool error = false; + + mcp.portMode( MCP23017_PORT::A, INPUT, 0xFF ); // PORT A is input inverted + mcp.portMode( MCP23017_PORT::B, OUTPUT ); // PORT B is output + mcp.writePort (MCP23017_PORT::B, 0xFF); + + Serial.println("##### Checking setting port mode #####\n" ); + for ( uint8_t i=0; i<8 ; i++ ){ + + error |= ( mcp.digitalRead(i) != mcp.digitalRead(i+8) ); + if ( mcp.digitalRead(i) != HIGH ){ + Serial.print( "Your connection "); + Serial.print( i ); + Serial.print(" was wrong, please check it: " ); + Serial.print("IN: " ); + Serial.print( mcp.digitalRead(i) ? "HIGH" : "LOW" ); + Serial.print(", OUT: " ); + Serial.println( mcp.digitalRead(i+8) ? "HIGH" : "LOW" ); + } + } + + if ( error ) + Serial.println("--------- FAILED (see above) ----------"); + else + Serial.println("------------- SUCCEEDED --------------"); + + error = false; + digitalWrite( A3, LOW ); + delay(50); + digitalWrite( A3, HIGH ); + delay(50); + + Serial.println("\n##### Checking setting pin mode #####\n" ); + + for ( uint8_t i=0; i<16; i++ ){ + if ( i< 8 ) + mcp.pinMode( i, OUTPUT ); // PORT A is output + else + mcp.pinMode( i, INPUT, true ); // PORT B is input inverted + } + + mcp.writePort (MCP23017_PORT::A, 0xFF); + Serial.print( mcp.readPort(MCP23017_PORT::B) ); + + for ( uint8_t i=0; i<8 ; i++ ){ + error |= ( mcp.digitalRead(i+8) != mcp.digitalRead(i) ); +// if ( mcp.digitalRead(i+8) == HIGH ){ + if ( true ){ + Serial.print( "Your connection " ); + Serial.print( i ); + Serial.print(" was wrong, please check it: " ); + Serial.print("IN: " ); + Serial.print( mcp.digitalRead(i+8) ? "HIGH" : "LOW" ); + Serial.print(", OUT: " ); + Serial.println( mcp.digitalRead(i) ? "HIGH" : "LOW" ); + } + } + + if ( error ) + Serial.println("--------- FAILED (see above) ----------"); + else + Serial.println("------------- SUCCEEDED --------------"); + +} + +void loop() {} diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 07a2ab0..984c001 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -7,50 +7,69 @@ MCP23017::MCP23017(uint8_t address, TwoWire& bus) { MCP23017::~MCP23017() {} -void MCP23017::init() -{ - //BANK = 0 : sequential register addresses - //MIRROR = 0 : use configureInterrupt - //SEQOP = 1 : sequential operation disabled, address pointer does not increment - //DISSLW = 0 : slew rate enabled - //HAEN = 0 : hardware address pin is always enabled on 23017 - //ODR = 0 : open drain output - //INTPOL = 0 : interrupt active low +void MCP23017::begin(uint8_t pullup_a, uint8_t pullup_b) +{ + //IOCON.BANK = 0 : sequential register addresses + //IOCON.MIRROR = 0 : use configureInterrupt + //IOCON.SEQOP = 1 : sequential operation disabled, address pointer does not increment + //IOCON.DISSLW = 0 : slew rate enabled + //IOCON.HAEN = 0 : hardware address pin is always enabled on 23017 + //IOCON.ODR = 0 : open drain output + //IOCON.INTPOL = 0 : interrupt active low + //IOCON bit 0 is spare writeRegister(MCP23017_REGISTER::IOCON, 0b00100000); //enable all pull up resistors (will be effective for input pins only) - writeRegister(MCP23017_REGISTER::GPPUA, 0xFF, 0xFF); + writeRegister(MCP23017_REGISTER::GPPUA, pullup_a, pullup_b); } -void MCP23017::portMode(MCP23017_PORT port, uint8_t dir, uint8_t inverted) +void MCP23017::portMode(MCP23017_PORT port, uint8_t modes, uint8_t pullups, uint8_t inverteds) { - writeRegister(MCP23017_REGISTER::IODIRA + port, dir); - writeRegister(MCP23017_REGISTER::IPOLA + port, inverted); + writeRegister(MCP23017_REGISTER::IODIRA + port, modes); + writeRegister(MCP23017_REGISTER::IPOLA + port, inverteds); + writeRegister(MCP23017_REGISTER::GPPUA + port, pullups); } void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) { MCP23017_REGISTER iodirreg = MCP23017_REGISTER::IODIRA; + MCP23017_REGISTER polreg = MCP23017_REGISTER::IPOLA; + MCP23017_REGISTER pullreg = MCP23017_REGISTER::GPPUA; uint8_t iodir; + uint8_t pol; + uint8_t pull; + if(pin > 7) { iodirreg = MCP23017_REGISTER::IODIRB; + polreg = MCP23017_REGISTER::IPOLB; + pullreg = MCP23017_REGISTER::GPPUB; pin -= 8; } iodir = readRegister(iodirreg); pol = readRegister(polreg); + pull = readRegister(pullreg); + if(mode == OUTPUT) { iodir &= ~_BV(pin); + pol &= ~_BV(pin); } else{ - iodir |= _BV(pin); - - if(inverted) pol |= _BV(pin); - else pol &= ~_BV(pin); + iodir |= _BV(pin); + + if(mode==INPUT_PULLUP) pull |= _BV(pin); + else pull &= ~_BV(pin); + + if(inverted) pol |= _BV(pin); + else pol &= ~_BV(pin); } writeRegister(iodirreg, iodir); writeRegister(polreg, pol); + + if(mode==INPUT_PULLUP){ + writeRegister(pullreg, pull); + } } void MCP23017::digitalWrite(uint8_t pin, uint8_t state) @@ -85,14 +104,14 @@ uint8_t MCP23017::digitalRead(uint8_t pin) return LOW; } -void MCP23017::writePort(MCP23017_PORT port, uint8_t value) +void MCP23017::writePort(MCP23017_PORT port, uint8_t values) { - writeRegister(MCP23017_REGISTER::GPIOA + port, value); + writeRegister(MCP23017_REGISTER::GPIOA + port, values); } -void MCP23017::write(uint16_t value) +void MCP23017::write(uint16_t values) { - writeRegister(MCP23017_REGISTER::GPIOA, lowByte(value), highByte(value)); + writeRegister(MCP23017_REGISTER::GPIOA, lowByte(values), highByte(values)); } uint8_t MCP23017::readPort(MCP23017_PORT port) @@ -194,7 +213,7 @@ void MCP23017::disableInterrupt(MCP23017_PORT port) void MCP23017::clearInterrupts() { - uint8_t a, b; + uint8_t a=0, b=0; clearInterrupts(a, b); } diff --git a/src/MCP23017.h b/src/MCP23017.h index cb47cff..ce45ced 100644 --- a/src/MCP23017.h +++ b/src/MCP23017.h @@ -51,6 +51,7 @@ enum class MCP23017_REGISTER : uint8_t OLATB = 0x15, ///< Provides access to the port B output latches. }; +/// @brief operator for adding a B-offset to the A-register inline MCP23017_REGISTER operator+(MCP23017_REGISTER a, MCP23017_PORT b) { return static_cast(static_cast(a) + static_cast(b)); }; @@ -63,119 +64,138 @@ class MCP23017 public: /** * Instantiates a new instance to interact with a MCP23017 at the specified address. + * @param address: bus address of MCP23017 (0x20 ~ 0x27) + * @param bus: refence to i2c bus object */ MCP23017(uint8_t address, TwoWire& bus = Wire); ~MCP23017(); #ifdef _DEBUG void debug(); #endif + /** * Initializes the chip with the default configuration. * Enables Byte mode (IOCON.BANK = 0 and IOCON.SEQOP = 1). - * Enables pull-up resistors for all pins. This will only be effective for input pins. + * Enables pull-up resistors for all pins by default. + * This will only be effective for input pins. + * * + * @param pullup_a: bitmask for port A + * @param pullup_b: bitmask for port B * See "3.2.1 Byte mode and Sequential mode". */ - void init(); + void begin(uint8_t pullup_a=0xFF, uint8_t pullup_b=0xFF); + /** * Controls the pins direction on a whole port at once. + * ", + * "3.5.2 I NPUT POLARITY REGISTER <0x01>", + * "3.5.7 PULL-UP RESISTOR CONFIGURATION REGISTER <0x06>"> + * @param port: MCP23017 port A or B + * @param modes: direction of whole port + * INPUT or 0x0 + * OUTPUT or0x01 + * @param pullup: bitmask for internal 100k pullup resistors + * @param inverteds: bitmask for inverted mode * - * 1 = Pin is configured as an input. - * 0 = Pin is configured as an output. - * - * See "3.5.1 I/O Direction register". */ - void portMode(MCP23017_PORT port, uint8_t dir, uint8_t inverted=0x00); + void portMode(MCP23017_PORT port, uint8_t modes, uint8_t pullups=0xFF, uint8_t inverteds=0x00); + /** - * Controls a single pin direction. - * Pin 0-7 for port A, 8-15 fo port B. - * - * 1 = Pin is configured as an input. - * 0 = Pin is configured as an output. - * - * See "3.5.1 I/O Direction register". + * Sets a single pins' direction. When the pin is an input pin + * a pullup and/or an inverted option can be specified + * ", + * "3.5.2 I NPUT POLARITY REGISTER <0x01>", + * "3.5.7 PULL-UP RESISTOR CONFIGURATION REGISTER <0x06>"> + * @param pin: Controls a single pin direction. + * Pin 0-7 for port A, 8-15 fo port B. + * @param mode: + * INPUT or 0x00 + * INPUT_PULLUP or 0x02 + * OUTPUT or 0x01 */ void pinMode(uint8_t pin, uint8_t mode, bool inverted=false); /** * Writes a single pin state. - * Pin 0-7 for port A, 8-15 for port B. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". + * ".> + * @param pin: Pin 0-7 for port A, 8-15 for port B. + * @param state: HIGH or 0x01 + * LOW or 0x00 */ void digitalWrite(uint8_t pin, uint8_t state); + /** * Reads a single pin state. - * Pin 0-7 for port A, 8-15 for port B. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". + * ".> + * @param pin: Pin 0-7 for port A, 8-15 for port B. + * @param return HIGH or 0x01, LOW or 0x00 + * depending the hardwarestate of the pin */ uint8_t digitalRead(uint8_t pin); /** * Writes pins state to a whole port. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". + * ".> + * @param port: MCP23017 port A or B + * @param values: bitmask to manipulate the given port as OUTPUT */ - void writePort(MCP23017_PORT port, uint8_t value); + void writePort(MCP23017_PORT port, uint8_t values); + /** * Writes pins state to both ports. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". + * ".> + * @param values: bitmask to manipulate all OUTPUT of the chip */ - void write(uint16_t value); + void write(uint16_t values); /** * Reads pins state for a whole port. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". + * ".> + * @param port: MCP23017 port A or B + * @param return HIGH or 0x01, LOW or 0x00 + * depending the hardwarestate of the pin */ uint8_t readPort(MCP23017_PORT port); + /** * Reads pins state for both ports. - * - * 1 = Logic-high - * 0 = Logic-low - * - * See "3.5.10 Port register". + * ".> + * @param return HIGH or 0x01, LOW or 0x00 + * depending the hardwarestate of the pin */ uint16_t read(); /** - * Writes a single register value. + * Writes a single register @reg with the specified value @val. */ void writeRegister(MCP23017_REGISTER reg, uint8_t value); + /** * Writes values to a register pair. * - * For portA and portB variable to effectively match the desired port, + * @note For portA and portB variable to effectively match the desired port, * you have to supply a portA register address to reg. Otherwise, values * will be reversed due to the way the MCP23017 works in Byte mode. */ void writeRegister(MCP23017_REGISTER reg, uint8_t portA, uint8_t portB); + /** - * Reads a single register value. + * Reads a single registers value. + * @param reg: register to read + * port A: 0x00 ~ 0A0 + * port B: 0x10 ~ 1A0 */ uint8_t readRegister(MCP23017_REGISTER reg); + /** * Reads the values from a register pair. + * @param reg: register to read + * port A: 0x00 ~ 0A0 + * @param portA: reference to port A value; returns the value by reference + * @param portB: reference to port B value; returns the value by reference * - * For portA and portB variable to effectively match the desired port, + * @note For portA and portB variable to effectively match the desired port, * you have to supply a portA register address to reg. Otherwise, values * will be reversed due to the way the MCP23017 works in Byte mode. */ @@ -184,33 +204,53 @@ class MCP23017 #ifdef _MCP23017_INTERRUPT_SUPPORT_ /** - * Controls how the interrupt pins act with each other. + * @brief Controls how the interrupt pins act with each other. * If intMode is SEPARATED, interrupt conditions on a port will cause its respective INT pin to active. * If intMode is OR, interrupt pins are OR'ed so an interrupt on one of the port will cause both pints to active. + * ".> * - * Controls the IOCON.MIRROR bit. - * See "3.5.6 Configuration register". + * @param intMode Controls the IOCON.MIRROR bit */ void interruptMode(MCP23017_INTMODE intMode); + /** - * Configures interrupt registers using an Arduino-like API. - * mode can be one of CHANGE, FALLING or RISING. + * @brief Configures interrupt registers using an Arduino-like API-mode . + * + * + * @param port MCP23017 port A or B + * @param mode Can be one of CHANGE, FALLING or RISING */ void interrupt(MCP23017_PORT port, uint8_t mode); + /** - * Disable interrupts for the specified port. + * @brief Disables interrupts for the specified port. + * + * + * @param port MCP23017 port A or B */ void disableInterrupt(MCP23017_PORT port); + /** - * Reads which pin caused the interrupt. + * @brief Reads which pin caused the interrupt. + * + * + * @param portA reference to port A value; returns the value by reference + * @param portB reference to port B value; returns the value by reference */ void interruptedBy(uint8_t& portA, uint8_t& portB); + /** - * Clears interrupts on both ports. + * @brief Clears interrupts on both ports. + * */ void clearInterrupts(); + /** - * Clear interrupts on both ports. Returns port values at the time the interrupt occured. + * @brief Clear interrupts on both ports. Returns port values at the time the interrupt occured. + * + * + * @param portA reference to port A value; returns the value by reference + * @param portB reference to port B value; returns the value by reference */ void clearInterrupts(uint8_t& portA, uint8_t& portB); From 7ab6cdf5439c00b70806d5a62a5f10c25d166132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Sun, 1 Mar 2020 19:06:24 +0100 Subject: [PATCH 12/15] Fixed pinMode() --- src/MCP23017.cpp | 52 +++++++++++++++++++++++++++++------------------- src/MCP23017.h | 21 +++++++++++++------ 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 984c001..3e168b1 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -35,9 +35,6 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) MCP23017_REGISTER iodirreg = MCP23017_REGISTER::IODIRA; MCP23017_REGISTER polreg = MCP23017_REGISTER::IPOLA; MCP23017_REGISTER pullreg = MCP23017_REGISTER::GPPUA; - uint8_t iodir; - uint8_t pol; - uint8_t pull; if(pin > 7) { @@ -47,29 +44,42 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) pin -= 8; } - iodir = readRegister(iodirreg); - pol = readRegister(polreg); - pull = readRegister(pullreg); + uint8_t iodir = readRegister(iodirreg); + uint8_t pol = readRegister(polreg); + uint8_t pull = readRegister(pullreg); - if(mode == OUTPUT) { - iodir &= ~_BV(pin); - pol &= ~_BV(pin); - } else{ + if(mode == OUTPUT) + { iodir |= _BV(pin); + pol &= ~_BV(pin); + pull &= ~_BV(pin); + } + else + { + iodir &= ~_BV(pin); - if(mode==INPUT_PULLUP) pull |= _BV(pin); - else pull &= ~_BV(pin); - - if(inverted) pol |= _BV(pin); - else pol &= ~_BV(pin); - } - - writeRegister(iodirreg, iodir); - writeRegister(polreg, pol); + if(mode==INPUT_PULLUP) + { + pull |= _BV(pin); + } + else + { + pull &= ~_BV(pin); + } - if(mode==INPUT_PULLUP){ writeRegister(pullreg, pull); + + if(inverted) + { + pol |= _BV(pin); + } + else + { + pol &= ~_BV(pin); + } + writeRegister(polreg, pol); } + writeRegister(iodirreg, iodir); } void MCP23017::digitalWrite(uint8_t pin, uint8_t state) @@ -222,4 +232,4 @@ void MCP23017::clearInterrupts(uint8_t& portA, uint8_t& portB) readRegister(MCP23017_REGISTER::INTCAPA, portA, portB); } -#endif +#endif // _MCP23017_INTERRUPT_SUPPORT_ diff --git a/src/MCP23017.h b/src/MCP23017.h index ce45ced..7a866a6 100644 --- a/src/MCP23017.h +++ b/src/MCP23017.h @@ -3,7 +3,7 @@ #include #include -#define _MCP23017_INTERRUPT_SUPPORT_ ///< Enables support for MCP23017 interrupts. +#define _MCP23017_INTERRUPT_SUPPORT_ ///< Enables support for MCP23017 interrupts. enum class MCP23017_PORT : uint8_t { @@ -13,7 +13,7 @@ enum class MCP23017_PORT : uint8_t /** * Controls if the two interrupt pins mirror each other. - * See "3.6 Interrupt Logic". + * */ enum class MCP23017_INTMODE : uint8_t { @@ -24,7 +24,7 @@ enum class MCP23017_INTMODE : uint8_t /** * Registers addresses. * The library use addresses for IOCON.BANK = 0. - * See "3.2.1 Byte mode and Sequential mode". + * */ enum class MCP23017_REGISTER : uint8_t { @@ -73,6 +73,14 @@ class MCP23017 void debug(); #endif + /** + * @brief deprecated, for backward compability only + * + */ + inline void init(){ + begin(); + } + /** * Initializes the chip with the default configuration. * Enables Byte mode (IOCON.BANK = 0 and IOCON.SEQOP = 1). @@ -84,7 +92,7 @@ class MCP23017 * @param pullup_b: bitmask for port B * See "3.2.1 Byte mode and Sequential mode". */ - void begin(uint8_t pullup_a=0xFF, uint8_t pullup_b=0xFF); + void begin(uint8_t pullup_a=0x00, uint8_t pullup_b=0x00); /** * Controls the pins direction on a whole port at once. @@ -99,7 +107,7 @@ class MCP23017 * @param inverteds: bitmask for inverted mode * */ - void portMode(MCP23017_PORT port, uint8_t modes, uint8_t pullups=0xFF, uint8_t inverteds=0x00); + void portMode(MCP23017_PORT port, uint8_t modes, uint8_t pullups=0xff, uint8_t inverteds=0x00); /** * Sets a single pins' direction. When the pin is an input pin @@ -222,6 +230,7 @@ class MCP23017 */ void interrupt(MCP23017_PORT port, uint8_t mode); + /** * @brief Disables interrupts for the specified port. * @@ -254,5 +263,5 @@ class MCP23017 */ void clearInterrupts(uint8_t& portA, uint8_t& portB); -#endif +#endif // _MCP23017_INTERRUPT_SUPPORT_ }; From 1baf2a04deef6b2e3e2b36a77030c83fa2c9c4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Sun, 1 Mar 2020 19:30:55 +0100 Subject: [PATCH 13/15] added interrupt capability in InvertedInputs.ino --- examples/InvertedInputs/InvertedInputs.ino | 188 ++++++++++++--------- src/MCP23017.cpp | 5 +- src/MCP23017.h | 2 +- 3 files changed, 114 insertions(+), 81 deletions(-) diff --git a/examples/InvertedInputs/InvertedInputs.ino b/examples/InvertedInputs/InvertedInputs.ino index 1eb0e37..550d93a 100644 --- a/examples/InvertedInputs/InvertedInputs.ino +++ b/examples/InvertedInputs/InvertedInputs.ino @@ -1,4 +1,6 @@ #include + +#define MCP23017_INTERRUPT_SUPPORT 1 #include /** @@ -17,89 +19,119 @@ */ #define MCP23017_ADDR 0x20 - + MCP23017 mcp = MCP23017(MCP23017_ADDR); -void setup() { - - Serial.begin(115200); - delay(200); - //Serial.write(27); Serial.print("[2J"); // CLRSCR - //Serial.write(27); Serial.print("[H"); // HOME - - pinMode( A3, OUTPUT ); - - digitalWrite( A3, LOW ); - delay(50); - digitalWrite( A3, HIGH ); - delay(50); - - Wire.begin(); - mcp.init(); - - bool error = false; - - mcp.portMode( MCP23017_PORT::A, INPUT, 0xFF ); // PORT A is input inverted - mcp.portMode( MCP23017_PORT::B, OUTPUT ); // PORT B is output - mcp.writePort (MCP23017_PORT::B, 0xFF); - - Serial.println("##### Checking setting port mode #####\n" ); - for ( uint8_t i=0; i<8 ; i++ ){ - - error |= ( mcp.digitalRead(i) != mcp.digitalRead(i+8) ); - if ( mcp.digitalRead(i) != HIGH ){ - Serial.print( "Your connection "); - Serial.print( i ); - Serial.print(" was wrong, please check it: " ); - Serial.print("IN: " ); - Serial.print( mcp.digitalRead(i) ? "HIGH" : "LOW" ); - Serial.print(", OUT: " ); - Serial.println( mcp.digitalRead(i+8) ? "HIGH" : "LOW" ); - } - } - - if ( error ) - Serial.println("--------- FAILED (see above) ----------"); +void int_pinA(){ + Serial.println("\n##### INTERRUPT PORT A FIRED #####\n"); +} + +void int_pinB(){ + Serial.println("\n##### INTERRUPT PORT B FIRED #####\n"); +} + +void setup() +{ + Serial.begin(115200); + delay(200); + // Serial.write(27); Serial.print("[2J"); // CLRSCR + // Serial.write(27); Serial.print("[H"); // HOME + + // reset pin + pinMode(A3, OUTPUT); + digitalWrite(A3, LOW); + delay(50); + digitalWrite(A3, HIGH); + delay(50); + + // interrupt pins + pinMode(2, INPUT_PULLUP); + pinMode(3, INPUT_PULLUP); + + attachInterrupt(digitalPinToInterrupt(2), int_pinA, RISING); + attachInterrupt(digitalPinToInterrupt(3), int_pinB, RISING); + + Wire.begin(); + mcp.begin(0x00, 0x00); + mcp.interruptMode(MCP23017_INTMODE::SEPARATED); + mcp.interrupt(MCP23017_PORT::A, CHANGE); + mcp.interrupt(MCP23017_PORT::B, CHANGE); + + bool error = false; + + // PORT A is input inverted with pullups + mcp.portMode( MCP23017_PORT::A, INPUT, 0xFF, 0xFF); + mcp.clearInterrupts(); + + // PORT B is output + mcp.portMode(MCP23017_PORT::B, OUTPUT); + + // Set all output pins to HIGH + mcp.writePort(MCP23017_PORT::B, 0xFF); + + Serial.println("##### Checking setting port mode #####\n"); + for (uint8_t i = 0; i < 8; i++) + { + + error |= (mcp.digitalRead(i) != mcp.digitalRead(i + 8)); + if (error) + { + Serial.print("Your connection "); + Serial.print(i); + Serial.print(" was wrong, please check it: "); + Serial.print("IN: "); + Serial.print(mcp.digitalRead(i) ? "HIGH" : "LOW"); + Serial.print(", OUT: "); + Serial.println(mcp.digitalRead(i + 8) ? "HIGH" : "LOW"); + } + } + + if (error) + Serial.println("--------- FAILED (see above) ----------"); else - Serial.println("------------- SUCCEEDED --------------"); - + Serial.println("------------- SUCCEEDED --------------"); + error = false; - digitalWrite( A3, LOW ); - delay(50); - digitalWrite( A3, HIGH ); - delay(50); - - Serial.println("\n##### Checking setting pin mode #####\n" ); - - for ( uint8_t i=0; i<16; i++ ){ - if ( i< 8 ) - mcp.pinMode( i, OUTPUT ); // PORT A is output - else - mcp.pinMode( i, INPUT, true ); // PORT B is input inverted - } - - mcp.writePort (MCP23017_PORT::A, 0xFF); - Serial.print( mcp.readPort(MCP23017_PORT::B) ); - - for ( uint8_t i=0; i<8 ; i++ ){ - error |= ( mcp.digitalRead(i+8) != mcp.digitalRead(i) ); -// if ( mcp.digitalRead(i+8) == HIGH ){ - if ( true ){ - Serial.print( "Your connection " ); - Serial.print( i ); - Serial.print(" was wrong, please check it: " ); - Serial.print("IN: " ); - Serial.print( mcp.digitalRead(i+8) ? "HIGH" : "LOW" ); - Serial.print(", OUT: " ); - Serial.println( mcp.digitalRead(i) ? "HIGH" : "LOW" ); - } - } - - if ( error ) - Serial.println("--------- FAILED (see above) ----------"); - else - Serial.println("------------- SUCCEEDED --------------"); + mcp.clearInterrupts(); + + Serial.println("\n##### Checking setting pin mode #####\n"); + + for (uint8_t i = 0; i < 16; i++) + { + if (i < 8) + { + // PORT A is output for now + mcp.pinMode(i, OUTPUT); + } + else + { + // PORT B is input for now, inverted inputs with pullups + mcp.pinMode(i, INPUT_PULLUP, true); + } + } + // Set all output pins to HIGH + mcp.writePort(MCP23017_PORT::A, 0xFF); + + for (uint8_t i = 0; i < 8; i++) + { + error |= (mcp.digitalRead(i) != mcp.digitalRead(i + 8)); + if (error) + { + Serial.print("Your connection "); + Serial.print(i); + Serial.print(" was wrong, please check it: "); + Serial.print("IN: "); + Serial.print(mcp.digitalRead(i + 8) ? "HIGH" : "LOW"); + Serial.print(", OUT: "); + Serial.println(mcp.digitalRead(i) ? "HIGH" : "LOW"); + } + } + + if (error) + Serial.println("--------- FAILED (see above) ----------"); + else + Serial.println("------------- SUCCEEDED --------------"); } void loop() {} diff --git a/src/MCP23017.cpp b/src/MCP23017.cpp index 3e168b1..da02b49 100644 --- a/src/MCP23017.cpp +++ b/src/MCP23017.cpp @@ -67,7 +67,6 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) pull &= ~_BV(pin); } - writeRegister(pullreg, pull); if(inverted) { @@ -77,8 +76,10 @@ void MCP23017::pinMode(uint8_t pin, uint8_t mode, bool inverted) { pol &= ~_BV(pin); } - writeRegister(polreg, pol); } + + writeRegister(polreg, pol); + writeRegister(pullreg, pull); writeRegister(iodirreg, iodir); } diff --git a/src/MCP23017.h b/src/MCP23017.h index 7a866a6..a23524f 100644 --- a/src/MCP23017.h +++ b/src/MCP23017.h @@ -217,7 +217,7 @@ class MCP23017 * If intMode is OR, interrupt pins are OR'ed so an interrupt on one of the port will cause both pints to active. * ".> * - * @param intMode Controls the IOCON.MIRROR bit + * @param intMode When OR, the INTn pins are functionally OR’ed so that an interrupt on either port will cause both pins to activate. Otherwise use SEPARATED as parameter. */ void interruptMode(MCP23017_INTMODE intMode); From 0fa87a0549e379ec77c5ca3a4e9eb2f5abb58033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Sun, 1 Mar 2020 20:12:44 +0100 Subject: [PATCH 14/15] Added comment to InvertedInputs.ino --- examples/InvertedInputs/InvertedInputs.ino | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/examples/InvertedInputs/InvertedInputs.ino b/examples/InvertedInputs/InvertedInputs.ino index 550d93a..cd57b90 100644 --- a/examples/InvertedInputs/InvertedInputs.ino +++ b/examples/InvertedInputs/InvertedInputs.ino @@ -4,18 +4,26 @@ #include /** + * This sketch demonstrates the pin capabilities in pin- and portmode. + * Each of the 16 bits can eigher be an input which is inverted or not + * or having a 100k pullup resistor in same mode or just beeing an output. + * + * Some Interrupt capabilites are also shown + * * Please connect: - * A5 => SCL (ON UNO R3) - * A4 => SDA (ON UNO R3) - * A3 => RST (ON UNO R3) - * A0 => B0 - * A1 => B1 - * A2 => B2 - * A3 => B3 - * A4 => B4 - * A5 => B5 - * A6 => B6 - * A7 => B7 + * A5 => SCL (ON UNO R3) + * A4 => SDA (ON UNO R3) + * A3 => RST (ON UNO R3) + * INTA => D2 (ON UNO R3) + * INTB => D3 (ON UNO R3) + * A0 => B0 + * A1 => B1 + * A2 => B2 + * A3 => B3 + * A4 => B4 + * A5 => B5 + * A6 => B6 + * A7 => B7 */ #define MCP23017_ADDR 0x20 From ccf1ad454e5e13aa801e095f7195b1eb739f1436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Bernau?= Date: Wed, 4 Mar 2020 13:29:25 +0100 Subject: [PATCH 15/15] Add files via upload --- DOCUMENTATION.MD | 721 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 721 insertions(+) create mode 100644 DOCUMENTATION.MD diff --git a/DOCUMENTATION.MD b/DOCUMENTATION.MD new file mode 100644 index 0000000..219c471 --- /dev/null +++ b/DOCUMENTATION.MD @@ -0,0 +1,721 @@ +
+ +
+ + +++ + + + + + +
+ +
+
+MCP23017 16-Bit I/O Expander with Serial Interface +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+ +## Public Member Functions + +
+ +#### [MCP23017](#mcp23017) (uint8\_t address, TwoWire \&bus=Wire) +#### void [init](#init)() +#### void [begin](#BEGIN)(uint8\_t pullup\_a=0x00, uint8\_t pullup\_b=0x00) +#### void [portMode](#400)(MCP23017\_PORT port, uint8\_t modes, uint8\_t pullups=0xff, uint8\_t inverteds=0x00) +#### void [pinMode](#500)(uint8\_t pin, uint8\_t mode, bool inverted=false) +#### void [digitalWrite](#600)(uint8\_t pin, uint8\_t state) +#### uint8\_t [digitalRead](#700)(uint8\_t pin) +#### void [writePort](#800)(MCP23017\_PORT port, uint8\_t values) +#### void [write](#900)(uint16\_t values) +#### uint8\_t [readPort](#1000)(MCP23017\_PORT port) +#### uint16\_t [read](#1100)() +#### void [writeRegister](#1200)(MCP23017\_REGISTER reg, uint8\_t value) +#### void [writeRegister](#1300)(MCP23017\_REGISTER reg, uint8\_t portA, uint8\_t portB) +#### uint8\_t [readRegister](#1400)(MCP23017\_REGISTER reg) +#### void [readRegister](#1500)(MCP23017\_REGISTER reg, uint8\_t \&portA, uint8\_t \&portB) +#### void [interruptMode](#1600)(MCP23017\_INTMODE intMode) +#### void [interrupt](#1700)(MCP23017\_PORT port, uint8\_t mode) +#### void [disableInterrupt](#1800)(MCP23017\_PORT port) +#### void [interruptedBy](#1900)(uint8\_t \&portA, uint8\_t \&portB) +#### void [clearInterrupts](#2000)() +#### void [clearInterrupts](#2100)(uint8\_t \&portA, uint8\_t \&portB) + +## Constructor & Destructor Documentation + +## [◆ ](#TOC)MCP23017() + +
+ +
+ +| | | | | +| ------------------ | - | --------- | -------------- | +| MCP23017::MCP23017 | ( | uint8\_t | *address*, | +| | | TwoWire & | *bus* = `Wire` | +| | ) | | | + +
+ +
+ +Instantiates a new instance to interact with a MCP23017 at the specified +address. + + - Parameters + + | | | + | ------- | -------------------------------------- | + | address | bus address of MCP23017 (0x20 \~ 0x27) | + | bus | refence to i2c bus object | + + +
+ +
+ +## Member Function Documentation + +## [◆ ](#TOC)begin() + +
+ +
+ +| | | | | +| -------------------- | - | -------- | --------------------- | +| void MCP23017::begin | ( | uint8\_t | *pullup\_a* = `0x00`, | +| | | uint8\_t | *pullup\_b* = `0x00` | +| | ) | | | + +
+ +
+ +Initializes the chip with the default configuration. Enables Byte mode +(IOCON.BANK = 0 and IOCON.SEQOP = 1). Enables pull-up resistors for all +pins by default. This will only be effective for input pins. + + - Note + See: "3.2.1 Byte mode and Sequential mode" + + + + - Parameters + + | | | + | --------- | ------------------------------------------------------------- | + | pullup\_a | bitmask for port A | + | pullup\_b | bitmask for port B See "3.2.1 Byte mode and Sequential mode". | + + +
+ +
+ + + +## [◆ ](#TOC)clearInterrupts() \[1/2\] + +
+ +
+ +Clears interrupts on both ports. + + - Note + See: "3.5.9 INTERRUPT CAPTURED REGISTER" + +
+ +
+ + + +## [◆ ](#TOC)clearInterrupts() \[2/2\] + +
+ +
+ +| | | | | +| ------------------------------ | - | ---------- | -------- | +| void MCP23017::clearInterrupts | ( | uint8\_t & | *portA*, | +| | | uint8\_t & | *portB* | +| | ) | | | + +
+ +
+ +Clear interrupts on both ports. Returns port values at the time the +interrupt occured. + + - Note + See: "3.5.9 INTERRUPT CAPTURED REGISTER" + + + + - Parameters + + | | | + | ----- | --------------------------------------------------------- | + | portA | reference to port A value; returns the value by reference | + | portB | reference to port B value; returns the value by reference | + + +
+ +
+ + + +## [◆ ](#TOC)digitalRead() + +
+ +
+ +Reads a single pin state. + + - Note + See: "3.5.10 Port register" + + + + - Parameters + + | | | + | ------ | ---------------------------------------------------------------- | + | pin | Pin 0-7 for port A, 8-15 for port B. | + | return | HIGH or 0x01, LOW or 0x00 depending the hardwarestate of the pin | + + +
+ +
+ + + +## [◆ ](#TOC)digitalWrite() + +
+ +
+ +| | | | | +| --------------------------- | - | -------- | ------- | +| void MCP23017::digitalWrite | ( | uint8\_t | *pin*, | +| | | uint8\_t | *state* | +| | ) | | | + +
+ +
+ +Writes a single pin state. + + - Note + See: "3.5.10 Port register" + + + + - Parameters + + | | | + | ----- | ------------------------------------ | + | pin | Pin 0-7 for port A, 8-15 for port B. | + | state | HIGH or 0x01 LOW or 0x00 | + + +
+ +
+ + + +## [◆ ](#TOC)disableInterrupt() + +
+ +
+ +| | | | | | +| ------------------------------- | - | -------------- | ------ | - | +| void MCP23017::disableInterrupt | ( | MCP23017\_PORT | *port* | ) | + +
+ +
+ +Disables interrupts for the specified port. + + - Note + See: "3.5.3 INTERRUPT-ON-CHANGE CONTROL REGISTER" + + + + - Parameters + + | | | + | ---- | -------------------- | + | port | MCP23017 port A or B | + + +
+ +
+ + + +## [◆ ](#TOC)interrupt() + +
+ +
+ +| | | | | +| ------------------------ | - | -------------- | ------- | +| void MCP23017::interrupt | ( | MCP23017\_PORT | *port*, | +| | | uint8\_t | *mode* | +| | ) | | | + +
+ +
+ +Configures interrupt registers using an Arduino-like API-mode . + + - Note + See: "3.5.3 INTERRUPT-ON-CHANGE CONTROL REGISTER" + + + + - Parameters + + | | | + | ---- | --------------------------------------- | + | port | MCP23017 port A or B | + | mode | Can be one of CHANGE, FALLING or RISING | + + +
+ +
+ + + +## [◆ ](#TOC)interruptedBy() + +
+ +
+ +| | | | | +| ---------------------------- | - | ---------- | -------- | +| void MCP23017::interruptedBy | ( | uint8\_t & | *portA*, | +| | | uint8\_t & | *portB* | +| | ) | | | + +
+ +
+ +Reads which pin caused the interrupt. + + - Note + See: "3.5.9 GPINTEN: INTERRUPT CAPTURED REGISTER" + + + + - Parameters + + | | | + | ----- | --------------------------------------------------------- | + | portA | reference to port A value; returns the value by reference | + | portB | reference to port B value; returns the value by reference | + + +
+ +
+ + + +## [◆ ](#TOC)interruptMode() + +
+ +
+ +| | | | | | +| ---------------------------- | - | ----------------- | --------- | - | +| void MCP23017::interruptMode | ( | MCP23017\_INTMODE | *intMode* | ) | + +
+ +
+ +Controls how the interrupt pins act with each other. If intMode is +SEPARATED, interrupt conditions on a port will cause its respective INT +pin to active. If intMode is OR, interrupt pins are OR'ed so an +interrupt on one of the port will cause both pints to active. + + - Note + See: "3.5.6 I/O EXPANDER CONFIGURATION REGISTER" + + + + - Parameters + + | | | + | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | + | intMode | When OR, the INTn pins are functionally OR’ed so that an interrupt on either port will cause both pins to activate. Otherwise use SEPARATED as parameter. | + + +
+ +
+ + + +## [◆ ](#TOC)pinMode() + +
+ +
+ +| | | | | +| ---------------------- | - | -------- | -------------------- | +| void MCP23017::pinMode | ( | uint8\_t | *pin*, | +| | | uint8\_t | *mode*, | +| | | bool | *inverted* = `false` | +| | ) | | | + +
+ +
+ +Sets a single pins' direction. When the pin is an input pin a pullup +and/or an inverted option can be specified. + + - Note + See: "3.5.1 I/O IODIR I/O DIRECTION REGISTER", "3.5.2 INPUT POLARITY REGISTER", "3.5.7 PULL-UP RESISTOR CONFIGURATION REGISTER" + + + + - Parameters + + | | | + | ---- | -------------------------------------------------------------------- | + | pin | Controls a single pin direction. Pin 0-7 for port A, 8-15 fo port B. | + | mode | INPUT or 0x00 INPUT\_PULLUP or 0x02 OUTPUT or 0x01 | + + +
+ +
+ + + +## [◆ ](#TOC)portMode() + +
+ +
+ +| | | | | +| ----------------------- | - | -------------- | -------------------- | +| void MCP23017::portMode | ( | MCP23017\_PORT | *port*, | +| | | uint8\_t | *modes*, | +| | | uint8\_t | *pullups* = `0xff`, | +| | | uint8\_t | *inverteds* = `0x00` | +| | ) | | | + +
+ +
+ +Controls the pins direction on a whole port at once. + + - Note + See: "3.5.1 I/O IODIR I/O DIRECTION REGISTER", "3.5.2 INPUT POLARITY REGISTER", "3.5.7 PULL-UP RESISTOR CONFIGURATION REGISTER + + + + - Parameters + + | | | + | --------- | -------------------------------------------------- | + | port | MCP23017 port A or B | + | modes | direction of whole port INPUT or 0x0 OUTPUT or0x01 | + | pullup | bitmask for internal 100k pullup resistors | + | inverteds | bitmask for inverted mode | + + +
+ +
+ + + +## [◆ ](#TOC)read() + +
+ +
+ +Reads pins state for both ports. + + - Note + See: "3.5.10 Port register" + + + + - Parameters + + | | | + | ------ | ---------------------------------------------------------------- | + | return | HIGH or 0x01, LOW or 0x00 depending the hardwarestate of the pin | + + +
+ +
+ + + +## [◆ ](#TOC)readPort() + +
+ +
+ +| | | | | | +| --------------------------- | - | -------------- | ------ | - | +| uint8\_t MCP23017::readPort | ( | MCP23017\_PORT | *port* | ) | + +
+ +
+ +Reads pins state for a whole port. + + - Note + See: "3.5.10 Port register" + + + + - Parameters + + | | | + | ------ | ---------------------------------------------------------------- | + | port | MCP23017 port A or B | + | return | HIGH or 0x01, LOW or 0x00 depending the hardwarestate of the pin | + + +
+ +
+ + + +## [◆ ](#TOC)readRegister() \[1/2\] + +
+ +
+ +| | | | | | +| ------------------------------- | - | ------------------ | ----- | - | +| uint8\_t MCP23017::readRegister | ( | MCP23017\_REGISTER | *reg* | ) | + +
+ +
+ +Reads a single registers value. + + - Parameters + + | | | + | --- | -------------------------------------------------------- | + | reg | register to read port A: 0x00 \~ 0A0 port B: 0x10 \~ 1A0 | + + +
+ +
+ + + +## [◆ ](#TOC)readRegister() \[2/2\] + +
+ +
+ +| | | | | +| --------------------------- | - | ------------------ | -------- | +| void MCP23017::readRegister | ( | MCP23017\_REGISTER | *reg*, | +| | | uint8\_t & | *portA*, | +| | | uint8\_t & | *portB* | +| | ) | | | + +
+ +
+ +Reads the values from a register pair. + + - Parameters + + | | | + | ----- | --------------------------------------------------------- | + | reg | register to read port A: 0x00 \~ 0A0 | + | portA | reference to port A value; returns the value by reference | + | portB | reference to port B value; returns the value by reference | + + + + + - Note + For portA and portB variable to effectively match the desired port, + you have to supply a portA register address to reg. Otherwise, + values will be reversed due to the way the MCP23017 works in Byte + mode. + +
+ +
+ + + +## [◆ ](#TOC)write() + +
+ +
+ +| | | | | | +| -------------------- | - | --------- | -------- | - | +| void MCP23017::write | ( | uint16\_t | *values* | ) | + +
+ +
+ +Writes pins state to both ports. + + - Note + See: "3.5.10 Port register" + + + + - Parameters + + | | | + | ------ | -------------------------------------------- | + | values | bitmask to manipulate all OUTPUT of the chip | + + +
+ +
+ + + +## [◆ ](#TOC)writePort() + +
+ +
+ +| | | | | +| ------------------------ | - | -------------- | -------- | +| void MCP23017::writePort | ( | MCP23017\_PORT | *port*, | +| | | uint8\_t | *values* | +| | ) | | | + +
+ +
+ +Writes pins state to a whole port. + + - Note + See: "3.5.10 Port register" + + + + - Parameters + + | | | + | ------ | ---------------------------------------------- | + | port | MCP23017 port A or B | + | values | bitmask to manipulate the given port as OUTPUT | + + +
+ +
+ + + +## [◆ ](#TOC)writeRegister() + +
+ +
+ +| | | | | +| ---------------------------- | - | ------------------ | -------- | +| void MCP23017::writeRegister | ( | MCP23017\_REGISTER | *reg*, | +| | | uint8\_t | *portA*, | +| | | uint8\_t | *portB* | +| | ) | | | + +
+ +
+ +Writes values to a register pair. + + - Note + For portA and portB variable to effectively match the desired port, + you have to supply a portA register address to reg. Otherwise, + values will be reversed due to the way the MCP23017 works in Byte + mode. + +
+ +
+ +----- \ No newline at end of file