mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-09-19 16:46:11 -04:00
0.6.3 MCP23017_RT
This commit is contained in:
parent
15fb91d42c
commit
52de8f6926
@ -22,6 +22,6 @@ compile:
|
|||||||
# - leonardo
|
# - leonardo
|
||||||
- m4
|
- m4
|
||||||
- esp32
|
- esp32
|
||||||
# - esp8266
|
- esp8266
|
||||||
# - mega2560
|
# - mega2560
|
||||||
- rpipico
|
- rpipico
|
@ -6,12 +6,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
|
||||||
|
## [0.6.3] 2024-05-25
|
||||||
|
- sync MCP23S17, add several interrupt functions (experimental)
|
||||||
|
- add **MCP23x17_registers.h**
|
||||||
|
- add **readReg16()** and **writeReg16()** optimization
|
||||||
|
- update readme.md
|
||||||
|
- update keywords.txt
|
||||||
|
|
||||||
## [0.6.2] 2024-03-02
|
## [0.6.2] 2024-03-02
|
||||||
- Fix #29, add parameter to **begin(bool pullup)**
|
- Fix #29, add parameter to **begin(bool pullup)**
|
||||||
- remove DATE field from examples as it adds no value.
|
- remove DATE field from examples as it adds no value.
|
||||||
- update GitHub/actions to version v4 in workflows.
|
- update GitHub/actions to version v4 in workflows.
|
||||||
|
|
||||||
|
|
||||||
## [0.6.1] 2024-01-05
|
## [0.6.1] 2024-01-05
|
||||||
- Fix URL in examples
|
- Fix URL in examples
|
||||||
- minor edits
|
- minor edits
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//
|
//
|
||||||
// FILE: MCP23017.cpp
|
// FILE: MCP23017.cpp
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// VERSION: 0.6.2
|
// VERSION: 0.6.3
|
||||||
// PURPOSE: Arduino library for I2C MCP23017 16 channel port expander
|
// PURPOSE: Arduino library for I2C MCP23017 16 channel port expander
|
||||||
// DATE: 2019-10-12
|
// DATE: 2019-10-12
|
||||||
// URL: https://github.com/RobTillaart/MCP23017_RT
|
// URL: https://github.com/RobTillaart/MCP23017_RT
|
||||||
@ -12,31 +12,6 @@
|
|||||||
#include "MCP23017.h"
|
#include "MCP23017.h"
|
||||||
|
|
||||||
|
|
||||||
// Registers // DESCRIPTION DATASHEET
|
|
||||||
#define MCP23017_DDR_A 0x00 // Data Direction Register A P18
|
|
||||||
#define MCP23017_DDR_B 0x01 // Data Direction Register B P18
|
|
||||||
#define MCP23017_POL_A 0x02 // Input Polarity A P18
|
|
||||||
#define MCP23017_POL_B 0x03 // Input Polarity B P18
|
|
||||||
#define MCP23017_GPINTEN_A 0x04 // NOT USED interrupt enable P19
|
|
||||||
#define MCP23017_GPINTEN_B 0x05 // NOT USED
|
|
||||||
#define MCP23017_DEFVAL_A 0x06 // NOT USED interrupt def P19
|
|
||||||
#define MCP23017_DEFVAL_B 0x07 // NOT USED
|
|
||||||
#define MCP23017_INTCON_A 0x08 // NOT USED interrupt control P20
|
|
||||||
#define MCP23017_INTCON_B 0x09 // NOT USED
|
|
||||||
#define MCP23017_IOCR 0x0A // IO control register P20
|
|
||||||
#define MCP23017_IOCR2 0x0B // NOT USED
|
|
||||||
#define MCP23017_PUR_A 0x0C // Pull Up Resistors A P22
|
|
||||||
#define MCP23017_PUR_B 0x0D // Pull Up Resistors A P22
|
|
||||||
#define MCP23017_INTF_A 0x0E // NOT USED interrupt flag P22
|
|
||||||
#define MCP23017_INTF_B 0x0F // NOT USED
|
|
||||||
#define MCP23017_INTCAP_A 0x10 // NOT USED interrupt capture P23
|
|
||||||
#define MCP23017_INTCAP_B 0x11 // NOT USED
|
|
||||||
#define MCP23017_GPIO_A 0x12 // General Purpose IO A P23
|
|
||||||
#define MCP23017_GPIO_B 0x13 // General Purpose IO B P23
|
|
||||||
#define MCP23017_OLAT_A 0x14 // NOT USED output latch P24
|
|
||||||
#define MCP23017_OLAT_B 0x15 // NOT USED
|
|
||||||
|
|
||||||
|
|
||||||
MCP23017::MCP23017(uint8_t address, TwoWire *wire)
|
MCP23017::MCP23017(uint8_t address, TwoWire *wire)
|
||||||
{
|
{
|
||||||
_address = address;
|
_address = address;
|
||||||
@ -49,13 +24,18 @@ bool MCP23017::begin(bool pullup)
|
|||||||
{
|
{
|
||||||
// check connected
|
// check connected
|
||||||
if (! isConnected()) return false;
|
if (! isConnected()) return false;
|
||||||
// disable address increment (datasheet)
|
|
||||||
if (! writeReg(MCP23017_IOCR, 0b00100000)) return false;
|
// disable address increment - datasheet P20
|
||||||
|
// SEQOP: Sequential Operation mode bit
|
||||||
|
// 1 = Sequential operation disabled, address pointer does not increment.
|
||||||
|
// 0 = Sequential operation enabled, address pointer increments.
|
||||||
|
// if (! writeReg(MCP23017_IOCR, MCP23017_IOCR_SEQOP)) return false;
|
||||||
|
|
||||||
if (pullup)
|
if (pullup)
|
||||||
{
|
{
|
||||||
// Force INPUT_PULLUP
|
// Force INPUT_PULLUP
|
||||||
if (! writeReg(MCP23017_PUR_A, 0xFF)) return false;
|
if (! writeReg(MCP23x17_PUR_A, 0xFF)) return false; // 0xFF == all UP
|
||||||
if (! writeReg(MCP23017_PUR_B, 0xFF)) return false;
|
if (! writeReg(MCP23x17_PUR_B, 0xFF)) return false; // 0xFF == all UP
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -80,7 +60,10 @@ uint8_t MCP23017::getAddress()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
// single pin interface
|
// single pin interface
|
||||||
|
//
|
||||||
// pin = 0..15
|
// pin = 0..15
|
||||||
// mode = INPUT, OUTPUT, INPUT_PULLUP (= same as INPUT)
|
// mode = INPUT, OUTPUT, INPUT_PULLUP (= same as INPUT)
|
||||||
bool MCP23017::pinMode1(uint8_t pin, uint8_t mode)
|
bool MCP23017::pinMode1(uint8_t pin, uint8_t mode)
|
||||||
@ -96,10 +79,10 @@ bool MCP23017::pinMode1(uint8_t pin, uint8_t mode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t dataDirectionRegister = MCP23017_DDR_A;
|
uint8_t dataDirectionRegister = MCP23x17_DDR_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
dataDirectionRegister = MCP23017_DDR_B;
|
dataDirectionRegister = MCP23x17_DDR_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
uint8_t val = readReg(dataDirectionRegister);
|
uint8_t val = readReg(dataDirectionRegister);
|
||||||
@ -136,10 +119,10 @@ bool MCP23017::write1(uint8_t pin, uint8_t value)
|
|||||||
_error = MCP23017_PIN_ERROR;
|
_error = MCP23017_PIN_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t IOR = MCP23017_GPIO_A;
|
uint8_t IOR = MCP23x17_GPIO_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
IOR = MCP23017_GPIO_B;
|
IOR = MCP23x17_GPIO_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +142,7 @@ bool MCP23017::write1(uint8_t pin, uint8_t value)
|
|||||||
{
|
{
|
||||||
val &= ~mask;
|
val &= ~mask;
|
||||||
}
|
}
|
||||||
|
// only write when changed.
|
||||||
if (pre != val)
|
if (pre != val)
|
||||||
{
|
{
|
||||||
writeReg(IOR, val);
|
writeReg(IOR, val);
|
||||||
@ -178,10 +162,10 @@ uint8_t MCP23017::read1(uint8_t pin)
|
|||||||
_error = MCP23017_PIN_ERROR;
|
_error = MCP23017_PIN_ERROR;
|
||||||
return MCP23017_INVALID_READ;
|
return MCP23017_INVALID_READ;
|
||||||
}
|
}
|
||||||
uint8_t IOR = MCP23017_GPIO_A;
|
uint8_t IOR = MCP23x17_GPIO_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
IOR = MCP23017_GPIO_B;
|
IOR = MCP23x17_GPIO_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,8 +180,8 @@ uint8_t MCP23017::read1(uint8_t pin)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// pin = 0..15
|
// pin = 0..15
|
||||||
// reverse = true or false
|
// reversed = true or false
|
||||||
bool MCP23017::setPolarity(uint8_t pin, bool reversed)
|
bool MCP23017::setPolarity(uint8_t pin, bool reversed)
|
||||||
{
|
{
|
||||||
if (pin > 15)
|
if (pin > 15)
|
||||||
@ -205,10 +189,10 @@ bool MCP23017::setPolarity(uint8_t pin, bool reversed)
|
|||||||
_error = MCP23017_PIN_ERROR;
|
_error = MCP23017_PIN_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t inputPolarityRegister = MCP23017_POL_A;
|
uint8_t inputPolarityRegister = MCP23x17_POL_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
inputPolarityRegister = MCP23017_POL_B;
|
inputPolarityRegister = MCP23x17_POL_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
uint8_t val = readReg(inputPolarityRegister);
|
uint8_t val = readReg(inputPolarityRegister);
|
||||||
@ -241,10 +225,10 @@ bool MCP23017::getPolarity(uint8_t pin, bool &reversed)
|
|||||||
_error = MCP23017_PIN_ERROR;
|
_error = MCP23017_PIN_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t inputPolarityRegister = MCP23017_POL_A;
|
uint8_t inputPolarityRegister = MCP23x17_POL_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
inputPolarityRegister = MCP23017_POL_B;
|
inputPolarityRegister = MCP23x17_POL_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
uint8_t val = readReg(inputPolarityRegister);
|
uint8_t val = readReg(inputPolarityRegister);
|
||||||
@ -258,8 +242,8 @@ bool MCP23017::getPolarity(uint8_t pin, bool &reversed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// pin = 0..15
|
// pin = 0..15
|
||||||
// reverse = true or false
|
// pullup = true or false
|
||||||
bool MCP23017::setPullup(uint8_t pin, bool pullup)
|
bool MCP23017::setPullup(uint8_t pin, bool pullup)
|
||||||
{
|
{
|
||||||
if (pin > 15)
|
if (pin > 15)
|
||||||
@ -267,10 +251,10 @@ bool MCP23017::setPullup(uint8_t pin, bool pullup)
|
|||||||
_error = MCP23017_PIN_ERROR;
|
_error = MCP23017_PIN_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t inputPullupRegister = MCP23017_PUR_A;
|
uint8_t inputPullupRegister = MCP23x17_PUR_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
inputPullupRegister = MCP23017_PUR_B;
|
inputPullupRegister = MCP23x17_PUR_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
uint8_t val = readReg(inputPullupRegister);
|
uint8_t val = readReg(inputPullupRegister);
|
||||||
@ -303,10 +287,10 @@ bool MCP23017::getPullup(uint8_t pin, bool &pullup)
|
|||||||
_error = MCP23017_PIN_ERROR;
|
_error = MCP23017_PIN_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t inputPullupRegister = MCP23017_PUR_A;
|
uint8_t inputPullupRegister = MCP23x17_PUR_A;
|
||||||
if (pin > 7)
|
if (pin > 7)
|
||||||
{
|
{
|
||||||
inputPullupRegister = MCP23017_PUR_B;
|
inputPullupRegister = MCP23x17_PUR_B;
|
||||||
pin -= 8;
|
pin -= 8;
|
||||||
}
|
}
|
||||||
uint8_t val = readReg(inputPullupRegister);
|
uint8_t val = readReg(inputPullupRegister);
|
||||||
@ -320,9 +304,10 @@ bool MCP23017::getPullup(uint8_t pin, bool &pullup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// 8 pins interface
|
// 8 pins interface
|
||||||
|
//
|
||||||
// whole register at once
|
// whole register at once
|
||||||
// port = 0..1
|
// port = 0..1
|
||||||
// value = 0..0xFF bit pattern
|
// value = 0..0xFF bit pattern
|
||||||
@ -333,22 +318,23 @@ bool MCP23017::pinMode8(uint8_t port, uint8_t value)
|
|||||||
_error = MCP23017_PORT_ERROR;
|
_error = MCP23017_PORT_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (port == 0) writeReg(MCP23017_DDR_A, value);
|
if (port == 0) writeReg(MCP23x17_DDR_A, value);
|
||||||
if (port == 1) writeReg(MCP23017_DDR_B, value);
|
if (port == 1) writeReg(MCP23x17_DDR_B, value);
|
||||||
_error = MCP23017_OK;
|
_error = MCP23017_OK;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MCP23017::write8(uint8_t port, uint8_t value) // port = 0..1
|
// port = 0..1
|
||||||
|
bool MCP23017::write8(uint8_t port, uint8_t value)
|
||||||
{
|
{
|
||||||
if (port > 1)
|
if (port > 1)
|
||||||
{
|
{
|
||||||
_error = MCP23017_PORT_ERROR;
|
_error = MCP23017_PORT_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (port == 0) writeReg(MCP23017_GPIO_A, value);
|
if (port == 0) writeReg(MCP23x17_GPIO_A, value);
|
||||||
if (port == 1) writeReg(MCP23017_GPIO_B, value);
|
if (port == 1) writeReg(MCP23x17_GPIO_B, value);
|
||||||
_error = MCP23017_OK;
|
_error = MCP23017_OK;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -362,8 +348,8 @@ int MCP23017::read8(uint8_t port)
|
|||||||
return MCP23017_INVALID_READ;
|
return MCP23017_INVALID_READ;
|
||||||
}
|
}
|
||||||
_error = MCP23017_OK;
|
_error = MCP23017_OK;
|
||||||
if (port == 0) return readReg(MCP23017_GPIO_A);
|
if (port == 0) return readReg(MCP23x17_GPIO_A);
|
||||||
return readReg(MCP23017_GPIO_B); // port == 1
|
return readReg(MCP23x17_GPIO_B); // port == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -376,8 +362,8 @@ bool MCP23017::setPolarity8(uint8_t port, uint8_t mask)
|
|||||||
_error = MCP23017_PORT_ERROR;
|
_error = MCP23017_PORT_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (port == 0) writeReg(MCP23017_POL_A, mask);
|
if (port == 0) writeReg(MCP23x17_POL_A, mask);
|
||||||
if (port == 1) writeReg(MCP23017_POL_B, mask);
|
if (port == 1) writeReg(MCP23x17_POL_B, mask);
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -393,8 +379,8 @@ bool MCP23017::getPolarity8(uint8_t port, uint8_t &mask)
|
|||||||
_error = MCP23017_PORT_ERROR;
|
_error = MCP23017_PORT_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (port == 0) mask = readReg(MCP23017_POL_A);
|
if (port == 0) mask = readReg(MCP23x17_POL_A);
|
||||||
if (port == 1) mask = readReg(MCP23017_POL_B);
|
if (port == 1) mask = readReg(MCP23x17_POL_B);
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -412,8 +398,8 @@ bool MCP23017::setPullup8(uint8_t port, uint8_t mask)
|
|||||||
_error = MCP23017_PORT_ERROR;
|
_error = MCP23017_PORT_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (port == 0) writeReg(MCP23017_PUR_A, mask);
|
if (port == 0) writeReg(MCP23x17_PUR_A, mask);
|
||||||
if (port == 1) writeReg(MCP23017_PUR_B, mask);
|
if (port == 1) writeReg(MCP23x17_PUR_B, mask);
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -429,8 +415,8 @@ bool MCP23017::getPullup8(uint8_t port, uint8_t &mask)
|
|||||||
_error = MCP23017_PORT_ERROR;
|
_error = MCP23017_PORT_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (port == 0) mask = readReg(MCP23017_PUR_A);
|
if (port == 0) mask = readReg(MCP23x17_PUR_A);
|
||||||
if (port == 1) mask = readReg(MCP23017_PUR_B);
|
if (port == 1) mask = readReg(MCP23x17_PUR_B);
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -439,15 +425,15 @@ bool MCP23017::getPullup8(uint8_t port, uint8_t &mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// 16 pins interface
|
// 16 pins interface
|
||||||
|
//
|
||||||
// two register at once
|
// two register at once
|
||||||
// value = 0x0000..0xFFFF bit pattern
|
// value = 0x0000..0xFFFF bit pattern
|
||||||
bool MCP23017::pinMode16(uint16_t value)
|
bool MCP23017::pinMode16(uint16_t value)
|
||||||
{
|
{
|
||||||
writeReg(MCP23017_DDR_A, value >> 8);
|
writeReg16(MCP23x17_DDR_A, value);
|
||||||
writeReg(MCP23017_DDR_B, value & 0xFF);
|
|
||||||
_error = MCP23017_OK;
|
_error = MCP23017_OK;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -456,8 +442,7 @@ bool MCP23017::pinMode16(uint16_t value)
|
|||||||
// value = 0x0000..0xFFFF bit pattern
|
// value = 0x0000..0xFFFF bit pattern
|
||||||
bool MCP23017::write16(uint16_t value)
|
bool MCP23017::write16(uint16_t value)
|
||||||
{
|
{
|
||||||
writeReg(MCP23017_GPIO_A, value >> 8);
|
writeReg16(MCP23x17_GPIO_A, value);
|
||||||
writeReg(MCP23017_GPIO_B, value & 0xFF);
|
|
||||||
_error = MCP23017_OK;
|
_error = MCP23017_OK;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -467,9 +452,7 @@ bool MCP23017::write16(uint16_t value)
|
|||||||
uint16_t MCP23017::read16()
|
uint16_t MCP23017::read16()
|
||||||
{
|
{
|
||||||
_error = MCP23017_OK;
|
_error = MCP23017_OK;
|
||||||
uint16_t value = readReg(MCP23017_GPIO_A);
|
uint16_t value = readReg16(MCP23x17_GPIO_A);
|
||||||
value <<= 8;
|
|
||||||
value += readReg(MCP23017_GPIO_B);
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,8 +460,7 @@ uint16_t MCP23017::read16()
|
|||||||
// mask = 0x0000..0xFFFF bit pattern
|
// mask = 0x0000..0xFFFF bit pattern
|
||||||
bool MCP23017::setPolarity16(uint16_t mask)
|
bool MCP23017::setPolarity16(uint16_t mask)
|
||||||
{
|
{
|
||||||
writeReg(MCP23017_POL_A, mask >> 8);
|
writeReg16(MCP23x17_POL_A, mask);
|
||||||
writeReg(MCP23017_POL_B, mask & 0xFF);
|
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -490,9 +472,7 @@ bool MCP23017::setPolarity16(uint16_t mask)
|
|||||||
// mask = 0x0000..0xFFFF bit pattern
|
// mask = 0x0000..0xFFFF bit pattern
|
||||||
bool MCP23017::getPolarity16(uint16_t &mask)
|
bool MCP23017::getPolarity16(uint16_t &mask)
|
||||||
{
|
{
|
||||||
mask = readReg(MCP23017_POL_A);
|
mask = readReg16(MCP23x17_POL_A);
|
||||||
mask <<= 8;
|
|
||||||
mask += readReg(MCP23017_POL_B);
|
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -504,8 +484,7 @@ bool MCP23017::getPolarity16(uint16_t &mask)
|
|||||||
// mask = 0x0000..0xFFFF bit pattern
|
// mask = 0x0000..0xFFFF bit pattern
|
||||||
bool MCP23017::setPullup16(uint16_t mask)
|
bool MCP23017::setPullup16(uint16_t mask)
|
||||||
{
|
{
|
||||||
writeReg(MCP23017_PUR_A, mask >> 8);
|
writeReg16(MCP23x17_PUR_A, mask);
|
||||||
writeReg(MCP23017_PUR_B, mask & 0xFF);
|
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -517,9 +496,7 @@ bool MCP23017::setPullup16(uint16_t mask)
|
|||||||
// mask = 0x0000..0xFFFF bit pattern
|
// mask = 0x0000..0xFFFF bit pattern
|
||||||
bool MCP23017::getPullup16(uint16_t &mask)
|
bool MCP23017::getPullup16(uint16_t &mask)
|
||||||
{
|
{
|
||||||
mask = readReg(MCP23017_PUR_A);
|
mask = readReg16(MCP23x17_PUR_A);
|
||||||
mask <<= 8;
|
|
||||||
mask += readReg(MCP23017_PUR_B);
|
|
||||||
if (_error != MCP23017_OK)
|
if (_error != MCP23017_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -528,21 +505,198 @@ bool MCP23017::getPullup16(uint16_t &mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// INTERRUPTS (experimental, see MCP23S17 - #40)
|
||||||
|
//
|
||||||
|
// TODO, catch writeReg errors
|
||||||
|
// TODO, MCP23x17_INT_MODE_ERROR?
|
||||||
|
// TODO, if register not changed no need to update?
|
||||||
|
// TODO, 8 bits optimize? more code vs speed?
|
||||||
|
//
|
||||||
|
// pin = 0..15, mode = { RISING, FALLING, CHANGE }
|
||||||
|
bool MCP23017::enableInterrupt(uint8_t pin, uint8_t mode)
|
||||||
|
{
|
||||||
|
if (pin > 15)
|
||||||
|
{
|
||||||
|
_error = MCP23017_PIN_ERROR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right mode
|
||||||
|
uint16_t intcon = readReg16(MCP23x17_INTCON_A);
|
||||||
|
if (mode == CHANGE)
|
||||||
|
{
|
||||||
|
// compare to previous value.
|
||||||
|
intcon &= ~(1 << pin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint16_t defval = readReg16(MCP23x17_DEFVAL_A);
|
||||||
|
if (mode == RISING)
|
||||||
|
{
|
||||||
|
intcon |= (1 << pin);
|
||||||
|
defval &= ~(1 << pin); // RISING == compare to 0
|
||||||
|
}
|
||||||
|
else if (mode == FALLING)
|
||||||
|
{
|
||||||
|
intcon |= (1 << pin);
|
||||||
|
defval |= ~(1 << pin); // FALLING == compare to 1
|
||||||
|
}
|
||||||
|
writeReg16(MCP23x17_DEFVAL_A, defval);
|
||||||
|
}
|
||||||
|
writeReg16(MCP23x17_INTCON_A, intcon);
|
||||||
|
|
||||||
|
// enable interrupt
|
||||||
|
uint16_t value = readReg16(MCP23x17_GPINTEN_A);
|
||||||
|
value |= (1 << pin);
|
||||||
|
return writeReg16(MCP23x17_GPINTEN_A, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::disableInterrupt(uint8_t pin)
|
||||||
|
{
|
||||||
|
if (pin > 15)
|
||||||
|
{
|
||||||
|
_error = MCP23017_PIN_ERROR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// disable interrupt
|
||||||
|
uint16_t value = readReg16(MCP23x17_GPINTEN_A);
|
||||||
|
value &= ~(1 << pin);
|
||||||
|
return writeReg16(MCP23x17_GPINTEN_A, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::enableInterrupt16(uint16_t mask, uint8_t mode)
|
||||||
|
{
|
||||||
|
uint16_t intcon = 0, defval = 0;
|
||||||
|
// right mode
|
||||||
|
if (mode == CHANGE)
|
||||||
|
{
|
||||||
|
// compare to previous value.
|
||||||
|
intcon = ~mask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mode == RISING)
|
||||||
|
{
|
||||||
|
intcon = mask;
|
||||||
|
defval = ~mask; // RISING == compare to 0
|
||||||
|
}
|
||||||
|
else if (mode == FALLING)
|
||||||
|
{
|
||||||
|
intcon = mask;
|
||||||
|
defval = mask; // FALLING == compare to 1
|
||||||
|
}
|
||||||
|
writeReg16(MCP23x17_DEFVAL_A, defval);
|
||||||
|
}
|
||||||
|
writeReg16(MCP23x17_INTCON_A, intcon);
|
||||||
|
|
||||||
|
// enable the mask
|
||||||
|
writeReg16(MCP23x17_GPINTEN_A, mask);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::disableInterrupt16(uint16_t mask)
|
||||||
|
{
|
||||||
|
return writeReg16(MCP23x17_GPINTEN_A, ~mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// which pins caused the INT?
|
||||||
|
uint16_t MCP23017::getInterruptFlagRegister()
|
||||||
|
{
|
||||||
|
return readReg16(MCP23x17_INTF_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t MCP23017::getInterruptCaptureRegister()
|
||||||
|
{
|
||||||
|
return readReg16(MCP23x17_INTCAP_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// polarity: 0 = LOW, 1 = HIGH, 2 = NONE/ODR
|
||||||
|
bool MCP23017::setInterruptPolarity(uint8_t polarity)
|
||||||
|
{
|
||||||
|
if (polarity > 2) return false;
|
||||||
|
uint8_t reg = readReg(MCP23x17_IOCR);
|
||||||
|
reg &= ~(MCP23x17_IOCR_ODR | MCP23x17_IOCR_INTPOL);
|
||||||
|
// LOW is default set.
|
||||||
|
if (polarity == 2) reg |= MCP23x17_IOCR_ODR;
|
||||||
|
if (polarity == 1) reg |= MCP23x17_IOCR_INTPOL;
|
||||||
|
return writeReg(MCP23x17_IOCR, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t MCP23017::getInterruptPolarity()
|
||||||
|
{
|
||||||
|
uint8_t reg = readReg(MCP23x17_IOCR);
|
||||||
|
if (reg & MCP23x17_IOCR_ODR) return 2;
|
||||||
|
if (reg & MCP23x17_IOCR_INTPOL) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::mirrorInterrupts(bool on)
|
||||||
|
{
|
||||||
|
if (on) return enableControlRegister(MCP23x17_IOCR_MIRROR);
|
||||||
|
return disableControlRegister(MCP23x17_IOCR_MIRROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::isMirroredInterrupts()
|
||||||
|
{
|
||||||
|
return (readReg(MCP23x17_IOCR) & MCP23x17_IOCR_MIRROR) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// MISC
|
||||||
|
//
|
||||||
int MCP23017::lastError()
|
int MCP23017::lastError()
|
||||||
{
|
{
|
||||||
int e = _error;
|
int e = _error;
|
||||||
_error = MCP23017_OK; // reset error after read.
|
_error = MCP23017_OK; // reset error after read.
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::enableControlRegister(uint8_t mask)
|
||||||
|
{
|
||||||
|
uint8_t reg = readReg(MCP23x17_IOCR);
|
||||||
|
reg |= mask;
|
||||||
|
return writeReg(MCP23x17_IOCR, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCP23017::disableControlRegister(uint8_t mask)
|
||||||
|
{
|
||||||
|
uint8_t reg = readReg(MCP23x17_IOCR);
|
||||||
|
reg &= ~mask;
|
||||||
|
return writeReg(MCP23x17_IOCR, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// PRIVATE
|
// PROTECTED
|
||||||
//
|
//
|
||||||
|
|
||||||
bool MCP23017::writeReg(uint8_t reg, uint8_t value)
|
bool MCP23017::writeReg(uint8_t reg, uint8_t value)
|
||||||
{
|
{
|
||||||
|
_error = MCP23017_OK;
|
||||||
|
|
||||||
|
if (reg > MCP23x17_OLAT_B)
|
||||||
|
{
|
||||||
|
_error = MCP23017_REGISTER_ERROR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start write
|
||||||
_wire->beginTransmission(_address);
|
_wire->beginTransmission(_address);
|
||||||
_wire->write(reg);
|
_wire->write(reg);
|
||||||
_wire->write(value);
|
_wire->write(value);
|
||||||
@ -551,13 +705,23 @@ bool MCP23017::writeReg(uint8_t reg, uint8_t value)
|
|||||||
_error = MCP23017_I2C_ERROR;
|
_error = MCP23017_I2C_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_error = MCP23017_OK;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t MCP23017::readReg(uint8_t reg)
|
uint8_t MCP23017::readReg(uint8_t reg)
|
||||||
{
|
{
|
||||||
|
uint8_t rv = 0;
|
||||||
|
|
||||||
|
_error = MCP23017_OK;
|
||||||
|
|
||||||
|
if (reg > MCP23x17_OLAT_B)
|
||||||
|
{
|
||||||
|
_error = MCP23017_REGISTER_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start read
|
||||||
_wire->beginTransmission(_address);
|
_wire->beginTransmission(_address);
|
||||||
_wire->write(reg);
|
_wire->write(reg);
|
||||||
if (_wire->endTransmission() != 0)
|
if (_wire->endTransmission() != 0)
|
||||||
@ -565,17 +729,73 @@ uint8_t MCP23017::readReg(uint8_t reg)
|
|||||||
_error = MCP23017_I2C_ERROR;
|
_error = MCP23017_I2C_ERROR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_error = MCP23017_OK;
|
|
||||||
}
|
|
||||||
uint8_t n = _wire->requestFrom(_address, (uint8_t)1);
|
uint8_t n = _wire->requestFrom(_address, (uint8_t)1);
|
||||||
if (n != 1)
|
if (n != 1)
|
||||||
{
|
{
|
||||||
_error = MCP23017_I2C_ERROR;
|
_error = MCP23017_I2C_ERROR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return _wire->read();
|
rv = _wire->read();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// writes HIGH byte first, LOW byte last
|
||||||
|
bool MCP23017::writeReg16(uint8_t reg, uint16_t value)
|
||||||
|
{
|
||||||
|
_error = MCP23017_OK;
|
||||||
|
|
||||||
|
if (reg > MCP23x17_OLAT_B)
|
||||||
|
{
|
||||||
|
_error = MCP23017_REGISTER_ERROR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start write
|
||||||
|
_wire->beginTransmission(_address);
|
||||||
|
_wire->write(reg);
|
||||||
|
_wire->write(value >> 8);
|
||||||
|
_wire->write(value && 0xFF);
|
||||||
|
if (_wire->endTransmission() != 0)
|
||||||
|
{
|
||||||
|
_error = MCP23017_I2C_ERROR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t MCP23017::readReg16(uint8_t reg)
|
||||||
|
{
|
||||||
|
uint16_t rv = 0;
|
||||||
|
|
||||||
|
_error = MCP23017_OK;
|
||||||
|
|
||||||
|
if (reg > MCP23x17_OLAT_B)
|
||||||
|
{
|
||||||
|
_error = MCP23017_REGISTER_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start read
|
||||||
|
_wire->beginTransmission(_address);
|
||||||
|
_wire->write(reg);
|
||||||
|
if (_wire->endTransmission() != 0)
|
||||||
|
{
|
||||||
|
_error = MCP23017_I2C_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t n = _wire->requestFrom(_address, (uint8_t)2);
|
||||||
|
if (n != 2)
|
||||||
|
{
|
||||||
|
_error = MCP23017_I2C_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rv = _wire->read() << 8;
|
||||||
|
rv += _wire->read();
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// FILE: MCP23017.h
|
// FILE: MCP23017.h
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// VERSION: 0.6.2
|
// VERSION: 0.6.3
|
||||||
// PURPOSE: Arduino library for I2C MCP23017 16 channel port expander
|
// PURPOSE: Arduino library for I2C MCP23017 16 channel port expander
|
||||||
// DATE: 2019-10-12
|
// DATE: 2019-10-12
|
||||||
// URL: https://github.com/RobTillaart/MCP23017_RT
|
// URL: https://github.com/RobTillaart/MCP23017_RT
|
||||||
@ -12,18 +12,18 @@
|
|||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include "Wire.h"
|
#include "Wire.h"
|
||||||
|
#include "MCP23x17_registers.h"
|
||||||
|
|
||||||
|
|
||||||
#define MCP23017_LIB_VERSION (F("0.6.2"))
|
#define MCP23017_LIB_VERSION (F("0.6.3"))
|
||||||
|
|
||||||
#define MCP23017_OK 0x00
|
#define MCP23017_OK 0x00
|
||||||
#define MCP23017_PIN_ERROR 0x81
|
#define MCP23017_PIN_ERROR 0x81
|
||||||
#define MCP23017_I2C_ERROR 0x82
|
#define MCP23017_I2C_ERROR 0x82
|
||||||
#define MCP23017_VALUE_ERROR 0x83
|
#define MCP23017_VALUE_ERROR 0x83
|
||||||
#define MCP23017_PORT_ERROR 0x84
|
#define MCP23017_PORT_ERROR 0x84
|
||||||
|
#define MCP23017_REGISTER_ERROR 0xFF
|
||||||
|
#define MCP23017_INVALID_READ 0xFF
|
||||||
#define MCP23017_INVALID_READ -100
|
|
||||||
|
|
||||||
|
|
||||||
class MCP23017
|
class MCP23017
|
||||||
@ -37,7 +37,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
// single pin interface
|
// single pin interface
|
||||||
// mode = INPUT, OUTPUT or INPUT_PULLUP (==INPUT)
|
// mode: 0 = OUTPUT, 1 = INPUT, 1 = INPUT_PULLUP (==INPUT)
|
||||||
bool pinMode1(uint8_t pin, uint8_t mode);
|
bool pinMode1(uint8_t pin, uint8_t mode);
|
||||||
bool write1(uint8_t pin, uint8_t value);
|
bool write1(uint8_t pin, uint8_t value);
|
||||||
uint8_t read1(uint8_t pin);
|
uint8_t read1(uint8_t pin);
|
||||||
@ -72,11 +72,43 @@ public:
|
|||||||
bool setPullup16(uint16_t mask);
|
bool setPullup16(uint16_t mask);
|
||||||
bool getPullup16(uint16_t &mask);
|
bool getPullup16(uint16_t &mask);
|
||||||
|
|
||||||
|
|
||||||
|
// INTERRUPTS (experimental)
|
||||||
|
// pin = 0..15, mode = { RISING, FALLING, CHANGE }
|
||||||
|
bool enableInterrupt(uint8_t pin, uint8_t mode);
|
||||||
|
bool disableInterrupt(uint8_t pin);
|
||||||
|
|
||||||
|
// mask = 0x0000..0xFFFF (overrides all earlier settings.
|
||||||
|
bool enableInterrupt16(uint16_t mask, uint8_t mode);
|
||||||
|
bool disableInterrupt16(uint16_t mask);
|
||||||
|
|
||||||
|
// which pins caused the INT?
|
||||||
|
uint16_t getInterruptFlagRegister();
|
||||||
|
uint16_t getInterruptCaptureRegister();
|
||||||
|
|
||||||
|
// polarity: 0 = LOW, 1 = HIGH, 2 = NONE/ODR
|
||||||
|
bool setInterruptPolarity(uint8_t polarity);
|
||||||
|
uint8_t getInterruptPolarity();
|
||||||
|
|
||||||
|
// merge INTA and INTB
|
||||||
|
bool mirrorInterrupts(bool on);
|
||||||
|
bool isMirroredInterrupts();
|
||||||
|
|
||||||
|
// debugging
|
||||||
int lastError();
|
int lastError();
|
||||||
|
|
||||||
|
// set/clear IOCR bit fields
|
||||||
|
bool enableControlRegister(uint8_t mask);
|
||||||
|
bool disableControlRegister(uint8_t mask);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// access to low level registers (just make these functions public).
|
||||||
|
// USE WITH CARE !!!
|
||||||
bool writeReg(uint8_t reg, uint8_t value);
|
bool writeReg(uint8_t reg, uint8_t value);
|
||||||
uint8_t readReg(uint8_t reg);
|
uint8_t readReg(uint8_t reg);
|
||||||
|
bool writeReg16(uint8_t reg, uint16_t value);
|
||||||
|
uint16_t readReg16(uint8_t reg);
|
||||||
|
|
||||||
uint8_t _address;
|
uint8_t _address;
|
||||||
TwoWire* _wire;
|
TwoWire* _wire;
|
||||||
|
47
libraries/MCP23017_RT/MCP23x17_registers.h
Normal file
47
libraries/MCP23017_RT/MCP23x17_registers.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
//
|
||||||
|
// FILE: MCP23x17_registers.h
|
||||||
|
// AUTHOR: Rob Tillaart
|
||||||
|
// PURPOSE: MCP23x17 register file
|
||||||
|
// URL: https://github.com/RobTillaart/MCP23017_RT
|
||||||
|
// URL: https://github.com/RobTillaart/MCP23S17
|
||||||
|
|
||||||
|
|
||||||
|
// REGISTERS // description datasheet
|
||||||
|
#define MCP23x17_DDR_A 0x00 // Data Direction Register A P18
|
||||||
|
#define MCP23x17_DDR_B 0x01 // Data Direction Register B P18
|
||||||
|
#define MCP23x17_POL_A 0x02 // Input Polarity A P18
|
||||||
|
#define MCP23x17_POL_B 0x03 // Input Polarity B P18
|
||||||
|
#define MCP23x17_GPINTEN_A 0x04 // Interrupt enable P19
|
||||||
|
#define MCP23x17_GPINTEN_B 0x05 // Interrupt enable P19
|
||||||
|
#define MCP23x17_DEFVAL_A 0x06 // Interrupt default P19
|
||||||
|
#define MCP23x17_DEFVAL_B 0x07 // Interrupt default P19
|
||||||
|
#define MCP23x17_INTCON_A 0x08 // Interrupt control register P20
|
||||||
|
#define MCP23x17_INTCON_B 0x09 // Interrupt control register P20
|
||||||
|
#define MCP23x17_IOCR 0x0A // IO control register P20
|
||||||
|
#define MCP23x17_IOCR2 0x0B // NOT USED
|
||||||
|
#define MCP23x17_PUR_A 0x0C // Pull Up Resistors A P22
|
||||||
|
#define MCP23x17_PUR_B 0x0D // Pull Up Resistors A P22
|
||||||
|
#define MCP23x17_INTF_A 0x0E // Interrupt flag register P22
|
||||||
|
#define MCP23x17_INTF_B 0x0F // Interrupt flag register P22
|
||||||
|
#define MCP23x17_INTCAP_A 0x10 // Interrupt capture register P23
|
||||||
|
#define MCP23x17_INTCAP_B 0x11 // Interrupt capture register P23
|
||||||
|
#define MCP23x17_GPIO_A 0x12 // General Purpose IO A P23
|
||||||
|
#define MCP23x17_GPIO_B 0x13 // General Purpose IO B P23
|
||||||
|
#define MCP23x17_OLAT_A 0x14 // NOT USED output latch P24
|
||||||
|
#define MCP23x17_OLAT_B 0x15 // NOT USED
|
||||||
|
|
||||||
|
|
||||||
|
// IOCR = IO CONTROL REGISTER bit masks - details datasheet P20
|
||||||
|
#define MCP23x17_IOCR_BANK 0x80 // Controls how the registers are addressed.
|
||||||
|
#define MCP23x17_IOCR_MIRROR 0x40 // INT Pins Mirror bit.
|
||||||
|
#define MCP23x17_IOCR_SEQOP 0x20 // Sequential Operation mode bit.
|
||||||
|
#define MCP23x17_IOCR_DISSLW 0x10 // Slew Rate control bit for SDA output.
|
||||||
|
#define MCP23x17_IOCR_HAEN 0x08 // Hardware Address Enable bit (MCP23S17 only).
|
||||||
|
#define MCP23x17_IOCR_ODR 0x04 // Configures the INT pin as an open-drain output.
|
||||||
|
#define MCP23x17_IOCR_INTPOL 0x02 // This bit sets the polarity of the INT output pin.
|
||||||
|
#define MCP23x17_IOCR_NI 0x01 // Not implemented.
|
||||||
|
|
||||||
|
|
||||||
|
// -- END OF FILE --
|
||||||
|
|
@ -18,7 +18,7 @@ Arduino library for MCP23017 16 channel I2C port expander.
|
|||||||
|
|
||||||
This library gives easy control over the 16 pins of a (I2C) MCP23017 chip.
|
This library gives easy control over the 16 pins of a (I2C) MCP23017 chip.
|
||||||
|
|
||||||
This IC is strongly related tot the MCP23S17 SPI port expander - https://github.com/RobTillaart/MCP23S17
|
This IC is strongly related to the MCP23S17 SPI port expander - https://github.com/RobTillaart/MCP23S17
|
||||||
Programming Interface is kept the same as much as possible.
|
Programming Interface is kept the same as much as possible.
|
||||||
|
|
||||||
The **write1(pin, value)** is optimized.
|
The **write1(pin, value)** is optimized.
|
||||||
@ -44,7 +44,7 @@ Some details see:
|
|||||||
|
|
||||||
Note: the library has no provisions (yet) for detecting DEV D chips or handle them in a special way.
|
Note: the library has no provisions (yet) for detecting DEV D chips or handle them in a special way.
|
||||||
There is an idea to implement a derived class MCP23017_REVD that provides automatic support.
|
There is an idea to implement a derived class MCP23017_REVD that provides automatic support.
|
||||||
However low prio.
|
However low priority.
|
||||||
|
|
||||||
Note that the MCP23S017 (SPI version) does not have this "feature" for GPA7 and GPB7.
|
Note that the MCP23S017 (SPI version) does not have this "feature" for GPA7 and GPB7.
|
||||||
|
|
||||||
@ -87,6 +87,24 @@ Supports 100kHz, 400kHz and 1.7MHz
|
|||||||
TODO - add performance data
|
TODO - add performance data
|
||||||
|
|
||||||
|
|
||||||
|
#### I2C multiplexing
|
||||||
|
|
||||||
|
Sometimes you need to control more devices than possible with the default
|
||||||
|
address range the device provides.
|
||||||
|
This is possible with an I2C multiplexer e.g. TCA9548 which creates up
|
||||||
|
to eight channels (think of it as I2C subnets) which can use the complete
|
||||||
|
address range of the device.
|
||||||
|
|
||||||
|
Drawback of using a multiplexer is that it takes more administration in
|
||||||
|
your code e.g. which device is on which channel.
|
||||||
|
This will slow down the access, which must be taken into account when
|
||||||
|
deciding which devices are on which channel.
|
||||||
|
Also note that switching between channels will slow down other devices
|
||||||
|
too if they are behind the multiplexer.
|
||||||
|
|
||||||
|
- https://github.com/RobTillaart/TCA9548
|
||||||
|
|
||||||
|
|
||||||
#### Related
|
#### Related
|
||||||
|
|
||||||
16 bit port expanders
|
16 bit port expanders
|
||||||
@ -119,7 +137,7 @@ Can be overruled with Wire0..WireN.
|
|||||||
Default sets the pins to INPUT PULLUP.
|
Default sets the pins to INPUT PULLUP.
|
||||||
Returns false if not connected or a register could not be set.
|
Returns false if not connected or a register could not be set.
|
||||||
- **bool isConnected()** returns true if connected, false otherwise.
|
- **bool isConnected()** returns true if connected, false otherwise.
|
||||||
- **uint8_t getADdress()** returns address set in the constructor.
|
- **uint8_t getAddress()** returns the address set in the constructor.
|
||||||
|
|
||||||
|
|
||||||
### Single pin interface
|
### Single pin interface
|
||||||
@ -142,8 +160,7 @@ Please note REVD remarks at top.
|
|||||||
- **bool pinMode8(uint8_t port, uint8_t value)** port = 0..1, value = 0..255. Returns true if successful.
|
- **bool pinMode8(uint8_t port, uint8_t value)** port = 0..1, value = 0..255. Returns true if successful.
|
||||||
- **bool write8(uint8_t port, uint8_t value)** port = 0..1, value = 0..255. Returns true if successful.
|
- **bool write8(uint8_t port, uint8_t value)** port = 0..1, value = 0..255. Returns true if successful.
|
||||||
- **uint8_t read8(uint8_t port)** port = 0..1, reads 8 pins into one byte.
|
- **uint8_t read8(uint8_t port)** port = 0..1, reads 8 pins into one byte.
|
||||||
- **bool setPolarity8(uint8_t port, uint8_t mask)** port = 0..1, sets polarity
|
- **bool setPolarity8(uint8_t port, uint8_t mask)** port = 0..1, sets polarity for 8 channels at once.
|
||||||
for 8 channels at once.
|
|
||||||
Returns true if successful.
|
Returns true if successful.
|
||||||
- **bool getPolarity8(uint8_t port, uint8_t &mask)** port = 0..1, reads polarity of 8 channels at once.
|
- **bool getPolarity8(uint8_t port, uint8_t &mask)** port = 0..1, reads polarity of 8 channels at once.
|
||||||
Returns true if successful.
|
Returns true if successful.
|
||||||
@ -157,8 +174,8 @@ Returns true if successful.
|
|||||||
|
|
||||||
Please note REVD remarks at top.
|
Please note REVD remarks at top.
|
||||||
|
|
||||||
- **bool pinMode16(uint16_t value)** value = 0..0xFFFF. Returns true if successful.
|
- **bool pinMode16(uint16_t value)** value = 0..0xFFFF, returns true if successful.
|
||||||
- **bool write16(uint16_t value)** value = 0..0xFFFF. Returns true if successful.
|
- **bool write16(uint16_t value)** value = 0..0xFFFF, returns true if successful.
|
||||||
- **uint16_t read16()** reads 16 pins into an uint16_t.
|
- **uint16_t read16()** reads 16 pins into an uint16_t.
|
||||||
- **bool setPolarity16(uint16_t mask)** sets polarity for 16 channels.
|
- **bool setPolarity16(uint16_t mask)** sets polarity for 16 channels.
|
||||||
Returns true if successful.
|
Returns true if successful.
|
||||||
@ -169,6 +186,69 @@ Returns true if successful.
|
|||||||
- **bool getPullup16(uint16_t &mask)** reads pull-up for 16 channels.
|
- **bool getPullup16(uint16_t &mask)** reads pull-up for 16 channels.
|
||||||
Returns true if successful.
|
Returns true if successful.
|
||||||
|
|
||||||
|
The reading and writing to registers have been performance optimized for the 16 bit interface.
|
||||||
|
If there are problems please open an issue.
|
||||||
|
|
||||||
|
|
||||||
|
### Interrupts (experimental 0.6.3)
|
||||||
|
|
||||||
|
Read the datasheet for the details, page 24,25.
|
||||||
|
Note: Error handling is limited.
|
||||||
|
|
||||||
|
pin = 0..15
|
||||||
|
mode = { RISING, FALLING, CHANGE }
|
||||||
|
- **bool enableInterrupt(uint8_t pin, uint8_t mode)**
|
||||||
|
Returns true if successful.
|
||||||
|
Returns MCP23017_PIN_ERROR if pin > 15.
|
||||||
|
- **bool disableInterrupt(uint8_t pin)**
|
||||||
|
Returns true if successful.
|
||||||
|
Returns MCP23017_PIN_ERROR if pin > 15.
|
||||||
|
|
||||||
|
|
||||||
|
16 pin interface, overrides all earlier settings.
|
||||||
|
Sets all pins to the same interrupt mode { RISING, FALLING, CHANGE }.
|
||||||
|
- **bool enableInterrupt16(uint16_t mask, uint8_t mode)** mask = 0x0000..0xFFFF.
|
||||||
|
- **bool disableInterrupt16(uint16_t mask)**
|
||||||
|
|
||||||
|
|
||||||
|
Determine which pins caused the Interrupt. (datasheet).
|
||||||
|
- **uint16_t getInterruptFlagRegister()** Reads all 16 pins.
|
||||||
|
- **uint16_t getInterruptCaptureRegister()** Reads all 16 pins.
|
||||||
|
Is used to detect if multiple pins triggered an interrupt.
|
||||||
|
|
||||||
|
|
||||||
|
- **bool setInterruptPolarity(uint8_t ipol)** polarity: 0 = LOW, 1 = HIGH, 2 = NONE/ODR
|
||||||
|
- **uint8_t getInterruptPolarity()** return set value.
|
||||||
|
|
||||||
|
|
||||||
|
Merge INTA and INTB into one signal so only one line handles all interrupts.
|
||||||
|
This reduces the number of interrupt lines to handle, however one has
|
||||||
|
to read more registers to find the changed ones.
|
||||||
|
|
||||||
|
- **bool mirrorInterrupts(bool on)** enables / disables mirror mode.
|
||||||
|
- **bool isMirroredInterrupts()** returns set option (0,1 or 2).
|
||||||
|
|
||||||
|
|
||||||
|
### IO Control Register
|
||||||
|
|
||||||
|
The library supports setting bit fields in the IO control register.
|
||||||
|
Read the datasheet carefully!
|
||||||
|
|
||||||
|
- **bool enableControlRegister(uint8_t mask)** set IOCR bit fields
|
||||||
|
- **bool disableControlRegister(uint8_t mask)** clear IOCR bit fields
|
||||||
|
|
||||||
|
|
||||||
|
| constant | mask | description |
|
||||||
|
|:-----------------------|:------:|:--------------|
|
||||||
|
| MCP23x17_IOCR_BANK | 0x80 | Controls how the registers are addressed.
|
||||||
|
| MCP23x17_IOCR_MIRROR | 0x40 | INT Pins Mirror bit.
|
||||||
|
| MCP23x17_IOCR_SEQOP | 0x20 | Sequential Operation mode bit.
|
||||||
|
| MCP23x17_IOCR_DISSLW | 0x10 | Slew Rate control bit for SDA output.
|
||||||
|
| MCP23x17_IOCR_HAEN | 0x08 | Hardware Address Enable bit (MCP23S17 only).
|
||||||
|
| MCP23x17_IOCR_ODR | 0x04 | Configures the INT pin as an open-drain output.
|
||||||
|
| MCP23x17_IOCR_INTPOL | 0x02 | This bit sets the polarity of the INT output pin.
|
||||||
|
| MCP23x17_IOCR_NI | 0x01 | Not implemented.
|
||||||
|
|
||||||
|
|
||||||
### Error codes
|
### Error codes
|
||||||
|
|
||||||
@ -177,18 +257,19 @@ If one of the above functions return false, there might be an error.
|
|||||||
- **int lastError()** Above functions set an error flag that can be read with this function.
|
- **int lastError()** Above functions set an error flag that can be read with this function.
|
||||||
Reading it will reset the flag to **MCP23017_OK**.
|
Reading it will reset the flag to **MCP23017_OK**.
|
||||||
|
|
||||||
| Description | Value |
|
| name | value | description |
|
||||||
|:-----------------------|:-------:|
|
|:--------------------------|:-------:|:--------------|
|
||||||
| MCP23017_OK | 0x00 |
|
| MCP23017_OK | 0x00 | No error |
|
||||||
| MCP23017_PIN_ERROR | 0x81 |
|
| MCP23017_PIN_ERROR | 0x81 |
|
||||||
| MCP23017_I2C_ERROR | 0x82 |
|
| MCP23017_I2C_ERROR | 0x82 | (compatibility)
|
||||||
| MCP23017_VALUE_ERROR | 0x83 |
|
| MCP23017_VALUE_ERROR | 0x83 |
|
||||||
| MCP23017_PORT_ERROR | 0x84 |
|
| MCP23017_PORT_ERROR | 0x84 |
|
||||||
|
| MCP23017_REGISTER_ERROR | 0xFF | low level.
|
||||||
|
| MCP23017_INVALID_READ | 0xFF | low level.
|
||||||
|
|
||||||
|
|
||||||
## Future
|
## Future
|
||||||
|
|
||||||
|
|
||||||
#### Must
|
#### Must
|
||||||
|
|
||||||
- Improve and extend documentation
|
- Improve and extend documentation
|
||||||
@ -196,15 +277,26 @@ Reading it will reset the flag to **MCP23017_OK**.
|
|||||||
|
|
||||||
#### Should
|
#### Should
|
||||||
|
|
||||||
- extend error codes
|
- keep functional in sync
|
||||||
|
- sync error codes to MCP23x17
|
||||||
|
- buy additional hardware
|
||||||
|
- test with multiple devices.
|
||||||
|
- multi SELECT lines
|
||||||
|
- add example with interrupts
|
||||||
|
- test
|
||||||
|
- extend error codes
|
||||||
- optimize code - squeeze footprint
|
- optimize code - squeeze footprint
|
||||||
|
- fix TODO's in code
|
||||||
- investigate if REV D chips can be detected.
|
- investigate if REV D chips can be detected.
|
||||||
|
|
||||||
#### Could
|
#### Could
|
||||||
|
|
||||||
|
- check need for writing in all functions (Polarity / Pull-up)
|
||||||
|
- check if bit mask changes.
|
||||||
|
- what is performance gain vs footprint?
|
||||||
|
- investigate and reimplement the INPUT_PULLUP for pinMode() ?
|
||||||
- initial value (16 bit?) as begin parameter (breaking change)
|
- initial value (16 bit?) as begin parameter (breaking change)
|
||||||
- depends on input output pull-up etc
|
- depends on input output pull-up etc.
|
||||||
- investigate auto address increment
|
|
||||||
- create a derived class **MCP23017_REVD**
|
- create a derived class **MCP23017_REVD**
|
||||||
|
|
||||||
#### Wont
|
#### Wont
|
||||||
@ -218,3 +310,4 @@ donate through PayPal or GitHub sponsors.
|
|||||||
|
|
||||||
Thank you,
|
Thank you,
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
MCP23017 MCP(0x38);
|
MCP23017 MCP(0x38);
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
@ -53,6 +54,7 @@ void setup()
|
|||||||
Serial.println("done...");
|
Serial.println("done...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
MCP23017 MCP(0x38);
|
MCP23017 MCP(0x38);
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(230400);
|
Serial.begin(230400);
|
||||||
@ -33,6 +34,7 @@ void setup()
|
|||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,23 @@ getPolarity16 KEYWORD2
|
|||||||
setPullup16 KEYWORD2
|
setPullup16 KEYWORD2
|
||||||
getPullup16 KEYWORD2
|
getPullup16 KEYWORD2
|
||||||
|
|
||||||
|
enableInterrupt KEYWORD2
|
||||||
|
disableInterrupt KEYWORD2
|
||||||
|
enableInterrupt16 KEYWORD2
|
||||||
|
disableInterrupt16 KEYWORD2
|
||||||
|
|
||||||
|
getInterruptFlagRegister KEYWORD2
|
||||||
|
getInterruptCaptureRegister KEYWORD2
|
||||||
|
setInterruptPolarity KEYWORD2
|
||||||
|
getInterruptPolarity KEYWORD2
|
||||||
|
|
||||||
|
mirrorInterrupts KEYWORD2
|
||||||
|
isMirroredInterrupts KEYWORD2
|
||||||
|
|
||||||
lastError KEYWORD2
|
lastError KEYWORD2
|
||||||
|
|
||||||
|
enableControlRegister KEYWORD2
|
||||||
|
disableControlRegister KEYWORD2
|
||||||
|
|
||||||
# Instances (KEYWORD2)
|
# Instances (KEYWORD2)
|
||||||
|
|
||||||
@ -50,4 +65,6 @@ MCP23017_PIN_ERROR LITERAL1
|
|||||||
MCP23017_I2C_ERROR LITERAL1
|
MCP23017_I2C_ERROR LITERAL1
|
||||||
MCP23017_VALUE_ERROR LITERAL1
|
MCP23017_VALUE_ERROR LITERAL1
|
||||||
MCP23017_PORT_ERROR LITERAL1
|
MCP23017_PORT_ERROR LITERAL1
|
||||||
|
MCP23017_REGISTER_ERROR LITERAL1
|
||||||
|
MCP23017_INVALID_READ LITERAL1
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/RobTillaart/MCP23017_RT.git"
|
"url": "https://github.com/RobTillaart/MCP23017_RT.git"
|
||||||
},
|
},
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"frameworks": "*",
|
"frameworks": "*",
|
||||||
"platforms": "*",
|
"platforms": "*",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=MCP23017_RT
|
name=MCP23017_RT
|
||||||
version=0.6.2
|
version=0.6.3
|
||||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
sentence=Arduino library for I2C MCP23017 16 channel port expander 16 IO-lines
|
sentence=Arduino library for I2C MCP23017 16 channel port expander 16 IO-lines
|
||||||
|
@ -49,12 +49,13 @@ unittest_teardown()
|
|||||||
|
|
||||||
unittest(test_constants)
|
unittest(test_constants)
|
||||||
{
|
{
|
||||||
assertEqual(MCP23017_OK , 0x00);
|
assertEqual(MCP23017_OK , 0x00);
|
||||||
assertEqual(MCP23017_PIN_ERROR , 0x81);
|
assertEqual(MCP23017_PIN_ERROR , 0x81);
|
||||||
assertEqual(MCP23017_I2C_ERROR , 0x82);
|
assertEqual(MCP23017_I2C_ERROR , 0x82);
|
||||||
assertEqual(MCP23017_VALUE_ERROR , 0x83);
|
assertEqual(MCP23017_VALUE_ERROR , 0x83);
|
||||||
assertEqual(MCP23017_PORT_ERROR , 0x84);
|
assertEqual(MCP23017_PORT_ERROR , 0x84);
|
||||||
assertEqual(MCP23017_INVALID_READ, -100);
|
assertEqual(MCP23017_REGISTER_ERROR, 0xFF);
|
||||||
|
assertEqual(MCP23017_INVALID_READ , 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user