atsamd-rs / atsamd

Target atsamd microcontrollers using Rust
https://matrix.to/#/#atsamd-rs:matrix.org
Apache License 2.0
563 stars 200 forks source link

RTC broken on SAMD51G #501

Open ryankurte opened 3 years ago

ryankurte commented 3 years ago

hey there,

i've been messing around with trying to get the RTC (and RTIC) working on a SAMD51G18A with (almost) no success. attempting to use atsamd-hal@master and cortex-m-rtic@v0.6.0-rc.2. possibly related to: #488.

i started with the setup from feather_m4/examples/sleeping_timer_rtc.rs which doesn't seem to actually kick off the RTC. looking at the datasheet the count32_mode function seems to be missing some steps, and there's a significant delta between Rtc::count32_mode and Rtc::into_count32_mode, in fact if one adds this line the RTC does start to function:

let rtc = Rtc::count32_mode(peripherals.RTC, 1024.hz(), &mut peripherals.MCLK);
let mut rtc = rtc.into_count32_mode();    // Adding this line starts the RTC ticking
rtc.enable_interrupt();

so it's possible that was just missed in a previous refactor.

from there i've been attempting to use the RTC as a Monotonic source for RTIC per feather_m0/examples/blinky_rtic.rs. one can observe that the RTC is running via increasing values from monotonics::now(), scheduling immediately (via ::spawn()) works so the dispatcher would seem to be okay, but ::spawn_after() does not. attaching a debugger i can see the first call, but can't seem to step into the scheduling to see what it thinks it's doing.

Screenshot from 2021-10-04 21-45-51

it's likely i've missed or misunderstood something, and some of this might be RTIC related, but, would definitely appreciate any advice y'all have ^_^

ryankurte commented 3 years ago

i haven't fully tracked this down but it seems that maybe the SCALING_FACTOR assumes a 32.768 kHz external oscillator rather than the 1024 Hz version from the internal low-power oscillator, likely related to https://github.com/FluenTech/embedded-time/issues/109.

#[cfg(feature = "rtic")]
impl Clock for Rtc<Count32Mode> {
    const SCALING_FACTOR: Fraction = Fraction::new(1, 32_768);
    type T = u32;
...

so patching that, it then gets weirder. if i set breakpoints on Monotonic::set_compare and Monotonic::clear_compare_flag the RTC compare values seem pretty reasonable, I can see the interrupts and TimerQueue::dequeue being called at the correct intervals, and the task gets scheduled and executed and the blinking light blinks as one would expect.

Screenshot from 2021-10-04 22-31-24

Screenshot from 2021-10-04 22-31-57

-imagine a screenshot of foo being run, which i forgot to take-

but, without these specific breakpoints the idle task runs fine but the scheduled task never seems to occur.

ryankurte commented 3 years ago

swapped to SysTick based monotonic and things get scheduled, so, it appears it's something to do with the RTC and/or embedded-time.

sajattack commented 3 years ago

@TDHolmes I feel like you're the most likely person to have an idea what the issue could be.

TDHolmes commented 3 years ago

Yeah pretty confident my most recent RTC change broke our monotonic RTIC implementation. I tried looking at this last weekend and couldn’t figure it out before I ran out of time. I can look st this again Saturday

On Tue, Oct 5, 2021 at 4:52 PM Paul Sajna @.***> wrote:

@TDHolmes https://github.com/TDHolmes I feel like you're the most likely person to have an idea what the issue could be.

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/atsamd-rs/atsamd/issues/501#issuecomment-935098966, or unsubscribe https://github.com/notifications/unsubscribe-auth/AC5YNWRHFF3GGR6CSCQOTF3UFOFUZANCNFSM5FI2M2SQ .

TDHolmes commented 3 years ago

Ping @henrikssn too

ryankurte commented 3 years ago

(with those couple of patches) that it works under debug but not while running has definitely thrown me, sorta seems like a race condition but it's unclear (to me) how a timer impl can cause this.

i'm still trying to work out what's going on but it seems like updating from 0.12.0 to master has changed something maybe in the clock configuration / distribution because the previously working / shamelessly ripped from the feather_m4 I2c and Timer examples also seem to have stopped working for me.

having a wee suspicious look at with_internal_32kosc vs. with_external_32kosc at the moment, and going to try setup a different board to make sure it's not something wrong with this hardware.

henrikssn commented 3 years ago

I pulled latest commit (3dc7f9) last night from master and tried the blinky_rtic example using the following command on a SAMD21E17 board which has an external 32K oscillator:

cargo flash --chip ATSAMD21E17A --example blinky_rtic --features rtic,unproven

Everything worked as expected. Maybe there is a difference between SAMD21 and SAMD51 in how the RTC works?

(with those couple of patches) that it works under debug but not while running has definitely thrown me, sorta seems like a race condition but it's unclear (to me) how a timer impl can cause this.

i'm still trying to work out what's going on but it seems like updating from 0.12.0 to master has changed something maybe in the clock configuration / distribution because the previously working / shamelessly ripped from the feather_m4 I2c and Timer examples also seem to have stopped working for me.

having a wee suspicious look at with_internal_32kosc vs. with_external_32kosc at the moment, and going to try setup a different board to make sure it's not something wrong with this hardware.

Honestly, I never tried the internal LP oscillator, but maybe this could be related to it not running in standby? Did you try commenting out core.SCB.set_sleepdeep(); in the Feather example? The debugger might force it to be active, which might be the reason it works in debugging mode but not without.

(also, sorry for being late to the party)

AfoHT commented 3 years ago

For both SAMD51 and SAMD21 I think one of the features of the OSCULP32K is that it is always on. At least on the SAMD51 it is only possible to mask the outputs, even though the oscillator is always on

From the datasheet for SAMD21, page 161:

image

jonapap commented 1 year ago

I've recently encountered the exact same issue on the SAME51J20A. The RTC monotonic clock doesn't work, and similarly adding breakpoints allows it to run.

For anyone else that encounters this, one workaround is to add a delay in either set_compare or clear_compare_flag. For example:

    fn clear_compare_flag(&mut self) {
        self.mode0().intflag.write(|w| w.cmp0().set_bit());

        for i in 1..10000 {
            nop();
        }
    }

Obviously, this is far from ideal. However, with this above change, everything works fine, including going to deep sleep along with wfi.

My (uneducated) guess is that some weird synchronization issue is happening here. However, the datasheet makes no mention of needing synchronization for either intflag or comp0. I've found some places (here and here) that talks about similar issues. I've tried various things, such as calling dsb() and lsb(), without success. If anyone else has an idea what could be causing this, I would be more than happy to test.