embedded-time 0.9.0

Fully defined, inter-operable, ergonomic, and fast human-time units (both duration and rate types) with hardware timer abstraction and software timers.
Documentation

embedded-time

embedded-time provides a comprehensive library implementing duration, rate, instant, and software timer types as well as a clock trait for abstracting over hardware timers/clocks.

Duration Types

Units Extension
Hours hours
Minutes minutes
Seconds seconds
Milliseconds milliseconds
Microseconds microseconds
Nanoseconds nanoseconds
  • Conversion from Rate types

    Microseconds(500_u32).to_rate() -> Ok(Kilohertz(2_u32))
    
  • Conversion to/from Generic Duration type

    Seconds(2_u64).to_generic(Fraction::new(1, 2_000)) -> Ok(Generic::new(4_000_u32, Fraction::new(1, 2_000))))
    Seconds::<u64>::try_from(Generic::new(2_000_u32, Fraction::new(1, 1_000))) -> Ok(Seconds(2_u64))
    

core Compatibility

  • Conversion to/from core::time::Duration

Benchmark Comparisons to core duration type

Construct and Read Milliseconds

let duration = Milliseconds::<u64>(ms); // 8 bytes
let count = duration.count();

(the size of embedded-time duration types is only the size of the inner type)

let core_duration = Duration::from_millis(ms); // 12 bytes
let count = core_duration.as_millis();

(the size of core duration type is 12 B)

Rate Types

Frequency

Units Extension
Mebihertz MiHz
Megahertz MHz
Kibihertz KiHz
Kilohertz kHz
Hertz Hz

Data Rate

Units Extension
MebibytePerSecond MiBps
MegabytePerSecond MBps
KibibytePerSecond KiBps
KiloBytePerSecond KBps
BytePerSecond Bps
MebibitPerSecond Mibps
MegabitPerSecond Mbps
KibibitPerSecond Kibps
KilobitPerSecond kbps
BitPerSecond bps

Symbol Rate

Units Extension
Mebibaud MiBd
Megabaud MBd
Kibibaud KiBd
Kilobaud kBd
Baud Bd
  • Conversion from/to all other rate types within the same class (frequency, data rate, etc.). For example, MBps (megabytes per second) --> Kibps (kibibits per second).

  • Conversion from Duration types

    Kilohertz(500_u32).to_duration() -> Ok(Microseconds(2_u32))
    
  • Conversion to/from Generic Rate type

    Hertz(2_u64).to_generic(Fraction::new(1,2_000)) -> Ok(Generic::new(4_000_u32, Fraction::new(1,2_000))))
    Hertz::<u64>::try_from(Generic::new(2_000_u32, Fraction::new(1,1_000))) -> Ok(Hertz(2_u64))
    

Hardware Abstraction

  • Clock trait allowing abstraction of hardware timers/clocks for timekeeping.

Timers

  • Software timers spawned from a Clock impl object.
  • One-shot or periodic/continuous
  • Blocking delay
  • Poll for expiration
  • Read elapsed/remaining duration

Reliability and Usability

  • Extensive tests
  • Thorough documentation with examples
  • Example for the nRF52_DK board

Motivation

The handling of time on embedded systems is generally much different than that of OSs. For instance, on an OS, the time is measured against an arbitrary epoch. Embedded systems generally don't know (nor do they care) what the real time is, but rather how much time has passed since the system has started.

Drawbacks of the standard library types

Duration

  • The storage is u64 seconds and u32 nanoseconds.
    • This is huge overkill and adds needless complexity beyond what is required (or desired) for embedded systems.
  • Any read (with the exception of seconds and nanoseconds) requires arithmetic to convert to the requested units
    • This is much slower than this project's implementation of what is analogous to a tagged union of time units.

Instant

  • The Instant type requires std.

Drawbacks of the time crate

The time crate is a remarkable library but isn't geared for embedded systems (although it does support a subset of features in no_std contexts). It suffers from some of the same drawbacks as the core::Duration type (namely the storage format) and the Instant struct dependency on std. It also adds a lot of functionally that would seldom be useful in an embedded context. For instance it has a comprehensive date/time formatting, timezone, and calendar support.

Background

What is an Instant?

In the Rust ecosystem, it appears to be idiomatic to call a now() associated function from an Instant type. There is generally no concept of a "Clock". I believe that using the Instant in this way is a violation of the separation of concerns principle. What is an Instant? Is it a time-keeping entity from which you read the current instant in time, or is it that instant in time itself. In this case, it's both.

As an alternative, the current instant in time is read from a Clock. The Instant read from the Clock has the same precision and width (inner type) as the Clock. Requesting the difference between two Instants gives a Duration which can have different precision and/or width.

License

This project is licensed under either of

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in embedded-time by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.