Skip to content

Commit 15b2316

Browse files
authored
Merge pull request #78 from maziu/master
HW Address pins support
2 parents 667cd73 + 33657b3 commit 15b2316

File tree

5 files changed

+62
-6
lines changed

5 files changed

+62
-6
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ MCP23x08 Pin # | MCP23x17 Pin # | Pin Name | Pin ID
3535
-- | 7 | GPB6 | 14
3636
-- | 8 | GPB7 | 15
3737

38+
# Use of HW address pins for SPI device
39+
40+
Library supports MCP23Sxx HW pin addressing (A2, A1, A0 for S17 and A1, A0 for S08)
41+
To use it provide HW address to begin_SPI(CS, SPI, HW_ADDR) function, and as a result each SPI message will contain correct chip address.
42+
43+
Example:
44+
mcp.begin_SPI(10, &SPI, 0b101);
45+
46+
MCP23S08 uses addr pins by default. For MCP23S17 address recognition must be enabled by enableAddrPins() function. **NOTE** Calling enableAddrPins() will enable IOCON.HAEN bit for all active (CS low) devices on SPI bus.
47+
**NOTE**
48+
There is hardware bug in the MCP23S17 chip, see "MCP23S17 Rev. A Silicon Errata".
49+
As a result, if using device with A2 = high, and not using addressing, hw address must be set to 0b1XX
50+
In such case, even if not using addressing, initalize your MCP23S17 chip with 0b1XX address, eg: mcp.begin_SPI(10, &SPI, 0b100);.
51+
3852
# Warning
3953

4054
Some people have reported an undocumented bug that can potentially corrupt the I2C bus.

src/Adafruit_MCP23X17.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,35 @@ void Adafruit_MCP23X17::writeGPIOAB(uint16_t value) {
6666
getRegister(MCP23XXX_GPIO, 0), 2);
6767
GPIO.write(value, 2);
6868
}
69+
70+
/**************************************************************************/
71+
/*!
72+
@brief Enable usage of HW address pins (A0, A1, A2) on MCP23S17
73+
74+
Send this message as first message after chip init, as it will
75+
set bits in IOCON register to default (except HAEN)
76+
By default pins are not used and disabled (see README for details)
77+
This message is sent to all devices on bus (no hw_addr is added to msg
78+
as it's not enabled yet)
79+
Due to HW bug in the chip message must be sent twice (to addr 0b000 and
80+
0b1xx)
81+
*/
82+
/**************************************************************************/
83+
void Adafruit_MCP23X17::enableAddrPins() {
84+
if (!spi_dev) // I2C dev always use addr, only makes sense for SPI dev
85+
return;
86+
87+
Adafruit_BusIO_Register GPIOAddr(i2c_dev, spi_dev, MCP23XXX_SPIREG,
88+
getRegister(MCP23XXX_IOCON, 0), 2);
89+
90+
// Send message to address 0b000 regardless of chip addr,
91+
// Because addressing is not yet enabled
92+
uint8_t tmp = this->hw_addr;
93+
this->hw_addr = 0; // Temporary set hw addr to 0
94+
Adafruit_BusIO_Register GPIONoAddr(i2c_dev, spi_dev, MCP23XXX_SPIREG,
95+
getRegister(MCP23XXX_IOCON, 0), 2);
96+
this->hw_addr = tmp;
97+
98+
GPIONoAddr.write((1 << 3), 1); // Bit3: HAEN, devices with A2 = 0
99+
GPIOAddr.write((1 << 3), 1); // Devices with A2 = 1 (if any)
100+
}

src/Adafruit_MCP23X17.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Adafruit_MCP23X17 : public Adafruit_MCP23XXX {
2222
void writeGPIOB(uint8_t value);
2323
uint16_t readGPIOAB();
2424
void writeGPIOAB(uint16_t value);
25+
void enableAddrPins();
2526
};
2627

2728
#endif

