With this tutorial we’re going to start using the I/O pins of the esp32 chip. The chip features 40 General Purpose I/O pads (GPIO), that are 40 “contacts” you can use in different ways, both for input and output functions.
The setup of those pads is quite complex: the esp32 chip allows indeed to “map” the internal peripherals (UART, SPI…) to different pads, via matrices that can be configured in your firmware. In the technical reference manual you can find a drawing that explains how it works:
In this first post about I/O I’m not going to explain in details the different registers involved… it’s however important that you understand by now that an initial configuration is always required to use a pin, even for basic I/O functionalities. The driver you have to include in your code to use all the functions described below is:
#include "driver/gpio.h" |
Basic I/O
As previously said, before using a pin you need to make a proper configuration of the internal registers. After the chip reset, most pins are automatically configured as basic I/O pins; this is not true for all the pins. You can configure a pin as a general purpose I/O pin with the function:
void gpio_pad_select_gpio(uint8_t gpio_num); |
The GPIO pins can work in 3 different “directions”:
- input
- output
- open drain
The corresponding constants are defined in the gpio.h file:
There are some exceptions, in particular pins > 33 can only work as input pins.
You can configure the direction of a pin with the function:
esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); |
gpio_num is the number of the pin to be configured, while mode is one of the three constants shown above. For example if you need to use pin 13 as output, the code is:
gpio_set_direction(GPIO_NUM_13, GPIO_MODE_DEF_OUTPUT); |
You can read the pin status, if configured as input, with the function:
int gpio_get_level(gpio_num_t gpio_num); |
while if the pin is configured as output or open drain, you can change its status with:
esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level); |
Pull-up and pull-down
Every pin also includes pull-up and pull-down resistors, you can enable them with the function:
esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); |
the possible constants are:
Alternatively, you can use the dedicated functions to enable/disable a resistor on a pin:
esp_err_t gpio_pullup_en(gpio_num_t gpio_num); esp_err_t gpio_pullup_dis(gpio_num_t gpio_num); esp_err_t gpio_pulldown_en(gpio_num_t gpio_num); esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num); |
Multiple configuration
So far, you learned how to configure a single pin. You can also configure some pins at the same time, applying to them the same configuration template.
First you have to declare a gpio_config_t struct:
gpio_config_t pin_config; |
The parameters that can be configured are:
The pins you want to configure must be specified in the pin_bit_mask variable as a “bit mask”. You can create it concatenating the different GPIO_SEL_x constants with the OR (|) operator. Let’s see a couple of examples (I’ll blog about interrupts in a future post, for now let’s keep them disabled):
[checklist]
- pin 2, 3 and 7 configured as output, pull-up and down resistors disabled:
[/checklist]
pin_config.pin_bit_mask = GPIO_SEL_2 | GPIO_SEL_3 | GPIO_SEL_7; pin_config.mode = GPIO_MODE_OUTPUT; pin_config.pull_up_en = GPIO_PULLUP_DISABLE; pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE; pin_config.intr_type = GPIO_PIN_INTR_DISABLE; |
[checklist]
- pin 6 and 8 configured as input, with pull-up resistor:
[/checklist]
pin_config.pin_bit_mask = GPIO_SEL_6 | GPIO_SEL_8; pin_config.mode = GPIO_MODE_INPUT; pin_config.pull_up_en = GPIO_PULLUP_ENABLE; pin_config.pull_down_en = GPIO_PULLDOWN_DISABLE; pin_config.intr_type = GPIO_PIN_INTR_DISABLE; |
The configuration template is finally applied with the function gpio_config(&pin_config).
Code
Because this tutorial is about I/O basic concepts, I didn’t prepare dedicated examples… with the framework are indeed shipped some programs that show what I explained above:
Hi Luca
I have read most of your web-site with interest. I wish I had found it 4 weeks ago while trying to set up Eclipse!
Excellent tutorials!
Would it be possible for you to explain how to send a data packet from a PC to the ESP32 on the same wireless home network (not accessing the external web)?
My goal is to send a simple graphic (much like your LED matrix project) to the ESP32 and use the I/O (SPI) to control some LEDs.
Would it require the ESP32 to have a fixed IP address or could the network be scanned to get the automatically assigned IP address?
Many thanks in advance.
Hi Karl, thanks for your comment! I’m working on a tutorial for using ESP32 as a server and… something also to solve the problem to “find” the ESP32 on the network 😉
Grazie per l’interessante articolo se volessi configurare come open drain utilizzando ide di Arduino come potrei farlo?
Grazie
Salve Andrea, i miei tutorial non sono per arduino, mi spiace
hello
In the Blink example how do I
Can run ‘make menuconfig’ to choose the GPIO to blink,
I cant see Any Settings in MenuConfig where I can set GPIO
in the “Example Configuration” menu… see the readme as this is an official example by Espressif