Controlling ESP32 GPIO with ESP-IDF

Introduction

In this post, you will learn about controlling ESP32 GPIO using APIs in ESP-IDF. We will explore functions in gpio.h to make a LED on or off and detect a button pressed by reading digital input from GPIO pins.

Components Used

In this article, we will implement a practical project which uses the following components

QTYComponent NameBuy on amazon.com
1ESP32 DevKit CAmazon
1LED KitAmazon
1Resistor KitAmazon
1Push buttonAmazon
1BreadboardAmazon
1Jumper Wire KitAmazon

Affiliate Disclosure: When you click on links in this section and make a purchase, this may result in this site earning a commission at no extra cost to you.

ESP-IDF GPIO APIs

In this section, we will examine the library gpio.h in ESP-IDF and see basic functions to control digital input and output ports of ESP32. Basic tasks to configure I/O ports include setting a port as input or output port, setting and clearing an output port and reading digital input port. We will go through one by one.

Control Digital Output

To configure a GPIO pin as output, use the function gpio_set_direction() and pass in the first argument as the pin to be configured, the second argument is GPIO_MODE_OUTPUT. Note that for the pin number, you need to use a value defined in enumeration gpio_num_t, that is, for pin 0, pass in GPIO_NUM_0. The example below configure GPIO0 as output port.

gpio_set_direction(GPIO_NUM_0, GPIO_MODE_OUTPUT);

To set a GPIO output pin high or low, you use the function gpio_set_level(). This function accepts two arguments: first argument is the pin number, second argument is the output level. If you want the pin to output high, use 1 in the second argument. Otherwise, pass 0 in the second argument. For instance, this example shows how to set GPIO_NUM_0 high.

gpio_set_level(GPIO_NUM_0, 1);

Read Input Pin

To configure a GPIO as Input pin, you use the function gpio_set_direction(), too. However, this time you need to pass in GPIO_MODE_INPUT as the second argument. This snippet shows how to configure GPIO1 as an input port.

gpio_set_direction(GPIO_NUM_1, GPIO_MODE_INPUT);

To read the digital input level of a GPIO pin, use the function gpio_get_level(). This function returns 0 or 1 depending on the voltage level of GPIO pin is low or high.

int gpio_get_level(GPIO_NUM_1);

ESP32 GPIO Project Example

To demonstrate the usage of the above functions, we will implement a simple project in which there is one LED and one button. If the button is not pressed, the LED is turned off. If the button is pressed, the LED is turned on.

Hardware description

In this project, we will be using ESP32 DevKitC, a LED connected in series with a resistor, and a push button. If you are using other development kit, you will need to check which GPIO pins are used to connect to a LED and button.

  • Connect GPIO 32 (pin 7 on the left hand side of the board with USB on the bottom) with a LED and a resistor. This pin is used to drive the LED and to turn it on or off.
  • Connect GPIO 36 (pin 3 on the left hand side of the board) with the push button.

The circuit is shown in the below figure

Code

The below code performs the task described above.

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"

#define LED_PIN     GPIO_NUM_32
#define BUTTON_PIN  GPIO_NUM_36

void app_main(void)
{
    gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);   
    gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);

    while(1) {       
        if (gpio_get_level(BUTTON_PIN) == 0) {  // If button is pressed
            gpio_set_level(LED_PIN, 1);         // Turn the LED on
        } else {
            gpio_set_level(LED_PIN, 0);         // Turn the LED off
        }

        vTaskDelay(1); // Add 1 tick delay (10 ms) so that current task does not starve idle task and trigger watchdog timer
    }
}

Code explanation

  • You first need to include the gpio.h driver in order to use GPIO APIs.
  • You then define the GPIO pins as LED_PIN and BUTTON_PIN. This allows you quickly modify the pins when necessary and eliminate magic numbers in your code, hence make it easier to read.
  • The next step is to configure LED_PIN as output port, BUTTON_PIN as input port.
  • In the main loop inside app_main(), you check if a button is pressed by reading input level of BUTTON_PIN using gpio_get_level(). If it is pressed, turn the LED on by calling gpio_set_level().
  • A delay of 1 tick (equal to 10 ms since the tick frequency is 100 Hz) is added in the main loop to avoid the main task consume all CPU resources, so that idle task can run and clear the watchdog timer. If there’s no delay, idle task has lower priority than the main task and can not run, hence watchdog timer will be triggered to reset the chip and your code will not work properly.

Building and flashing

To build and flash the code to target ESP32 board, make sure all the necessary tools are installed.

All you need to do now is to run

get_idf
idf.py build

Then wait until the build process completes. Next, determine the port that your board is connecting to and run the following command to flash the code on the ESP32.

idf.py -p [PORT] flash

After flashing, you should see that pressing the button will turn the LED light on. Otherwise, the LED light will be off.

Wrapping Up

In this tutorial, you have learnt about using APIs in ESP-IDF to control GPIO pins of ESP32. Your knowledge is solidified by doing a practical project. To learn more, the ESP32 official documentation is a good place to go. You can find more GPIO API functions in the API reference page. If you have any comments, leave it in the comment section. See you in the next tutorials.

Leave a Comment