5.5.15 · D2Embedded Systems & Real-Time Software

Visual walkthrough — Bare-metal vs RTOS — when to use each

2,648 words12 min readBack to topic

Step 1 — One cook, many dishes: the thing we are sharing

WHAT. Before any maths, picture the hardware. There is exactly one CPU — one worker who can do exactly one thing at a time. We hand it several jobs (also called tasks): reading a sensor, refreshing a screen, and so on.

WHY. Every formula on this page exists only because of this bottleneck. If we had one CPU per job, there would be no scheduling problem and no page. The whole subject is: how do we share one worker among many demands?

PICTURE. One chalk box = the CPU. Arrows from many little job-boxes point into it. They cannot all enter at once — that queue is the entire problem.


Step 2 — The super-loop: finish every dish, in order, forever

WHAT. Bare-metal firmware usually looks like one endless loop that runs each job to completion, in a fixed order, then starts over.

WHY. It is the simplest thing that could possibly work: no kernel, no scheduler, tiny memory. You can read it top to bottom and know exactly what happens.

PICTURE. A circular track. Four coloured tiles sit on it end-to-end — their widths are their execution times . The CPU is a chalk dot that crawls around the ring at constant speed, one full lap = one loop iteration.

Look at the widths: the display tile (pink) is huge. The CPU dot must travel across it every single lap — even the tiny sensor tile has to wait for that whole crossing.


Step 3 — The worst-case wait: a job asks, "just missed me"

WHAT. We now derive the killer number for the super-loop: the worst-case latency — the longest a job can sit ready-but-unserved.

WHY this exact scenario. "Worst case" is not paranoia; a real-time system is judged by its worst moment, never its average. So we ask: when is the wait longest? Answer: when the job becomes ready the instant after the CPU just checked it. Now it must sit through the entire rest of the lap before the CPU comes around again.

PICTURE. A red "READY!" flag pops up on the sensor tile just after the CPU dot has left it. The red arc shows how far the dot must still travel — all the remaining tiles — before it returns.

In the worst case that remaining arc is almost the whole loop, so we bound the wait by one full loop:


Step 4 — Pre-emption: "drop everything and stir the soup NOW"

WHAT. An RTOS adds one superpower: a high-priority task may interrupt (pre-empt) a low-priority task mid-execution, run, then hand control back. (This mid-flight hand-off is exactly Context Switching, and the interrupt trigger is an Interrupts and ISRs mechanism.)

WHY. In the super-loop the fast job's wait depended on slow jobs. Pre-emption flips the logic: a job is now delayed only by jobs more important than itself, never by less important ones.

PICTURE. A timeline. The low-priority UI task (pink bar) is running. Halfway through, the high-priority control task (blue) becomes ready — a blue arrow slices into the pink bar, the pink bar pauses, blue runs to completion, then pink resumes. The blue task did not wait for the pink one.


Step 5 — Counting the interruptions: why a ceiling appears

WHAT. We want task 's response time — the time from "job becomes ready" to "job finishes." Task needs of CPU for itself, but during that stretch, higher-priority tasks keep barging in. We must count how many times each barges in.

WHY a ceiling function. Take a higher-priority task with period . Over a window of length , how many times does arrive? It arrives once at the start, then again every . If ms and ms, arrivals land at — that is 3 arrivals, not 2.5. You cannot have half an arrival; a partial period still triggers one more full interruption. Rounding up to the next whole number is exactly the "ceiling" operation.

PICTURE. A horizontal window of length . Tick marks every show task 's arrivals. We count the ticks inside the window; the last partial slot still counts as one whole tick — the picture shows why we round up, not down.

Now assemble the response time:


Step 6 — The snake bites its tail: solving by iteration

WHAT. appears on both sides of the equation (inside the ceiling too). You cannot just "compute the right side" — you would need the answer to get the answer. So we solve it as a repeating loop.

WHY iterate. Start with a guess that is obviously too small — the task's own work alone, . Feed it in, get a bigger value (interruptions added), feed that back in, and so on. Each round can only add more interruptions, so the number grows and then stalls. When it stops changing, we have found the true . (If it grows past the deadline first, the task is unschedulable.)

PICTURE. A staircase climbing to a flat plateau: each step taller than the last but by less each time, until the line goes flat — the fixed point.


Step 7 — "Will it all even fit?" — the utilisation gate

WHAT. Computing every is work. There is a faster first screen: add up how busy each task keeps the CPU and compare to a bound. This is the Liu & Layland test for Rate-Monotonic Scheduling.

WHY a fraction . A task that needs ms of CPU every ms occupies the fraction of the CPU's time. Sum those fractions and you get total demand . If you have asked for more than 100% of one CPU — impossible, no scheduler saves you.

PICTURE. A bar representing 100% of CPU time, sliced into coloured demand chunks stacked up. A dashed chalk-yellow line marks the guarantee bound; if the stack stays under the line, deadlines are guaranteed.


Step 8 — Degenerate & edge cases (never leave a gap)

WHAT. Corners where the formulas do something surprising. Each earns its own moment.

WHY. A reader who hits an unhandled corner loses all trust. Here they are, exhaustively.

  • Only one job (N = 1). Super-loop latency — the job waits for nobody but itself. Response time . Bare-metal and RTOS agree; the RTOS adds only overhead. → bare-metal wins.
  • Highest-priority task. (empty set), sum is zero, . This is the best case pre-emption can give — used deliberately for the most critical job.
  • Lowest-priority task. Everyone is in ; it absorbs all interruptions and has the largest . Put your non-urgent slow work here.
  • exactly. The utilisation test fails (bound ), but the system might still be schedulable — you must fall back to the exact recurrence. The bound is sufficient, not necessary.
  • never stops growing (climbs past the deadline ): the task is unschedulable — no priority ordering under this scheme meets its deadline. Redesign (faster hardware, lower demand, or offload).
  • Two tasks share a resource — a low-priority task holding a lock can stall a high-priority one, breaking the "only higher priorities delay me" rule. That leak is Priority Inversion and Mutexes, patched separately. And if a task hangs entirely, a watchdog resets the system.

The one-picture summary

Two timelines, same three jobs, stacked for comparison. Top (super-loop): the fast control job (blue) is stuck behind the fat Wi-Fi + UI blocks — its wait is the whole loop, ms. Bottom (RTOS): control is highest priority; a blue spike fires instantly whenever it is ready, slicing through the slow work, wait ms. Same hardware, same jobs — only the sharing rule changed.

Recall Feynman retelling — the whole walkthrough in plain words

One cook, many dishes. Bare-metal cook finishes each dish fully, in a fixed order, round and round. If the tiny "stir the soup" job becomes urgent right after the cook walked past it, it must wait for every other dish to finish first — that total wait is just adding up all the dish sizes, . One giant dish (the display, the Wi-Fi) makes even the tiniest urgent job wait forever.

RTOS cook carries a smart timer. He labels dishes by importance. When an important dish calls, he pauses whatever less important thing he's doing, handles the urgent one, then resumes. So an urgent dish now only ever waits for dishes more important than itself — count how many times those barge in (rounding up, because a half-visit still fully interrupts you), add their sizes, plus your own work: that's the response time . Since shows up on both sides, you guess-and-refine until the number stops moving.

Before doing any of that, a quick sanity check: add up each dish's "fraction of the cook's day" (). If the total sits under a safety line, every deadline is guaranteed — no detailed work needed.

The moral: give your one urgent job the top priority and an RTOS makes its wait shrink from "the whole loop" to "just itself." That is the entire reason RTOSes exist.


Connections