Skip to content

kernel::clock

A monotonic microsecond clock.

The scheduler tick is milliseconds and is the wrong instrument for two jobs: measuring something shorter than a tick, and answering a caller that wants absolute time rather than a count of scheduling periods. Espressif’s radio blobs want the second — esp_timer_get_time is one of the entries in wifi_osi_funcs_t and the blob calls it constantly.

The kernel reads the clock through [hal::clock::MonotonicClock], selecting one implementation with the SoC. A SoC with a spare hardware counter — the ESP32’s is TIMG1/T1 (below), the RP2040’s is its free-running 1 MHz timer — implements it; one without takes the trait default, and [now_us] falls back to the scaled scheduler tick. So callers — syscall, the self-tests, the radio adapter — name no chip.

Why the ESP32 implementation lives here, not in soc-esp32

Section titled “Why the ESP32 implementation lives here, not in soc-esp32”

It is built on esp32-timg, a Layer-1 driver, and soc-esp32 is Layer 0 — it may not depend on a driver. The kernel may, so the implementation is a kernel-local type behind the portable trait rather than a chip name in the kernel’s neutral code. radio/* still cannot reach TIMG (it may not name drivers/physical/*), which is why a clock is a kernel service at all.

The counter is 64 bits at 1 MHz, so it wraps after about 584,000 years. There is deliberately no wrap handling: code that reads a 32-bit counter and compensates is code with a bug waiting for the boundary, and here the boundary does not exist.

struct Clock;

The kernel’s monotonic clock, selected by SoC.

A kernel-local type so the kernel may implement the hal trait for it — the esp32-timg the ESP32 body needs is a driver neither hal nor soc-esp32 may depend on (see the module header).

Implements: MonotonicClock

unsafe fn init() -> bool

Claim and start the monotonic clock. See [MonotonicClock::init].

Takes exclusive ownership of the SoC’s monotonic timer.

fn now_us() -> u64

Microseconds since [init].

Monotonic: it counts up and never goes back, including across a task switch on either core. On a SoC with a hardware microsecond counter this is that counter (zero before init); on one without, it is the scheduler tick scaled to microseconds — monotonic and correctly ordered, but a thousand times coarser, so callers may check ordering and must not check resolution.