David-OConnor / stm32-hal

This library provides access to STM32 peripherals in Rust.
MIT License
147 stars 44 forks source link

Could you provide an example to implement rtic_monotonic::Monotonic trait? #59

Closed seanybaggins closed 1 year ago

seanybaggins commented 1 year ago

It would be nice if there was an example to implement the Monotonic trait using the hal api calls.

Here is an example using the peripheral access crate. https://github.com/kalkyl/f411-rtic/blob/c1c74d887e3620bddcaf9217c93767e9f743d7b1/src/mono.rs

David-OConnor commented 1 year ago

Good idea. I personally haven't used Monotomic (have been using RTIC just for the interrupt and shared-state functionality), but agree that would be a good addition. Perhaps instead of an example, actually implementing it for timers, although I'm not sure that's how it works.

David-OConnor commented 1 year ago

WIP: https://github.com/David-OConnor/stm32-hal/blob/main/src/timer.rs#L813

David-OConnor commented 1 year ago

In the latest release. I think there's a bug with it; can't get it to work properly. Hopefully an easy fix; LMK if you have any ideas, or if you're able to get it working as-is.

seanybaggins commented 1 year ago

I did manage to implement my own timer. Here is the code. Might circle back and open up a PR for an example. Currently don't have the bandwidth to check the default implementation for the stm32. I might be able to take a look at it during a weekend during the holidays.

use rtic::Monotonic;
use stm32_hal2::clocks::Clocks;
use stm32_hal2::pac::TIM2;
use stm32_hal2::timer::{Alignment, CaptureCompareDma, CountDir, Timer, TimerConfig, UpdateReqSrc};

pub struct MonoTimer<T, const FREQ: u32>(Timer<T>);

impl<const FREQ: u32> MonoTimer<TIM2, FREQ> {
    pub fn new(timer: TIM2, clocks: &Clocks) -> Self {
        let timer_config = TimerConfig {
            one_pulse_mode: false,
            update_request_source: UpdateReqSrc::Any,
            auto_reload_preload: false,
            alignment: Alignment::Edge,
            capture_compare_dma: CaptureCompareDma::Update,
            direction: CountDir::Up,
        };
        let mut timer = Timer::new_tim2(timer, FREQ as f32, timer_config, &clocks);
        let prescaler = clocks.sysclk() / FREQ - 1;

        timer.set_auto_reload(u32::MAX);
        timer.set_prescaler(prescaler as u16);

        timer.regs.egr.write(|w| w.ug().set_bit());
        timer.regs.sr.write(|w| w.uif().clear_bit());
        timer.regs.cr1.write(|w| w.cen().set_bit().udis().set_bit());

        Self(timer)
    }

    pub fn counts(&self) -> u32 {
        self.0.read_count()
    }
}

impl<const FREQ: u32> Monotonic for MonoTimer<TIM2, FREQ> {
    type Instant = fugit::TimerInstantU32<FREQ>;
    type Duration = fugit::TimerDurationU32<FREQ>;

    #[inline(always)]
    fn now(&mut self) -> Self::Instant {
        let ticks = self.0.read_count();
        Self::Instant::from_ticks(ticks)
    }

    fn set_compare(&mut self, instant: Self::Instant) {
        // No idea. Taken from https://github.com/kalkyl/f411-rtic/blob/a696fce7d6d19fda2356c37642c4d53547982cca/src/mono.rs#L87
        self.0
            .regs
            .ccr1()
            .write(|w| w.ccr().bits(instant.duration_since_epoch().ticks()))
    }

    fn clear_compare_flag(&mut self) {
        self.0.regs.sr.write(|w| w.cc1if().clear_bit())
    }

    #[inline(always)]
    fn zero() -> Self::Instant {
        Self::Instant::from_ticks(0)
    }

    unsafe fn reset(&mut self) {
        self.0.regs.dier.write(|w| w.cc1ie().set_bit())
    }
}
David-OConnor commented 1 year ago

Nice! Check the current impl here: https://github.com/David-OConnor/stm32-hal/blob/main/src/timer.rs#L791

Overall, same idea as what you posted, with the following exceptions:

seanybaggins commented 1 year ago

Are you calling spawn_after or spawn? It could be the timer is hitting the auto_reload value and resetting before it hits the value you asked to wait for.

David-OConnor commented 1 year ago

Looks like spawn works; tried increasing the timer timeout period, but something is still not working with spawn_after.

David-OConnor commented 1 year ago

I'm dropping further integration due to the direction RTIC is moving.

seanybaggins commented 1 year ago

Can you elaborate on due to the direction RTIC is moving?

David-OConnor commented 1 year ago

Async for RTIC 2.

seanybaggins commented 1 year ago

I wonder if it will play nice with embassy. It would be cool if you could use an RTIC 2 executor with embassy hals. Never used embassy's hals but have wanted to give them a try.

David-OConnor commented 1 year ago

From what I gather from some chats, it should play nice with Embassy, although I don't know how the interactions will work. I think the intent is to keep the core RTIC functionality (Resource sharing and interrupts) the same, but to move everything else, which would include monotonic, to async.