RTOS Fundamentals & Scheduling
Real-time operating systems guarantee that tasks meet deadlines. Learn tasks, priorities and preemptive scheduling, rate-monotonic scheduling and the utilisation bound, response-time analysis, interrupts, resource sharing and priority inversion, OSEK/AUTOSAR OS and FreeRTOS.
An airbag controller must decide within milliseconds; an engine ECU must fire injectors at exact crank angles. A real-time OS isn't about being fast — it's about being predictably on time, every time.
Correct priority assignment and timing analysis prove that every task meets its deadline even in the worst case.
An analogy
An RTOS is like an emergency-room triage nurse: the most urgent patient is always treated first, and the schedule is planned so no one waits beyond their critical time.
Tasks and scheduling
Code is split into tasks with priorities. A preemptive scheduler always runs the highest-priority ready task; interrupts handle urgent hardware events. Periodic tasks (1, 5, 10, 100 ms) are typical in automotive ECUs.
Rate-monotonic scheduling
Assign higher priority to shorter periods. Liu & Layland proved a task set is schedulable if utilisation is below n(2^(1/n) − 1) (≈ 69 % for many tasks) — sufficient, not necessary; exact response-time analysis can accept higher loads.
Shared resources
Tasks sharing data need mutexes or critical sections. Priority inversion (a low-priority task holding a lock blocks a high-priority one while a medium task runs) is solved by priority inheritance or the priority ceiling protocol (used in OSEK/AUTOSAR OS).
Automotive OS and multicore
OSEK/VDX and AUTOSAR OS are static (tasks configured at build time), with alarms, events, resources and scalability/protection classes (timing and memory protection for mixed-criticality). Multi-core ECUs add partitioning, spinlocks and inter-core communication; WCET analysis tools (aiT) bound execution times.
Formulas
- Utilisation:
U = Σ C_i / T_i - Liu & Layland bound (RMS):
U ≤ n (2^(1/n) − 1) (n = 3 → 0.780) - Response-time analysis:
R_i = C_i + Σ_{j∈hp(i)} ⌈R_i / T_j⌉ C_j (iterate) - Schedulable if:
R_i ≤ D_i for all tasks
Worked example: Utilisation test
Given: Tasks (C/T): 1/5, 2/10, 4/20 ms
Find: U and RMS bound.
- U = 0.2 + 0.2 + 0.2 = 0.60
- Bound for n = 3: 0.780 → 0.60 ≤ 0.78 ✓ schedulable
Answer: Schedulable
Worked example: Response-time analysis
Given: Same tasks, task 3 (C = 4, T = 20) lowest priority
Find: Worst-case R₃.
- R⁰ = 4
- R¹ = 4 + ⌈4/5⌉1 + ⌈4/10⌉2 = 7
- R² = 4 + ⌈7/5⌉1 + ⌈7/10⌉2 = 8
- R³ = 4 + ⌈8/5⌉1 + ⌈8/10⌉2 = 8 → converged
Answer: R₃ = 8 ms ≤ 20 ms ✓
Two periodic tasks with FreeRTOS
#include "FreeRTOS.h"
#include "task.h"
static void Task10ms(void *arg) {
TickType_t last = xTaskGetTickCount();
for (;;) {
ReadSensors();
RunControlLoop(); /* WCET must be < 10 ms */
vTaskDelayUntil(&last, pdMS_TO_TICKS(10));
}
}
static void Task100ms(void *arg) {
TickType_t last = xTaskGetTickCount();
for (;;) {
UpdateDiagnostics();
vTaskDelayUntil(&last, pdMS_TO_TICKS(100));
}
}
int main(void) {
xTaskCreate(Task10ms, "ctrl", 512, NULL, 3, NULL); /* higher priority: shorter period (RMS) */
xTaskCreate(Task100ms, "diag", 512, NULL, 1, NULL);
vTaskStartScheduler();
for (;;) {}
}vTaskDelayUntil gives drift-free periodic execution; priorities follow rate-monotonic order (shorter period → higher priority).
Common mistakes
- Wrong: Assuming average execution time is enough. — Right: Use worst-case execution times (WCET) for analysis.
- Wrong: Unbounded blocking on shared resources. — Right: Use priority ceiling/inheritance and keep critical sections short.
Applications
- Engine & transmission ECUs: Angle- and time-synchronous tasks with tight deadlines.
- Safety systems: Airbag, ABS/ESC and EPS with guaranteed response times.
- Body & infotainment: RTOS for MCUs; Linux/QNX for rich HMIs.
Key takeaways
- Preemptive priorities; RMS for periodic tasks.
- U ≤ n(2^(1/n) − 1) sufficient test.
- Response-time analysis: iterate R.
- Guard shared resources against priority inversion.
Going further
- WCET analysis: Static analysis of machine code and caches to bound execution time.
- Mixed-criticality: Timing protection prevents low-ASIL tasks from starving high-ASIL ones.
- Logical execution time: Fixed input/output instants make multicore timing deterministic.