Objective
- Understand how to use the Espressif GPIO interrupts. This lab will consist of simulating your own fire alarm!!! There is an additional driver that was developed to facilitate the use of LEDs. Student must use 2 external interrupts either pull-up or pull-down configuration.
Bonus
- Undergrad Bonus:
- Display fire alarm
status
in terminal whenever it is active
- Grad Bonus:
- Add another
LED
to indicate when fire alarm is disable
ESP32 Pinout
+-----------------------+
| O | USB | O |
| ------- |
3V3 | [ ] [ ] | VIN
GND | [ ] [ ] | GND
Touch3 / HSPI_CS0 / ADC2_3 / GPIO15 | [ ] [ ] | GPIO13 / ADC2_4 / HSPI_ID / Touch4
CS / Touch2 / HSPI_WP / ADC2_2 / GPIO2 | [ ] [ ] | GPIO12 / ADC2_5 / HSPI_Q / Touch5
Touch0 / HSPI_HD / ADC2_0 / GPIO4 | [ ] [ ] | GPIO14 / ADC2_6 / HSPI_CLK / Touch6
U2_RXD / GPIO16 | [ ] [ ] | GPIO27 / ADC2_7 / Touch7
U2_TXD / GPIO17 | [ ] [ ] | GPIO26 / ADC2_9 / DAC2
V_SPI_CS0 / GPIO5 | [ ] ___________ [ ] | GPIO25 / ADC2_8 / DAC1
SCK / V_SPI_CLK / GPIO18 | [ ] | | [ ] | GPIO33 / ADC1_5 / Touch8 / XTAL32
U0_CTS / MSIO / V_SPI_Q / GPIO19 | [ ] | | [ ] | GPIO32 / ADC1_4 / Touch9 / XTAL32
SDA / V_SPI_HD / GPIO21 | [ ] | | [ ] | GPIO35 / ADC1_7
CLK2 / U0_RXD / GPIO3 | [ ] | | [ ] | GPIO34 / ADC1_6
CLK3 / U0_TXD / GPIO1 | [ ] | | [ ] | GPIO39 / ADC1_3 / SensVN
SCL / U0_RTS / V_SPI_WP / GPIO22 | [ ] | | [ ] | GPIO36 / ADC1_0 / SensVP
MOSI / V_SPI_WP / GPIO23 | [ ] |___________| [ ] | EN
| |
| | | ____ ____ | |
| | | | | | | | |
| |__|__| |__| |__| |
| O O |
+-----------------------+
Example
Here is an example of how to use ESP32 GPIO advance setup. The following code will have an external LED toggling every half second and will toggle the onboard led and external button if they are pressed. The example code uses to separate interrupts routines.
#include <stdio.h>
#include <stdbool.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#define ESP_INTR_FLAG_DEFAULT 0
#define LOW 0
#define HIGH 1
#define ONBOARD_LED 2
#define EXTERNAL_LED 22
#define BUTTON_0 23
#define BUTTON_1 13
#define BUTTON_2 12
void toggle(gpio_num_t pin){
static bool on;
gpio_set_level(pin, on);
on = !on;
}
static void IRAM_ATTR gpio_onboard_led_isr_handler(void* arg) {
gpio_num_t gpio = (gpio_num_t) arg;
toggle(gpio);
}
static void IRAM_ATTR gpio_button_isr_handler(void * arg){
gpio_num_t gpio = (gpio_num_t) arg;
if(gpio == BUTTON_1){
gpio_set_level(EXTERNAL_LED,
LOW);
}else{
gpio_set_level(EXTERNAL_LED,
HIGH);
}
}
void gpio_setup(void) {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_POSEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = (1ULL << BUTTON_0) | (1ULL << BUTTON_1) | (1ULL << BUTTON_2);
io_conf.pull_down_en = 1;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = (1ULL <<
ONBOARD_LED) | (1ULL << EXTERNAL_LED);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
gpio_isr_handler_add(BUTTON_0, gpio_onboard_led_isr_handler, (
void*)
ONBOARD_LED);
gpio_isr_handler_add(BUTTON_1, gpio_button_isr_handler, (void*) BUTTON_1);
gpio_isr_handler_add(BUTTON_2, gpio_button_isr_handler, (void*) BUTTON_2);
}
gpio_setup();
while(1){
toggle(EXTERNAL_LED);
vTaskDelay(500/portTICK_PERIOD_MS);
}
}
void app_main()
Definition main.c:261
#define HIGH
Definition main.c:28
#define LOW
Definition main.c:27
#define ONBOARD_LED
Definition main.c:31
#define ESP_INTR_FLAG_DEFAULT
Definition main.c:29
Use IRAM_ATTR for any function that will use as interrupt routine.
LED driver Example
Here is an example of a how to use the led driver.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
while(1){
vTaskDelay(1000 / portTICK_PERIOD_MS);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
Custom LED driver header file.
void led_off(led_t *const led)
Turn off LED object pin.
Definition led.c:63
void led_enable(led_t *const led)
LED enable.
Definition led.c:27
void led_on(led_t *const led)
Turn on LED object pin.
Definition led.c:50
void led_toggle(led_t *const led)
Toggle LED object pin.
Definition led.c:76
LED object.
Definition led.h:38
gpio_num_t pin
Definition led.h:39
Lab Template
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#define ESP_INTR_FLAG_DEFAULT 0
#define ONBOARD_LED 2
#define SMOKE_DETECTOR_PIN 0
#define DISABLE_ALARM_PIN 0
typedef struct{
gpio_num_t smokeDetector;
gpio_num_t disableAlarm;
bool active;
static void IRAM_ATTR gpio_interrupt_handler(void * arg) {
gpio_num_t gpio = (gpio_num_t) arg;
}
gpio_config_t io_conf;
io_conf.intr_type = ;
io_conf.mode = ;
io_conf.pin_bit_mask = ;
io_conf.pull_down_en = ;
io_conf.pull_up_en = ;
gpio_config(&io_conf);
}
{
while(1){
}else{
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
}
void fire_alarm_interrupt_setup(fire_alarm_t *const alarm)
Set up fire alarm interrupt.
Definition main.c:67
fire_alarm_t utep_alarm
Definition main.c:50
Fire alarm object.
Definition main.c:42
gpio_num_t smokeDetector
Definition main.c:44
bool active
Definition main.c:46
C helpful functions
For this lab, there are a couple of additional functions from Espressif
that are important for using inputs. In the previous lab, we had used gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
set our inputs and outputs. However, will now use a different approach by using gpio_config_t
. This new apporach allows users to create inputs and outputs in a more condense fashion with structures. The structure has various members with their own data types. Please look into them in order to select the correct values when developing the lab.
typedef struct {
uint64_t pin_bit_mask;
gpio_mode_t mode;
gpio_pullup_t pull_up_en;
gpio_pulldown_t pull_down_en;
gpio_int_type_t intr_type;
} gpio_config_t;
There are significant difference in how to set the interrupts. Here is a brief description of pull-up and pull-down to help you for the lab.
Interrupt Configuration | Description | Logic |
Pull-up | Falling edge | 1 -> 0 |
Pull-down | Rising edge | 0 -> 1 |
For this lab will we keep the interrupt flag to its default settings which would be 0
. In order to set the interrupt flag, the following function is required: gpio_install_isr_service(int intr_alloc_flags)
.
esp_err_t gpio_install_isr_service(int intr_alloc_flags)
Lastly, static void IRAM_ATTR gpio_isr_handler(void* arg)
is the interrupt service routine and can be modified if necessary as long as it has IRAM_ATTR
which it is required for interrupts. Also, in order to add any input to enter the interrupt routine, you must add
it to isr handler: gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args)
.
esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void *args)
Warning
The bit mask in gpio_config_t
is an uint64_t
value and ESP32 uses enum
for its pinout. Therefore, in order to mask the bits correctly you must bit shift the desire pin by an unsigned long long (ULL
).
Add led driver to ESP32 Project
-
Copy driver folder
-
Paste into esp project
-
Edit project CMakeLists.txt to use led.c:
idf_component_register(SRCS "main.c"
"driver/led.c"
INCLUDE_DIRS ".")
Additional Links
Authors
GitHub
Read Next: Lab 3