mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add IDF support to dallas (#2578)
This commit is contained in:
		| @@ -6,26 +6,20 @@ from esphome.const import CONF_ID, CONF_PIN | ||||
| MULTI_CONF = True | ||||
| AUTO_LOAD = ["sensor"] | ||||
|  | ||||
| CONF_ONE_WIRE_ID = "one_wire_id" | ||||
| dallas_ns = cg.esphome_ns.namespace("dallas") | ||||
| DallasComponent = dallas_ns.class_("DallasComponent", cg.PollingComponent) | ||||
| ESPOneWire = dallas_ns.class_("ESPOneWire") | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             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, | ||||
|         } | ||||
|     ).extend(cv.polling_component_schema("60s")), | ||||
|     # pin_mode call logs in esp-idf, but InterruptLock is active -> crash | ||||
|     cv.only_with_arduino, | ||||
| ) | ||||
| CONFIG_SCHEMA = cv.Schema( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(DallasComponent), | ||||
|         cv.Required(CONF_PIN): pins.internal_gpio_output_pin_schema, | ||||
|     } | ||||
| ).extend(cv.polling_component_schema("60s")) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     pin = await cg.gpio_pin_expression(config[CONF_PIN]) | ||||
|     one_wire = cg.new_Pvariable(config[CONF_ONE_WIRE_ID], pin) | ||||
|     var = cg.new_Pvariable(config[CONF_ID], one_wire) | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     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() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up DallasComponent..."); | ||||
|  | ||||
|   yield(); | ||||
|   pin_->setup(); | ||||
|   one_wire_ = new ESPOneWire(pin_);  // NOLINT(cppcoreguidelines-owning-memory) | ||||
|  | ||||
|   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) { | ||||
|     std::string s = uint64_to_string(address); | ||||
| @@ -70,7 +69,7 @@ void DallasComponent::setup() { | ||||
| } | ||||
| void DallasComponent::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "DallasComponent:"); | ||||
|   LOG_PIN("  Pin: ", this->one_wire_->get_pin()); | ||||
|   LOG_PIN("  Pin: ", this->pin_); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
|  | ||||
|   if (this->found_sensors_.empty()) { | ||||
| @@ -102,15 +101,12 @@ void DallasComponent::update() { | ||||
|   this->status_clear_warning(); | ||||
|  | ||||
|   bool result; | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     if (!this->one_wire_->reset()) { | ||||
|       result = false; | ||||
|     } else { | ||||
|       result = true; | ||||
|       this->one_wire_->skip(); | ||||
|       this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); | ||||
|     } | ||||
|   if (!this->one_wire_->reset()) { | ||||
|     result = false; | ||||
|   } else { | ||||
|     result = true; | ||||
|     this->one_wire_->skip(); | ||||
|     this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION); | ||||
|   } | ||||
|  | ||||
|   if (!result) { | ||||
| @@ -121,11 +117,7 @@ void DallasComponent::update() { | ||||
|  | ||||
|   for (auto *sensor : this->sensors_) { | ||||
|     this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] { | ||||
|       bool res; | ||||
|       { | ||||
|         InterruptLock lock; | ||||
|         res = sensor->read_scratch_pad(); | ||||
|       } | ||||
|       bool res = sensor->read_scratch_pad(); | ||||
|  | ||||
|       if (!res) { | ||||
|         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; } | ||||
| uint8_t DallasTemperatureSensor::get_resolution() const { return this->resolution_; } | ||||
| @@ -162,7 +153,7 @@ const std::string &DallasTemperatureSensor::get_address_name() { | ||||
|   return this->address_name_; | ||||
| } | ||||
| bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() { | ||||
|   ESPOneWire *wire = this->parent_->one_wire_; | ||||
|   auto *wire = this->parent_->one_wire_; | ||||
|   if (!wire->reset()) { | ||||
|     return false; | ||||
|   } | ||||
| @@ -176,11 +167,7 @@ bool IRAM_ATTR DallasTemperatureSensor::read_scratch_pad() { | ||||
|   return true; | ||||
| } | ||||
| bool DallasTemperatureSensor::setup_sensor() { | ||||
|   bool r; | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     r = this->read_scratch_pad(); | ||||
|   } | ||||
|   bool r = this->read_scratch_pad(); | ||||
|  | ||||
|   if (!r) { | ||||
|     ESP_LOGE(TAG, "Reading scratchpad failed: reset"); | ||||
| @@ -214,21 +201,18 @@ bool DallasTemperatureSensor::setup_sensor() { | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   ESPOneWire *wire = this->parent_->one_wire_; | ||||
|   { | ||||
|     InterruptLock lock; | ||||
|     if (wire->reset()) { | ||||
|       wire->select(this->address_); | ||||
|       wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); | ||||
|       wire->write8(this->scratch_pad_[2]);  // high alarm temp | ||||
|       wire->write8(this->scratch_pad_[3]);  // low alarm temp | ||||
|       wire->write8(this->scratch_pad_[4]);  // resolution | ||||
|       wire->reset(); | ||||
|   auto *wire = this->parent_->one_wire_; | ||||
|   if (wire->reset()) { | ||||
|     wire->select(this->address_); | ||||
|     wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD); | ||||
|     wire->write8(this->scratch_pad_[2]);  // high alarm temp | ||||
|     wire->write8(this->scratch_pad_[3]);  // low alarm temp | ||||
|     wire->write8(this->scratch_pad_[4]);  // resolution | ||||
|     wire->reset(); | ||||
|  | ||||
|       // write value to EEPROM | ||||
|       wire->select(this->address_); | ||||
|       wire->write8(0x48); | ||||
|     } | ||||
|     // write value to EEPROM | ||||
|     wire->select(this->address_); | ||||
|     wire->write8(0x48); | ||||
|   } | ||||
|  | ||||
|   delay(20);  // allow it to finish operation | ||||
|   | ||||
| @@ -11,8 +11,7 @@ class DallasTemperatureSensor; | ||||
|  | ||||
| class DallasComponent : public PollingComponent { | ||||
|  public: | ||||
|   explicit DallasComponent(ESPOneWire *one_wire); | ||||
|  | ||||
|   void set_pin(InternalGPIOPin *pin) { pin_ = pin; } | ||||
|   void register_sensor(DallasTemperatureSensor *sensor); | ||||
|  | ||||
|   void setup() override; | ||||
| @@ -24,6 +23,7 @@ class DallasComponent : public PollingComponent { | ||||
|  protected: | ||||
|   friend DallasTemperatureSensor; | ||||
|  | ||||
|   InternalGPIOPin *pin_; | ||||
|   ESPOneWire *one_wire_; | ||||
|   std::vector<DallasTemperatureSensor *> 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 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() { | ||||
|   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 | ||||
|   this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||
|   // Wait for communication to clear (delay G) | ||||
|   pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||
|   uint8_t retries = 125; | ||||
|   do { | ||||
|     if (--retries == 0) | ||||
|       return false; | ||||
|     delayMicroseconds(2); | ||||
|   } while (!this->pin_->digital_read()); | ||||
|   } while (!pin_.digital_read()); | ||||
|  | ||||
|   // Send 480µs LOW TX reset pulse | ||||
|   this->pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||
|   this->pin_->digital_write(false); | ||||
|   // Send 480µs LOW TX reset pulse (drive bus low, delay H) | ||||
|   pin_.pin_mode(gpio::FLAG_OUTPUT); | ||||
|   pin_.digital_write(false); | ||||
|   delayMicroseconds(480); | ||||
|  | ||||
|   // Switch into RX mode, letting the pin float | ||||
|   this->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 | ||||
|   // Release the bus, delay I | ||||
|   pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||
|   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); | ||||
|   return r; | ||||
| } | ||||
|  | ||||
| void HOT IRAM_ATTR ESPOneWire::write_bit(bool bit) { | ||||
|   // Initiate write/read by pulling low. | ||||
|   this->pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||
|   this->pin_->digital_write(false); | ||||
|   // See write 1/0 bit here: | ||||
|   // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html | ||||
|   InterruptLock lock; | ||||
|  | ||||
|   // bus sampled within 15µs and 60µs after pulling LOW. | ||||
|   if (bit) { | ||||
|     // pull high/release within 15µs | ||||
|     delayMicroseconds(10); | ||||
|     this->pin_->digital_write(true); | ||||
|     // in total minimum of 60µs long | ||||
|     delayMicroseconds(55); | ||||
|   } else { | ||||
|     // continue pulling LOW for at least 60µs | ||||
|     delayMicroseconds(65); | ||||
|     this->pin_->digital_write(true); | ||||
|     // grace period, 1µs recovery time | ||||
|     delayMicroseconds(5); | ||||
|   } | ||||
|   // drive bus low | ||||
|   pin_.pin_mode(gpio::FLAG_OUTPUT); | ||||
|   pin_.digital_write(false); | ||||
|  | ||||
|   uint32_t delay0 = bit ? 10 : 65; | ||||
|   uint32_t delay1 = bit ? 55 : 5; | ||||
|  | ||||
|   // delay A/C | ||||
|   delayMicroseconds(delay0); | ||||
|   // release bus | ||||
|   pin_.digital_write(true); | ||||
|   // delay B/D | ||||
|   delayMicroseconds(delay1); | ||||
| } | ||||
|  | ||||
| bool HOT IRAM_ATTR ESPOneWire::read_bit() { | ||||
|   // Initiate read slot by pulling LOW for at least 1µs | ||||
|   this->pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||
|   this->pin_->digital_write(false); | ||||
|   // See read bit here: | ||||
|   // https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/126.html | ||||
|   InterruptLock lock; | ||||
|  | ||||
|   // drive bus low, delay A | ||||
|   pin_.pin_mode(gpio::FLAG_OUTPUT); | ||||
|   pin_.digital_write(false); | ||||
|   delayMicroseconds(3); | ||||
|  | ||||
|   // release bus, we have to sample within 15µs of pulling low | ||||
|   this->pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||
|   // release bus, delay E | ||||
|   pin_.pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||||
|   delayMicroseconds(10); | ||||
|  | ||||
|   bool r = this->pin_->digital_read(); | ||||
|   // read time slot at least 60µs long + 1µs recovery time between slots | ||||
|   // sample bus to read bit from peer | ||||
|   bool r = pin_.digital_read(); | ||||
|  | ||||
|   // delay F | ||||
|   delayMicroseconds(53); | ||||
|   return r; | ||||
| } | ||||
|  | ||||
| void IRAM_ATTR ESPOneWire::write8(uint8_t val) { | ||||
| void ESPOneWire::write8(uint8_t val) { | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     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++) { | ||||
|     this->write_bit(bool((1ULL << i) & val)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| uint8_t IRAM_ATTR ESPOneWire::read8() { | ||||
| uint8_t ESPOneWire::read8() { | ||||
|   uint8_t ret = 0; | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     ret |= (uint8_t(this->read_bit()) << i); | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
| uint64_t IRAM_ATTR ESPOneWire::read64() { | ||||
| uint64_t ESPOneWire::read64() { | ||||
|   uint64_t ret = 0; | ||||
|   for (uint8_t i = 0; i < 8; i++) { | ||||
|     ret |= (uint64_t(this->read_bit()) << i); | ||||
|   } | ||||
|   return ret; | ||||
| } | ||||
| void IRAM_ATTR ESPOneWire::select(uint64_t address) { | ||||
| void ESPOneWire::select(uint64_t address) { | ||||
|   this->write8(ONE_WIRE_ROM_SELECT); | ||||
|   this->write64(address); | ||||
| } | ||||
| void IRAM_ATTR ESPOneWire::reset_search() { | ||||
| void ESPOneWire::reset_search() { | ||||
|   this->last_discrepancy_ = 0; | ||||
|   this->last_device_flag_ = false; | ||||
|   this->last_family_discrepancy_ = 0; | ||||
|   this->rom_number_ = 0; | ||||
| } | ||||
| uint64_t HOT IRAM_ATTR ESPOneWire::search() { | ||||
| uint64_t ESPOneWire::search() { | ||||
|   if (this->last_device_flag_) { | ||||
|     return 0u; | ||||
|   } | ||||
|  | ||||
|   if (!this->reset()) { | ||||
|     // Reset failed | ||||
|     // Reset failed or no devices present | ||||
|     this->reset_search(); | ||||
|     return 0u; | ||||
|   } | ||||
| @@ -196,7 +204,7 @@ uint64_t HOT IRAM_ATTR ESPOneWire::search() { | ||||
|  | ||||
|   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; | ||||
|  | ||||
|   this->reset_search(); | ||||
| @@ -206,10 +214,9 @@ std::vector<uint64_t> IRAM_ATTR ESPOneWire::search_vec() { | ||||
|  | ||||
|   return res; | ||||
| } | ||||
| void IRAM_ATTR ESPOneWire::skip() { | ||||
| void ESPOneWire::skip() { | ||||
|   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_); } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include <vector> | ||||
|  | ||||
| @@ -12,7 +11,7 @@ extern const int ONE_WIRE_ROM_SEARCH; | ||||
|  | ||||
| class ESPOneWire { | ||||
|  public: | ||||
|   explicit ESPOneWire(GPIOPin *pin); | ||||
|   explicit ESPOneWire(InternalGPIOPin *pin); | ||||
|  | ||||
|   /** Reset the bus, should be done before all write operations. | ||||
|    * | ||||
| @@ -55,13 +54,11 @@ class ESPOneWire { | ||||
|   /// Helper that wraps search in a std::vector. | ||||
|   std::vector<uint64_t> search_vec(); | ||||
|  | ||||
|   GPIOPin *get_pin(); | ||||
|  | ||||
|  protected: | ||||
|   /// Helper to get the internal 64-bit unsigned rom number as a 8-bit integer pointer. | ||||
|   inline uint8_t *rom_number8_(); | ||||
|  | ||||
|   GPIOPin *pin_; | ||||
|   ISRInternalGPIOPin pin_; | ||||
|   uint8_t last_discrepancy_{0}; | ||||
|   uint8_t last_family_discrepancy_{0}; | ||||
|   bool last_device_flag_{false}; | ||||
|   | ||||
| @@ -9,6 +9,22 @@ namespace 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 { | ||||
|   uint8_t pin; | ||||
|   bool inverted; | ||||
| @@ -43,22 +59,9 @@ void ArduinoInternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, g | ||||
|  | ||||
|   attachInterruptArg(pin_, func, arg, arduino_mode); | ||||
| } | ||||
|  | ||||
| void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) { | ||||
|   uint8_t mode; | ||||
|   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 | ||||
|   pinMode(pin_, flags_to_mode(flags));  // NOLINT | ||||
| } | ||||
|  | ||||
| std::string ArduinoInternalGPIOPin::dump_summary() const { | ||||
| @@ -101,6 +104,10 @@ void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | ||||
|   } | ||||
| #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 | ||||
|  | ||||
|   | ||||
| @@ -10,38 +10,7 @@ static const char *const TAG = "esp32"; | ||||
|  | ||||
| bool IDFInternalGPIOPin::isr_service_installed = false;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) | ||||
|  | ||||
| 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::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) { | ||||
| static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) { | ||||
|   flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN)); | ||||
|   if (flags == gpio::FLAG_NONE) { | ||||
|     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 { | ||||
|   gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE; | ||||
|   switch (type) { | ||||
| @@ -99,6 +80,35 @@ std::string IDFInternalGPIOPin::dump_summary() const { | ||||
|   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 | ||||
|  | ||||
| using namespace esp32; | ||||
| @@ -114,6 +124,19 @@ void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) { | ||||
| void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | ||||
|   // 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 | ||||
|  | ||||
|   | ||||
| @@ -18,13 +18,12 @@ class IDFInternalGPIOPin : public InternalGPIOPin { | ||||
|   bool digital_read() override; | ||||
|   void digital_write(bool value) 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; | ||||
|   uint8_t get_pin() const override { return (uint8_t) pin_; } | ||||
|   bool is_inverted() const override { return inverted_; } | ||||
|  | ||||
|  protected: | ||||
|   static gpio_mode_t flags_to_mode(gpio::Flags flags); | ||||
|   void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override; | ||||
|  | ||||
|   gpio_num_t pin_; | ||||
|   | ||||
| @@ -8,6 +8,29 @@ namespace 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 { | ||||
|   uint8_t pin; | ||||
|   bool inverted; | ||||
| @@ -43,28 +66,7 @@ void ESP8266GPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::Int | ||||
|   attachInterruptArg(pin_, func, arg, arduino_mode); | ||||
| } | ||||
| void ESP8266GPIOPin::pin_mode(gpio::Flags flags) { | ||||
|   uint8_t mode; | ||||
|   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 | ||||
|   pinMode(pin_, flags_to_mode(flags, pin_));  // NOLINT | ||||
| } | ||||
|  | ||||
| std::string ESP8266GPIOPin::dump_summary() const { | ||||
| @@ -97,6 +99,10 @@ void IRAM_ATTR ISRInternalGPIOPin::clear_interrupt() { | ||||
|   auto *arg = reinterpret_cast<ISRPinArg *>(arg_); | ||||
|   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 | ||||
|  | ||||
|   | ||||
| @@ -70,6 +70,7 @@ class ISRInternalGPIOPin { | ||||
|   bool digital_read(); | ||||
|   void digital_write(bool value); | ||||
|   void clear_interrupt(); | ||||
|   void pin_mode(gpio::Flags flags); | ||||
|  | ||||
|  protected: | ||||
|   void *arg_ = nullptr; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user