Add IDF support to dallas (#2578)

This commit is contained in:
Otto Winter 2021-10-21 22:48:28 +02:00 committed by GitHub
parent 1468acfced
commit 68c8547067
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 201 additions and 183 deletions

View File

@ -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))

View File

@ -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();

View File

@ -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_;

View File

@ -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_); }

View File

@ -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};

View File

@ -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

View File

@ -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

View File

@ -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_;

View File

@ -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

View File

@ -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;