fiber
Loading...
Searching...
No Matches
Overflow aware: Clocks, Time-Points and Durations

Disable all checks and assertions

TODO: Rewrite for new TimePoint and Duration

The fiber library provides a fully overflow-aware timing system including:

  • Clocks
  • Time points
  • Durations

These types integrate seamlessly with the C++ <chrono> standard library while being specifically optimized for bare-metal embedded systems. They allow safe and precise tracking of time using wraparound counters (hardware timer-style), while preserving intuitive arithmetic and comparison operations.


Overflow Awareness

Unlike the standard std::chrono types which assume linear time, fiber’s types are built on ClockTick, which wraps and tracks tick values modulo an overflow:

  • Overflow handling is transparent.
  • All operations (e.g., a < b, b - a) work correctly even when the counter has wrapped.
  • Tick differences and time comparisons are reliable as long as differences are less than half the overflow window.

This means the clock counter must count to at least double the maximum interval between two time points that are to be reliably compared.

Note: The library is heavily optimised to avoid modulo operations and divisions. The fastest is to always use the full range of the integer datatype. If your hardware timer does not cover the full range, for example a 10 or 24-bit counter, then always make sure that the counter overflows on a power of 2 / the maximal value is 2^n-1. ⚠️ If arbitrary overflows are used, the library will use additional modulo operations, but only for constructions (can be mittigated by using ClockTick::reinterpret) and multiplication.


Integration with <chrono>

fiber::Duration, fiber::TimePoint, and fiber::Clock all follow the exact semantics and layout of their standard counterparts:

You can freely mix fiber clocks with standard std::chrono durations where appropriate.


Example: Creating Your Own Clock

Creating a custom hardware-aware overflow-safe clock is extremely simple. All you need to provide is:

  • the underlying integer type of your timer register (e.g. uint32_t)
  • a std::ratio expressing its period relative to 1s (e.g. std::micro if each tick represents a micro second)
  • a constexpr function that returns the current counter value
  • (optional) the maximum value that the counter reaches before wrapping (default is the max of the type)

✔️ Full-range timer:

uint32_t get_timer_count(); // your hardware counter
using MyClock = fiber::Clock<uint32_t, std::micro, get_timer_count>;

✔️ Timer that wraps at a custom maximum (e.g., 1023):

using MyClock = fiber::Clock<uint32_t, std::micro, get_timer_count, 1024-1>;

⚠️ The fourth template argument is the maximum value the counter counts to, not the value after overflow.

Once defined, you can use this clock directly:

MyClock::time_point start = MyClock::now();
...
MyClock::time_point now = MyClock::now();
...
fiber::Scheduler<MyClock> rtscheduler;
rtscheduler.addTask(task);
Overflow aware duration for hardware timers/counters.
Definition Duration.hpp:42

Why Use This?

  • Fully portable overflow handling — just like hardware timers
  • Clean, standard-compliant chrono API
  • Backed by real unit tests with corner-case handling (Clock_test.cpp)
  • Integrates easily into Fiber or any cooperative scheduler
  • Avoids common embedded bugs with counter wraparound and time comparison

Summary

fiber makes working with microcontroller timers as safe and intuitive as modern C++ chrono types — without giving up performance or hardware alignment. You keep full control over the tick source, overflow range, and resolution, and the library guarantees that comparisons and arithmetic Just Work™.

See also
fiber::ClockTick
fiber::TimePoint
fiber::Duration
fiber::CClock
fiber::Clock