ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
gpio.cpp
Go to the documentation of this file.
1#ifdef USE_ESP8266
2
3#include "gpio.h"
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6
7namespace esphome::esp8266 {
8
9ESPHOME_LOG_TAG(TAG, "esp8266");
10
11static int flags_to_mode(gpio::Flags flags, uint8_t pin) {
12 flags =
15 return OUTPUT;
16 }
17 if (flags == gpio::FLAG_INPUT) {
18 return INPUT;
19 }
21 if (pin == 16) {
22 // GPIO16 doesn't have a pullup, so pinMode would fail.
23 // However, sometimes this method is called with pullup mode anyway
24 // for example from dallas one_wire. For those cases convert this
25 // to a INPUT mode.
26 return INPUT;
27 }
28 return INPUT_PULLUP;
29 }
31 return INPUT_PULLDOWN_16;
32 }
34 return OUTPUT_OPEN_DRAIN;
35 }
36 return INPUT;
37}
38
39struct ISRPinArg {
40 uint8_t pin;
41 bool inverted;
42 volatile uint32_t *in_reg;
43 volatile uint32_t *out_set_reg;
44 volatile uint32_t *out_clr_reg;
45 volatile uint32_t *mode_set_reg;
46 volatile uint32_t *mode_clr_reg;
47 volatile uint32_t *func_reg;
48 volatile uint32_t *control_reg;
49 uint32_t mask;
50};
51
53 auto *arg = new ISRPinArg{}; // NOLINT(cppcoreguidelines-owning-memory)
54 arg->pin = this->pin_;
55 arg->inverted = this->inverted_;
56 if (this->pin_ < 16) {
57 arg->in_reg = &GPI;
58 arg->out_set_reg = &GPOS;
59 arg->out_clr_reg = &GPOC;
60 arg->mode_set_reg = &GPES;
61 arg->mode_clr_reg = &GPEC;
62 arg->func_reg = &GPF(this->pin_);
63 arg->control_reg = &GPC(this->pin_);
64 arg->mask = 1 << this->pin_;
65 } else {
66 arg->in_reg = &GP16I;
67 arg->out_set_reg = &GP16O;
68 arg->out_clr_reg = nullptr;
69 arg->mode_set_reg = &GP16E;
70 arg->mode_clr_reg = nullptr;
71 arg->func_reg = &GPF16;
72 arg->control_reg = nullptr;
73 arg->mask = 1;
74 }
75 return ISRInternalGPIOPin((void *) arg);
76}
77
78void ESP8266GPIOPin::attach_interrupt_(void (*func)(void *), void *arg, gpio::InterruptType type) const {
79 uint8_t arduino_mode = 0;
80 switch (type) {
82 arduino_mode = inverted_ ? FALLING : RISING;
83 break;
85 arduino_mode = inverted_ ? RISING : FALLING;
86 break;
88 arduino_mode = CHANGE;
89 break;
91 arduino_mode = inverted_ ? ONHIGH : ONLOW;
92 break;
94 arduino_mode = inverted_ ? ONLOW : ONHIGH;
95 break;
96 }
97
98 attachInterruptArg(pin_, func, arg, arduino_mode);
99}
101 pinMode(pin_, flags_to_mode(flags, pin_)); // NOLINT
102}
103
104size_t ESP8266GPIOPin::dump_summary(char *buffer, size_t len) const {
105 return buf_append_printf(buffer, len, 0, "GPIO%u", this->pin_);
106}
107
109 return bool(digitalRead(pin_)) != inverted_; // NOLINT
110}
112 digitalWrite(pin_, value != inverted_ ? 1 : 0); // NOLINT
113}
114void ESP8266GPIOPin::detach_interrupt() const { detachInterrupt(pin_); }
115
116} // namespace esphome::esp8266
117
118namespace esphome {
119
120using esp8266::ISRPinArg;
121
122bool IRAM_ATTR ISRInternalGPIOPin::digital_read() {
123 auto *arg = reinterpret_cast<ISRPinArg *>(this->arg_);
124 return bool(*arg->in_reg & arg->mask) != arg->inverted;
125}
126
127void IRAM_ATTR ISRInternalGPIOPin::digital_write(bool value) {
128 auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
129 if (arg->pin < 16) {
130 if (value != arg->inverted) {
131 *arg->out_set_reg = arg->mask;
132 } else {
133 *arg->out_clr_reg = arg->mask;
134 }
135 } else {
136 if (value != arg->inverted) {
137 *arg->out_set_reg = *arg->out_set_reg | 1;
138 } else {
139 *arg->out_set_reg = *arg->out_set_reg & ~1;
140 }
141 }
142}
143
145 auto *arg = reinterpret_cast<ISRPinArg *>(arg_);
146 // NOLINTNEXTLINE(clang-analyzer-core.FixedAddressDereference) -- GPIO_REG_WRITE is MMIO at a fixed address
147 GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1UL << arg->pin);
148}
149
151 auto *arg = reinterpret_cast<ISRPinArg *>(this->arg_);
152 if (arg->pin < 16) {
153 if (flags & gpio::FLAG_OUTPUT) {
154 *arg->mode_set_reg = arg->mask;
156 *arg->control_reg = *arg->control_reg | (1 << GPCD);
157 } else {
158 *arg->control_reg &= ~(1 << GPCD);
159 }
160 } else if (flags & gpio::FLAG_INPUT) {
161 *arg->mode_clr_reg = arg->mask;
162 }
163 if (flags & gpio::FLAG_PULLUP) {
164 *arg->func_reg = *arg->func_reg | (1 << GPFPU);
165 *arg->control_reg = *arg->control_reg | (1 << GPCD);
166 } else {
167 *arg->func_reg = *arg->func_reg & ~(1 << GPFPU);
168 }
169 } else {
170 if (flags & gpio::FLAG_OUTPUT) {
171 *arg->mode_set_reg = *arg->mode_set_reg | 1;
172 } else {
173 *arg->mode_set_reg = *arg->mode_set_reg & ~1;
174 }
176 *arg->func_reg = *arg->func_reg | (1 << GP16FPD);
177 } else {
178 *arg->func_reg = *arg->func_reg & ~(1 << GP16FPD);
179 }
180 }
181}
182
183} // namespace esphome
184
185#endif // USE_ESP8266
Copy of GPIOPin that is safe to use from ISRs (with no virtual functions)
Definition gpio_pin.h:98
void digital_write(bool value)
Definition gpio.cpp:227
void pin_mode(gpio::Flags flags)
Definition gpio.cpp:239
ISRInternalGPIOPin to_isr() const
Definition gpio.cpp:52
void attach_interrupt_(void(*func)(void *), void *arg, gpio::InterruptType type) const
Definition gpio.cpp:78
bool digital_read() override
Definition gpio.cpp:108
void digital_write(bool value) override
Definition gpio.cpp:111
void pin_mode(gpio::Flags flags) override
Definition gpio.cpp:100
size_t dump_summary(char *buffer, size_t len) const override
Definition gpio.cpp:104
uint16_t flags
uint8_t type
uint32_t buffer
Definition gif.cpp:50
ESPHOME_LOG_TAG(TAG, "esp8266")
@ INTERRUPT_FALLING_EDGE
Definition gpio_pin.h:53
@ INTERRUPT_RISING_EDGE
Definition gpio_pin.h:52
@ INTERRUPT_HIGH_LEVEL
Definition gpio_pin.h:56
@ INTERRUPT_LOW_LEVEL
Definition gpio_pin.h:55
@ INTERRUPT_ANY_EDGE
Definition gpio_pin.h:54
const void size_t len
Definition hal.h:68
static void uint32_t