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