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