From b71c1adb26a71dc8d514d8125a2f327799eb4cb5 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Fri, 17 Jul 2026 08:00:45 +0800 Subject: [PATCH] stm32wl: add hardware RTC support (rak3172) (#10961) * stm32wl: add hardware RTC support infrastructure Wires the STM32WL chip's internal RTC (running off the LSE 32.768kHz crystal) into meshtastic's existing time-of-day framework (perhapsSetRTC()/readFromRTC()), following the same pattern already used for I2C RTC chips (RV3028, PCF8563/85063, RX8130CE). LSE is started and polled manually before ever calling into the STM32RTC library, with our own bounded timeout - the library's own internal LSE startup path has no bounded fallback and hangs forever via Error_Handler() if the crystal never locks, so this is required for a board with a missing/faulty crystal to boot normally rather than hang. Gated behind a new HAS_LSE variant flag (currently unset everywhere, so this is inert until a variant opts in - see follow-up commit). Signed-off-by: Andrew Yong Assisted-by: Claude Sonnet 5 * gps: qualify RTC.h includes to avoid case-insensitive filesystem collision with STM32RTC The stm32duino STM32RTC library (added to lib_deps in a follow-up commit) ships its own src/rtc.h. On case-insensitive filesystems (the macOS default), an unqualified #include "RTC.h"/ from any file outside src/gps/ resolves to the library's rtc.h instead of src/gps/RTC.h, since PlatformIO's LDF puts lib_deps include paths ahead of the project's own -Isrc/gps. Qualify every include as gps/RTC.h so it can't collide with any same-named header a future dependency might ship, regardless of filesystem case sensitivity. Purely mechanical, no behavior change. Signed-off-by: Andrew Yong Assisted-by: Claude Sonnet 5 * stm32wl(rak3172): enable hardware RTC support Opts rak3172 into the HAS_LSE infrastructure added previously: sets STM32WL_LSE_DRIVE to a conservative default and pulls in the STM32RTC library. rak3172 has ~63KB flash headroom going in; build-verified at 76.7% flash usage after this change (up from a 73.8% baseline), well within budget. wio-e5 is not opted in here despite sharing the same STM32WLE5 chip - it's already at 96.8% flash usage today (GPS + I2C sensor support compiled in, unlike rak3172), leaving too little headroom to safely add STM32RTC without first trimming something else. Signed-off-by: Andrew Yong Assisted-by: Claude Sonnet 5 * stm32wl: add docstrings for LSE/RTC setup functions Addresses CodeRabbit's docstring coverage check on PR #10961. Signed-off-by: Andrew Yong Assisted-by: Claude Sonnet 5 * stm32wl: address CodeRabbit nitpicks on PR #10961 - Brace the single-statement HAS_LSE branch in perhapsSetRTC() to match the sibling readFromRTC() branch's style. - Quote the RTC.h include in PhoneAPI.cpp for consistency with every other qualified include site. Signed-off-by: Andrew Yong Assisted-by: Claude Sonnet 5 --------- Signed-off-by: Andrew Yong Co-authored-by: Ben Meadors --- src/RedirectablePrint.cpp | 2 +- src/gps/GPS.cpp | 2 +- src/gps/NMEAWPL.cpp | 2 +- src/gps/RTC.cpp | 34 +++++++++++- src/gps/RTC.h | 5 ++ src/graphics/SharedUIDisplay.cpp | 2 +- src/graphics/draw/UIRenderer.cpp | 2 +- src/graphics/niche/InkHUD/Applet.cpp | 2 +- .../Applets/Bases/NodeList/NodeListApplet.cpp | 2 +- .../InkHUD/Applets/System/Menu/MenuApplet.cpp | 2 +- .../Notification/NotificationApplet.cpp | 2 +- .../InkHUD/Applets/User/Heard/HeardApplet.cpp | 2 +- .../User/RecentsList/RecentsListApplet.cpp | 2 +- .../ThreadedMessage/ThreadedMessageApplet.cpp | 2 +- src/graphics/niche/InkHUD/Events.cpp | 2 +- src/main.cpp | 6 ++- src/main.h | 3 +- src/mesh/MeshService.cpp | 2 +- src/mesh/NodeDB.cpp | 2 +- src/mesh/PhoneAPI.cpp | 2 +- src/mesh/Router.cpp | 2 +- src/mesh/StreamAPI.cpp | 2 +- src/mesh/TransmitHistory.cpp | 2 +- src/mesh/eth/ethClient.cpp | 2 +- src/mesh/wifi/WiFiAPClient.cpp | 2 +- src/modules/AdminModule.cpp | 2 +- src/modules/ExternalNotificationModule.cpp | 2 +- src/modules/KeyVerificationModule.cpp | 2 +- src/modules/MeshBeaconModule.cpp | 2 +- src/modules/NeighborInfoModule.cpp | 2 +- src/modules/NodeInfoModule.cpp | 2 +- src/modules/PositionModule.cpp | 2 +- src/modules/PowerStressModule.cpp | 2 +- src/modules/RangeTestModule.cpp | 2 +- src/modules/RemoteHardwareModule.cpp | 2 +- src/modules/SerialModule.cpp | 2 +- src/modules/StoreForwardModule.cpp | 2 +- src/modules/Telemetry/AirQualityTelemetry.cpp | 2 +- src/modules/Telemetry/DeviceTelemetry.cpp | 2 +- .../Telemetry/EnvironmentTelemetry.cpp | 2 +- src/modules/Telemetry/HealthTelemetry.cpp | 2 +- src/modules/Telemetry/PowerTelemetry.cpp | 2 +- src/modules/Telemetry/Sensor/PMSA003ISensor.h | 2 +- src/modules/Telemetry/Sensor/SCD4XSensor.h | 2 +- src/modules/Telemetry/Sensor/SEN5XSensor.h | 2 +- src/modules/Telemetry/Sensor/SFA30Sensor.h | 2 +- src/modules/esp32/AudioModule.cpp | 2 +- src/mqtt/MQTT.cpp | 2 +- src/platform/stm32wl/architecture.h | 16 ++++++ src/platform/stm32wl/main-stm32wl.cpp | 54 ++++++++++++++++++- src/security/EncryptedStorage.cpp | 2 +- variants/stm32/rak3172/platformio.ini | 5 ++ variants/stm32/rak3172/variant.h | 3 ++ 53 files changed, 167 insertions(+), 49 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 3ca197ca4..e53806ac7 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -1,8 +1,8 @@ #include "RedirectablePrint.h" #include "NodeDB.h" -#include "RTC.h" #include "concurrency/OSThread.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "memGet.h" #include "mesh/generated/meshtastic/mesh.pb.h" diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 430030422..0a942f10d 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -8,10 +8,10 @@ #include "GpioLogic.h" #include "NodeDB.h" #include "PowerMon.h" -#include "RTC.h" #include "Throttle.h" #include "buzz.h" #include "concurrency/Periodic.h" +#include "gps/RTC.h" #include "meshUtils.h" #include "main.h" // pmu_found diff --git a/src/gps/NMEAWPL.cpp b/src/gps/NMEAWPL.cpp index f4249ca62..5259427e6 100644 --- a/src/gps/NMEAWPL.cpp +++ b/src/gps/NMEAWPL.cpp @@ -1,7 +1,7 @@ #if !MESHTASTIC_EXCLUDE_GPS #include "NMEAWPL.h" #include "GeoCoord.h" -#include "RTC.h" +#include "gps/RTC.h" #include /* ------------------------------------------- diff --git a/src/gps/RTC.cpp b/src/gps/RTC.cpp index ad0bdec04..400bfd1aa 100644 --- a/src/gps/RTC.cpp +++ b/src/gps/RTC.cpp @@ -1,4 +1,4 @@ -#include "RTC.h" +#include "gps/RTC.h" #include "configuration.h" #include "detect/ScanI2C.h" #include "main.h" @@ -7,6 +7,10 @@ #include #include +#if HAS_LSE +#include +#endif + static RTCQuality currentQuality = RTCQualityNone; uint32_t lastSetFromPhoneNtpOrGps = 0; @@ -211,6 +215,30 @@ RTCSetResult readFromRTC() return RTCSetResultSuccess; } } +#elif HAS_LSE + if (stm32wlRtcAvailable()) { + uint32_t now = millis(); + tv.tv_sec = STM32RTC::getInstance().getEpoch(); + tv.tv_usec = 0; + uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms +#ifdef BUILD_EPOCH + if (tv.tv_sec < BUILD_EPOCH) { + if (Throttle::isWithinTimespanMs(lastTimeValidationWarning, TIME_VALIDATION_WARNING_INTERVAL_MS) == false) { + LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH); + lastTimeValidationWarning = millis(); + } + return RTCSetResultInvalidTime; + } +#endif + if (currentQuality == RTCQualityNone) { + RTCQuality oldQuality = currentQuality; + timeStartMsec = now; + zeroOffsetSecs = tv.tv_sec; + currentQuality = RTCQualityDevice; + triggerNodeInfoCheckOnTimeSource(oldQuality, currentQuality); + } + return RTCSetResultSuccess; + } #else return readFromSystemTimeFallback(); #endif @@ -335,6 +363,10 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd LOG_WARN("Failed to set time for RX8130CE"); } } +#elif HAS_LSE + if (stm32wlRtcAvailable()) { + STM32RTC::getInstance().setEpoch(tv->tv_sec); + } #elif defined(ARCH_ESP32) || defined(ARCH_RP2040) settimeofday(tv, NULL); #endif diff --git a/src/gps/RTC.h b/src/gps/RTC.h index b69a99ec9..2eb5293ea 100644 --- a/src/gps/RTC.h +++ b/src/gps/RTC.h @@ -8,6 +8,11 @@ #include #endif +#if HAS_LSE +// True once the STM32WL LSE crystal has locked and the hardware RTC is running (see stm32wlSetup()). +bool stm32wlRtcAvailable(); +#endif + enum RTCQuality { /// We haven't had our RTC set yet diff --git a/src/graphics/SharedUIDisplay.cpp b/src/graphics/SharedUIDisplay.cpp index e60fe6128..88ba3f96b 100644 --- a/src/graphics/SharedUIDisplay.cpp +++ b/src/graphics/SharedUIDisplay.cpp @@ -3,8 +3,8 @@ #include "MeshService.h" #include "NodeDB.h" #include "Power.h" -#include "RTC.h" #include "draw/NodeListRenderer.h" +#include "gps/RTC.h" #include "graphics/ScreenFonts.h" #include "graphics/SharedUIDisplay.h" #include "graphics/TFTColorRegions.h" diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index f38d27d7d..53f016645 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -24,8 +24,8 @@ #include "main.h" #include "target_specific.h" #include -#include #include +#include // External variables extern graphics::Screen *screen; diff --git a/src/graphics/niche/InkHUD/Applet.cpp b/src/graphics/niche/InkHUD/Applet.cpp index 82c67c9ff..d2fdc41f9 100644 --- a/src/graphics/niche/InkHUD/Applet.cpp +++ b/src/graphics/niche/InkHUD/Applet.cpp @@ -6,7 +6,7 @@ #include "main.h" -#include "RTC.h" +#include "gps/RTC.h" using namespace NicheGraphics; diff --git a/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp b/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp index 3da912a78..69dbf61af 100644 --- a/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/Bases/NodeList/NodeListApplet.cpp @@ -1,6 +1,6 @@ #ifdef MESHTASTIC_INCLUDE_INKHUD -#include "RTC.h" +#include "gps/RTC.h" #include "GeoCoord.h" #include "NodeDB.h" diff --git a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp index 1d4ac8355..ac1fd1e73 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Menu/MenuApplet.cpp @@ -8,9 +8,9 @@ #include "MeshService.h" #include "MessageStore.h" #include "Power.h" -#include "RTC.h" #include "Router.h" #include "airtime.h" +#include "gps/RTC.h" #include "graphics/niche/InkHUD/Applets/Bases/Map/MapApplet.h" #include "graphics/niche/Utils/FlashData.h" #include "main.h" diff --git a/src/graphics/niche/InkHUD/Applets/System/Notification/NotificationApplet.cpp b/src/graphics/niche/InkHUD/Applets/System/Notification/NotificationApplet.cpp index 195de8ecd..682c4de5e 100644 --- a/src/graphics/niche/InkHUD/Applets/System/Notification/NotificationApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/System/Notification/NotificationApplet.cpp @@ -9,7 +9,7 @@ #include "meshUtils.h" #include "modules/TextMessageModule.h" -#include "RTC.h" +#include "gps/RTC.h" using namespace NicheGraphics; diff --git a/src/graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.cpp b/src/graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.cpp index 94a87d23d..f3ea67a77 100644 --- a/src/graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.cpp @@ -1,6 +1,6 @@ #ifdef MESHTASTIC_INCLUDE_INKHUD -#include "RTC.h" +#include "gps/RTC.h" #include "gps/GeoCoord.h" diff --git a/src/graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.cpp b/src/graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.cpp index 1ccf7fc14..2f16da5f5 100644 --- a/src/graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.cpp @@ -2,7 +2,7 @@ #include "./RecentsListApplet.h" -#include "RTC.h" +#include "gps/RTC.h" using namespace NicheGraphics; diff --git a/src/graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.cpp b/src/graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.cpp index 0edde0f7f..31aeaa814 100644 --- a/src/graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.cpp +++ b/src/graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.cpp @@ -2,7 +2,7 @@ #include "./ThreadedMessageApplet.h" -#include "RTC.h" +#include "gps/RTC.h" #include "mesh/NodeDB.h" using namespace NicheGraphics; diff --git a/src/graphics/niche/InkHUD/Events.cpp b/src/graphics/niche/InkHUD/Events.cpp index 6a2c8b46d..ddb4a57b7 100644 --- a/src/graphics/niche/InkHUD/Events.cpp +++ b/src/graphics/niche/InkHUD/Events.cpp @@ -4,8 +4,8 @@ #include "MessageStore.h" #include "PowerFSM.h" -#include "RTC.h" #include "buzz.h" +#include "gps/RTC.h" #include "modules/ExternalNotificationModule.h" #include "modules/TextMessageModule.h" #include "sleep.h" diff --git a/src/main.cpp b/src/main.cpp index cc7c239a4..47d51dea3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,13 +22,13 @@ #include "FSCommon.h" #include "Power.h" -#include "RTC.h" #include "SPILock.h" #include "Throttle.h" #include "concurrency/OSThread.h" #include "concurrency/Periodic.h" #include "detect/ScanI2C.h" #include "error.h" +#include "gps/RTC.h" #if !MESHTASTIC_EXCLUDE_I2C #include "detect/ScanI2CConsumer.h" @@ -816,6 +816,10 @@ void setup() rp2040Setup(); #endif +#ifdef ARCH_STM32WL + stm32wlSetup(); +#endif + // We do this as early as possible because this loads preferences from flash // but we need to do this after main cpu init (esp32setup), because we need the random seed set nodeDB = new NodeDB; diff --git a/src/main.h b/src/main.h index 36995f694..98dcccc71 100644 --- a/src/main.h +++ b/src/main.h @@ -113,7 +113,8 @@ extern bool runASAP; extern bool pauseBluetoothLogging; -void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), rp2040Loop(), clearBonds(), enterDfuMode(); +void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), rp2040Loop(), clearBonds(), enterDfuMode(), + stm32wlSetup(); #ifdef ARCH_ESP32 void esp32ReleaseBluetoothMemoryIfUnused(); #endif diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 29be2769c..ca062abb9 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -11,8 +11,8 @@ #include "NodeDB.h" #include "Power.h" #include "PowerFSM.h" -#include "RTC.h" #include "TypeConversions.h" +#include "gps/RTC.h" #include "graphics/draw/MessageRenderer.h" #include "main.h" #include "mesh-pb-constants.h" diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 035da67e0..1e88ea873 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -13,7 +13,6 @@ #include "NodeDB.h" #include "PacketHistory.h" #include "PowerFSM.h" -#include "RTC.h" #include "RadioInterface.h" #include "Router.h" #include "SPILock.h" @@ -21,6 +20,7 @@ #include "TransmitHistory.h" #include "TypeConversions.h" #include "error.h" +#include "gps/RTC.h" #include "main.h" #include "memory/MemAudit.h" #include "mesh-pb-constants.h" diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 4c9697114..8b924a167 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -38,7 +38,7 @@ #include "mqtt/MQTT.h" #endif #include "Throttle.h" -#include +#include "gps/RTC.h" namespace { diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 7ae78cbb1..aa0c96b8a 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -5,7 +5,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PositionPrecision.h" -#include "RTC.h" +#include "gps/RTC.h" #include "configuration.h" #include "main.h" diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 12649e031..5dd1ef99b 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -1,9 +1,9 @@ #include "StreamAPI.h" #include "PowerFSM.h" -#include "RTC.h" #include "Throttle.h" #include "concurrency/LockGuard.h" #include "configuration.h" +#include "gps/RTC.h" #define START1 0x94 #define START2 0xc3 diff --git a/src/mesh/TransmitHistory.cpp b/src/mesh/TransmitHistory.cpp index 9238942ac..35144ec0d 100644 --- a/src/mesh/TransmitHistory.cpp +++ b/src/mesh/TransmitHistory.cpp @@ -1,7 +1,7 @@ #include "TransmitHistory.h" #include "FSCommon.h" -#include "RTC.h" #include "SPILock.h" +#include "gps/RTC.h" #include #ifdef FSCom diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 46981498f..bf6be0b9c 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -1,8 +1,8 @@ #include "mesh/eth/ethClient.h" #include "NodeDB.h" -#include "RTC.h" #include "concurrency/Periodic.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "mesh/api/ethServerAPI.h" #include "target_specific.h" diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 3d0f4baaa..d84bbfeb7 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,8 +1,8 @@ #include "configuration.h" #if HAS_WIFI #include "NodeDB.h" -#include "RTC.h" #include "concurrency/Periodic.h" +#include "gps/RTC.h" #include "mesh/wifi/WiFiAPClient.h" #include "main.h" diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 32f06f3cb..b98df39cd 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -5,8 +5,8 @@ #include "NodeDB.h" #include "PositionPrecision.h" #include "PowerFSM.h" -#include "RTC.h" #include "SPILock.h" +#include "gps/RTC.h" #include "input/InputBroker.h" #include "meshUtils.h" #include diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index a6757e04b..276c382a1 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -16,10 +16,10 @@ #include "ExternalNotificationModule.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "buzz/buzz.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "mesh/generated/meshtastic/rtttl.pb.h" #include diff --git a/src/modules/KeyVerificationModule.cpp b/src/modules/KeyVerificationModule.cpp index 4c2782241..c275ce1d9 100644 --- a/src/modules/KeyVerificationModule.cpp +++ b/src/modules/KeyVerificationModule.cpp @@ -3,7 +3,7 @@ #include "CryptoEngine.h" #include "HardwareRNG.h" #include "MeshService.h" -#include "RTC.h" +#include "gps/RTC.h" #include "graphics/draw/MenuHandler.h" #include "main.h" #include "meshUtils.h" diff --git a/src/modules/MeshBeaconModule.cpp b/src/modules/MeshBeaconModule.cpp index 6ab917ef9..2e9d865a6 100644 --- a/src/modules/MeshBeaconModule.cpp +++ b/src/modules/MeshBeaconModule.cpp @@ -2,11 +2,11 @@ #include "Default.h" #include "DisplayFormatters.h" #include "NodeDB.h" -#include "RTC.h" #include "RadioInterface.h" #include "Router.h" #include "TransmitHistory.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include #include diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 6c4b452ba..a626bbcaa 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -2,7 +2,7 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" +#include "gps/RTC.h" #include NeighborInfoModule *neighborInfoModule; diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp index c86c54aff..0e40daf10 100644 --- a/src/modules/NodeInfoModule.cpp +++ b/src/modules/NodeInfoModule.cpp @@ -3,10 +3,10 @@ #include "MeshService.h" #include "NodeDB.h" #include "NodeStatus.h" -#include "RTC.h" #include "Router.h" #include "TransmitHistory.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include #include diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index d3a702946..18931da12 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -5,13 +5,13 @@ #include "MeshService.h" #include "NodeDB.h" #include "PositionPrecision.h" -#include "RTC.h" #include "Router.h" #include "TransmitHistory.h" #include "TypeConversions.h" #include "airtime.h" #include "configuration.h" #include "gps/GeoCoord.h" +#include "gps/RTC.h" #include "main.h" #include "meshUtils.h" #include "meshtastic/atak.pb.h" diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp index 1c073a10a..b818e8895 100644 --- a/src/modules/PowerStressModule.cpp +++ b/src/modules/PowerStressModule.cpp @@ -2,9 +2,9 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerMon.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "sleep.h" #include "target_specific.h" diff --git a/src/modules/RangeTestModule.cpp b/src/modules/RangeTestModule.cpp index 57001919d..c2e3f76aa 100644 --- a/src/modules/RangeTestModule.cpp +++ b/src/modules/RangeTestModule.cpp @@ -13,12 +13,12 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "SPILock.h" #include "airtime.h" #include "configuration.h" #include "gps/GeoCoord.h" +#include "gps/RTC.h" #include #include diff --git a/src/modules/RemoteHardwareModule.cpp b/src/modules/RemoteHardwareModule.cpp index 04cfeb651..ef2b23c8f 100644 --- a/src/modules/RemoteHardwareModule.cpp +++ b/src/modules/RemoteHardwareModule.cpp @@ -1,9 +1,9 @@ #include "RemoteHardwareModule.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 23e8e9790..94b27c0cc 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -3,9 +3,9 @@ #include "MeshService.h" #include "NMEAWPL.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "configuration.h" +#include "gps/RTC.h" #include #include diff --git a/src/modules/StoreForwardModule.cpp b/src/modules/StoreForwardModule.cpp index 413006d6e..3254d11a3 100644 --- a/src/modules/StoreForwardModule.cpp +++ b/src/modules/StoreForwardModule.cpp @@ -15,11 +15,11 @@ #include "StoreForwardModule.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" #include "Throttle.h" #include "airtime.h" #include "configuration.h" +#include "gps/RTC.h" #include "memGet.h" #include "mesh-pb-constants.h" #include "mesh/generated/meshtastic/storeforward.pb.h" diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index ceef4dbb6..7ab0ed3d4 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -9,11 +9,11 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "TransmitHistory.h" #include "UnitConversions.h" #include "detect/ScanI2CTwoWire.h" +#include "gps/RTC.h" #include "graphics/ScreenFonts.h" #include "graphics/SharedUIDisplay.h" #include "graphics/images.h" diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 06e220296..d8f17963d 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -4,11 +4,11 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "RTC.h" #include "RadioLibInterface.h" #include "Router.h" #include "TransmitHistory.h" #include "configuration.h" +#include "gps/RTC.h" #include "main.h" #include "memGet.h" #include diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 876d9ca07..63273239d 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -9,11 +9,11 @@ #include "NodeDB.h" #include "Power.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "TransmitHistory.h" #include "UnitConversions.h" #include "buzz.h" +#include "gps/RTC.h" #include "graphics/SharedUIDisplay.h" #include "graphics/images.h" #include "main.h" diff --git a/src/modules/Telemetry/HealthTelemetry.cpp b/src/modules/Telemetry/HealthTelemetry.cpp index 56700010f..f68c92e1b 100644 --- a/src/modules/Telemetry/HealthTelemetry.cpp +++ b/src/modules/Telemetry/HealthTelemetry.cpp @@ -9,10 +9,10 @@ #include "NodeDB.h" #include "Power.h" #include "PowerFSM.h" -#include "RTC.h" #include "Router.h" #include "TransmitHistory.h" #include "UnitConversions.h" +#include "gps/RTC.h" #include "main.h" #include "sleep.h" #include "target_specific.h" diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 3fa111e43..816f02898 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -9,9 +9,9 @@ #include "Power.h" #include "PowerFSM.h" #include "PowerTelemetry.h" -#include "RTC.h" #include "Router.h" #include "TransmitHistory.h" +#include "gps/RTC.h" #include "graphics/SharedUIDisplay.h" #include "main.h" #include "sleep.h" diff --git a/src/modules/Telemetry/Sensor/PMSA003ISensor.h b/src/modules/Telemetry/Sensor/PMSA003ISensor.h index 9b9cad37a..419c28bd9 100644 --- a/src/modules/Telemetry/Sensor/PMSA003ISensor.h +++ b/src/modules/Telemetry/Sensor/PMSA003ISensor.h @@ -4,8 +4,8 @@ #include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "RTC.h" #include "TelemetrySensor.h" +#include "gps/RTC.h" #define PMSA003I_I2C_CLOCK_SPEED 100000 #define PMSA003I_FRAME_LENGTH 32 diff --git a/src/modules/Telemetry/Sensor/SCD4XSensor.h b/src/modules/Telemetry/Sensor/SCD4XSensor.h index 0e1a46f44..065c82a13 100644 --- a/src/modules/Telemetry/Sensor/SCD4XSensor.h +++ b/src/modules/Telemetry/Sensor/SCD4XSensor.h @@ -4,8 +4,8 @@ #include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "RTC.h" #include "TelemetrySensor.h" +#include "gps/RTC.h" #include // Max speed 400kHz diff --git a/src/modules/Telemetry/Sensor/SEN5XSensor.h b/src/modules/Telemetry/Sensor/SEN5XSensor.h index 935c8cb21..5d84b8916 100644 --- a/src/modules/Telemetry/Sensor/SEN5XSensor.h +++ b/src/modules/Telemetry/Sensor/SEN5XSensor.h @@ -4,9 +4,9 @@ #include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "RTC.h" #include "TelemetrySensor.h" #include "Wire.h" +#include "gps/RTC.h" // Warm up times for SEN5X from the datasheet #ifndef SEN5X_WARMUP_MS_1 diff --git a/src/modules/Telemetry/Sensor/SFA30Sensor.h b/src/modules/Telemetry/Sensor/SFA30Sensor.h index 009138b90..a72bef252 100644 --- a/src/modules/Telemetry/Sensor/SFA30Sensor.h +++ b/src/modules/Telemetry/Sensor/SFA30Sensor.h @@ -4,8 +4,8 @@ #include "../detect/ReClockI2C.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "RTC.h" #include "TelemetrySensor.h" +#include "gps/RTC.h" #include #define SFA30_I2C_CLOCK_SPEED 100000 diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index b1d0f9d9a..6da8534e4 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -4,8 +4,8 @@ #include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" -#include "RTC.h" #include "Router.h" +#include "gps/RTC.h" /* AudioModule diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index b6f0ce24d..907888bff 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -38,7 +38,7 @@ #include #define ntohl __ntohl #endif -#include +#include MQTT *mqtt; diff --git a/src/platform/stm32wl/architecture.h b/src/platform/stm32wl/architecture.h index d269b3fa1..0aa59ff70 100644 --- a/src/platform/stm32wl/architecture.h +++ b/src/platform/stm32wl/architecture.h @@ -16,6 +16,22 @@ #ifndef HAS_WIRE #define HAS_WIRE 1 #endif +#ifndef HAS_LSE +#define HAS_LSE 0 +#endif + +// How long to wait for the LSE 32.768kHz crystal to lock before giving up on hardware RTC support. +// Override in a variant's variant.h if that board's crystal needs longer to stabilize. +#ifndef STM32WL_LSE_TIMEOUT_MS +#define STM32WL_LSE_TIMEOUT_MS 2000 +#endif + +// A variant that sets HAS_LSE must also define STM32WL_LSE_DRIVE - catch that mistake here, not as a confusing +// HAL compile error deep in main-stm32wl.cpp. +#if HAS_LSE && !defined(STM32WL_LSE_DRIVE) +#error \ + "HAS_LSE is set but STM32WL_LSE_DRIVE is not defined - set it in the variant's variant.h to one of RCC_LSEDRIVE_LOW/MEDIUMLOW/MEDIUMHIGH/HIGH" +#endif // // set HW_VENDOR diff --git a/src/platform/stm32wl/main-stm32wl.cpp b/src/platform/stm32wl/main-stm32wl.cpp index 8ec87092b..97b63a965 100644 --- a/src/platform/stm32wl/main-stm32wl.cpp +++ b/src/platform/stm32wl/main-stm32wl.cpp @@ -1,10 +1,21 @@ -#include "RTC.h" #include "configuration.h" +#include "gps/RTC.h" +#include #include #include #include #include +#if HAS_LSE +#include + +// LSEDRV is a 2-bit RCC_BDCR field where every combination is a legal drive level, so this covers all 4 values. +static_assert((STM32WL_LSE_DRIVE & ~RCC_LSEDRIVE_HIGH) == 0, + "STM32WL_LSE_DRIVE must be one of RCC_LSEDRIVE_LOW/MEDIUMLOW/MEDIUMHIGH/HIGH"); + +static bool stm32wlRtcValid = false; +#endif + // ─── Bootloader redirect ────────────────────────────────────────────────────── // // Why .noinit + constructor instead of TAMP backup registers: @@ -86,6 +97,47 @@ bool getDeviceId(uint8_t *deviceId) return true; } +#if HAS_LSE +// Starts the LSE crystal with a bounded timeout and, if it locks, brings up the STM32 hardware RTC on it. +void stm32wlSetup() +{ + HAL_PWR_EnableBkUpAccess(); + __HAL_RCC_LSEDRIVE_CONFIG(STM32WL_LSE_DRIVE); + __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); + + uint32_t start = millis(); + bool lseReady = false; + while (Throttle::isWithinTimespanMs(start, STM32WL_LSE_TIMEOUT_MS)) { + if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY)) { + lseReady = true; + break; + } + delay(5); + } + + if (lseReady) { + STM32RTC &rtc = STM32RTC::getInstance(); + rtc.setClockSource(STM32RTC::LSE_CLOCK); + rtc.begin(); + stm32wlRtcValid = true; + LOG_INFO("STM32WL: LSE locked, hardware RTC available"); + } else { + // Don't leave a failed oscillator burning current. + __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); + LOG_WARN("STM32WL: LSE failed to start within %dms (crystal missing/faulty?) - hardware RTC unavailable", + STM32WL_LSE_TIMEOUT_MS); + } +} + +// True once stm32wlSetup() has confirmed the LSE crystal is locked and the hardware RTC is running. +bool stm32wlRtcAvailable() +{ + return stm32wlRtcValid; +} +#else +void stm32wlSetup() {} +#endif + void cpuDeepSleep(uint32_t msecToWake) {} // Hacks to force more code and data out. diff --git a/src/security/EncryptedStorage.cpp b/src/security/EncryptedStorage.cpp index e2c4deb05..206bb4ac2 100644 --- a/src/security/EncryptedStorage.cpp +++ b/src/security/EncryptedStorage.cpp @@ -5,10 +5,10 @@ // Common includes - available for all platform implementations #include "EncryptedStorage.h" #include "FSCommon.h" -#include "RTC.h" #include "SPILock.h" #include "SafeFile.h" #include "SecureZero.h" +#include "gps/RTC.h" #include #ifdef ARCH_NRF52 diff --git a/variants/stm32/rak3172/platformio.ini b/variants/stm32/rak3172/platformio.ini index de8f2b74b..514668a12 100644 --- a/variants/stm32/rak3172/platformio.ini +++ b/variants/stm32/rak3172/platformio.ini @@ -16,4 +16,9 @@ build_flags = -DMESHTASTIC_EXCLUDE_I2C=1 -DMESHTASTIC_EXCLUDE_GPS=1 +lib_deps = + ${stm32_base.lib_deps} + # renovate: datasource=github-tags depName=STM32RTC packageName=stm32duino/STM32RTC + https://github.com/stm32duino/STM32RTC/archive/refs/tags/1.9.0.zip + upload_port = stlink diff --git a/variants/stm32/rak3172/variant.h b/variants/stm32/rak3172/variant.h index 75e3e0c91..b7afefc3f 100644 --- a/variants/stm32/rak3172/variant.h +++ b/variants/stm32/rak3172/variant.h @@ -24,4 +24,7 @@ Do not expect a working Meshtastic device with this target. #define RAK3172 #define SERIAL_PRINT_PORT 1 +#define HAS_LSE 1 +#define STM32WL_LSE_DRIVE RCC_LSEDRIVE_LOW + #endif