stm32/boards: Set the RTC prescalers for the LSI on Arduino boards. - #19650
stm32/boards: Set the RTC prescalers for the LSI on Arduino boards.#19650kwagyeman wants to merge 1 commit into
Conversation
|
Code size report: |
Oh wow! That's an oversight. The SiT1532 is a really nice time source, so it's a shame it's not usable. I guess it's not easy to update the MCUboot bootloader to configure it with LSE=true? I think the config here should explicitly mention this limitation, and explicitly enable LSI. Suggest all Arduino boards use the following: // There is an external 32kHz oscillator but the stock MCUboot bootloader is built
// with lse_available=false and resets the RTC if it's not using LSI. So use LSI.
#define RTC_ASYNCH_PREDIV (0)
#define RTC_SYNCH_PREDIV (31999)
#define MICROPY_HW_RTC_USE_LSE (0)
#define MICROPY_HW_RTC_USE_US (1)
#define MICROPY_HW_RTC_USE_CALOUT (1) |
|
Yeah, it's quite bad. And we cannot update the bootloader, though. So, it's a locked-in issue. Updating... |
The Arduino Giga, Nicla Vision, Opta and Portenta H7 run the RTC from the ~32kHz LSI, but with the prescalers set for a 32768Hz source, so the RTC keeps time about 2.3% slow -- over half an hour per day, far beyond what rtc.calibration() can correct. Divide by the LSI's nominal 32000 instead. Measured on a Nicla Vision this takes the error from -22300ppm to -684ppm, and the remaining part-specific offset is small enough that rtc.calibration() can trim most of it. These boards do have an accurate external 32768Hz oscillator (a SiT1532 wired to OSC32_IN, +-20ppm), but it cannot be used: the boards' stock Arduino MCUboot bootloader (built with Mbed's lse_available=false) reinitialises the RTC onto the LSI at every hard reset when it finds any other clock source selected, and the backup-domain reset that requires wipes the calendar. Verified on a Nicla Vision -- with the RTC switched to LSE bypass (which does start and keep +-0ppm time while running), every machine.reset() and deep-sleep wake came back on the LSI with the calendar reset to the bootloader's 2021-01-01 epoch. The RTC config is therefore now explicitly LSI (MICROPY_HW_RTC_USE_LSE disabled, replacing the never-reachable MICROPY_HW_RTC_USE_BYPASS setting), with a comment recording the limitation; with the sources agreeing the bootloader leaves the RTC alone and the time survives reset and deep sleep. Tested on an Arduino Nicla Vision: -684ppm over a 240s measurement against the HSE-derived SysTick (previously -22300ppm measured over two hours against NTP), time preserved through machine.deepsleep(20000) and machine.reset(), and the 31.25us subsecond resolution still divides exactly for the microsecond datetime fields. Signed-off-by: Kwabena W. Agyeman <kwagyeman@live.com>
c94f67d to
5065be8
Compare
Is it at all possible to update the bootloader, eg use mboot? (Just out of curiosity.) |
|
No, it would need to be done via jtag which is not something you can count on users having. Arduino boards aren't meant to be flashed by the end user. |
|
It might be possible to make a bootloader-updater app, eg running in MicroPython "user space" which rewrites the bootloader. We already have such code in Anyway, I'm not suggesting to do that, just noting that it could be an option if someone really wants to use the LSE. |
|
Very dangerous. Could brick niclas. Wouldn't suggest. |
Summary
The Arduino Giga, Nicla Vision, Opta and Portenta H7 run the RTC from the
~32kHz LSI, but with the RTC prescalers set for a 32768Hz source — so the
RTC keeps time about 2.3% slow (over half an hour per day), far beyond what
rtc.calibration()can correct. Reported with measurements inhttps://forums.openmv.io/t/rtc-behind-on-arduino-nicla-vision/11861.
This changes the prescalers to divide by the LSI's nominal 32000.
These boards do carry an accurate external 32768Hz oscillator (a SiT1532,
±20ppm) on OSC32_IN and configure
MICROPY_HW_RTC_USE_BYPASS, and it doeswork — switched to LSE bypass the RTC held ±0ppm on the bench. But it can't
be shipped: the boards' stock Arduino MCUboot bootloader (built with Mbed's
lse_available=false) reinitialises the RTC onto the LSI at every hardreset when any other clock source is selected, and the backup-domain reset
that requires wipes the calendar. Verified on a Nicla Vision: with the RTC
on LSE, every
machine.reset()and deep-sleep wake came back on the LSIwith the calendar reset to the bootloader's 2021-01-01 epoch. So the RTC
clock source stays LSI (matching the bootloader, which then leaves the RTC
completely alone), and only the divider changes.
Testing
Measured on an Arduino Nicla Vision against the HSE-derived SysTick over
240s windows: -22300ppm before, -684ppm after (the remainder is
part-specific LSI tolerance). Time is preserved through
machine.deepsleep()andmachine.reset(), including the prescaler valueitself. The microsecond subsecond fields still divide exactly
(32000/64 = 500). Build-tested on all four boards.
Generative AI
I used generative AI tools when creating this PR, but a human has checked the
code and is responsible for the code and the description above.