/* MCP23S08 MODULE Copyright (C) 2020 by Eddi De Pieri Copyright (C) 2016-2017 by Xose PĂ©rez Copyright (C) 2016 Plamen Kovandjiev & Dimitar Antonov */ #include "mcp23s08.h" #if MCP23S08_SUPPORT #include #include // TODO: check if this needed for SPI operation #define MCP23S08_CS_PIN 15 // Known commands #define READ_CMD 0x41 #define WRITE_CMD 0x40 // Registers #define IODIR 0x00 #define IPOL 0x01 #define GPINTEN 0x02 #define DEFVAL 0x03 #define INTCON 0x04 #define IOCON 0x05 #define GPPU 0x06 #define INTF 0x07 #define INTCAP 0x08 #define GPIO 0x09 #define OLAT 0x0A static uint8_t _mcp23s08TxData[16] __attribute__((aligned(4))); static uint8_t _mcp23s08RxData[16] __attribute__((aligned(4))); McpGpioPin::McpGpioPin(unsigned char pin) : BasePin(pin) {} inline void McpGpioPin::pinMode(int8_t mode) { ::MCP23S08SetDirection(this->pin, mode); } inline void McpGpioPin::digitalWrite(int8_t val) { ::MCP23S08SetPin(this->pin, val); } inline int McpGpioPin::digitalRead() { return ::MCP23S08GetPin(this->pin); } void MCP23S08Setup() { DEBUG_MSG_P(PSTR("[MCP23S08] Initialize SPI bus\n")); // Expander SPI settings SPI.begin(); SPI.setHwCs(true); SPI.setFrequency(1000000); SPI.setDataMode(SPI_MODE0); pinMode(MCP23S08_CS_PIN, OUTPUT); digitalWrite(MCP23S08_CS_PIN, HIGH); } /** * @brief Set a expander MCP23S08 the pin direction. * * @param pinNumber Pin number for set. * @param mode direction mode. 0 - INPUT, 1 - OUTPUT. * * @return void */ void MCP23S08SetDirection(uint8_t pinNumber, uint8_t mode) { uint8_t registerData = MCP23S08ReadRegister(IODIR); if (INPUT == mode) { registerData |= (1 << pinNumber); } else { registerData &= ~(1 << pinNumber); } MCP23S08WriteRegister(IODIR, registerData); } /** * @brief Read an expander MCP23S08 a register. * * @param address A register address. * * @return The data from the register. */ uint8_t MCP23S08ReadRegister(uint8_t address) { _mcp23s08TxData[0] = READ_CMD; _mcp23s08TxData[1] = address; digitalWrite(MCP23S08_CS_PIN, LOW); SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3); digitalWrite(MCP23S08_CS_PIN, HIGH); return _mcp23s08RxData[2]; } /** * @brief Write data in expander MCP23S08 register. * * @param address A register address. * @param data A byte for write. * * @return void. */ void MCP23S08WriteRegister(uint8_t address, uint8_t data) { _mcp23s08TxData[0] = WRITE_CMD; _mcp23s08TxData[1] = address; _mcp23s08TxData[2] = data; digitalWrite(MCP23S08_CS_PIN, LOW); SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3); digitalWrite(MCP23S08_CS_PIN, HIGH); } /** * @brief Set expander MCP23S08 pin state. * * @param pinNumber The number of pin to be set. * @param state The pin state, true - 1, false - 0. * * @return void */ void MCP23S08SetPin(uint8_t pinNumber, bool state) { uint8_t registerData = MCP23S08ReadRegister(OLAT); if (state) { registerData |= (1 << pinNumber); } else { registerData &= ~(1 << pinNumber); } MCP23S08WriteRegister(OLAT, registerData); } /** * @brief Get MCP23S08 pin state. * * @param pinNumber The number of pin to get. * * @return State true - 1, false - 0. */ bool MCP23S08GetPin(uint8_t pinNumber) { uint8_t registerData = MCP23S08ReadRegister(GPIO); return registerData & (1 << pinNumber); } /** * @brief Ensure pin number is valid. * * @param pinNumber The number of pin to be get. * * @return State true - 1, false - 0. */ bool mcpGpioValid(unsigned char gpio) { return gpio < McpGpioPins; } #endif // MCP23S08_SUPPORT