src/Adafruit_MCP23XXX.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@ bool Adafruit_MCP23XXX::begin_I2C(uint8_t i2c_addr, TwoWire *wire) {
4040
@brief Initialize MCP using hardware SPI.
4141
@param cs_pin Pin to use for SPI chip select
4242
@param theSPI Pointer to SPI instance
43+
@param _hw_addr Hardware address (pins A2, A1, A0)
4344
@return true if initialization successful, otherwise false.
4445
*/
4546
/**************************************************************************/
46-
bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) {
47+
bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI,
48+
uint8_t _hw_addr) {
49+
this->hw_addr = _hw_addr;
4750
spi_dev = new Adafruit_SPIDevice(cs_pin, 1000000, SPI_BITORDER_MSBFIRST,
4851
SPI_MODE0, theSPI);
4952
return spi_dev->begin();
@@ -56,18 +59,22 @@ bool Adafruit_MCP23XXX::begin_SPI(uint8_t cs_pin, SPIClass *theSPI) {
5659
@param sck_pin Pin to use for SPI clock
5760
@param miso_pin Pin to use for SPI MISO
5861
@param mosi_pin Pin to use for SPI MOSI
62+
@param _hw_addr Hardware address (pins A2, A1, A0)
5963
@return true if initialization successful, otherwise false.
6064
*/
6165
/**************************************************************************/
6266
bool Adafruit_MCP23XXX::begin_SPI(int8_t cs_pin, int8_t sck_pin,
63-
int8_t miso_pin, int8_t mosi_pin) {
67+
int8_t miso_pin, int8_t mosi_pin,
68+
uint8_t _hw_addr) {
69+
this->hw_addr = _hw_addr;
6470
spi_dev = new Adafruit_SPIDevice(cs_pin, sck_pin, miso_pin, mosi_pin);
6571
return spi_dev->begin();
6672
}
6773

6874
/**************************************************************************/
6975
/*!
70-
@brief Configures the specified pin to behave either as an input or an output.
76+
@brief Configures the specified pin to behave either as an input or an
77+
output.
7178
@param pin the Arduino pin number to set the mode of
7279
@param mode INPUT, OUTPUT, or INPUT_PULLUP
7380
*/
@@ -262,5 +269,5 @@ uint16_t Adafruit_MCP23XXX::getRegister(uint8_t baseAddress, uint8_t port) {
262269
reg++;
263270
}
264271
// for SPI, add opcode as high byte
265-
return (spi_dev) ? (0x4000 | reg) : reg;
272+
return (spi_dev) ? (0x4000 | (hw_addr << 9) | reg) : reg;
266273
}

src/Adafruit_MCP23XXX.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ class Adafruit_MCP23XXX {
3939
public:
4040
// init
4141
bool begin_I2C(uint8_t i2c_addr = MCP23XXX_ADDR, TwoWire *wire = &Wire);
42-
bool begin_SPI(uint8_t cs_pin, SPIClass *theSPI = &SPI);
42+
bool begin_SPI(uint8_t cs_pin, SPIClass *theSPI = &SPI,
43+
uint8_t _hw_addr = 0x00);
4344
bool begin_SPI(int8_t cs_pin, int8_t sck_pin, int8_t miso_pin,
44-
int8_t mosi_pin);
45+
int8_t mosi_pin, uint8_t _hw_addr = 0x00);
4546

4647
// main Arduino API methods
4748
void pinMode(uint8_t pin, uint8_t mode);
@@ -62,6 +63,7 @@ class Adafruit_MCP23XXX {
6263
Adafruit_I2CDevice *i2c_dev = NULL; ///< Pointer to I2C bus interface
6364
Adafruit_SPIDevice *spi_dev = NULL; ///< Pointer to SPI bus interface
6465
uint8_t pinCount; ///< Total number of GPIO pins
66+
uint8_t hw_addr; ///< HW address matching A2/A1/A0 pins
6567
uint16_t getRegister(uint8_t baseAddress, uint8_t port = 0);
6668

6769
private:

0 commit comments

Comments
 (0)