9#include "mcp23s17_drv.h"
25 static const uint8_t IODIR_REG = 0x00;
27 static const uint8_t GPINTEN_REG = 0x04;
28 static const uint8_t DEFVAL_REG = 0x06;
29 static const uint8_t INTCON_REG = 0x08;
30 static const uint8_t IOCON_REG = 0x0A;
31 static const uint8_t GPPU_REG = 0x0C;
32 static const uint8_t INTF_REG = 0x0E;
33 static const uint8_t INTCAP_REG = 0x10;
34 static const uint8_t GPIO_REG = 0x12;
35 static const uint8_t OLAT_REG = 0x14;
38mcp23s17_drv::mcp23s17_drv(
spi_interface &hw, uint8_t spi_addr)
39 : _spi(hw), _spi_addr(spi_addr) {
41 _iodir = readRegister(MCP23S17::IODIR_REG);
42 _gppu = readRegister(MCP23S17::GPPU_REG);
43 _olat = readRegister(MCP23S17::OLAT_REG);
44 _gpinten = readRegister(MCP23S17::GPINTEN_REG);
45 _defval = readRegister(MCP23S17::DEFVAL_REG);
46 _intcon = readRegister(MCP23S17::INTCON_REG);
49 writeRegister(MCP23S17::IOCON_REG, 0x4a4a);
52void mcp23s17_drv::gpioMode(uint16_t mode) {
53 uint16_t mask = (1 << (_port * 8 + _pin));
54 uint16_t iodir_old = _iodir;
55 uint16_t gppu_old = _gppu;
56 uint16_t olat_old = _olat;
58 switch (mode & ~GPIO::INIT_HIGH & ~GPIO::INIT_LOW) {
64 case GPIO::INPUT | GPIO::PULLUP: {
78 if (mode & GPIO::INIT_HIGH) _olat |= mask;
79 if (mode & GPIO::INIT_LOW) _olat &= ~mask;
82 if (iodir_old != _iodir)
83 writeRegister(MCP23S17::IODIR_REG, _iodir);
84 if (gppu_old != _gppu)
85 writeRegister(MCP23S17::GPPU_REG, _gppu);
86 if (olat_old != _olat)
87 writeRegister(MCP23S17::OLAT_REG, _olat);
90bool mcp23s17_drv::gpioRead() {
91 uint16_t mask = (1 << (_port * 8 + _pin));
92 return readRegister(MCP23S17::GPIO_REG) & mask ? true :
false;
95void mcp23s17_drv::gpioWrite(
bool value) {
96 uint16_t mask = (1 << (_port * 8 + _pin));
97 uint16_t olat_old = _olat;
103 if (olat_old != _olat)
104 writeRegister(MCP23S17::OLAT_REG, _olat);
107void mcp23s17_drv::attachInterrupt(
void (*handler)(uint16_t gpio),
109 uint16_t mask = (1 << (_port * 8 + _pin));
110 uint16_t defvalold = _defval;
111 uint16_t intconold = _intcon;
116 case GPIO::RISING | GPIO::FALLING: {
120 case GPIO::LEVEL_HIGH: {
125 case GPIO::LEVEL_LOW: {
133 intHandler[_port][_pin] = handler;
134 intMode[_port][_pin] = mode;
136 if (defvalold != _defval)
137 writeRegister(MCP23S17::DEFVAL_REG, _defval);
138 if (intconold != _intcon)
139 writeRegister(MCP23S17::INTCON_REG, _intcon);
144void mcp23s17_drv::detachInterrupt() {
146 intHandler[_port][_pin] = 0;
147 intMode[_port][_pin] = 0;
150void mcp23s17_drv::enableInterrupt() {
151 uint16_t mask = (1 << (_port * 8 + _pin));
152 uint16_t gpintenold = _gpinten;
154 if (gpintenold != _gpinten)
155 writeRegister(MCP23S17::GPINTEN_REG, _gpinten);
158void mcp23s17_drv::disableInterrupt() {
159 uint16_t mask = (1 << (_port * 8 + _pin));
160 uint16_t gpintenold = _gpinten;
162 if (gpintenold != _gpinten)
163 writeRegister(MCP23S17::GPINTEN_REG, _gpinten);
166void mcp23s17_drv::handleInterrupt() {
168 uint16_t intFlags = readRegister(MCP23S17::INTF_REG);
169 uint16_t intValue = readRegister(MCP23S17::INTCAP_REG);
170 uint16_t mask = 0x0001;
171 for (uint8_t i = 0; i < 16; i++) {
172 if (intFlags & mask) {
173 uint8_t port = i / 8;
175 switch (intMode[port][pin]) {
177 if ((intValue & mask) != 0)
178 intHandler[port][pin](PORT_PIN(port, pin));
181 if ((intValue & mask) == 0)
182 intHandler[port][pin](PORT_PIN(port, pin));
185 intHandler[port][pin](PORT_PIN(port, pin));
193uint16_t mcp23s17_drv::digitalReadPort(uint16_t mask) {
194 return readRegister(MCP23S17::GPIO_REG) & mask;
197void mcp23s17_drv::digitalWritePort(uint16_t value, uint16_t mask) {
198 uint16_t olat_old = _olat;
202 if (olat_old != _olat)
203 writeRegister(MCP23S17::OLAT_REG, _olat);
206uint16_t mcp23s17_drv::readRegister(uint8_t reg) {
207 unsigned char txbuf[4];
208 unsigned char rxbuf[4];
210 txbuf[0] = 0x41 | (_spi_addr << 1);
215 _spi.spiTxRx(txbuf, rxbuf, 4);
216 return (rxbuf[3] << 8) | rxbuf[2];
219void mcp23s17_drv::writeRegister(uint8_t reg, uint16_t value) {
220 unsigned char txbuf[4];
221 unsigned char rxbuf[4];
223 txbuf[0] = 0x40 | (_spi_addr << 1);
225 txbuf[2] = value & 0xff;
226 txbuf[3] = value >> 8;
228 _spi.spiTxRx(txbuf, rxbuf, 4);