mirror of
https://github.com/esphome/esphome.git
synced 2024-12-24 16:58:07 +01:00
Add IDF support to dallas (#2578)
This commit is contained in:
parent
1468acfced
commit
68c8547067
@ -6,26 +6,20 @@ from esphome.const import CONF_ID, CONF_PIN
|
|||||||
MULTI_CONF = True
|
MULTI_CONF = True
|
||||||
AUTO_LOAD = ["sensor"]
|
AUTO_LOAD = ["sensor"]
|
||||||
|
|
||||||
CONF_ONE_WIRE_ID = "one_wire_id"
|
|
||||||
dallas_ns = cg.esphome_ns.namespace("dallas")
|
dallas_ns = cg.esphome_ns.namespace("dallas")
|
||||||
DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent)
|
DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent)
|
||||||
ESPOneWire = dallas_ns.class_("ESPOneWire")
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
cv.Schema(
|
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(DallasComponent),
|
cv.GenerateID(): cv.declare_id(DallasComponent),
|
||||||
cv.GenerateID(CONF_ONE_WIRE_ID): cv.declare_id(ESPOneWire),
|
|
||||||
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema,
|
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema,
|
||||||
}
|
}
|
||||||
).extend(cv.polling_component_schema("60s")),
|
).extend(cv.polling_component_schema("60s"))
|
||||||
# pin_mode call logs in esp-idf, but InterruptLock is active -> crash
|
|
||||||
cv.only_with_arduino,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
one_wire = cg.new_Pvariable(config[CONF_ONE_WIRE_ID], pin)
|
|
||||||
var = cg.new_Pvariable(config[CONF_ID], one_wire)
|
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||||
|
cg.add(var.set_pin(pin))
|
||||||
|
@ -31,12 +31,11 @@ uint16_t DallasTemperatureSensor::millis_to_wait_for_conversion() const {
|
|||||||
void DallasComponent::setup() {
|
void DallasComponent::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
|
ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
|
||||||
|
|
||||||
yield();
|
pin_->setup();
|
||||||
|
one_wire_ = new ESPOneWire(pin_); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
|
||||||
std::vector<uint64_t> raw_sensors;
|
std::vector<uint64_t> raw_sensors;
|
||||||
{
|
|
||||||
InterruptLock lock;
|
|
||||||
raw_sensors = this->one_wire_->search_vec();
|
raw_sensors = this->one_wire_->search_vec();
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &address : raw_sensors) {
|
for (auto &address : raw_sensors) {
|
||||||
std::string s = uint64_to_string(address);
|
std::string s = uint64_to_string(address);
|
||||||
@ -70,7 +69,7 @@ void DallasComponent::setup() {
|
|||||||
}
|
}
|
||||||
void DallasComponent::dump_config() {
|
void DallasComponent::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "DallasComponent:");
|
ESP_LOGCONFIG(TAG, "DallasComponent:");
|
||||||
LOG_PIN(" Pin: ", this->one_wire_->get_pin());
|
LOG_PIN(" Pin: ", this->pin_);
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
|
||||||
if (this->found_sensors_.empty()) {
|
if (this->found_sensors_.empty()) {
|
||||||
@ -102,8 +101,6 @@ void DallasComponent::update() {
|
|||||||
this->status_clear_warning();
|
this->status_clear_warning();
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
{
|
|
||||||
InterruptLock lock;
|
|
||||||
if (!this->one_wire_->reset()) {
|
if (!this->one_wire_->reset()) {
|
||||||
result = false;
|
result = false;
|
||||||
} else {
|
} else {
|
||||||
@ -111,7 +108,6 @@ void DallasComponent::update() {
|
|||||||
this->one_wire_->skip();
|
this->one_wire_->skip();
|
||||||
this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
|
this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
ESP_LOGE(TAG, "Requesting conversion failed");
|
ESP_LOGE(TAG, "Requesting conversion failed");
|
||||||
@ -121,11 +117,7 @@ void DallasComponent::update() {
|
|||||||
|
|
||||||
for (auto *sensor : this->sensors_) {
|
for (auto *sensor : this->sensors_) {
|
||||||
this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] {
|
this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] {
|
||||||
bool res;
|
bool res = sensor->read_scratch_pad();
|
||||||
{
|
|
||||||
InterruptLock lock;
|
|
||||||
res = sensor->read_scratch_pad();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str());
|
ESP_LOGW(TAG, "'%s' - Resetting bus for read failed!", sensor->get_name().c_str());
|
||||||
@ -146,7 +138,6 @@ void DallasComponent::update() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DallasComponent::DallasComponent(ESPOneWire *one_wire) : one_wire_(one_wire) {}
|
|
||||||
|
|
||||||
void DallasTemperatureSensor::set_address(uint64_t address) { this->address_ = address; }
|
void DallasTemperatureSensor::set_address(uint64_t address) { this->address_ = address; }
|
||||||
uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; }
|
uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; }
|
||||||
@ -162,7 +153,7 @@ const std::string &DallasTemperatureSensor::get_address_name() {
|
|||||||
return this->address_name_;
|
return this->address_name_;
|
||||||
}
|
}
|
||||||
bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
|
bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
|
||||||
ESPOneWire *wire = this->parent_->one_wire_;
|
auto *wire = this->parent_->one_wire_;
|
||||||
if (!wire->reset()) {
|
if (!wire->reset()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -176,11 +167,7 @@ bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool DallasTemperatureSensor::setup_sensor() {
|
bool DallasTemperatureSensor::setup_sensor() {
|
||||||
bool r;
|
bool r = this->read_scratch_pad();
|
||||||
{
|
|
||||||
InterruptLock lock;
|
|
||||||
r = this->read_scratch_pad();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
ESP_LOGE(TAG, "Reading scratchpad failed: reset");
|
ESP_LOGE(TAG, "Reading scratchpad failed: reset");
|
||||||
@ -214,9 +201,7 @@ bool DallasTemperatureSensor::setup_sensor() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESPOneWire *wire = this->parent_->one_wire_;
|
auto *wire = this->parent_->one_wire_;
|
||||||
{
|
|
||||||
InterruptLock lock;
|
|
||||||
if (wire->reset()) {
|
if (wire->reset()) {
|
||||||
wire->select(this->address_);
|
wire->select(this->address_);
|
||||||
wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
|
wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
|
||||||
@ -229,7 +214,6 @@ bool DallasTemperatureSensor::setup_sensor() {
|
|||||||
wire->select(this->address_);
|
wire->select(this->address_);
|
||||||
wire->write8(0x48);
|
wire->write8(0x48);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
delay(20); // allow it to finish operation
|
delay(20); // allow it to finish operation
|
||||||
wire->reset();
|
wire->reset();
|
||||||
|
@ -11,8 +11,7 @@ class DallasTemperatureSensor;
|
|||||||
|
|
||||||
class DallasComponent : public PollingComponent {
|
class DallasComponent : public PollingComponent {
|
||||||
public:
|
public:
|
||||||
explicit DallasComponent(ESPOneWire *one_wire);
|
void set_pin(InternalGPIOPin *pin) { pin_ = pin; }
|
||||||
|
|
||||||
void register_sensor(DallasTemperatureSensor *sensor);
|
void register_sensor(DallasTemperatureSensor *sensor);
|
||||||
|
|
||||||
void setup() override;
|
void setup() override;
|
||||||
@ -24,6 +23,7 @@ class DallasComponent : public PollingComponent {
|
|||||||
protected:
|
protected:
|
||||||
friend DallasTemperatureSensor;
|
friend DallasTemperatureSensor;
|
||||||
|
|
||||||
|
InternalGPIOPin *pin_;
|
||||||
ESPOneWire *one_wire_;
|
ESPOneWire *one_wire_;
|
||||||
std::vector<DallasTemperatureSensor *> sensors_;
|
std::vector<DallasTemperatureSensor *> sensors_;
|
||||||
std::vector<uint64_t> found_sensors_;
|
std::vector<uint64_t> found_sensors_;
|
||||||
|
@ -10,115 +10,123 @@ static const char *const TAG = "dallas.one_wire";
|
|||||||
const uint8_t ONE_WIRE_ROM_SELECT = 0x55;
|
const uint8_t ONE_WIRE_ROM_SELECT = 0x55;
|
||||||
const int ONE_WIRE_ROM_SEARCH = 0xF0;
|
const int ONE_WIRE_ROM_SEARCH = 0xF0;
|
||||||
|
|
||||||
ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {}
|
ESPOneWire::ESPOneWire(InternalGPIOPin *pin) { pin_ = pin->to_isr(); }
|
||||||
|
|
||||||
bool HOT IRAM_ATTR ESPOneWire::reset() {
|
bool HOT IRAM_ATTR ESPOneWire::reset() {
|
||||||
uint8_t retries = 125;
|
// See reset here:
|
||||||
|
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
||||||
|
InterruptLock lock;
|
||||||
|
|
||||||
// Wait for communication to clear
|
// Wait for communication to clear (delay G)
|
||||||
this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
|
uint8_t retries = 125;
|
||||||
do {
|
do {
|
||||||
if (--retries == 0)
|
if (--retries == 0)
|
||||||
return false;
|
return false;
|
||||||
delayMicroseconds(2);
|
delayMicroseconds(2);
|
||||||
} while (!this->pin_->digital_read());
|
} while (!pin_.digital_read());
|
||||||
|
|
||||||
// Send 480µs LOW TX reset pulse
|
// Send 480µs LOW TX reset pulse (drive bus low, delay H)
|
||||||
this->pin_->pin_mode(gpio::FLAG_OUTPUT);
|
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
||||||
this->pin_->digital_write(false);
|
pin_.digital_write(false);
|
||||||
delayMicroseconds(480);
|
delayMicroseconds(480);
|
||||||
|
|
||||||
// Switch into RX mode, letting the pin float
|
// Release the bus, delay I
|
||||||
this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
// after 15µs-60µs wait time, responder pulls low for 60µs-240µs
|
|
||||||
// let's have 70µs just in case
|
|
||||||
delayMicroseconds(70);
|
delayMicroseconds(70);
|
||||||
|
|
||||||
bool r = !this->pin_->digital_read();
|
// sample bus, 0=device(s) present, 1=no device present
|
||||||
|
bool r = !pin_.digital_read();
|
||||||
|
// delay J
|
||||||
delayMicroseconds(410);
|
delayMicroseconds(410);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
|
void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) {
|
||||||
// Initiate write/read by pulling low.
|
// See write 1/0 bit here:
|
||||||
this->pin_->pin_mode(gpio::FLAG_OUTPUT);
|
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
||||||
this->pin_->digital_write(false);
|
InterruptLock lock;
|
||||||
|
|
||||||
// bus sampled within 15µs and 60µs after pulling LOW.
|
// drive bus low
|
||||||
if (bit) {
|
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
||||||
// pull high/release within 15µs
|
pin_.digital_write(false);
|
||||||
delayMicroseconds(10);
|
|
||||||
this->pin_->digital_write(true);
|
uint32_t delay0 = bit ? 10 : 65;
|
||||||
// in total minimum of 60µs long
|
uint32_t delay1 = bit ? 55 : 5;
|
||||||
delayMicroseconds(55);
|
|
||||||
} else {
|
// delay A/C
|
||||||
// continue pulling LOW for at least 60µs
|
delayMicroseconds(delay0);
|
||||||
delayMicroseconds(65);
|
// release bus
|
||||||
this->pin_->digital_write(true);
|
pin_.digital_write(true);
|
||||||
// grace period, 1µs recovery time
|
// delay B/D
|
||||||
delayMicroseconds(5);
|
delayMicroseconds(delay1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HOT IRAM_ATTR ESPOneWire::read_bit() {
|
bool HOT IRAM_ATTR ESPOneWire::read_bit() {
|
||||||
// Initiate read slot by pulling LOW for at least 1µs
|
// See read bit here:
|
||||||
this->pin_->pin_mode(gpio::FLAG_OUTPUT);
|
// https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html
|
||||||
this->pin_->digital_write(false);
|
InterruptLock lock;
|
||||||
|
|
||||||
|
// drive bus low, delay A
|
||||||
|
pin_.pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
pin_.digital_write(false);
|
||||||
delayMicroseconds(3);
|
delayMicroseconds(3);
|
||||||
|
|
||||||
// release bus, we have to sample within 15µs of pulling low
|
// release bus, delay E
|
||||||
this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
delayMicroseconds(10);
|
delayMicroseconds(10);
|
||||||
|
|
||||||
bool r = this->pin_->digital_read();
|
// sample bus to read bit from peer
|
||||||
// read time slot at least 60µs long + 1µs recovery time between slots
|
bool r = pin_.digital_read();
|
||||||
|
|
||||||
|
// delay F
|
||||||
delayMicroseconds(53);
|
delayMicroseconds(53);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR ESPOneWire::write8(uint8_t val) {
|
void ESPOneWire::write8(uint8_t val) {
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
this->write_bit(bool((1u << i) & val));
|
this->write_bit(bool((1u << i) & val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR ESPOneWire::write64(uint64_t val) {
|
void ESPOneWire::write64(uint64_t val) {
|
||||||
for (uint8_t i = 0; i < 64; i++) {
|
for (uint8_t i = 0; i < 64; i++) {
|
||||||
this->write_bit(bool((1ULL << i) & val));
|
this->write_bit(bool((1ULL << i) & val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t IRAM_ATTR ESPOneWire::read8() {
|
uint8_t ESPOneWire::read8() {
|
||||||
uint8_t ret = 0;
|
uint8_t ret = 0;
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
ret |= (uint8_t(this->read_bit()) << i);
|
ret |= (uint8_t(this->read_bit()) << i);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
uint64_t IRAM_ATTR ESPOneWire::read64() {
|
uint64_t ESPOneWire::read64() {
|
||||||
uint64_t ret = 0;
|
uint64_t ret = 0;
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
ret |= (uint64_t(this->read_bit()) << i);
|
ret |= (uint64_t(this->read_bit()) << i);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
void IRAM_ATTR ESPOneWire::select(uint64_t address) {
|
void ESPOneWire::select(uint64_t address) {
|
||||||
this->write8(ONE_WIRE_ROM_SELECT);
|
this->write8(ONE_WIRE_ROM_SELECT);
|
||||||
this->write64(address);
|
this->write64(address);
|
||||||
}
|
}
|
||||||
void IRAM_ATTR ESPOneWire::reset_search() {
|
void ESPOneWire::reset_search() {
|
||||||
this->last_discrepancy_ = 0;
|
this->last_discrepancy_ = 0;
|
||||||
this->last_device_flag_ = false;
|
this->last_device_flag_ = false;
|
||||||
this->last_family_discrepancy_ = 0;
|
this->last_family_discrepancy_ = 0;
|
||||||
this->rom_number_ = 0;
|
this->rom_number_ = 0;
|
||||||
}
|
}
|
||||||
uint64_t HOT IRAM_ATTR ESPOneWire::search() {
|
uint64_t ESPOneWire::search() {
|
||||||
if (this->last_device_flag_) {
|
if (this->last_device_flag_) {
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->reset()) {
|
if (!this->reset()) {
|
||||||
// Reset failed
|
// Reset failed or no devices present
|
||||||
this->reset_search();
|
this->reset_search();
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
@ -196,7 +204,7 @@ uint64_t HOT IRAM_ATTR ESPOneWire::search() {
|
|||||||
|
|
||||||
return this->rom_number_;
|
return this->rom_number_;
|
||||||
}
|
}
|
||||||
std::vector<uint64_t> IRAM_ATTR ESPOneWire::search_vec() {
|
std::vector<uint64_t> ESPOneWire::search_vec() {
|
||||||
std::vector<uint64_t> res;
|
std::vector<uint64_t> res;
|
||||||
|
|
||||||
this->reset_search();
|
this->reset_search();
|
||||||
@ -206,10 +214,9 @@ std::vector<uint64_t> IRAM_ATTR ESPOneWire::search_vec() {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
void IRAM_ATTR ESPOneWire::skip() {
|
void ESPOneWire::skip() {
|
||||||
this->write8(0xCC); // skip ROM
|
this->write8(0xCC); // skip ROM
|
||||||
}
|
}
|
||||||
GPIOPin *ESPOneWire::get_pin() { return this->pin_; }
|
|
||||||
|
|
||||||
uint8_t IRAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); }
|
uint8_t IRAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); }
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ extern const int ONE_WIRE_ROM_SEARCH;
|
|||||||
|
|
||||||
class ESPOneWire {
|
class ESPOneWire {
|
||||||
public:
|
public:
|
||||||
explicit ESPOneWire(GPIOPin *pin);
|
explicit ESPOneWire(InternalGPIOPin *pin);
|
||||||
|
|
||||||
/** Reset the bus, should be done before all write operations.
|
/** Reset the bus, should be done before all write operations.
|
||||||
*
|
*
|
||||||
@ -55,13 +54,11 @@ class ESPOneWire {
|
|||||||
/// Helper that wraps search in a std::vector.
|
/// Helper that wraps search in a std::vector.
|
||||||
std::vector<uint64_t> search_vec();
|
std::vector<uint64_t> search_vec();
|
||||||
|
|
||||||
GPIOPin *get_pin();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer.
|
/// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer.
|
||||||
inline uint8_t *rom_number8_();
|
inline uint8_t *rom_number8_();
|
||||||
|
|
||||||
GPIOPin *pin_;
|
ISRInternalGPIOPin pin_;
|
||||||
uint8_t last_discrepancy_{0};
|
uint8_t last_discrepancy_{0};
|
||||||
uint8_t last_family_discrepancy_{0};
|
uint8_t last_family_discrepancy_{0};
|
||||||
bool last_device_flag_{false};
|
bool last_device_flag_{false};
|
||||||
|
@ -9,6 +9,22 @@ namespace esp32 {
|
|||||||
|
|
||||||
static const char *const TAG = "esp32";
|
static const char *const TAG = "esp32";
|
||||||
|
|
||||||
|
static int IRAM_ATTR flags_to_mode(gpio::Flags flags) {
|
||||||
|
if (flags == gpio::FLAG_INPUT) {
|
||||||
|
return INPUT;
|
||||||
|
} else if (flags == gpio::FLAG_OUTPUT) {
|
||||||
|
return OUTPUT;
|
||||||
|
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
|
||||||
|
return INPUT_PULLUP;
|
||||||
|
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) {
|
||||||
|
return INPUT_PULLDOWN;
|
||||||
|
} else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
|
||||||
|
return OUTPUT_OPEN_DRAIN;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ISRPinArg {
|
struct ISRPinArg {
|
||||||
uint8_t pin;
|
uint8_t pin;
|
||||||
bool inverted;
|
bool inverted;
|
||||||
@ -43,22 +59,9 @@ void ArduinoInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, g
|
|||||||
|
|
||||||
attachInterruptArg(pin_, func, arg, arduino_mode);
|
attachInterruptArg(pin_, func, arg, arduino_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||||
uint8_t mode;
|
pinMode(pin_, flags_to_mode(flags)); // NOLINT
|
||||||
if (flags == gpio::FLAG_INPUT) {
|
|
||||||
mode = INPUT;
|
|
||||||
} else if (flags == gpio::FLAG_OUTPUT) {
|
|
||||||
mode = OUTPUT;
|
|
||||||
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
|
|
||||||
mode = INPUT_PULLUP;
|
|
||||||
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) {
|
|
||||||
mode = INPUT_PULLDOWN;
|
|
||||||
} else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
|
|
||||||
mode = OUTPUT_OPEN_DRAIN;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(pin_, mode); // NOLINT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ArduinoInternalGPIOPin::dump_summary() const {
|
std::string ArduinoInternalGPIOPin::dump_summary() const {
|
||||||
@ -101,6 +104,10 @@ void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||||
|
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||||
|
pinMode(arg->pin, flags_to_mode(flags)); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
@ -10,38 +10,7 @@ static const char *const TAG = "esp32";
|
|||||||
|
|
||||||
bool IDFInternalGPIOPin::isr_service_installed = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
bool IDFInternalGPIOPin::isr_service_installed = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
struct ISRPinArg {
|
static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) {
|
||||||
gpio_num_t pin;
|
|
||||||
bool inverted;
|
|
||||||
};
|
|
||||||
|
|
||||||
ISRInternalGPIOPin IDFInternalGPIOPin::to_isr() const {
|
|
||||||
auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
|
|
||||||
arg->pin = pin_;
|
|
||||||
arg->inverted = inverted_;
|
|
||||||
return ISRInternalGPIOPin((void *) arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDFInternalGPIOPin::setup() {
|
|
||||||
pin_mode(flags_);
|
|
||||||
gpio_set_drive_capability(pin_, drive_strength_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
|
||||||
gpio_config_t conf{};
|
|
||||||
conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_);
|
|
||||||
conf.mode = flags_to_mode(flags);
|
|
||||||
conf.pull_up_en = flags & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
|
|
||||||
conf.pull_down_en = flags & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE;
|
|
||||||
conf.intr_type = GPIO_INTR_DISABLE;
|
|
||||||
gpio_config(&conf);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDFInternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; }
|
|
||||||
|
|
||||||
void IDFInternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); }
|
|
||||||
|
|
||||||
gpio_mode_t IDFInternalGPIOPin::flags_to_mode(gpio::Flags flags) {
|
|
||||||
flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN));
|
flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN));
|
||||||
if (flags == gpio::FLAG_NONE) {
|
if (flags == gpio::FLAG_NONE) {
|
||||||
return GPIO_MODE_DISABLE;
|
return GPIO_MODE_DISABLE;
|
||||||
@ -61,6 +30,18 @@ gpio_mode_t IDFInternalGPIOPin::flags_to_mode(gpio::Flags flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ISRPinArg {
|
||||||
|
gpio_num_t pin;
|
||||||
|
bool inverted;
|
||||||
|
};
|
||||||
|
|
||||||
|
ISRInternalGPIOPin IDFInternalGPIOPin::to_isr() const {
|
||||||
|
auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
arg->pin = pin_;
|
||||||
|
arg->inverted = inverted_;
|
||||||
|
return ISRInternalGPIOPin((void *) arg);
|
||||||
|
}
|
||||||
|
|
||||||
void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
|
void IDFInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
|
||||||
gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE;
|
gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -99,6 +80,35 @@ std::string IDFInternalGPIOPin::dump_summary() const {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IDFInternalGPIOPin::setup() {
|
||||||
|
gpio_config_t conf{};
|
||||||
|
conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_);
|
||||||
|
conf.mode = flags_to_mode(flags_);
|
||||||
|
conf.pull_up_en = flags_ & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
|
||||||
|
conf.pull_down_en = flags_ & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE;
|
||||||
|
conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
|
gpio_config(&conf);
|
||||||
|
gpio_set_drive_capability(pin_, drive_strength_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IDFInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||||
|
// can't call gpio_config here because that logs in esp-idf which may cause issues
|
||||||
|
gpio_set_direction(pin_, flags_to_mode(flags));
|
||||||
|
gpio_pull_mode_t pull_mode = GPIO_FLOATING;
|
||||||
|
if (flags & (gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)) {
|
||||||
|
pull_mode = GPIO_PULLUP_PULLDOWN;
|
||||||
|
} else if (flags & gpio::FLAG_PULLUP) {
|
||||||
|
pull_mode = GPIO_PULLUP_ONLY;
|
||||||
|
} else if (flags & gpio::FLAG_PULLDOWN) {
|
||||||
|
pull_mode = GPIO_PULLDOWN_ONLY;
|
||||||
|
}
|
||||||
|
gpio_set_pull_mode(pin_, pull_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IDFInternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; }
|
||||||
|
void IDFInternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); }
|
||||||
|
void IDFInternalGPIOPin::detach_interrupt() const { gpio_intr_disable(pin_); }
|
||||||
|
|
||||||
} // namespace esp32
|
} // namespace esp32
|
||||||
|
|
||||||
using namespace esp32;
|
using namespace esp32;
|
||||||
@ -114,6 +124,19 @@ void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) {
|
|||||||
void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
||||||
// not supported
|
// not supported
|
||||||
}
|
}
|
||||||
|
void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||||
|
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||||
|
gpio_set_direction(arg->pin, flags_to_mode(flags));
|
||||||
|
gpio_pull_mode_t pull_mode = GPIO_FLOATING;
|
||||||
|
if (flags & (gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)) {
|
||||||
|
pull_mode = GPIO_PULLUP_PULLDOWN;
|
||||||
|
} else if (flags & gpio::FLAG_PULLUP) {
|
||||||
|
pull_mode = GPIO_PULLUP_ONLY;
|
||||||
|
} else if (flags & gpio::FLAG_PULLDOWN) {
|
||||||
|
pull_mode = GPIO_PULLDOWN_ONLY;
|
||||||
|
}
|
||||||
|
gpio_set_pull_mode(arg->pin, pull_mode);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
@ -18,13 +18,12 @@ class IDFInternalGPIOPin : public InternalGPIOPin {
|
|||||||
bool digital_read() override;
|
bool digital_read() override;
|
||||||
void digital_write(bool value) override;
|
void digital_write(bool value) override;
|
||||||
std::string dump_summary() const override;
|
std::string dump_summary() const override;
|
||||||
void detach_interrupt() const override { gpio_intr_disable(pin_); }
|
void detach_interrupt() const override;
|
||||||
ISRInternalGPIOPin to_isr() const override;
|
ISRInternalGPIOPin to_isr() const override;
|
||||||
uint8_t get_pin() const override { return (uint8_t) pin_; }
|
uint8_t get_pin() const override { return (uint8_t) pin_; }
|
||||||
bool is_inverted() const override { return inverted_; }
|
bool is_inverted() const override { return inverted_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static gpio_mode_t flags_to_mode(gpio::Flags flags);
|
|
||||||
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
|
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
|
||||||
|
|
||||||
gpio_num_t pin_;
|
gpio_num_t pin_;
|
||||||
|
@ -8,6 +8,29 @@ namespace esp8266 {
|
|||||||
|
|
||||||
static const char *const TAG = "esp8266";
|
static const char *const TAG = "esp8266";
|
||||||
|
|
||||||
|
static int IRAM_ATTR flags_to_mode(gpio::Flags flags, uint8_t pin) {
|
||||||
|
if (flags == gpio::FLAG_INPUT) {
|
||||||
|
return INPUT;
|
||||||
|
} else if (flags == gpio::FLAG_OUTPUT) {
|
||||||
|
return OUTPUT;
|
||||||
|
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
|
||||||
|
if (pin == 16) {
|
||||||
|
// GPIO16 doesn't have a pullup, so pinMode would fail.
|
||||||
|
// However, sometimes this method is called with pullup mode anyway
|
||||||
|
// for example from dallas one_wire. For those cases convert this
|
||||||
|
// to a INPUT mode.
|
||||||
|
return INPUT;
|
||||||
|
}
|
||||||
|
return INPUT_PULLUP;
|
||||||
|
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) {
|
||||||
|
return INPUT_PULLDOWN_16;
|
||||||
|
} else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
|
||||||
|
return OUTPUT_OPEN_DRAIN;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct ISRPinArg {
|
struct ISRPinArg {
|
||||||
uint8_t pin;
|
uint8_t pin;
|
||||||
bool inverted;
|
bool inverted;
|
||||||
@ -43,28 +66,7 @@ void ESP8266GPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::Int
|
|||||||
attachInterruptArg(pin_, func, arg, arduino_mode);
|
attachInterruptArg(pin_, func, arg, arduino_mode);
|
||||||
}
|
}
|
||||||
void ESP8266GPIOPin::pin_mode(gpio::Flags flags) {
|
void ESP8266GPIOPin::pin_mode(gpio::Flags flags) {
|
||||||
uint8_t mode;
|
pinMode(pin_, flags_to_mode(flags, pin_)); // NOLINT
|
||||||
if (flags == gpio::FLAG_INPUT) {
|
|
||||||
mode = INPUT;
|
|
||||||
} else if (flags == gpio::FLAG_OUTPUT) {
|
|
||||||
mode = OUTPUT;
|
|
||||||
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLUP)) {
|
|
||||||
mode = INPUT_PULLUP;
|
|
||||||
if (pin_ == 16) {
|
|
||||||
// GPIO16 doesn't have a pullup, so pinMode would fail.
|
|
||||||
// However, sometimes this method is called with pullup mode anyway
|
|
||||||
// for example from dallas one_wire. For those cases convert this
|
|
||||||
// to a INPUT mode.
|
|
||||||
mode = INPUT;
|
|
||||||
}
|
|
||||||
} else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_PULLDOWN)) {
|
|
||||||
mode = INPUT_PULLDOWN_16;
|
|
||||||
} else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
|
|
||||||
mode = OUTPUT_OPEN_DRAIN;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pinMode(pin_, mode); // NOLINT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ESP8266GPIOPin::dump_summary() const {
|
std::string ESP8266GPIOPin::dump_summary() const {
|
||||||
@ -97,6 +99,10 @@ void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() {
|
|||||||
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||||
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin);
|
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin);
|
||||||
}
|
}
|
||||||
|
void IRAM_ATTR ISRInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||||
|
auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
|
||||||
|
pinMode(arg->pin, flags_to_mode(flags, arg->pin)); // NOLINT
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ class ISRInternalGPIOPin {
|
|||||||
bool digital_read();
|
bool digital_read();
|
||||||
void digital_write(bool value);
|
void digital_write(bool value);
|
||||||
void clear_interrupt();
|
void clear_interrupt();
|
||||||
|
void pin_mode(gpio::Flags flags);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void *arg_ = nullptr;
|
void *arg_ = nullptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user