stm32duino / STM32LoRaWAN

Arduino library to support LoRaWAN communication using the STM32WL series.
https://stm32duino.github.io/STM32LoRaWAN/
Other
34 stars 7 forks source link

LowPower.deepSleep not working after modem.begin #36

Open janvrska opened 8 months ago

janvrska commented 8 months ago

Expected Behavior

After setting modem.begin(EU868) and LowPower.deepSleep() it goes sleep, and the chip will not wake up.

Current Behavior

After setting modem.begin(EU868) and LowPower.deepSleep() it goes sleep, but after around 900ms it wakes up.

If modem.begin(EU868) isn't used then it works as intended, and the chip will not wake up.

Minimal example

#include <Arduino.h>
#include <STM32LoRaWAN.h>
#include <STM32RTC.h>
#include "STM32LowPower.h"

STM32RTC& rtc = STM32RTC::getInstance();
STM32LoRaWAN modem;

void setup() {
    Serial.begin(115200);
    modem.begin(EU868);
    LowPower.begin();
    LowPower.deepSleep();
}

void loop() {
    Serial.begin(115200);
    Serial.println("wakes up");
    delay(1000);
    LowPower.deepSleep();
}

Power Profiler screenshot with modem.begin() image

Power Profiler screenshot without modem.begin() image

Details (what I tried)

I tried to look on https://github.com/stm32duino/STM32LoRaWAN/blob/192c1234a8661f72f1635e5675db0d11fb110920/src/STM32LoRaWAN.cpp#L62-L81 and tried in my main code to:

rtc.detachInterrupt, rtc.detachSecondsInterrupt, rtc.disableAlarm (both A ,B), but none of it worked.

Only when I after modem.begin() called rtc.end() and then rtc.begin() it stops waking up, but after joining the network (which was successfull), modem.send() didn't send any message (propably some problem with RTC settings that should have been set in modem.begin() and was cleared after rtc.end())

Context

I'm using supported LORA-E5 chip (STM32WLE5JC) on custom PCB

platformio.ini:

[env:lora_e5_mini]
platform = ststm32
board = lora_e5_mini
framework = arduino
lib_deps = 
    https://github.com/stm32duino/STM32LoRaWAN.git#0.2.0
    https://github.com/stm32duino/STM32RTC.git#1.4.0
    https://github.com/stm32duino/STM32LowPower.git#5ae219c
monitor_speed = 115200
monitor_filters = time
upload_protocol = stlink
debug_tool = stlink
HelgeSeidel commented 8 months ago

Hi @janvrska, using rtc.begin(true) to reset the RTC after modem.begin(EU868) helped for me.

fpistm commented 8 months ago

Did you try to add a small delay after the modem begin? Did you try this example: https://github.com/stm32duino/STM32LoRaWAN/blob/main/examples/LowPowerBasic/LowPowerBasic.ino Is it working?

HelgeSeidel commented 8 months ago

Hi @fpistm, I tried the example on the RAK3172T and unfortunately it is not working. The example send the data package every 6 seconds. Using rtc.begin(true) to reset the RTC after modem.begin(EU868) helped here as well.

Screenshot

fpistm commented 8 months ago

Using rtc.begin(true) to reset the RTC after modem.begin(EU868) helped here as well.

Seems strange as the modem.begin() call the rtc.begin(true). https://github.com/stm32duino/STM32LoRaWAN/blob/192c1234a8661f72f1635e5675db0d11fb110920/src/STM32LoRaWAN.cpp#L73C1-L75

My guess is something is pending which wake up the mcu. Calling deepSleep() simply enter in STOP mode 2 but several source (event) can wake it (LPUART, PWR_WKUP pin, RTC...). So before entering in deepSleep you have to ensure you can.

@janvrska Some notes, we do not support PIO only Arduino IDE. We saw several times misalignment on PIO setup and so would not invest time on wrong configurations.

Your code is not correct:

void loop() {
    //Serial.begin(115200); --> Avoid to init each loop the instance
    Serial.println("wakes up");
    //delay(1000); --> Simply do a flush to prevent Serial IT to wakeup the board.
    Serial.flush();
    LowPower.deepSleep();
}

and tried in my main code to: rtc.detachInterrupt, rtc.detachSecondsInterrupt, rtc.disableAlarm (both A ,B), but none of it worked.

Only when I after modem.begin() called rtc.end() and then rtc.begin() it stops waking up, but after joining the network (which was successfull), modem.send() didn't send any message (propably some problem with RTC settings that should have been set in modem.begin() and was cleared after rtc.end())

That is normal you can't send anything, if you remove the callback required for the modem timing or by reseting yourself the RTC as is do not set those callback.

I tried within my LoRa-E5 mini and the low power is functional. Please try he example then give us your feedback (preferably with Arduino).

@HelgeSeidel I don't understand your point:

I tried the example on the RAK3172T and unfortunately it is not working. The example send the data package every 6 seconds. Using rtc.begin(true) to reset the RTC after modem.begin(EU868) helped here as well.

This mean that if you call rtc.begin(true) after modem.begin(), it works? If true as stated before, seems very strange as we already reset the RTC in the begin. Or one explanation, could be you have a battery, in that case RTC always running and alarm configured. So maybe an alarm IT still pending in this timeframe but I doubt on this as with begin(true) the backup domain is reset. This board/module is not supported, you even enter yourself this #34 so not very relevant here as maybe other issue related to this.

