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