Open japaric opened 5 years ago
On the somewhat related note, maybe it's time to move time.rs that is currently copied to almost every hal implementation somewhere? I found https://github.com/dfrankland/bitrate, but maybe @rust-embedded should provide smth strandard.
I would love to see something like this. Has there been any discussion / progress on this topic so far outside of this GitHub issue?
I would also like to see this abstraction. The Duration
struct from time.rs is now (as of 0.2.10) usable in embedded contexts. I would like to have an architecture/device agnostic way to retrieve the clock frequency. I believe this would enable crates like RTFM to allow scheduling and other time-related operations be done in human time rather than clock cycles.
I also feel the need for a good abstaraction over durations, instant, delays, clock freq., etc.
For example these existing solutions have big overlap: https://github.com/rtfm-rs/cortex-m-rtfm/blob/master/src/cyccnt.rs https://github.com/stm32-rs/stm32f1xx-hal/blob/master/src/time.rs
I like the cyccnt.rs more, but it is still not good/generic enough (so I have my own version).
In my opinion we need an Instant and a Duration with meaningful arithmetic operations implemented on them (like in cyccnt.rs above). But this implementation should be generic over the counter data type (u32 / u64) depending on the performance needs) and the unit (with a macro implementation for cycles / us / ms / s / etc.).
If one wants to work with few us accuracy (like one-wire protocol) he will not have the luxury to work with 64 bit counters, and more expensive div/mul on a 32 bit processor, also he wants to count with every clock. This of course means that on a 72Mhz clock rate he will get a counter overflow in every minute, so in his arithmetic, the choice between the add / wrapping add / saturating add is pretty important.
On the other hand other things can be fine with 'ms' or sec accuracy and with 64 bit counters so no need to worry about overflows.
Of course there is a need to sometimes jump from one time/duration unit to an other and in this case the clock freq may be needed to implement From / Into. Accessing it "globally" is much better than to store it in every Duration struct instance, or requiring it as a parameter at every conversion.
What I've been currently pursuing is an Instant struct with a nanoseconds: i64
field and a const Ratio to where the the tick count (from my underlying counter/timer) * the Ratio = nanoseconds. I also copied time.rs's duration literals (numberical_traits) where 2.seconds()
creates a Duration of 2 seconds (obvs). At this point, any Instant and Duration is stored as nanoseconds.
One requirement for me is to have signed Durations.
I have used C++'s std::chrono library extensively over the years and would like to have something at least as easy to use as that.
@tib888 This certainly wouldn't be a good solution for something fast like you mentioned, but seems to work well as a general purpose system time solution. I'm a new Rustacean, but I'm going to try to wrap my head around what it might look like to convert between different time bases.
I've put my current effort up here: embedded-time. Comments, suggestions, and PRs are welcome.
I've put my current effort up here: embedded-time. Comments, suggestions, and PRs are welcome.
I've looked at several approaches including const generics and others. At the moment my ratiometric branch seems the most promising. It can (or hopefully will be able to) store the value in either i32
or i64
and have a const num-rational::Ratio<i32>
serving as both a tag for the unit of the duration, and also allowing conversion between units (C++'s std::chrono does nearly the identical structure except it actually does use const generics).
NOTE I don't think the idea presented here should live in this crate, but it could live in a crate maintained by the HAL team. In any case, the only reason I'm posting this here is that it's more likely to be seen by authors of HAL crates, but feel free to move this thread elsewhere.
Goal
Expose the core clock frequency in a device agnostic manner for use in device agnostic APIs. This piece of information is required to translate human time (e.g. milliseconds) into "core clock cycles" which is what time-related peripherals, like timers, work with.
Motivation
The
cortex-m
crate provides anasm::delay(x)
API to perform a delay ofx
clock cycles. Application authors usually don't (directly or indirectly) use that API because they want an API that works with human time like milliseconds.Although
asm::delay
is device agnostic (but not architecture agnostic) it's not possible to create a device agnosticasm::delay_ms
on top of it because the core clock (CPU) frequency can't be accessed in a device agnostic manner. The result? Code duplication: HAL crates end up providing their owndelay_ms
API on top ofasm::delay
orcortex_m::SYST
that takes or interacts with some struct that represents the clock configuration of the device.With this proposal we could create a
cortex-m-hal
crate that depends oncortex-m
and provides a device agnostic function likedelay_ms(x: u32)
.Design
We use the global singleton pattern to implement a crate with zero dependencies that provides access to the core clock frequency.
Then we can create a crate like
cortex-m-hal
to provide methods likedelay_ms
.HAL crates would integrate with
core_frequency
like this:Other thoughts
This only uses atomic stores / loads so it also works with architectures that don't have CAS instructions, like ARMv6-M and MSP430.
A few HAL APIs could be simplified with this API: for example the
clocks
argument could be removed fromstm32f1xx::MonoTimer
constructor.The
core_frequency
crate plus a few more atomics (for the prescalers) could replace thestm32f1xx::Clocks
struct. This change would reduce the number of arguments of many constructors by one.RTFM could use this to provide a variation of the
schedule
API that works with human time (the current API works with core clock cycles).Suggestion: do not make the
cortex-m
crate depend oncore-frequency
. That would make users ofcortex-m
run into weird linker errors ("undefined reference toCORE_FREQUENCY
") if they are not using a HAL crate that integrates withcore-frequency
. Also it would make the versioning of thecortex-m
crate harder: bumping the minor of versioncore-frequency
would require bumping the minor version of thecortex-m
crate.Suggestion: do not make
embedded-hal
depend oncore-frequency
.embedded-hal
is a pure crate that mainly contains interfaces; making it depend oncore-frequency
would add "impurity" to it making it depend on a symbol defined elsewhere. It also would make versioning harder.