mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
MCP23SXX I/O Expander - SPI (#1068)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
c12c9e97c2
commit
7cd4c3bdd3
9 changed files with 571 additions and 0 deletions
|
@ -40,6 +40,8 @@ esphome/components/json/* @OttoWinter
|
||||||
esphome/components/ledc/* @OttoWinter
|
esphome/components/ledc/* @OttoWinter
|
||||||
esphome/components/light/* @esphome/core
|
esphome/components/light/* @esphome/core
|
||||||
esphome/components/logger/* @esphome/core
|
esphome/components/logger/* @esphome/core
|
||||||
|
esphome/components/mcp23s08/* @SenexCrenshaw
|
||||||
|
esphome/components/mcp23s17/* @SenexCrenshaw
|
||||||
esphome/components/mcp9808/* @k7hpn
|
esphome/components/mcp9808/* @k7hpn
|
||||||
esphome/components/network/* @esphome/core
|
esphome/components/network/* @esphome/core
|
||||||
esphome/components/ota/* @esphome/core
|
esphome/components/ota/* @esphome/core
|
||||||
|
|
58
esphome/components/mcp23s08/__init__.py
Normal file
58
esphome/components/mcp23s08/__init__.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import pins
|
||||||
|
from esphome.components import spi
|
||||||
|
from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED
|
||||||
|
|
||||||
|
CODEOWNERS = ['@SenexCrenshaw']
|
||||||
|
|
||||||
|
DEPENDENCIES = ['spi']
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
|
CONF_DEVICEADDRESS = "deviceaddress"
|
||||||
|
|
||||||
|
mcp23S08_ns = cg.esphome_ns.namespace('mcp23s08')
|
||||||
|
mcp23S08GPIOMode = mcp23S08_ns.enum('MCP23S08GPIOMode')
|
||||||
|
mcp23S08_GPIO_MODES = {
|
||||||
|
'INPUT': mcp23S08GPIOMode.MCP23S08_INPUT,
|
||||||
|
'INPUT_PULLUP': mcp23S08GPIOMode.MCP23S08_INPUT_PULLUP,
|
||||||
|
'OUTPUT': mcp23S08GPIOMode.MCP23S08_OUTPUT,
|
||||||
|
}
|
||||||
|
|
||||||
|
mcp23S08 = mcp23S08_ns.class_('MCP23S08', cg.Component, spi.SPIDevice)
|
||||||
|
mcp23S08GPIOPin = mcp23S08_ns.class_('MCP23S08GPIOPin', cg.GPIOPin)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema({
|
||||||
|
cv.Required(CONF_ID): cv.declare_id(mcp23S08),
|
||||||
|
cv.Optional(CONF_DEVICEADDRESS, default=0): cv.uint8_t,
|
||||||
|
}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema())
|
||||||
|
|
||||||
|
|
||||||
|
def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
cg.add(var.set_device_address(config[CONF_DEVICEADDRESS]))
|
||||||
|
yield cg.register_component(var, config)
|
||||||
|
yield spi.register_spi_device(var, config)
|
||||||
|
|
||||||
|
|
||||||
|
CONF_MCP23S08 = 'mcp23s08'
|
||||||
|
|
||||||
|
mcp23S08_OUTPUT_PIN_SCHEMA = cv.Schema({
|
||||||
|
cv.GenerateID(CONF_MCP23S08): cv.use_id(mcp23S08),
|
||||||
|
cv.Required(CONF_NUMBER): cv.int_,
|
||||||
|
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(mcp23S08_GPIO_MODES, upper=True),
|
||||||
|
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||||
|
})
|
||||||
|
mcp23S08_INPUT_PIN_SCHEMA = cv.Schema({
|
||||||
|
cv.GenerateID(CONF_MCP23S08): cv.use_id(mcp23S08),
|
||||||
|
cv.Required(CONF_NUMBER): cv.int_range(0, 7),
|
||||||
|
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(mcp23S08_GPIO_MODES, upper=True),
|
||||||
|
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@pins.PIN_SCHEMA_REGISTRY.register(CONF_MCP23S08,
|
||||||
|
(mcp23S08_OUTPUT_PIN_SCHEMA, mcp23S08_INPUT_PIN_SCHEMA))
|
||||||
|
def mcp23S08_pin_to_code(config):
|
||||||
|
parent = yield cg.get_variable(config[CONF_MCP23S08])
|
||||||
|
yield mcp23S08GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED])
|
121
esphome/components/mcp23s08/mcp23s08.cpp
Normal file
121
esphome/components/mcp23s08/mcp23s08.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#include "mcp23s08.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp23s08 {
|
||||||
|
|
||||||
|
static const char *TAG = "mcp23s08";
|
||||||
|
|
||||||
|
void MCP23S08::set_device_address(uint8_t device_addr) {
|
||||||
|
if (device_addr != 0) {
|
||||||
|
this->device_opcode_ |= ((device_addr & 0x03) << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S08::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up MCP23S08...");
|
||||||
|
this->spi_setup();
|
||||||
|
this->enable();
|
||||||
|
|
||||||
|
this->transfer_byte(MCP23S08_IODIR);
|
||||||
|
this->transfer_byte(0xFF);
|
||||||
|
for (uint8_t i = 0; i < MCP23S08_OLAT; i++) {
|
||||||
|
this->transfer_byte(0x00);
|
||||||
|
}
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S08::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "MCP23S08:");
|
||||||
|
LOG_PIN(" CS Pin: ", this->cs_);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MCP23S08::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
|
bool MCP23S08::digital_read(uint8_t pin) {
|
||||||
|
if (pin > 7) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t bit = pin % 8;
|
||||||
|
uint8_t reg_addr = MCP23S08_GPIO;
|
||||||
|
uint8_t value = 0;
|
||||||
|
this->read_reg(reg_addr, &value);
|
||||||
|
return value & (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S08::digital_write(uint8_t pin, bool value) {
|
||||||
|
if (pin > 7) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t reg_addr = MCP23S08_OLAT;
|
||||||
|
this->update_reg(pin, value, reg_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S08::pin_mode(uint8_t pin, uint8_t mode) {
|
||||||
|
uint8_t iodir = MCP23S08_IODIR;
|
||||||
|
uint8_t gppu = MCP23S08_GPPU;
|
||||||
|
switch (mode) {
|
||||||
|
case MCP23S08_INPUT:
|
||||||
|
this->update_reg(pin, true, iodir);
|
||||||
|
break;
|
||||||
|
case MCP23S08_INPUT_PULLUP:
|
||||||
|
this->update_reg(pin, true, iodir);
|
||||||
|
this->update_reg(pin, true, gppu);
|
||||||
|
break;
|
||||||
|
case MCP23S08_OUTPUT:
|
||||||
|
this->update_reg(pin, false, iodir);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S08::update_reg(uint8_t pin, bool pin_value, uint8_t reg_addr) {
|
||||||
|
uint8_t bit = pin % 8;
|
||||||
|
uint8_t reg_value = 0;
|
||||||
|
if (reg_addr == MCP23S08_OLAT) {
|
||||||
|
reg_value = this->olat_;
|
||||||
|
} else {
|
||||||
|
this->read_reg(reg_addr, ®_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pin_value)
|
||||||
|
reg_value |= 1 << bit;
|
||||||
|
else
|
||||||
|
reg_value &= ~(1 << bit);
|
||||||
|
|
||||||
|
this->write_reg(reg_addr, reg_value);
|
||||||
|
|
||||||
|
if (reg_addr == MCP23S08_OLAT) {
|
||||||
|
this->olat_ = reg_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCP23S08::write_reg(uint8_t reg, uint8_t value) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(this->device_opcode_);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
this->transfer_byte(value);
|
||||||
|
this->disable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCP23S08::read_reg(uint8_t reg, uint8_t *value) {
|
||||||
|
uint8_t data;
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(this->device_opcode_ | 1);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
*value = this->transfer_byte(0);
|
||||||
|
this->disable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCP23S08GPIOPin::MCP23S08GPIOPin(MCP23S08 *parent, uint8_t pin, uint8_t mode, bool inverted)
|
||||||
|
: GPIOPin(pin, mode, inverted), parent_(parent) {}
|
||||||
|
void MCP23S08GPIOPin::setup() { this->pin_mode(this->mode_); }
|
||||||
|
void MCP23S08GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); }
|
||||||
|
bool MCP23S08GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||||
|
void MCP23S08GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||||
|
|
||||||
|
} // namespace mcp23s08
|
||||||
|
} // namespace esphome
|
74
esphome/components/mcp23s08/mcp23s08.h
Normal file
74
esphome/components/mcp23s08/mcp23s08.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/esphal.h"
|
||||||
|
#include "esphome/components/spi/spi.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp23s08 {
|
||||||
|
|
||||||
|
/// Modes for MCP23S08 pins
|
||||||
|
enum MCP23S08GPIOMode : uint8_t {
|
||||||
|
MCP23S08_INPUT = INPUT, // 0x00
|
||||||
|
MCP23S08_INPUT_PULLUP = INPUT_PULLUP, // 0x02
|
||||||
|
MCP23S08_OUTPUT = OUTPUT // 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MCP23S08GPIORegisters {
|
||||||
|
// A side
|
||||||
|
MCP23S08_IODIR = 0x00,
|
||||||
|
MCP23S08_IPOL = 0x01,
|
||||||
|
MCP23S08_GPINTEN = 0x02,
|
||||||
|
MCP23S08_DEFVAL = 0x03,
|
||||||
|
MCP23S08_INTCON = 0x04,
|
||||||
|
MCP23S08_IOCON = 0x05,
|
||||||
|
MCP23S08_GPPU = 0x06,
|
||||||
|
MCP23S08_INTF = 0x07,
|
||||||
|
MCP23S08_INTCAP = 0x08,
|
||||||
|
MCP23S08_GPIO = 0x09,
|
||||||
|
MCP23S08_OLAT = 0x0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MCP23S08 : public Component,
|
||||||
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||||
|
spi::DATA_RATE_10MHZ> {
|
||||||
|
public:
|
||||||
|
MCP23S08() = default;
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
bool digital_read(uint8_t pin);
|
||||||
|
void digital_write(uint8_t pin, bool value);
|
||||||
|
void pin_mode(uint8_t pin, uint8_t mode);
|
||||||
|
|
||||||
|
void set_device_address(uint8_t device_addr);
|
||||||
|
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
|
// read a given register
|
||||||
|
bool read_reg(uint8_t reg, uint8_t *value);
|
||||||
|
// write a value to a given register
|
||||||
|
bool write_reg(uint8_t reg, uint8_t value);
|
||||||
|
// update registers with given pin value.
|
||||||
|
void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t device_opcode_ = 0x40;
|
||||||
|
uint8_t olat_{0x00};
|
||||||
|
};
|
||||||
|
|
||||||
|
class MCP23S08GPIOPin : public GPIOPin {
|
||||||
|
public:
|
||||||
|
MCP23S08GPIOPin(MCP23S08 *parent, uint8_t pin, uint8_t mode, bool inverted = false);
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void pin_mode(uint8_t mode) override;
|
||||||
|
bool digital_read() override;
|
||||||
|
void digital_write(bool value) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MCP23S08 *parent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mcp23s08
|
||||||
|
} // namespace esphome
|
58
esphome/components/mcp23s17/__init__.py
Normal file
58
esphome/components/mcp23s17/__init__.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import pins
|
||||||
|
from esphome.components import spi
|
||||||
|
from esphome.const import CONF_ID, CONF_NUMBER, CONF_MODE, CONF_INVERTED
|
||||||
|
|
||||||
|
CODEOWNERS = ['@SenexCrenshaw']
|
||||||
|
|
||||||
|
DEPENDENCIES = ['spi']
|
||||||
|
MULTI_CONF = True
|
||||||
|
|
||||||
|
CONF_DEVICEADDRESS = "deviceaddress"
|
||||||
|
|
||||||
|
mcp23S17_ns = cg.esphome_ns.namespace('mcp23s17')
|
||||||
|
mcp23S17GPIOMode = mcp23S17_ns.enum('MCP23S17GPIOMode')
|
||||||
|
mcp23S17_GPIO_MODES = {
|
||||||
|
'INPUT': mcp23S17GPIOMode.MCP23S17_INPUT,
|
||||||
|
'INPUT_PULLUP': mcp23S17GPIOMode.MCP23S17_INPUT_PULLUP,
|
||||||
|
'OUTPUT': mcp23S17GPIOMode.MCP23S17_OUTPUT,
|
||||||
|
}
|
||||||
|
|
||||||
|
mcp23S17 = mcp23S17_ns.class_('MCP23S17', cg.Component, spi.SPIDevice)
|
||||||
|
mcp23S17GPIOPin = mcp23S17_ns.class_('MCP23S17GPIOPin', cg.GPIOPin)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema({
|
||||||
|
cv.Required(CONF_ID): cv.declare_id(mcp23S17),
|
||||||
|
cv.Optional(CONF_DEVICEADDRESS, default=0): cv.uint8_t,
|
||||||
|
}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema())
|
||||||
|
|
||||||
|
|
||||||
|
def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
cg.add(var.set_device_address(config[CONF_DEVICEADDRESS]))
|
||||||
|
yield cg.register_component(var, config)
|
||||||
|
yield spi.register_spi_device(var, config)
|
||||||
|
|
||||||
|
|
||||||
|
CONF_MCP23S17 = 'mcp23s17'
|
||||||
|
|
||||||
|
mcp23S17_OUTPUT_PIN_SCHEMA = cv.Schema({
|
||||||
|
cv.GenerateID(CONF_MCP23S17): cv.use_id(mcp23S17),
|
||||||
|
cv.Required(CONF_NUMBER): cv.int_,
|
||||||
|
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(mcp23S17_GPIO_MODES, upper=True),
|
||||||
|
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||||
|
})
|
||||||
|
mcp23S17_INPUT_PIN_SCHEMA = cv.Schema({
|
||||||
|
cv.Required(CONF_MCP23S17): cv.use_id(mcp23S17),
|
||||||
|
cv.Required(CONF_NUMBER): cv.int_range(0, 15),
|
||||||
|
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(mcp23S17_GPIO_MODES, upper=True),
|
||||||
|
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@pins.PIN_SCHEMA_REGISTRY.register(CONF_MCP23S17,
|
||||||
|
(mcp23S17_OUTPUT_PIN_SCHEMA, mcp23S17_INPUT_PIN_SCHEMA))
|
||||||
|
def mcp23S17_pin_to_code(config):
|
||||||
|
parent = yield cg.get_variable(config[CONF_MCP23S17])
|
||||||
|
yield mcp23S17GPIOPin.new(parent, config[CONF_NUMBER], config[CONF_MODE], config[CONF_INVERTED])
|
126
esphome/components/mcp23s17/mcp23s17.cpp
Normal file
126
esphome/components/mcp23s17/mcp23s17.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
#include "mcp23s17.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp23s17 {
|
||||||
|
|
||||||
|
static const char *TAG = "mcp23s17";
|
||||||
|
|
||||||
|
void MCP23S17::set_device_address(uint8_t device_addr) {
|
||||||
|
if (device_addr != 0) {
|
||||||
|
this->device_opcode_ |= ((device_addr & 0b111) << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S17::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up MCP23S17...");
|
||||||
|
this->spi_setup();
|
||||||
|
|
||||||
|
this->enable();
|
||||||
|
uint8_t cmd = 0b01000000;
|
||||||
|
this->transfer_byte(cmd);
|
||||||
|
this->transfer_byte(0x18);
|
||||||
|
this->transfer_byte(0x0A);
|
||||||
|
this->transfer_byte(this->device_opcode_);
|
||||||
|
this->transfer_byte(0);
|
||||||
|
this->transfer_byte(0xFF);
|
||||||
|
this->transfer_byte(0xFF);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 20; i++) {
|
||||||
|
this->transfer_byte(0);
|
||||||
|
}
|
||||||
|
this->disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S17::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "MCP23S17:");
|
||||||
|
LOG_PIN(" CS Pin: ", this->cs_);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MCP23S17::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
|
bool MCP23S17::digital_read(uint8_t pin) {
|
||||||
|
uint8_t bit = pin % 8;
|
||||||
|
uint8_t reg_addr = pin < 8 ? MCP23S17_GPIOA : MCP23S17_GPIOB;
|
||||||
|
uint8_t value = 0;
|
||||||
|
this->read_reg(reg_addr, &value);
|
||||||
|
return value & (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S17::digital_write(uint8_t pin, bool value) {
|
||||||
|
uint8_t reg_addr = pin < 8 ? MCP23S17_OLATA : MCP23S17_OLATB;
|
||||||
|
this->update_reg(pin, value, reg_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S17::pin_mode(uint8_t pin, uint8_t mode) {
|
||||||
|
uint8_t iodir = pin < 8 ? MCP23S17_IODIRA : MCP23S17_IODIRB;
|
||||||
|
uint8_t gppu = pin < 8 ? MCP23S17_GPPUA : MCP23S17_GPPUB;
|
||||||
|
switch (mode) {
|
||||||
|
case MCP23S17_INPUT:
|
||||||
|
this->update_reg(pin, true, iodir);
|
||||||
|
break;
|
||||||
|
case MCP23S17_INPUT_PULLUP:
|
||||||
|
this->update_reg(pin, true, iodir);
|
||||||
|
this->update_reg(pin, true, gppu);
|
||||||
|
break;
|
||||||
|
case MCP23S17_OUTPUT:
|
||||||
|
this->update_reg(pin, false, iodir);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCP23S17::update_reg(uint8_t pin, bool pin_value, uint8_t reg_addr) {
|
||||||
|
uint8_t bit = pin % 8;
|
||||||
|
uint8_t reg_value = 0;
|
||||||
|
if (reg_addr == MCP23S17_OLATA) {
|
||||||
|
reg_value = this->olat_a_;
|
||||||
|
} else if (reg_addr == MCP23S17_OLATB) {
|
||||||
|
reg_value = this->olat_b_;
|
||||||
|
} else {
|
||||||
|
this->read_reg(reg_addr, ®_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pin_value)
|
||||||
|
reg_value |= 1 << bit;
|
||||||
|
else
|
||||||
|
reg_value &= ~(1 << bit);
|
||||||
|
|
||||||
|
this->write_reg(reg_addr, reg_value);
|
||||||
|
|
||||||
|
if (reg_addr == MCP23S17_OLATA) {
|
||||||
|
this->olat_a_ = reg_value;
|
||||||
|
} else if (reg_addr == MCP23S17_OLATB) {
|
||||||
|
this->olat_b_ = reg_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCP23S17::read_reg(uint8_t reg, uint8_t *value) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(this->device_opcode_ | 1);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
*value = this->transfer_byte(0xFF);
|
||||||
|
this->disable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCP23S17::write_reg(uint8_t reg, uint8_t value) {
|
||||||
|
this->enable();
|
||||||
|
this->transfer_byte(this->device_opcode_);
|
||||||
|
this->transfer_byte(reg);
|
||||||
|
this->transfer_byte(value);
|
||||||
|
|
||||||
|
this->disable();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCP23S17GPIOPin::MCP23S17GPIOPin(MCP23S17 *parent, uint8_t pin, uint8_t mode, bool inverted)
|
||||||
|
: GPIOPin(pin, mode, inverted), parent_(parent) {}
|
||||||
|
void MCP23S17GPIOPin::setup() { this->pin_mode(this->mode_); }
|
||||||
|
void MCP23S17GPIOPin::pin_mode(uint8_t mode) { this->parent_->pin_mode(this->pin_, mode); }
|
||||||
|
bool MCP23S17GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||||
|
void MCP23S17GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||||
|
|
||||||
|
} // namespace mcp23s17
|
||||||
|
} // namespace esphome
|
87
esphome/components/mcp23s17/mcp23s17.h
Normal file
87
esphome/components/mcp23s17/mcp23s17.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/esphal.h"
|
||||||
|
#include "esphome/components/spi/spi.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace mcp23s17 {
|
||||||
|
|
||||||
|
/// Modes for MCP23S17 pins
|
||||||
|
enum MCP23S17GPIOMode : uint8_t {
|
||||||
|
MCP23S17_INPUT = INPUT, // 0x00
|
||||||
|
MCP23S17_INPUT_PULLUP = INPUT_PULLUP, // 0x02
|
||||||
|
MCP23S17_OUTPUT = OUTPUT // 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MCP23S17GPIORegisters {
|
||||||
|
// A side
|
||||||
|
MCP23S17_IODIRA = 0x00,
|
||||||
|
MCP23S17_IPOLA = 0x02,
|
||||||
|
MCP23S17_GPINTENA = 0x04,
|
||||||
|
MCP23S17_DEFVALA = 0x06,
|
||||||
|
MCP23S17_INTCONA = 0x08,
|
||||||
|
MCP23S17_IOCONA = 0x0A,
|
||||||
|
MCP23S17_GPPUA = 0x0C,
|
||||||
|
MCP23S17_INTFA = 0x0E,
|
||||||
|
MCP23S17_INTCAPA = 0x10,
|
||||||
|
MCP23S17_GPIOA = 0x12,
|
||||||
|
MCP23S17_OLATA = 0x14,
|
||||||
|
// B side
|
||||||
|
MCP23S17_IODIRB = 0x01,
|
||||||
|
MCP23S17_IPOLB = 0x03,
|
||||||
|
MCP23S17_GPINTENB = 0x05,
|
||||||
|
MCP23S17_DEFVALB = 0x07,
|
||||||
|
MCP23S17_INTCONB = 0x09,
|
||||||
|
MCP23S17_IOCONB = 0x0B,
|
||||||
|
MCP23S17_GPPUB = 0x0D,
|
||||||
|
MCP23S17_INTFB = 0x0F,
|
||||||
|
MCP23S17_INTCAPB = 0x11,
|
||||||
|
MCP23S17_GPIOB = 0x13,
|
||||||
|
MCP23S17_OLATB = 0x15,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MCP23S17 : public Component,
|
||||||
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||||
|
spi::DATA_RATE_8MHZ> {
|
||||||
|
public:
|
||||||
|
MCP23S17() = default;
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
void set_device_address(uint8_t device_addr);
|
||||||
|
|
||||||
|
bool digital_read(uint8_t pin);
|
||||||
|
void digital_write(uint8_t pin, bool value);
|
||||||
|
void pin_mode(uint8_t pin, uint8_t mode);
|
||||||
|
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
|
// read a given register
|
||||||
|
bool read_reg(uint8_t reg, uint8_t *value);
|
||||||
|
// write a value to a given register
|
||||||
|
bool write_reg(uint8_t reg, uint8_t value);
|
||||||
|
// update registers with given pin value.
|
||||||
|
void update_reg(uint8_t pin, bool pin_value, uint8_t reg_a);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t device_opcode_ = 0x40;
|
||||||
|
uint8_t olat_a_{0x00};
|
||||||
|
uint8_t olat_b_{0x00};
|
||||||
|
};
|
||||||
|
|
||||||
|
class MCP23S17GPIOPin : public GPIOPin {
|
||||||
|
public:
|
||||||
|
MCP23S17GPIOPin(MCP23S17 *parent, uint8_t pin, uint8_t mode, bool inverted = false);
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void pin_mode(uint8_t mode) override;
|
||||||
|
bool digital_read() override;
|
||||||
|
void digital_write(bool value) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MCP23S17 *parent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mcp23s17
|
||||||
|
} // namespace esphome
|
|
@ -55,6 +55,7 @@ enum SPIDataRate : uint32_t {
|
||||||
DATA_RATE_2MHZ = 2000000,
|
DATA_RATE_2MHZ = 2000000,
|
||||||
DATA_RATE_4MHZ = 4000000,
|
DATA_RATE_4MHZ = 4000000,
|
||||||
DATA_RATE_8MHZ = 8000000,
|
DATA_RATE_8MHZ = 8000000,
|
||||||
|
DATA_RATE_10MHZ = 10000000,
|
||||||
DATA_RATE_20MHZ = 20000000,
|
DATA_RATE_20MHZ = 20000000,
|
||||||
DATA_RATE_40MHZ = 40000000,
|
DATA_RATE_40MHZ = 40000000,
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,6 +197,16 @@ wled:
|
||||||
|
|
||||||
adalight:
|
adalight:
|
||||||
|
|
||||||
|
mcp23s08:
|
||||||
|
- id: 'mcp23s08_hub'
|
||||||
|
cs_pin: GPIO12
|
||||||
|
deviceaddress: 0
|
||||||
|
|
||||||
|
mcp23s17:
|
||||||
|
- id: 'mcp23s17_hub'
|
||||||
|
cs_pin: GPIO12
|
||||||
|
deviceaddress: 1
|
||||||
|
|
||||||
sensor:
|
sensor:
|
||||||
- platform: adc
|
- platform: adc
|
||||||
pin: A0
|
pin: A0
|
||||||
|
@ -802,6 +812,24 @@ esp32_touch:
|
||||||
voltage_attenuation: 1.5V
|
voltage_attenuation: 1.5V
|
||||||
|
|
||||||
binary_sensor:
|
binary_sensor:
|
||||||
|
- platform: gpio
|
||||||
|
name: "MCP23S08 Pin #1"
|
||||||
|
pin:
|
||||||
|
mcp23s08: mcp23s08_hub
|
||||||
|
# Use pin number 1
|
||||||
|
number: 1
|
||||||
|
# One of INPUT or INPUT_PULLUP
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: False
|
||||||
|
- platform: gpio
|
||||||
|
name: "MCP23S17 Pin #1"
|
||||||
|
pin:
|
||||||
|
mcp23s17: mcp23s17_hub
|
||||||
|
# Use pin number 1
|
||||||
|
number: 1
|
||||||
|
# One of INPUT or INPUT_PULLUP
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
inverted: False
|
||||||
- platform: gpio
|
- platform: gpio
|
||||||
pin: GPIO9
|
pin: GPIO9
|
||||||
name: 'Living Room Window'
|
name: 'Living Room Window'
|
||||||
|
@ -1362,6 +1390,22 @@ climate:
|
||||||
name: Hitachi Climate
|
name: Hitachi Climate
|
||||||
|
|
||||||
switch:
|
switch:
|
||||||
|
- platform: gpio
|
||||||
|
name: "MCP23S08 Pin #0"
|
||||||
|
pin:
|
||||||
|
mcp23s08: mcp23s08_hub
|
||||||
|
# Use pin number 0
|
||||||
|
number: 0
|
||||||
|
mode: OUTPUT
|
||||||
|
inverted: False
|
||||||
|
- platform: gpio
|
||||||
|
name: "MCP23S17 Pin #0"
|
||||||
|
pin:
|
||||||
|
mcp23s17: mcp23s17_hub
|
||||||
|
# Use pin number 0
|
||||||
|
number: 1
|
||||||
|
mode: OUTPUT
|
||||||
|
inverted: False
|
||||||
- platform: gpio
|
- platform: gpio
|
||||||
pin: GPIO25
|
pin: GPIO25
|
||||||
name: 'Living Room Dehumidifier'
|
name: 'Living Room Dehumidifier'
|
||||||
|
|
Loading…
Reference in a new issue