Index
In FreeRTOS, interrupts are a critical part of handling events that need immediate attention, such as button presses, sensor readings, or receiving data from a communication protocol. When an interrupt occurs, the associated Interrupt Service Routine (ISR) is triggered, which can perform simple tasks directly or notify FreeRTOS tasks.
Key Concepts in FreeRTOS Interrupts
- ISR (Interrupt Service Routine):
- A function that executes in response to an interrupt.
- Should be kept short to avoid blocking other interrupts.
- Handling Interrupts in FreeRTOS:
- You can use an ISR to interact with FreeRTOS tasks by giving a semaphore, sending to a queue, or notifying a task.
xSemaphoreGiveFromISR()
,xQueueSendFromISR()
, andvTaskNotifyGiveFromISR()
are FreeRTOS functions designed for ISRs.
- Interrupt Priority:
- Configured to control the priority level of interrupts.
- Lower numbers indicate higher priority.
Example: Setting Up and Handling Interrupts
In this example, we set up an interrupt to respond to a button press, and the ISR notifies a FreeRTOS task to toggle an LED.
Example Code
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
// Pin definitions
#define BUTTON_PIN 0 // GPIO0 for the button input
#define LED_PIN 2 // GPIO2 for the LED output
// Semaphore handle
SemaphoreHandle_t xButtonSemaphore;
// ISR for handling button press
void IRAM_ATTR button_isr_handler(void* arg) {
// Give semaphore from ISR
xSemaphoreGiveFromISR(xButtonSemaphore, NULL);
}
// Task to toggle LED on button press
void vTaskButtonHandler(void* pvParameters) {
// Configure LED_PIN as output
gpio_pad_select_gpio(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
while (1) {
// Wait for the semaphore to be given by the ISR
if (xSemaphoreTake(xButtonSemaphore, portMAX_DELAY) == pdTRUE) {
// Toggle LED
static int ledState = 0;
ledState = !ledState;
gpio_set_level(LED_PIN, ledState);
printf("Button pressed, LED toggled\n");
}
}
}
void app_main(void) {
// Initialize button semaphore
xButtonSemaphore = xSemaphoreCreateBinary();
if (xButtonSemaphore == NULL) {
printf("Failed to create semaphore\n");
return;
}
// Configure BUTTON_PIN as input with interrupt on the rising edge
gpio_pad_select_gpio(BUTTON_PIN);
gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
gpio_set_intr_type(BUTTON_PIN, GPIO_INTR_POSEDGE);
// Install ISR for BUTTON_PIN
gpio_install_isr_service(0);
gpio_isr_handler_add(BUTTON_PIN, button_isr_handler, NULL);
// Create task to handle button press and toggle LED
xTaskCreate(vTaskButtonHandler, "Button Task", 2048, NULL, 1, NULL);
}
Explanation of the Code
- Defining the GPIO Pins:
BUTTON_PIN
is set as the input pin for a button.LED_PIN
is set as the output pin for an LED.
- Creating a Semaphore:
xButtonSemaphore
is created usingxSemaphoreCreateBinary()
. This semaphore is given from the ISR and taken by the task when the button is pressed.
- Setting up the ISR:
gpio_set_intr_type()
sets up an interrupt onBUTTON_PIN
to trigger on the rising edge, meaning the button press.gpio_install_isr_service(0)
installs the ISR service.gpio_isr_handler_add()
assigns thebutton_isr_handler
ISR function toBUTTON_PIN
.
- Button ISR:
- When the button is pressed,
button_isr_handler
is called. - It gives the semaphore
xButtonSemaphore
usingxSemaphoreGiveFromISR()
, which wakes up the task that’s waiting for the button press event.
- When the button is pressed,
- Task Handling the Button Press:
vTaskButtonHandler
waits forxButtonSemaphore
.- When
xButtonSemaphore
is given by the ISR, it toggles the LED connected toLED_PIN
.
app_main
Function:- Sets up GPIO configurations, initializes the semaphore, and creates the task.
Output Explanation
When you press the button connected to BUTTON_PIN
, the following happens:
- The button ISR (
button_isr_handler
) gives the semaphorexButtonSemaphore
. vTaskButtonHandler
takes the semaphore and toggles the LED.- You’ll see a message like
Button pressed, LED toggled
on the console.
Summary
- ISR: Triggered by an interrupt (button press), executes quickly, and uses
xSemaphoreGiveFromISR()
to notify a task. - Semaphore: Used to synchronize between ISR and task.
- Task: Waits for the semaphore, and upon receiving it, toggles the LED.
This setup allows you to handle interrupts efficiently in FreeRTOS without blocking tasks, while keeping the ISR short and responsive.