HelgeSeidel commented 8 months ago

@fpistm Same behaviour on the RAK3172 Evaluation Board which is supported. Running the example as is will send the packet every 6 seconds. Calling rtc.begin(true) after modem.begin() and the example worked as expected.

No battery connected to the board / RTC.

janvrska commented 7 months ago

Thank you for quick response. I tried LowPowerBasic example in ArduinoIDE and have same result as @HelgeSeidel image image

After adding rtc.begin(true) after modem.begin, example works as expected image

fpistm commented 7 months ago

@FRASTM do you have any idea on this subject?

slavendam commented 5 months ago

Just to confirm that I also have the same issue on RAK3172 module (waking up after ~1s). Adding rtc.begin(true) solved issue.

Whoever came to this (temporary) solution - thank you a lot for saving lot of nerves! @HelgeSeidel

FRASTM commented 4 months ago

In case of rtc reset, rtc.begin(true), the RCC BDCR register bits RTCEN and RTCSEL are 0. __HAL_RCC_RTC_ENABLE() will set the RTCEN bit but RTCSEL should also be set with else no source is selected to clock the RTC. The RTC peripheral is not supposed to be accessed before RTC clock is selected. Resetting the Backup domain earlier in the RTC_init will also give more clock cycles to access the RCC BDCR register

Can you please try with this:

diff --git a/src/rtc.c b/src/rtc.c
index 73c911f..23cb143 100644
--- a/src/rtc.c
+++ b/src/rtc.c
@@ -411,6 +411,20 @@ bool RTC_init(hourFormat_t format, binaryMode_t mode, sourceClock_t source, bool
   bool isAlarmBSet = false;
 #endif

+  /* Ensure backup domain is enabled before we init the RTC so we can use the backup registers for date retention on stm32f1xx boards */
+  enableBackupDomain();
+
+  if (reset) {
+    resetBackupDomain();
+    /* After Backup domain reset, RTC is disabled and no RTC clock selected */
+  }
+
+#ifdef __HAL_RCC_RTCAPB_CLK_ENABLE
+  __HAL_RCC_RTCAPB_CLK_ENABLE();
+#endif
+  __HAL_RCC_RTC_ENABLE();
+  /* Also need to select the RTC clock source asap with RTC_initClock */
+
   initFormat = format;
   initMode = mode;
   /* Ensure all RtcHandle properly set */
@@ -431,22 +445,6 @@ bool RTC_init(hourFormat_t format, binaryMode_t mode, sourceClock_t source, bool
 #endif /* RTC_OUTPUT_REMAP_NONE */
 #endif /* STM32F1xx */

-  /* Ensure backup domain is enabled before we init the RTC so we can use the backup registers for date retention on stm32f1xx boards */
-  enableBackupDomain();
-
-  if (reset) {
-    resetBackupDomain();
-  }
-
-#ifdef __HAL_RCC_RTCAPB_CLK_ENABLE
-  __HAL_RCC_RTCAPB_CLK_ENABLE();
-#endif
-  __HAL_RCC_RTC_ENABLE();
-
-  isAlarmASet = RTC_IsAlarmSet(ALARM_A);
-#ifdef RTC_ALARM_B
-  isAlarmBSet = RTC_IsAlarmSet(ALARM_B);
-#endif
 #if defined(STM32F1xx)
   uint32_t BackupDate;
   BackupDate = getBackupRegister(RTC_BKP_DATE) << 16;
@@ -510,6 +508,12 @@ bool RTC_init(hourFormat_t format, binaryMode_t mode, sourceClock_t source, bool
 #else
       RTC_setPrediv(predivAsync, predivSync);
 #endif
+
+      isAlarmASet = RTC_IsAlarmSet(ALARM_A);
+#ifdef RTC_ALARM_B
+      isAlarmBSet = RTC_IsAlarmSet(ALARM_B);
+#endif
+
       if (isAlarmASet) {
         RTC_GetAlarm(ALARM_A, &alarmDay, &alarmHours, &alarmMinutes, &alarmSeconds, &alarmSubseconds, &alarmPeriod, &alarmMask);
       }
slavendam commented 4 months ago

In case of rtc reset, rtc.begin(true), the RCC BDCR register bits RTCEN and RTCSEL are 0. __HAL_RCC_RTC_ENABLE() will set the RTCEN bit but RTCSEL should also be set with else no source is selected to clock the RTC. The RTC peripheral is not supposed to be accessed before RTC clock is selected. Resetting the Backup domain earlier in the RTC_init will also give more clock cycles to access the RCC BDCR register

Can you please try with this: ...

I've tried suggested change, but behaviour is the same.

I also saw that setting up LoRaWAN (modem.begin) will reset time and date which are set up prior to that call

FRASTM commented 4 months ago

If the rtc has already been initialized, we could skip the rtc init sequence requested by the Lorawan (calling a _rtc.begin(false,STM32RTC::HOUR_24); instead ) and only set the binary mode to MIX mode (if differs). The Lorawan setting the binary mode will only update the RTC binary mode bits, without changing calendar registers. This is possible when the first rtc initialisation has configured the same LSE clock as the lorawan requires the LSE

FRASTM commented 4 months ago

Change the STM32RTC : RTC_init function to force the update of the RTC ICS BIN and BDCU register in case of RTC is already initiliazed. See https://github.com/stm32duino/STM32RTC/pull/106