29#include "freertos/FreeRTOS.h"
30#include "freertos/task.h"
42 : m_SPIDevHandle(nullptr)
53bool MCP23S17::begin(
int MISO,
int MOSI,
int CLK,
int CS,
int CSActiveState,
int host)
60 switch (getChipPackage()) {
61 case ChipPackage::ESP32PICOD4:
66 case ChipPackage::ESP32D0WDQ5:
69 if (CSActiveState == -1)
85 m_MISO = int2gpio(MISO);
86 m_MOSI = int2gpio(MOSI);
87 m_CLK = int2gpio(CLK);
89 m_SPIHost = (spi_host_device_t) host;
91 bool r = SPIBegin(CSActiveState) && initDevice(0);
101bool MCP23S17::initDevice(uint8_t hwAddr)
104 if (hwAddr < MCP_MAXDEVICES) {
105 m_IOCON[hwAddr] = MCP_IOCON_SEQOP | MCP_IOCON_HAEN;
106 writeReg(MCP_IOCON, m_IOCON[hwAddr], hwAddr);
107 r = readReg(MCP_IOCON, hwAddr) == m_IOCON[hwAddr];
119bool MCP23S17::SPIBegin(
int CSActiveState)
121 spi_bus_config_t busconf = { };
122 busconf.mosi_io_num = m_MOSI;
123 busconf.miso_io_num = m_MISO;
124 busconf.sclk_io_num = m_CLK;
125 busconf.quadwp_io_num = -1;
126 busconf.quadhd_io_num = -1;
127 busconf.flags = SPICOMMON_BUSFLAG_MASTER;
128 auto r = spi_bus_initialize(m_SPIHost, &busconf, MCP_DMACHANNEL);
129 if (r == ESP_OK || r == ESP_ERR_INVALID_STATE) {
130 spi_device_interface_config_t devconf = { };
132 devconf.clock_speed_hz = MCP_SPI_FREQ;
133 devconf.spics_io_num = m_CS;
134 devconf.flags = (CSActiveState == 1 ? SPI_DEVICE_POSITIVE_CS : 0);
135 devconf.queue_size = 1;
136 r = spi_bus_add_device(m_SPIHost, &devconf, &m_SPIDevHandle);
137 if (r != ESP_OK && !FileBrowser::mountedSDCard())
138 spi_bus_free(m_SPIHost);
145void MCP23S17::SPIEnd()
147 if (m_SPIDevHandle) {
148 spi_bus_remove_device(m_SPIDevHandle);
149 m_SPIDevHandle =
nullptr;
150 if (!FileBrowser::mountedSDCard())
151 spi_bus_free(m_SPIHost);
156void MCP23S17::writeReg(uint8_t addr, uint8_t value, uint8_t hwAddr)
158 spi_device_acquire_bus(m_SPIDevHandle, portMAX_DELAY);
160 uint8_t txdata[3] = { (uint8_t)(0b01000000 | (hwAddr << 1)), addr, value };
161 spi_transaction_t ta;
165 ta.rx_buffer =
nullptr;
166 ta.tx_buffer = txdata;
167 spi_device_transmit(m_SPIDevHandle, &ta);
169 spi_device_release_bus(m_SPIDevHandle);
173uint8_t MCP23S17::readReg(uint8_t addr, uint8_t hwAddr)
175 spi_device_acquire_bus(m_SPIDevHandle, portMAX_DELAY);
177 uint8_t txdata[3] = { (uint8_t)(0b01000001 | (hwAddr << 1)), addr };
178 uint8_t rxdata[3] = { 0 };
179 spi_transaction_t ta;
183 ta.rx_buffer = rxdata;
184 ta.tx_buffer = txdata;
186 if (spi_device_transmit(m_SPIDevHandle, &ta) == ESP_OK)
189 spi_device_release_bus(m_SPIDevHandle);
195void MCP23S17::writeReg16(uint8_t addr, uint16_t value, uint8_t hwAddr)
197 spi_device_acquire_bus(m_SPIDevHandle, portMAX_DELAY);
199 uint8_t txdata[4] = { (uint8_t)(0b01000000 | (hwAddr << 1)), addr, (uint8_t)(value & 0xff), (uint8_t)(value >> 8) };
200 spi_transaction_t ta;
204 ta.rx_buffer =
nullptr;
205 ta.tx_buffer = txdata;
206 spi_device_transmit(m_SPIDevHandle, &ta);
208 spi_device_release_bus(m_SPIDevHandle);
212uint16_t MCP23S17::readReg16(uint8_t addr, uint8_t hwAddr)
214 spi_device_acquire_bus(m_SPIDevHandle, portMAX_DELAY);
216 uint8_t txdata[4] = { (uint8_t)(0b01000001 | (hwAddr << 1)), addr };
217 uint8_t rxdata[4] = { 0 };
218 spi_transaction_t ta;
222 ta.rx_buffer = rxdata;
223 ta.tx_buffer = txdata;
225 if (spi_device_transmit(m_SPIDevHandle, &ta) == ESP_OK)
226 r = rxdata[2] | (rxdata[3] << 8);
228 spi_device_release_bus(m_SPIDevHandle);
234void MCP23S17::enableINTMirroring(
bool value, uint8_t hwAddr)
236 writeReg(MCP_IOCON, value ? m_IOCON[hwAddr] | MCP_IOCON_MIRROR : m_IOCON[hwAddr] & ~MCP_IOCON_MIRROR, hwAddr);
240void MCP23S17::enableINTOpenDrain(
bool value, uint8_t hwAddr)
242 writeReg(MCP_IOCON, value ? m_IOCON[hwAddr] | MCP_IOCON_ODR : m_IOCON[hwAddr] & ~MCP_IOCON_ODR, hwAddr);
246void MCP23S17::setINTActiveHigh(
bool value, uint8_t hwAddr)
248 writeReg(MCP_IOCON, value ? m_IOCON[hwAddr] | MCP_IOCON_INTPOL : m_IOCON[hwAddr] & ~MCP_IOCON_INTPOL, hwAddr);
252void MCP23S17::configureGPIO(
int gpio,
MCPDir dir,
bool pullup, uint8_t hwAddr)
254 uint8_t mask = MCP_GPIO2MASK(gpio);
256 uint8_t reg = MCP_GPIO2REG(MCP_IODIR, gpio);
257 if (dir == MCPDir::Input)
258 writeReg(reg, readReg(reg, hwAddr) | mask, hwAddr);
260 writeReg(reg, readReg(reg, hwAddr) & ~mask, hwAddr);
262 reg = MCP_GPIO2REG(MCP_GPPU, gpio);
263 writeReg(reg, (readReg(reg, hwAddr) & ~mask) | ((
int)pullup * mask), hwAddr);
267void MCP23S17::writeGPIO(
int gpio,
bool value, uint8_t hwAddr)
269 uint8_t olat = readReg(MCP_GPIO2REG(MCP_OLAT, gpio), hwAddr);
270 uint8_t mask = MCP_GPIO2MASK(gpio);
271 uint8_t reg = MCP_GPIO2REG(MCP_OLAT, gpio);
272 writeReg(reg, value ? olat | mask : olat & ~mask, hwAddr);
276bool MCP23S17::readGPIO(
int gpio, uint8_t hwAddr)
278 return readReg(MCP_GPIO2REG(MCP_GPIO, gpio), hwAddr) & MCP_GPIO2MASK(gpio);
282void MCP23S17::enableInterrupt(
int gpio,
MCPIntTrigger trigger,
bool defaultValue, uint8_t hwAddr)
284 uint8_t mask = MCP_GPIO2MASK(gpio);
286 if (trigger == MCPIntTrigger::DefaultChange) {
288 writeReg(MCP_GPIO2REG(MCP_INTCON, gpio), readReg(MCP_GPIO2REG(MCP_INTCON, gpio), hwAddr) | mask, hwAddr);
289 writeReg(MCP_GPIO2REG(MCP_DEFVAL, gpio), (readReg(MCP_GPIO2REG(MCP_DEFVAL, gpio), hwAddr) & ~mask) | ((
int)defaultValue * mask), hwAddr);
292 writeReg(MCP_GPIO2REG(MCP_INTCON, gpio), readReg(MCP_GPIO2REG(MCP_INTCON, gpio), hwAddr) & ~mask, hwAddr);
295 writeReg(MCP_GPIO2REG(MCP_GPINTEN, gpio), readReg(MCP_GPIO2REG(MCP_GPINTEN, gpio), hwAddr) | mask, hwAddr);
299void MCP23S17::disableInterrupt(
int gpio, uint8_t hwAddr)
301 uint8_t reg = MCP_GPIO2REG(MCP_GPINTEN, gpio);
302 writeReg(reg, readReg(reg, hwAddr) & ~MCP_GPIO2MASK(gpio), hwAddr);
306void MCP23S17::writePort(
int port,
void const * buffer,
size_t length, uint8_t hwAddr)
310 writeReg(MCP_IOCON, m_IOCON[hwAddr] | MCP_IOCON_SEQOP | MCP_IOCON_BANK);
312 spi_device_acquire_bus(m_SPIDevHandle, portMAX_DELAY);
314 spi_transaction_ext_t ta = { };
317 ta.base.cmd = 0b01000000 | (hwAddr << 1);
318 ta.base.addr = MCP_BNK1_OLAT + port * 0x10;
319 ta.base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR;
320 ta.base.length = 16 + 8 * length;
321 ta.base.rxlength = 0;
322 ta.base.rx_buffer =
nullptr;
323 ta.base.tx_buffer = buffer;
324 spi_device_polling_transmit(m_SPIDevHandle, (spi_transaction_t*) &ta);
326 spi_device_release_bus(m_SPIDevHandle);
329 writeReg(MCP_BNK1_IOCON, m_IOCON[hwAddr]);
333void MCP23S17::readPort(
int port,
void * buffer,
size_t length, uint8_t hwAddr)
337 writeReg(MCP_IOCON, m_IOCON[hwAddr] | MCP_IOCON_SEQOP | MCP_IOCON_BANK);
339 spi_device_acquire_bus(m_SPIDevHandle, portMAX_DELAY);
341 spi_transaction_ext_t ta = { };
344 ta.base.cmd = 0b01000001 | (hwAddr << 1);
345 ta.base.addr = MCP_BNK1_GPIO + port * 0x10;
346 ta.base.flags = SPI_TRANS_VARIABLE_CMD | SPI_TRANS_VARIABLE_ADDR;
347 ta.base.length = 16 + 8 * length;
348 ta.base.rxlength = 8 * length;
349 ta.base.rx_buffer = buffer;
350 ta.base.tx_buffer =
nullptr;
351 spi_device_polling_transmit(m_SPIDevHandle, (spi_transaction_t*) &ta);
353 spi_device_release_bus(m_SPIDevHandle);
356 writeReg(MCP_BNK1_IOCON, m_IOCON[hwAddr]);
This file contains the MCP23S17 driver class.
MCPDir
Represents GPIO directioon.
MCPIntTrigger
Represents interrupt trigger mode.