Timing & Clocks — Time
One object, four verbs. Time covers the whole timing vocabulary: a yielding sleep, two monotonic clocks, and a spin for sub-millisecond protocol timing. Every call lowers to one Zephyr kernel call — k_msleep(), k_uptime_get(), k_busy_wait().
import { Time } from '@typecad/hal';Sleep
Blocking sleep
Time.sleep(1000); // k_msleep — blocks the calling threadAt the top level this blocks main, the way delay() did on Arduino. Inside a Thread it blocks that thread only — the scheduler runs everything else.
Cooperative sleep
Inside an async function, await the same call and it stops blocking: the async state machine arms a deadline and yields, so every task sharing the loop runs until the deadline passes.
async function poll() {
while (true) {
await Time.sleep(50); // other tasks run during the wait
// …read a sensor, update a display…
}
}Busy wait
Time.busyWaitUs(3); // k_busy_wait — spins, no schedule pointFor sub-millisecond protocol timing where a yield would break the waveform. This is the only Time call that never yields — do not use it for long waits; it holds the CPU.
Clocks
Two monotonic clocks, both counting from boot. Both return doubles, so they never wrap.
const start = Time.now(); // milliseconds since boot
const us = Time.nowUs(); // microseconds since bootElapsed-time arithmetic is plain subtraction — there is no unsigned wraparound to guard against:
if (Time.now() - start > 5000) { // correct at minute 1 and month 6
// five seconds have passed
}Time.now() is the equivalent of Arduino’s millis(), with one deliberate difference: Arduino’s version is a uint32_t that wraps every 49.7 days and needs the (long)(now - start) subtraction trick; Time.now() is a double that holds milliseconds exactly for centuries.
| Arduino | Cuttlefish |
|---|---|
millis() | Time.now() — ms, monotonic, no wrap |
micros() | Time.nowUs() — µs, monotonic, no wrap |
delay(ms) | Time.sleep(ms) — yielding; await-able |
delayMicroseconds(us) | Time.busyWaitUs(us) — spin, no yield |
Time.nowUs() is uptime-derived on every board, so its resolution is the uptime tick — one millisecond. The cycle-counter alternative reads as a constant on chips without a free-running 64-bit counter, so the uniform expression wins over per-chip precision. For sub-millisecond deterministic timing use the hardware Counter — it fires from interrupt context and does not depend on any thread.
Periodic work
Time deliberately has no callback timers. Periodic work belongs to a Thread:
import { Thread } from '@typecad/hal';
const blinker = new Thread(0, { stackKb: 2 });
blinker.start(() => {
while (true) {
led.toggle();
Time.sleep(500);
}
});Or, when the period must be exact to the microsecond, to a hardware Counter alarm.
API Reference
| Member | Description |
|---|---|
Time.sleep(ms) | Yielding sleep (k_msleep); await-ing it inside async code is cooperative. |
Time.now() | Milliseconds since boot, monotonic, double — no wrap. |
Time.nowUs() | Microseconds since boot, double; millisecond resolution on every board. |
Time.busyWaitUs(us) | Spin-wait (k_busy_wait) — no yield; sub-ms protocol timing only. |
On This Page