Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linked Upcounting Timer #114

Closed
dbrgn opened this issue Jun 28, 2020 · 3 comments
Closed

Linked Upcounting Timer #114

dbrgn opened this issue Jun 28, 2020 · 3 comments

Comments

@dbrgn
Copy link
Contributor

dbrgn commented Jun 28, 2020

I wrote some code to link two 16 bit timers on an STM32L0 in order to form a 32 bit upcounting timer that can be used to measure relative time. The goal is to use this abstraction in order to implement the Monotonic trait for the RTIC scheduler.

Here's the current code, needs more testing & should be made more general (there are other timer pairs that allow linking), but seems to work already:

/// Two linked 16 bit timers that form a 32 bit upcounter.
pub struct LinkedTimer {
    /// Timer in master mode
    tim2: TIM2,
    /// Timer in slave mode
    tim3: TIM3,
}

impl LinkedTimer {
    /// Create a new `LinkedTimer` with TIM2 as master and TIM3 as slave.
    pub fn new(tim2: TIM2, tim3: TIM3, rcc: &mut Rcc) -> Self {
        // Enable timers
        rcc.rb.apb1enr.modify(|_, w| w.tim2en().set_bit());
        rcc.rb.apb1enr.modify(|_, w| w.tim3en().set_bit());

        // Reset timers
        rcc.rb.apb1rstr.modify(|_, w| w.tim2rst().set_bit());
        rcc.rb.apb1rstr.modify(|_, w| w.tim2rst().clear_bit());
        rcc.rb.apb1rstr.modify(|_, w| w.tim3rst().set_bit());
        rcc.rb.apb1rstr.modify(|_, w| w.tim3rst().clear_bit());

        // Enable counter
        tim2.cr1.modify(|_, w| w.cen().set_bit());
        tim3.cr1.modify(|_, w| w.cen().set_bit());

        // In the MMS (Master Mode Selection) register, set the master mode so
        // that a rising edge is output on the trigger output TRGO every time
        // an update event is generated.
        tim2.cr2.modify(|_, w| w.mms().variant(tim2::cr2::MMS_A::UPDATE));

        // In the SMCR (Slave Mode Control Register), select the internal
        // trigger 0 (ITR0) as trigger source (TS).
        //
        // See table 76 ("TIM2/TIM3 internal trigger connection") in the
        // reference manual RM0377.
        tim3.smcr.modify(|_, w| w.ts().variant(tim2::smcr::TS_A::ITR0));
        // Set the SMS (Slave Mode Selection) register to "external clock mode 1",
        // where the rising edges of the selected trigger (TRGI) clock the counter.
        tim3.smcr.modify(|_, w| w.sms().variant(tim2::smcr::SMS_A::EXT_CLOCK_MODE));

        Self { tim2, tim3 }
    }

    fn master(&self) -> &TIM2 {
        &self.tim2
    }

    fn slave(&self) -> &TIM3 {
        &self.tim3
    }

    /// Return the current 32 bit counter value.
    pub fn get_counter(&self) -> u32 {
        let lsb = self.master().cnt.read().cnt().bits() as u32;
        let msb = self.slave().cnt.read().cnt().bits() as u32;
        (msb << 16) | lsb
    }
}

When polling the value with 10 Hz:

...
Counter m=6110 s=861, combined=56432622, delta=1600025
Counter m=33271 s=885, combined=58032647, delta=1600025
Counter m=60432 s=909, combined=59632672, delta=1600025
Counter m=22057 s=934, combined=61232697, delta=1600025
Counter m=49218 s=958, combined=62832722, delta=1600025
Counter m=10843 s=983, combined=64432747, delta=1600025
Counter m=38004 s=1007, combined=66032772, delta=1600025
...

Should this go into the stm32l0-hal? If yes, how should it be called? Should there be a trait involved that's implemented for all timers that allow linking? Or a trait for upcounting timers that cannot be reset?

If yes, should there also be logic for detecting overflows in the HAL, or should that be part of user code?

Right now there's no API in embedded-hal that matches this pattern (see also this discussion). It also cannot be combined with CountDown because resetting the timer (on start) also resets the counter.

CC @astro @hannobraun @rnestler

@dbrgn
Copy link
Contributor Author

dbrgn commented Jun 28, 2020

Implementation is in #115, so this should probably be discussed there.

@jcard0na
Copy link
Contributor

jcard0na commented Oct 2, 2022

Can this issue be closed?

@dbrgn
Copy link
Contributor Author

dbrgn commented Oct 2, 2022

Yes, good catch!

@dbrgn dbrgn closed this as completed Oct 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants