Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

187 lines
3.9 KiB

/*
MCP23S08 MODULE
Copyright (C) 2020 by Eddi De Pieri <eddi at depieri dot com>
Adapted from https://github.com/kmpelectronics/Arduino
Copyright (C) 2016 Plamen Kovandjiev <p.kovandiev@kmpelectronics.eu> & Dimitar Antonov <d.antonov@kmpelectronics.eu>
(ref. https://github.com/kmpelectronics/Arduino/blob/master/ProDinoWiFiEsp/src/PRODINoESP8266/src/KMPDinoWiFiESP.cpp)
*/
#include "mcp23s08.h"
#if MCP23S08_SUPPORT
#include <SPI.h>
#include <bitset>
// 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