ESPHome  2024.4.1
gpio.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP32
2 
3 #include "gpio.h"
4 #include "esphome/core/log.h"
5 #include <cinttypes>
6 
7 namespace esphome {
8 namespace esp32 {
9 
10 static const char *const TAG = "esp32";
11 
12 bool ESP32InternalGPIOPin::isr_service_installed = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
13 
14 static gpio_mode_t IRAM_ATTR flags_to_mode(gpio::Flags flags) {
15  flags = (gpio::Flags)(flags & ~(gpio::FLAG_PULLUP | gpio::FLAG_PULLDOWN));
16  if (flags == gpio::FLAG_INPUT) {
17  return GPIO_MODE_INPUT;
18  } else if (flags == gpio::FLAG_OUTPUT) {
19  return GPIO_MODE_OUTPUT;
20  } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
21  return GPIO_MODE_OUTPUT_OD;
22  } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
23  return GPIO_MODE_INPUT_OUTPUT_OD;
24  } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT)) {
25  return GPIO_MODE_INPUT_OUTPUT;
26  } else {
27  // unsupported or gpio::FLAG_NONE
28  return GPIO_MODE_DISABLE;
29  }
30 }
31 
32 struct ISRPinArg {
33  gpio_num_t pin;
34  bool inverted;
35 };
36 
38  auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
39  arg->pin = pin_;
40  arg->inverted = inverted_;
41  return ISRInternalGPIOPin((void *) arg);
42 }
43 
44 void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
45  gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE;
46  switch (type) {
48  idf_type = inverted_ ? GPIO_INTR_NEGEDGE : GPIO_INTR_POSEDGE;
49  break;
51  idf_type = inverted_ ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE;
52  break;
54  idf_type = GPIO_INTR_ANYEDGE;
55  break;
57  idf_type = inverted_ ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL;
58  break;
60  idf_type = inverted_ ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL;
61  break;
62  }
63  gpio_set_intr_type(pin_, idf_type);
64  gpio_intr_enable(pin_);
65  if (!isr_service_installed) {
66  auto res = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3);
67  if (res != ESP_OK) {
68  ESP_LOGE(TAG, "attach_interrupt(): call to gpio_install_isr_service() failed, error code: %d", res);
69  return;
70  }
71  isr_service_installed = true;
72  }
73  gpio_isr_handler_add(pin_, func, arg);
74 }
75 
77  char buffer[32];
78  snprintf(buffer, sizeof(buffer), "GPIO%" PRIu32, static_cast<uint32_t>(pin_));
79  return buffer;
80 }
81 
83  gpio_config_t conf{};
84  conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_);
85  conf.mode = flags_to_mode(flags_);
86  conf.pull_up_en = flags_ & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
87  conf.pull_down_en = flags_ & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE;
88  conf.intr_type = GPIO_INTR_DISABLE;
89  gpio_config(&conf);
90  if (flags_ & gpio::FLAG_OUTPUT) {
91  gpio_set_drive_capability(pin_, drive_strength_);
92  }
93 }
94 
96  // can't call gpio_config here because that logs in esp-idf which may cause issues
97  gpio_set_direction(pin_, flags_to_mode(flags));
98  gpio_pull_mode_t pull_mode = GPIO_FLOATING;
99  if ((flags & gpio::FLAG_PULLUP) && (flags & gpio::FLAG_PULLDOWN)) {
100  pull_mode = GPIO_PULLUP_PULLDOWN;
101  } else if (flags & gpio::FLAG_PULLUP) {
102  pull_mode = GPIO_PULLUP_ONLY;
103  } else if (flags & gpio::FLAG_PULLDOWN) {
104  pull_mode = GPIO_PULLDOWN_ONLY;
105  }
106  gpio_set_pull_mode(pin_, pull_mode);
107 }
108 
109 bool ESP32InternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; }
110 void ESP32InternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); }
111 void ESP32InternalGPIOPin::detach_interrupt() const { gpio_intr_disable(pin_); }
112 
113 } // namespace esp32
114 
115 using namespace esp32;
116 
118  auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
119  return bool(gpio_get_level(arg->pin)) != arg->inverted;
120 }
121 void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) {
122  auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
123  gpio_set_level(arg->pin, value != arg->inverted ? 1 : 0);
124 }
126  // not supported
127 }
129  auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
130  gpio_set_direction(arg->pin, flags_to_mode(flags));
131  gpio_pull_mode_t pull_mode = GPIO_FLOATING;
132  if ((flags & gpio::FLAG_PULLUP) && (flags & gpio::FLAG_PULLDOWN)) {
133  pull_mode = GPIO_PULLUP_PULLDOWN;
134  } else if (flags & gpio::FLAG_PULLUP) {
135  pull_mode = GPIO_PULLUP_ONLY;
136  } else if (flags & gpio::FLAG_PULLDOWN) {
137  pull_mode = GPIO_PULLDOWN_ONLY;
138  }
139  gpio_set_pull_mode(arg->pin, pull_mode);
140 }
141 
142 } // namespace esphome
143 
144 #endif // USE_ESP32
ISRInternalGPIOPin to_isr() const override
Definition: gpio.cpp:37
Copy of GPIOPin that is safe to use from ISRs (with no virtual functions)
Definition: gpio.h:66
void detach_interrupt() const override
Definition: gpio.cpp:111
void pin_mode(gpio::Flags flags)
Definition: gpio.cpp:128
void digital_write(bool value) override
Definition: gpio.cpp:110
uint8_t type
void pin_mode(gpio::Flags flags) override
Definition: gpio.cpp:95
const uint32_t flags
Definition: stm32flash.h:85
InterruptType
Definition: gpio.h:40
void attach_interrupt(void(*func)(void *), void *arg, gpio::InterruptType type) const override
Definition: gpio.cpp:44
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
std::string dump_summary() const override
Definition: gpio.cpp:76
void digital_write(bool value)
Definition: gpio.cpp:121