Interrupt handling is a crucial aspect of programming in FreeRTOS, as it allows for efficient handling of external events and interrupts. These interrupts can come from a variety of sources such as timers, sensors, or other peripherals. In this blog post, we will discuss how to handle interrupts in FreeRTOS using the Arduino IDE and the FreeRTOS interrupt management functions.
What is Interrupt?
First, it is important to understand the concept of an interrupt. Interrupts are signals sent to the microcontroller to indicate that an event has occurred. These events can be triggered by external devices, such as sensors or buttons, or by internal events, such as a timer reaching a certain value. When an interrupt occurs, the microcontroller stops its current task and handles the interrupt before returning to the previous task.
An interrupt in FreeRTOS is a hardware event that triggers the processor to temporarily suspend the current task and execute a predefined interrupt service routine (ISR) to handle the interrupt event. Interrupts are commonly used to handle events that occur asynchronously, such as receiving data on a serial port, detecting a timer event, or responding to a hardware interrupt from a peripheral device.
In FreeRTOS, interrupts are managed using a priority-based interrupt handling mechanism.The FreeRTOS kernel assigns a priority level to each interrupt, and when an interrupt occurs,the kernel will temporarily suspend the current task and execute the ISR associated with the highest priority interrupt. After the ISR completes, the kernel will then resume the previously interrupted task, ensuring that no high-priority events are missed.
In FreeRTOS, interrupts are handled using the FreeRTOS interrupt management functions. These functions include:
vPortEnterCritical(): This function disables interrupts and is typically used at the start of a critical section of code.
vPortExitCritical(): This function re-enables interrupts and is typically used at the end of a critical section of code.
xPortDisableInterrupts(): This function disables interrupts and returns the previous interrupt state.
xPortEnableInterrupts(): This function re-enables interrupts and sets the interrupt state to the value passed in.
To use these functions in the Arduino IDE with ESP32 Board, we can use the interrupt management functions in our code. For example, let's say we have a button connected to pin 2 of our Arduino board and we want to handle the button press as an interrupt. We can use the following code to handle the interrupt:
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
portMUX_TYPE mySpinlock;
#define LED_BUILTIN 2
//interrupt service routine (ISR) for button press
void buttonPressISR() {
//disable interrupts
vPortEnterCritical(&mySpinlock);
//perform button press actions
digitalWrite(LED_BUILTIN, HIGH);
//enable interrupts
vPortExitCritical(&mySpinlock);
}
//setup function
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
spinlock_initialize(&mySpinlock);
digitalWrite(LED_BUILTIN, LOW);
//attach interrupt to button press
attachInterrupt(digitalPinToInterrupt(15), buttonPressISR, RISING);
}
void loop()
{
}
In this example, we have defined an interrupt service routine (ISR) for the button press. The ISR is called every time the button press is detected. Inside the ISR, we first disable interrupts using the vPortEnterCritical() function. This is to ensure that the microcontroller does not handle any other interrupts while the button press is being handled. We then perform the actions for the button press, such as setting LED.on Finally, we re-enable interrupts using the vPortExitCritical() function.
Example to set up a software timer interrupt
Here is an example of how to set up a software timer interrupt using FreeRTOS for Arduino using the Arduino IDE.
#if CONFIG_FREERTOS_UNICORE
#define ARDUINO_RUNNING_CORE 0
#else
#define ARDUINO_RUNNING_CORE 1
#endif
xTimerHandle timer;
#define LED_BUILTIN 2
//interrupt service routine (ISR) for button press
void vTimerCallback(xTimerHandle pxTimer) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
//setup function
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
//attach interrupt to button press
// initialize software timer interrupt
timer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, vTimerCallback);
xTimerStart(timer, 0);
}
void loop()
{
}
FreeRTOS has special APIs to be used in the interrupt service routines such as xSemaphore Give From ISR xQueue Send From ISR xQueue Send To BackFrom ISR etc You can refer the documentation for FreeRTOS given on FreeRTOS site Now Let us see the code to implement interrupt handling in freeRTOS
What is deferred interupt in freeRTOS?
In FreeRTOS, a deferred interrupt is a mechanism for handling interrupts that allows time-critical interrupt service routines (ISRs) to defer non-time-critical processing to a later time, after the interrupt has been handled. This is achieved by using a special deferred interrupt processing mechanism, which is built into the FreeRTOS kernel.
The basic idea behind deferred interrupt processing is to minimize the amount of time that the processor spends executing interrupt service routines, which can be critical for real-time systems. Instead of performing all of the processing required by an interrupt within the ISR, deferred interrupt processing enables some of this processing to be deferred to other task.
Interrupt handling in FreeRTOS Code
It's worth noting that the FreeRTOS interrupt management functions are designed to be used in conjunction with the FreeRTOS scheduler. This means that if the scheduler is not running, the interrupt management functions will not work as expected. Therefore, it's important to ensure that the scheduler is running before using the interrupt management functions in your code.For Arduino IDE there no neeed write statement for starting scheduler.It is taken care by the Arduino only.