Skip to content
This repository has been archived by the owner on May 15, 2021. It is now read-only.

Timers #12

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open

Timers #12

wants to merge 17 commits into from

Conversation

droogmic
Copy link
Contributor

@droogmic droogmic commented Oct 20, 2018

Based on #8, appears to work as required. It is however, very messy, I am just happy I got it working.
I am not totally up to speed with recent embedded rust developments and roadmap, nor am I very experienced with rust, so a skim read and advice if there is a better standard to follow would be appreciated.

Changes:

Consider / TODO:

  • Duplicate start method
  • Commented out features
  • Move things to a time.rs file
  • hal::timer::Periodic marker trait flag, doesn't apply as for the nrf51 this can be changed at runtime, how is this usually handled?
  • A robust testing strategy is probably needed; some tests are provided in microbit which are a good start for manual verification, but ideally these would be run as tests not examples; also briefly discussed in fix typo'd target name #10
  • Compare with other examples, e.g. stm32f* hal crates
  • What should be the API for shortcuts
  • How should the similar feature set between TIMER and RTC be combined to a unified API

src/timer.rs Outdated
{

// Reset comparison interrupt
self.reset_compare(0);
Copy link
Contributor Author

@droogmic droogmic Oct 21, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Remove duplication from start

@droogmic droogmic changed the title [WIP] Timers Timers Oct 22, 2018
@droogmic
Copy link
Contributor Author

droogmic commented Oct 22, 2018

I think this is ready for an initial review, I have qualified the functionality of all 5 peripherals on my device.
I can rebase on request
I can run rustfmt on request

src/timer.rs Outdated

impl Timer<$RTC> {
/// Construct RTC based timer with prescaler
/// *WARNING* The LFCLK needs to be activated first, e.g.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically, this will breach the embedded-hal Countdown trait contract

@droogmic
Copy link
Contributor Author

Fixes following discussion with @therealprof.

Still some open issues, but a lot is down to shortcomings in embedded-hal

src/lib.rs Outdated
#![feature(const_fn)]
#![feature(try_from)]
#![feature(duration_as_u128)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try to get rid of all those features. This should eventually be Rust 2018 stable-able.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I had forgotten about that:

  • Remove all 3 2018-incompatible features

I used core::time::Duration to get it working, but it is expensive in an MCU to use u128s to manipulate time. It seems there are many ongoing discussions about how to handle real unite both in rust and rust-embedded, none nearing conclusion. So for now I will just make 3 types: tick (An nrf51 specific tick, 1/16th of a μs, a μs and a ms.

src/delay.rs Outdated
macro_rules! delay {
( $($TIM:ty),+ ) => {
$(
impl DelayMs<u32> for Timer<$TIM> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you've renamed Delay to Timer? That'll break all some stuff, including your own examples in microbit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll create an alias to Delay as a structural fix, as that what clients will expect. Behind the scenes though it makes no sense to have a distinction.

src/timer.rs Outdated

/// Error to respresent a stopped countdown
#[derive(Debug)]
pub struct CountdownStoppedError;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused

src/timer.rs Outdated

impl From<Millis> for Lfticks {
fn from(millis: Millis) -> Self {
Lfticks(u32(f64::from(millis.0) * 32.768).unwrap())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f64 is a very expensive type on this platform. Is this really necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh my, that is an unacceptably bad bit of code..., it isn't even mathematically correct, apologies:

Lfticks(millis.0 * LFCLK_FREQ)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, it was mathematically correct, ( 32.768 =/= 32_768)
I need to find a table which lists how expensive various operations are...

Copy link
Collaborator

@therealprof therealprof Oct 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is a Cortex-M0, so no hardware division. And no FPU, so floating point is all emulated.

@droogmic
Copy link
Contributor Author

droogmic commented Oct 28, 2018

Don't merge this, I think there is a major flaw with this as is.
If DelayMs and Timer are implemented on the same struct, then they can currently both be used at the same time. Obviously this currently breaks everything...
e.g. start an asynchronous countdown, use a delay on the same struct, then waiting for the countdown (hint: the countdown will block forever as the timer is now stopped)
2 options:

  1. Macro everything to have a full duplicate implementation of everything in Delay and Timer, with the exception of the embedded-hal traits, which will be only in one or the other
  2. (Possibly, I need to think further if it is possible) take a performance penalty (might need to do more computations and store a u32 in the struct) but enable more functionality: use the second comparison registers and events on the nrf51's timers and rtcs to enable compliant functionality

Thoughts?

@therealprof therealprof added the DNM Do not merge! label Oct 28, 2018
@therealprof
Copy link
Collaborator

@droogmic Just from reading the code I'm not sure how conflicting use would be possible. Is this due to Delay being a type alias for a Timer? If so this could be solved by using a type state, i.e. have some general timer initialisation code and then two different types implementing either HAL functionality.

@droogmic
Copy link
Contributor Author

@droogmic Just from reading the code I'm not sure how conflicting use would be possible. Is this due to Delay being a type alias for a Timer? If so this could be solved by using a type state, i.e. have some general timer initialisation code and then two different types implementing either HAL functionality.

Ah yeah, that would be option 1, don't actually need macros.
That is the simplest and probably the best, as testing for interactions will be painful

@droogmic
Copy link
Contributor Author

droogmic commented Oct 28, 2018

@therealprof And yes, because of the alias you can make a Delay item with both DelayMs and Timer traits implemented

After @therealprof review
+ Move time to a seperate file
+ Move generic timer/counter implementation to file
+ Create newtype Delay and Timer from TimCo
@droogmic
Copy link
Contributor Author

droogmic commented Nov 3, 2018

@therealprof I am not sure if this is what you meant

using a type state

@therealprof
Copy link
Collaborator

@droogmic I don't have the time right now to look into your update but typestate programming is something like this: https://github.com/therealprof/stm32f042-hal/blob/master/src/gpio.rs

Basically what you had previously but with empty structs for the different possibilities (e.g. Countdown or Delay), functions to move the generic timer into those states and then only impl the traits on the timers which are in that specific state.

@droogmic
Copy link
Contributor Author

droogmic commented Nov 3, 2018

@therealprof Thanks, I'll try that and get back to you.

Used to seperate Countdown and Delay trait implementation for same Timer struct
@droogmic
Copy link
Contributor Author

droogmic commented Nov 4, 2018

@therealprof I have made an attempt, but I am not really happy with the result...

@droogmic
Copy link
Contributor Author

@therealprof bump, a quick look to see if this is what you meant would be appreciated.

Copy link
Collaborator

@therealprof therealprof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good structure-wise (except maybe for the excess blank lines) but I'm a bit lost on how to actually use this, i.e. how do I turn a RTCx or TIMERx peripheral into a timer I can actually call into_delay() or into_countdown() on? As a nice litmus test it would be great if you could also come up with a PR that changes the microbit crate to make use of the changed interface.

@droogmic
Copy link
Contributor Author

@therealprof
See nrf-rs/microbit#11 for a demo.

Not sure type state is the way to go anymore, as the moment the struct specializes most of the methods should probably be removed. I think having 3 different structs would be simpler, where Delay and Countdown structs container a single Timer struct.

@therealprof
Copy link
Collaborator

@droogmic Actually I was hoping that instead of Timer<Generic, TIMERx> we would have something like Timer<TIMERx<Generic>>, potentially even without the additional Timer though I'm not sure whether that would work register-wise.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
DNM Do not merge!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants