Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Esp32Gpio.hxx
Go to the documentation of this file.
1
35#ifndef _DRIVERS_ESP32GPIO_HXX_
36#define _DRIVERS_ESP32GPIO_HXX_
37
40#include "os/Gpio.hxx"
41#include "utils/logging.h"
42#include "utils/macros.h"
43
44#include <driver/gpio.h>
45#include <esp_rom_gpio.h>
46
47#include <soc/gpio_struct.h>
48
49#if defined(CONFIG_IDF_TARGET_ESP32C3)
53#define IS_GPIO_OUTPUT(pin) (GPIO_IS_VALID_OUTPUT_GPIO(pin) && \
54 GPIO.enable.data & BIT(pin & 25))
55#else // NOT ESP32-C3
59#define IS_GPIO_OUTPUT(pin) (GPIO_IS_VALID_OUTPUT_GPIO(pin) && \
60 (pin < 32) ? GPIO.enable & BIT(pin & 31) : \
61 GPIO.enable1.data & BIT(pin & 31))
62#endif // CONFIG_IDF_TARGET_ESP32C3
63
64template <class Defs, bool SAFE_VALUE, bool INVERT> struct GpioOutputPin;
65template <class Defs, bool PUEN, bool PDEN> struct GpioInputPin;
66
74template <gpio_num_t PIN_NUM, bool INVERTED = false>
75class Esp32Gpio : public Gpio
76{
77public:
78#if CONFIG_IDF_TARGET_ESP32S3
79 static_assert(PIN_NUM >= 0 && PIN_NUM <= 48, "Valid pin range is 0..48.");
80 static_assert(!(PIN_NUM >= 22 && PIN_NUM <= 25)
81 , "Pin does not exist");
82 static_assert(!(PIN_NUM >= 26 && PIN_NUM <= 32)
83 , "Pin is reserved for flash usage.");
84#if defined(CONFIG_SPIRAM_MODE_OCT) || defined(CONFIG_ESPTOOLPY_OCT_FLASH)
85 static_assert(!(PIN_NUM >= 33 && PIN_NUM <= 37),
86 "Pin is not available when Octal SPI mode is enabled.");
87#endif // ESP32S3 with Octal SPI
88#elif CONFIG_IDF_TARGET_ESP32S2
89 static_assert(PIN_NUM >= 0 && PIN_NUM <= 46, "Valid pin range is 0..46.");
90 static_assert(!(PIN_NUM >= 22 && PIN_NUM <= 25)
91 , "Pin does not exist");
92 static_assert(!(PIN_NUM >= 26 && PIN_NUM <= 32)
93 , "Pin is reserved for flash usage.");
94#elif CONFIG_IDF_TARGET_ESP32C3
95 static_assert(PIN_NUM >= 0 && PIN_NUM <= 21, "Valid pin range is 0..21.");
96 // these pins are connected to the embedded flash and are not exposed on
97 // the DevKitM-1 board.
98 static_assert(!(PIN_NUM >= 11 && PIN_NUM <= 17)
99 , "Pin is reserved for flash usage.");
100#else // ESP32
101 static_assert(PIN_NUM >= 0 && PIN_NUM <= 39, "Valid pin range is 0..39.");
102 static_assert(PIN_NUM != 24, "Pin does not exist");
103 static_assert(!(PIN_NUM >= 28 && PIN_NUM <= 31), "Pin does not exist");
104 // Most commercially available boards include a capacitor on these two
105 // pins, however, there is no available define that can be used to allow
106 // usage of these when building for a custom PCB using the bare QFN chip.
107 // static_assert(PIN_NUM != 37, "Pin is connected to GPIO 36 via capacitor.");
108 // static_assert(PIN_NUM != 38, "Pin is connected to GPIO 39 via capacitor.");
109#if defined(ESP32_PICO)
110 static_assert(!(PIN_NUM >= 6 && PIN_NUM <= 8)
111 , "Pin is reserved for flash usage.");
112 static_assert(PIN_NUM != 11 && PIN_NUM != 16 && PIN_NUM != 17
113 , "Pin is reserved for flash usage.");
114#else
115 static_assert(!(PIN_NUM >= 6 && PIN_NUM <= 11)
116 , "Pin is reserved for flash usage.");
117#if defined(BOARD_HAS_PSRAM) || defined(CONFIG_SPIRAM_SUPPORT)
118 static_assert(PIN_NUM != 16 && PIN_NUM != 17
119 , "Pin is reserved for PSRAM usage.");
120#endif // BOARD_HAS_PSRAM
121#endif // ESP32_PICO
122#endif // CONFIG_IDF_TARGET_ESP32S2 / CONFIG_IDF_TARGET_ESP32S3
123
127 void write(Value new_state) const override
128 {
129 if (INVERTED)
130 {
131 LOG(VERBOSE, "Esp32Gpio(%d) write %s", PIN_NUM,
132 new_state == Value::SET ? "CLR" : "SET");
133 ESP_ERROR_CHECK(gpio_set_level(PIN_NUM, new_state == Value::CLR));
134 }
135 else
136 {
137 LOG(VERBOSE, "Esp32Gpio(%d) write %s", PIN_NUM,
138 new_state == Value::SET ? "SET" : "CLR");
139 ESP_ERROR_CHECK(gpio_set_level(PIN_NUM, new_state));
140 }
141 }
142
145 Value read() const override
146 {
147 return (Value)gpio_get_level(PIN_NUM);
148 }
149
151 void set() const override
152 {
153 write(Value::SET);
154 }
155
157 void clr() const override
158 {
159 write(Value::CLR);
160 }
161
163 void set_direction(Direction dir) const override
164 {
165 if (dir == Direction::DOUTPUT)
166 {
167 HASSERT(GPIO_IS_VALID_OUTPUT_GPIO(PIN_NUM));
168 // using GPIO_MODE_INPUT_OUTPUT instead of GPIO_MODE_OUTPUT so that
169 // we can read the IO state
170 ESP_ERROR_CHECK(
171 gpio_set_direction(PIN_NUM, GPIO_MODE_INPUT_OUTPUT));
172 LOG(VERBOSE, "Esp32Gpio(%d) configured as OUTPUT", PIN_NUM);
173 }
174 else
175 {
176 ESP_ERROR_CHECK(gpio_set_direction(PIN_NUM, GPIO_MODE_INPUT));
177 LOG(VERBOSE, "Esp32Gpio(%d) configured as INPUT", PIN_NUM);
178 }
179 }
180
183 Direction direction() const override
184 {
185 if (IS_GPIO_OUTPUT(PIN_NUM))
186 {
187 return Direction::DOUTPUT;
188 }
189 return Direction::DINPUT;
190 }
191private:
192 template <class Defs, bool SAFE_VALUE, bool INVERT> friend struct GpioOutputPin;
193 template <class Defs, bool PUEN, bool PDEN> friend struct GpioInputPin;
199 static const Esp32Gpio instance_;
200};
201
203template <gpio_num_t PIN_NUM, bool INVERTED>
205
211template <class Defs, bool SAFE_VALUE, bool INVERT = false>
212struct GpioOutputPin : public Defs
213{
214public:
215 using Defs::PIN_NUM;
216// compile time sanity check that the selected pin is valid for output.
217#if CONFIG_IDF_TARGET_ESP32S2
218 static_assert(PIN_NUM != 46, "Pin 46 can not be used for output.");
219#elif CONFIG_IDF_TARGET_ESP32
220 static_assert(PIN_NUM < 34, "Pins 34 and above can not be used as output.");
221#endif // CONFIG_IDF_TARGET_ESP32S2 / CONFIG_IDF_TARGET_ESP32S3
222
224 static void hw_init()
225 {
226 LOG(VERBOSE,
227 "[Esp32Gpio] Configuring output pin %d, default value: %d",
228 PIN_NUM, SAFE_VALUE);
229 esp_rom_gpio_pad_select_gpio(PIN_NUM);
230 gpio_config_t cfg;
231 memset(&cfg, 0, sizeof(gpio_config_t));
232 cfg.pin_bit_mask = BIT64(PIN_NUM);
233 // using GPIO_MODE_INPUT_OUTPUT instead of GPIO_MODE_OUTPUT so that
234 // we can read the IO state
235 cfg.mode = GPIO_MODE_INPUT_OUTPUT;
236 ESP_ERROR_CHECK(gpio_config(&cfg));
237 ESP_ERROR_CHECK(gpio_set_level(PIN_NUM, SAFE_VALUE));
238 }
239
241 static void hw_set_to_safe()
242 {
243 ESP_ERROR_CHECK(gpio_set_level(PIN_NUM, SAFE_VALUE));
244 }
245
247 static void toggle()
248 {
249 instance()->write(!instance()->read());
250 }
251
254 static void set(bool value)
255 {
256 instance()->write(value);
257 }
258
260 static constexpr const Gpio *instance()
261 {
263 }
264};
265
269template <class Defs>
270struct GpioOutputSafeLow : public GpioOutputPin<Defs, false>
271{
272};
273
278template <class Defs>
279struct GpioOutputSafeLowInvert : public GpioOutputPin<Defs, false, true>
280{
281};
282
286template <class Defs>
287struct GpioOutputSafeHigh : public GpioOutputPin<Defs, true>
288{
289};
290
295template <class Defs>
296struct GpioOutputSafeHighInvert : public GpioOutputPin<Defs, true, true>
297{
298};
299
305template <class Defs, bool PUEN, bool PDEN> struct GpioInputPin : public Defs
306{
307public:
308 using Defs::PIN_NUM;
309#if CONFIG_IDF_TARGET_ESP32S2
310 // GPIO 45 and 46 typically have pull-down resistors.
311 static_assert(!PUEN || (PUEN && (PIN_NUM != 45 && PIN_NUM != 46)),
312 "GPIO 45 and 46 typically have built-in pull-down "
313 "resistors, enabling pull-up is not possible.");
314 // GPIO 0 typically has a pull-up resistor
315 static_assert(!PDEN || (PDEN && PIN_NUM != 0),
316 "GPIO 0 typically has a built-in pull-up resistors, "
317 "enabling pull-down is not possible.");
318#elif CONFIG_IDF_TARGET_ESP32S3
319 // GPIO 0 typically has a pull-up resistor
320 static_assert(!PDEN || (PDEN && PIN_NUM != 0),
321 "GPIO 0 typically has a built-in pull-up resistors, "
322 "enabling pull-down is not possible.");
323#elif CONFIG_IDF_TARGET_ESP32C3
324 // GPIO 9 typically has a pull-up resistor
325 static_assert(!PDEN || (PDEN && PIN_NUM != 9),
326 "GPIO 9 typically has a built-in pull-up resistors, "
327 "enabling pull-down is not possible.");
328#else // ESP32
329 // GPIO 2, 4 and 12 typically have pull-down resistors.
330 static_assert(!PUEN ||
331 (PUEN && (PIN_NUM != 2 && PIN_NUM != 4 && PIN_NUM != 12)),
332 "GPIO 2, 4, 12 typically have built-in pull-down resistors, "
333 "enabling pull-up is not possible.");
334 // GPIO 0, 5 and 15 typically have pull-up resistors.
335 static_assert(!PDEN ||
336 (PDEN && (PIN_NUM != 0 && PIN_NUM != 5 && PIN_NUM == 15)),
337 "GPIO 0, 5, 15 typically have built-in pull-up resistors, "
338 "enabling pull-down is not possible.");
339#endif // CONFIG_IDF_TARGET_ESP32S2
341 static void hw_init()
342 {
343 LOG(VERBOSE, "[Esp32Gpio] Configuring input pin %d, PUEN: %d, PDEN: %d",
344 PIN_NUM, PUEN, PDEN);
345 esp_rom_gpio_pad_select_gpio(PIN_NUM);
346 gpio_config_t cfg;
347 memset(&cfg, 0, sizeof(gpio_config_t));
348 cfg.pin_bit_mask = BIT64(PIN_NUM);
349 // using GPIO_MODE_INPUT_OUTPUT instead of GPIO_MODE_OUTPUT so that
350 // we can read the IO state
351 cfg.mode = GPIO_MODE_INPUT;
352 if (PUEN)
353 {
354 cfg.pull_up_en = GPIO_PULLUP_ENABLE;
355 }
356 if (PDEN)
357 {
358 cfg.pull_down_en = GPIO_PULLDOWN_ENABLE;
359 }
360 ESP_ERROR_CHECK(gpio_config(&cfg));
361 }
363 static void hw_set_to_safe()
364 {
365 hw_init();
366 }
367
370 static bool get()
371 {
372 return instance()->read();
373 }
374
376 static constexpr const Gpio *instance()
377 {
379 }
380};
381
385template <class Defs> struct GpioInputNP : public GpioInputPin<Defs, false, false>
386{
387};
388
392template <class Defs> struct GpioInputPU : public GpioInputPin<Defs, true, false>
393{
394};
395
399template <class Defs> struct GpioInputPD : public GpioInputPin<Defs, false, true>
400{
401};
402
406template <class Defs> struct GpioInputPUPD : public GpioInputPin<Defs, true, true>
407{
408};
409
558#define GPIO_PIN(NAME, BaseClass, NUM) \
559 struct NAME##Defs \
560 { \
561 static const gpio_num_t PIN_NUM = (gpio_num_t)NUM; \
562 \
563 public: \
564 static gpio_num_t pin() \
565 { \
566 return PIN_NUM; \
567 } \
568 }; \
569 typedef BaseClass<NAME##Defs> NAME##_Pin
570
571#endif // _DRIVERS_ESP32GPIO_HXX_
#define IS_GPIO_OUTPUT(pin)
Helper macro to test if a pin has been configured for output.
Definition Esp32Gpio.hxx:59
Defines a GPIO output pin.
Definition Esp32Gpio.hxx:76
void clr() const override
Sets output to LOW.
void set() const override
Sets output to HIGH.
void set_direction(Direction dir) const override
Sets the direction of the connected GPIO pin.
static const Esp32Gpio instance_
Static instance variable that can be used for libraries expecting a generic Gpio pointer.
Direction direction() const override
Gets the GPIO direction.
void write(Value new_state) const override
Sets the output state of the connected GPIO pin.
Value read() const override
Reads the current state of the connected GPIO pin.
OS-independent abstraction for GPIO.
Definition Gpio.hxx:43
virtual void write(Value new_state) const =0
Writes a GPIO output pin (set or clear to a specific state).
Value
Defines the options for GPIO level.
Definition Gpio.hxx:62
Direction
Defines the options for GPIO direction.
Definition Gpio.hxx:73
virtual Value read() const =0
Retrieves the current Value of a GPIO input pin.
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
Definition logging.h:59
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
Defines a GPIO input pin.
Defines a GPIO input pin with pull-down enabled.
Defines a GPIO input pin with pull-up and pull-down enabled.
Defines a GPIO input pin with pull-up.
Parametric GPIO input class.
static bool get()
Get the current pin state.
static void hw_init()
Initializes the hardware pin.
static void hw_set_to_safe()
Sets the hardware pin to a safe state.
static constexpr const Gpio * instance()
Parametric GPIO output class.
static constexpr const Gpio * instance()
static void toggle()
Toggles the state of the pin to the opposite of what it is currently.
static void hw_init()
Initializes the hardware pin.
static void set(bool value)
Sets the output pin.
static void hw_set_to_safe()
Sets the hardware pin to a safe value.
Defines a GPIO output pin, initialized to be an output pin with high level.
Defines a GPIO output pin, initialized to be an output pin with high level.
Defines a GPIO output pin, initialized to be an output pin with low level.
Defines a GPIO output pin, initialized to be an output pin with low level.