interval_buffer_isr: The Tiny Motion-Control Engine That Won’t Lose Its Phase

A stepper-motor ISR planner that carries sub-step position across frames, survives direction flips, and uses formal verification to prove the error stays bounded.

8 min read • View on GitHub • More from dbuezas

A clockwork stepper mechanism spans two timing frames, with a narrow channel carrying motion from one frame to the next. The image explains that the important state is not the pulse itself, but the phase that survives between pulses.
The repo’s main idea is simple to say and hard to implement: preserve phase across frame boundaries instead of recalculating from scratch.
Key Takeaways

The hidden state inside every step

Stepper motors look discrete from the outside. Inside the firmware, they are anything but. The real job is to keep track of a hidden fractional state, then turn that state into timer-driven pulses without letting the error wander.

That is why interval_buffer_isr stands out. It is not just a buffer for interrupts. It is an attempt to preserve phase continuity across frames, direction changes, and ISR boundaries, while still fitting the math into a small embedded footprint.

Why this repo exists

There is no public launch post or founder story to lean on here, so the code has to do the talking. What it says is clear: somebody wanted a stepper planner that would not quietly lose sub-step position every time the timer frame rolled over.

That matters in CNC and 3D printer firmware, where motion is continuous but execution is chopped into interrupts. If you round too early, reset too eagerly, or treat each frame as a fresh start, the machine can drift. The repo’s answer is to keep the invariant explicit and keep carrying it forward.

The trick: carry phase, do not reset it

The core idea is a half-step-centered phase model. Instead of asking only, “How many steps fit in this frame?” the planner asks, “Where is the continuous motion path relative to the next pulse, and how do I carry the leftover phase into the next interval?”

This diagram shows the central invariant: the planner keeps fractional phase alive across frames, then inverts it on direction change instead of throwing it away.

The subtle part is the boundary behavior. A frame can end before the next pulse is due, or it can end right after one has been scheduled. The planner has to avoid phantom steps at the seam, so the phase offset is centered and the remaining fraction survives into the next frame.

That is why the project feels more like a proof sketch than a queue. It is less concerned with storing events than with preserving a relationship between target position, actual pulses, and residual error.

How the planner, runner, and simulator fit together

That split is elegant because each layer does one job. The planner reasons about motion, the runner reasons about timing, and the simulator reasons about end-to-end behavior. The verification layer then asks whether the invariant still holds for every valid input it can explore.

Why fixed-point math is the real enabler

The repo leans on fixed-point formats such as Q15.16 and Q27.5 because embedded motion code needs predictable cost. Floating point can be fine on bigger chips, but it is often a poor trade on tiny controllers where every interrupt has a budget.

There is also a very practical twist: the research notes point to 64-bit-free multiplication tricks, which is a strong signal that the code is designed for hardware where wide math is expensive. That is the difference between a neat algorithm and one that can actually live inside an ISR.

The technical charm here is not just precision. It is precision at a price the microcontroller can afford.

The proof matters more than the simulation

Simulation can show a trajectory that looks good. Formal verification tries to show that the bad case cannot happen at all, at least within the modeled assumptions. That is a very different bar.

In this repo, CBMC is not a decorative extra. It is the mechanism that turns a motion heuristic into something closer to a contract: for valid inputs, the error bound should hold. That is a much stronger claim than, “It passed my test path.”

For motion control, that distinction is huge. Boundary mistakes are exactly the kind of bug that show up rarely, hide in timing edges, and cost real hardware time when they do.

What this beats, and what it does not

ApproachPhase handlingError behaviorWhat it buys you
Naive per-frame roundingResets the story at each boundaryBoundary drift can accumulate into visible jitterVery simple, but the hidden invariant is implicit
interval_buffer_isrCarries fractional phase forward and centers it around the half-stepKeeps the commanded path aligned across frame changesAn explicit correctness model for ISR timing
Generic queue-based ISR planningSchedules work well, but usually abstracts away the motion invariantFlexible, yet less focused on phase continuityUseful as plumbing, not as a proof-oriented motion model

That comparison is the right one. This repo is not trying to be a full industrial firmware stack. It is a focused lab for one hard subproblem: how to preserve motion state without paying a heavy math tax.

Seen that way, its value is bigger than its size. It shows how a small embedded algorithm can be written as if correctness were the product.