ESPHome  2023.3.2
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 
6 namespace esphome {
7 namespace esp32 {
8 
9 static const char *const TAG = "esp32";
10 
11 bool ESP32InternalGPIOPin::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_INPUT) {
16  return GPIO_MODE_INPUT;
17  } else if (flags == gpio::FLAG_OUTPUT) {
18  return GPIO_MODE_OUTPUT;
19  } else if (flags == (gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
20  return GPIO_MODE_OUTPUT_OD;
21  } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT | gpio::FLAG_OPEN_DRAIN)) {
22  return GPIO_MODE_INPUT_OUTPUT_OD;
23  } else if (flags == (gpio::FLAG_INPUT | gpio::FLAG_OUTPUT)) {
24  return GPIO_MODE_INPUT_OUTPUT;
25  } else {
26  // unsupported or gpio::FLAG_NONE
27  return GPIO_MODE_DISABLE;
28  }
29 }
30 
31 struct ISRPinArg {
32  gpio_num_t pin;
33  bool inverted;
34 };
35 
37  auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
38  arg->pin = pin_;
39  arg->inverted = inverted_;
40  return ISRInternalGPIOPin((void *) arg);
41 }
42 
43 void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const {
44  gpio_int_type_t idf_type = GPIO_INTR_ANYEDGE;
45  switch (type) {
47  idf_type = inverted_ ? GPIO_INTR_NEGEDGE : GPIO_INTR_POSEDGE;
48  break;
50  idf_type = inverted_ ? GPIO_INTR_POSEDGE : GPIO_INTR_NEGEDGE;
51  break;
53  idf_type = GPIO_INTR_ANYEDGE;
54  break;
56  idf_type = inverted_ ? GPIO_INTR_HIGH_LEVEL : GPIO_INTR_LOW_LEVEL;
57  break;
59  idf_type = inverted_ ? GPIO_INTR_LOW_LEVEL : GPIO_INTR_HIGH_LEVEL;
60  break;
61  }
62  gpio_set_intr_type(pin_, idf_type);
63  gpio_intr_enable(pin_);
64  if (!isr_service_installed) {
65  auto res = gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3);
66  if (res != ESP_OK) {
67  ESP_LOGE(TAG, "attach_interrupt(): call to gpio_install_isr_service() failed, error code: %d", res);
68  return;
69  }
70  isr_service_installed = true;
71  }
72  gpio_isr_handler_add(pin_, func, arg);
73 }
74 
76  char buffer[32];
77  snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast<uint32_t>(pin_));
78  return buffer;
79 }
80 
82  gpio_config_t conf{};
83  conf.pin_bit_mask = 1ULL << static_cast<uint32_t>(pin_);
84  conf.mode = flags_to_mode(flags_);
85  conf.pull_up_en = flags_ & gpio::FLAG_PULLUP ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
86  conf.pull_down_en = flags_ & gpio::FLAG_PULLDOWN ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE;
87  conf.intr_type = GPIO_INTR_DISABLE;
88  gpio_config(&conf);
89  if (flags_ & gpio::FLAG_OUTPUT) {
90  gpio_set_drive_capability(pin_, drive_strength_);
91  }
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) && (flags & 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 ESP32InternalGPIOPin::digital_read() { return bool(gpio_get_level(pin_)) != inverted_; }
109 void ESP32InternalGPIOPin::digital_write(bool value) { gpio_set_level(pin_, value != inverted_ ? 1 : 0); }
110 void ESP32InternalGPIOPin::detach_interrupt() const { gpio_intr_disable(pin_); }
111 
112 } // namespace esp32
113 
114 using namespace esp32;
115 
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 }
125  // not supported
126 }
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) && (flags & 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
ISRInternalGPIOPin to_isr() const override
Definition: gpio.cpp:36
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:110
void pin_mode(gpio::Flags flags)
Definition: gpio.cpp:127
void digital_write(bool value) override
Definition: gpio.cpp:109
uint8_t type
void pin_mode(gpio::Flags flags) override
Definition: gpio.cpp:94
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:43
Definition: a4988.cpp:4
std::string dump_summary() const override
Definition: gpio.cpp:75
void digital_write(bool value)
Definition: gpio.cpp:120