-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
samd: Don't rely on RTC interrupt #6202
Conversation
I instrumented RTC_Handler and determined that on SAMD51 it was possible for the interrupt to be delivered well before the actual overflow of the RTC COUNT register (e.g., a value as small as 0xffff_fffd could be seen at the time of overflow) Rather than depending on the overflow interrupt coming in at the same time as COUNT overflows (exactly), rely only on observed values of COUNT in _get_count, overflowing when it wraps around from a high value to a low one. With this change, PLUS a second change so that it is possible to warp the RTC counter close to an overflow and test in 20ms instead of 3 days, there was no problem detected over 20000+ overflows. Before, a substantial fraction (much greater than 10%) of overflows failed. Fixes adafruit#5985 Change to common-hal/rtc/RTC.c for time warping (plus make rtc_old_count non-static): ```patch void common_hal_rtc_set_calibration(int calibration) { + + common_hal_mcu_disable_interrupts(); + + RTC->MODE0.COUNT.reg = 0xffffff00; + rtc_old_count = 0; + do { + while ((RTC->MODE0.SYNCBUSY.reg & (RTC_MODE0_SYNCBUSY_COUNTSYNC | RTC_MODE0_SYNCBUSY_COUNT)) != 0) { } + } + while(RTC->MODE0.COUNT.reg < 0xffffff00); + common_hal_mcu_enable_interrupts(); + + mp_printf(&mp_plat_print, "Warping RTC in calibration setter count=%08x rtc_old_count=%08x\n", RTC->MODE0.COUNT.reg, rtc_old_count); ``` Test program: ```python import time from rtc import RTC i = 0 while True: RTC().calibration = 1 # Warps to ~16ms before overflow, with patch to RTC code t0 = time.monotonic_ns() et = t0 + 20_000_000 # 20ms while (t1 := time.monotonic_ns()) < et: pass i += 1 print(f"{i:6d}: duration {t1-t0}") if t1-t0 > 200_000_000: break print() ```
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your excellent sleuthing on this.
@jwfmcclain any chance you would be able to take a look at this possible fix for your issue? |
@jepler, sure, but I think I need a some help finding the right build artifact (M4 Feather Express). |
The artifacts are at the bottom of this page: https://github.com/adafruit/circuitpython/actions/runs/2041944567, but GitHub is having trouble right now. Here is a Feather M4 build; just unzip to get the UF2: |
@jepler I tested this on a CPX, using your test code above, with the
|
@dhalbert that's good, thanks for testing! While I think there's still the very unlikely problem in the case that the time isn't checked for a whole 3-day roll-over (or maybe just a 1.5 day half roll-over, not sure) that an overflow is lost, the fix of adding any calls to |
@jwfmcclain It'd be great to have your feedback if you were able to test with this, but if not we'll merge it soon anyway. |
Sorry, I didn't see Dan's message until this morning. Have both my M4 running the alpha code now
|
@jwfmcclain Did you see any issues yet? Maybe no news is good news :) . |
Merging this to get it in. Will revisit if necessary. |
greps log files @dhalbert -- no sign of the problem with the Thanks |
Still no signs of the problem while using 7.3.0-alpha.0-63-g372306411-dirty ... looking forward to 7.3 |
I instrumented RTC_Handler and determined that on SAMD51 it was possible for the interrupt to be delivered well before the actual overflow of the RTC COUNT register (e.g., a value as small as 0xffff_fffd could be seen at the time of overflow)
Rather than depending on the overflow interrupt coming in at the same time as COUNT overflows (exactly), rely only on observed values of COUNT in _get_count, overflowing when it wraps around from a high value to a low one.
With this change, PLUS a second change so that it is possible to warp the RTC counter close to an overflow and test in 20ms instead of 3 days, there was no problem detected over 20000+ overflows. Before, a substantial fraction (much greater than 10%) of overflows failed.
If a user program carefully avoids calling any time-related function for over 1.5 days, it's possible that an overflow would get lost with the new formulation.
Fixes #5985
Change to common-hal/rtc/RTC.c for time warping (plus make rtc_old_count non-static):
Test program: