ANTIRTOS
ANTIRTOS is an ultra-lightweight, universal C++ library designed for task management in embedded and IoT applications, particularly suitable for the Arduino platform. Developed by Aleksei Tertychnyi, ANTIRTOS offers an efficient way to handle multitasking without the complexity and overhead associated with RTOS. It is specifically crafted to keep interrupts fast and non-blocking, making it ideal for resource-constrained environments.
Key Features
-
Function Queues:
- ANTIRTOS utilizes function queues to manage tasks. These queues allow function pointers to be stored and executed in an orderly manner.
- Queues can handle functions with or without parameters, and templated queues enable handling functions with specific parameter types.
-
Non-Blocking Interrupts:
- One of the standout features of ANTIRTOS is its ability to keep interrupts fast and non-blocking. Tasks can be pushed to queues from within Interrupt Service Routines (ISRs), deferring the execution to the main loop.
-
Delayed Execution:
- ANTIRTOS supports delayed execution of tasks, allowing functions to be scheduled to run after a specified delay.
-
Ease of Integration:
- The library is designed to be lightweight and easy to integrate into existing projects. It consists of a single, small file of about 5KB, making it easy to include and use.
-
Modularity and Scalability:
- ANTIRTOS's modular design ensures that it can be scaled to fit various applications, from simple microcontrollers to more complex embedded systems.
Usage
Basic Example with Interrupts
To demonstrate the power of ANTIRTOS in handling interrupts, we can use two digital input pins with interrupts and dedicated queues for each:
#include <antirtos.h>
#include <TimerOne.h> // Include the TimerOne library
// Define two function queues for handling tasks
fQ F1(8); // Queue for the first interrupt
fQ F2(8); // Queue for the second interrupt
// Task function for the first interrupt
void task1() {
Serial.println("Task 1 executed");
}
// Task function for the second interrupt
void task2() {
Serial.println("Task 2 executed");
}
// Interrupt Service Routine (ISR) for the first digital input
void ISR1() {
F1.push(task1); // Push the task to the first queue
}
// Interrupt Service Routine (ISR) for the second digital input
void ISR2() {
F2.push(task2); // Push the task to the second queue
}
void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP); // Set up the first digital input pin
pinMode(3, INPUT_PULLUP); // Set up the second digital input pin
attachInterrupt(digitalPinToInterrupt(2), ISR1, FALLING); // Attach ISR1 to pin 2
attachInterrupt(digitalPinToInterrupt(3), ISR2, FALLING); // Attach ISR2 to pin 3
}
void loop() {
F1.pull(); // Execute tasks from the first queue
F2.pull(); // Execute tasks from the second queue
}
Handling Interrupts and Delayed Execution
ANTIRTOS excels at keeping interrupts non-blocking. By pushing tasks to queues within ISRs, the actual task processing is deferred to the main loop, ensuring that the interrupts are handled swiftly and efficiently.
Example with Timer and Button Interrupts
Here's an enhanced example demonstrating how to use ANTIRTOS with a timer interrupt for delayed execution and a button press interrupt:
#include <antirtos.h>
#include <TimerOne.h> // Include the TimerOne library
// Define a templated queue for functions with an int32_t parameter
fQP<int32_t> F4(10);
// Define a delayed function queue
del_fQ F5(8);
// Example task function that takes an int32_t parameter
void taskFunction(int32_t param) {
Serial.print("Task executed with parameter: ");
Serial.println(param);
}
// Interrupt Service Routine (ISR) for timer
void timerISR() {
F5.tick(); // Increment the internal timer for delayed execution
}
// Example task to push from a button press
void buttonTask() {
int32_t value = analogRead(A0); // Read a value from an analog pin
F4.push(taskFunction, value); // Push the task to the queue
}
// Function to be executed after a delay
void delayedTask() {
Serial.println("Delayed task executed");
}
void setup() {
Serial.begin(9600);
pinMode(2, INPUT_PULLUP); // Button pin setup
// Set up a timer interrupt to trigger the ISR
Timer1.initialize(100000); // Set timer to trigger every 100 milliseconds
Timer1.attachInterrupt(timerISR); // Attach the ISR
attachInterrupt(digitalPinToInterrupt(2), buttonTask, FALLING); // Attach the button interrupt
// Schedule a delayed task to be executed after 500 ms
F5.push(delayedTask, 5);
}
void loop() {
// Execute tasks from the queues
F4.pull();
F5.pull();
}
How to easily use delayed functions with parameters you may see on Wokwi here.
Revocation function from conveyers
You may easily revoke your tasks from delayed functional queues like following:
F5.revoke(yourTask); // revoke function from the queue
Kindly find an example of usage revocation on Wokwi.
Benefits of Non-Blocking Interrupts
- Fast Interrupt Handling: By pushing tasks to a queue, the ISR execution time is minimized, keeping the system responsive.
- Efficient Task Management: Tasks are processed in the main loop without blocking, allowing the system to handle multiple tasks concurrently.
- Modularity: Functions can be easily pushed and pulled from queues, making the code more modular and easier to manage.
Advantages over Traditional RTOS
ANTIRTOS offers several advantages over traditional RTOS, particularly in the context of simpler and resource-constrained applications:
-
Simplicity:
- Traditional RTOS often come with features like context switching, mutexes, semaphores, and critical sections. These features, while powerful, add complexity to the system.
- Managing content copy and restoring, ensuring mutual exclusion (mutexes), handling synchronization (semaphores), and protecting critical sections can be intricate and error-prone.
-
Lower Overhead:
- RTOS typically require more memory and processing power to manage these features, which might not be available on smaller microcontrollers.
- ANTIRTOS, being lightweight, avoids these complexities and overhead, making it suitable for low-resource environments.
-
Ease of Use:
- The straightforward API of ANTIRTOS, centered around function queues, makes it easy to implement and understand. Developers can quickly integrate multitasking without delving into the nuances of an RTOS.
-
Fast Interrupts:
- By keeping ISRs short and non-blocking, ANTIRTOS ensures that the system remains responsive. Traditional RTOS might require more extensive context switching, which can slow down interrupt handling.
Conclusion
ANTIRTOS provides an effective solution for task management in Arduino and other embedded projects. Its ability to keep interrupts non-blocking, combined with the ease of handling delayed and parameterized tasks, makes it a valuable tool for developers looking to implement efficient multitasking without the complexity of an RTOS.
For more detailed information and examples, refer to the ANTIRTOS GitHub repository and the Arduino Library reference.
Ongoing update: templated (with parameter) 'delayed' function queue: the same like fQP, but for delayed execution. Coming soon. Stay tuned!