Skip to content
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

LowPower.deepSleep not working after modem.begin #36

Open
3 tasks done
janvrska opened this issue Nov 4, 2023 · 12 comments
Open
3 tasks done

LowPower.deepSleep not working after modem.begin #36

janvrska opened this issue Nov 4, 2023 · 12 comments
Assignees

Comments

@janvrska
Copy link

janvrska commented Nov 4, 2023

  • I am running the latest version of this repository (dependencies too)
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been created

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

bool STM32LoRaWAN::begin(_lora_band band)
{
if (instance != nullptr)
return failure("Only one STM32LoRaWAN instance can be used");
instance = this;
/*
* Init RTC as an object :
* use the MIX mode = free running BCD calendar + binary mode for
* the sub-second counter RTC_SSR on 32 bit
*/
_rtc.setClockSource(STM32RTC::LSE_CLOCK);
_rtc.setBinaryMode(STM32RTC::MODE_MIX);
_rtc.begin(true, STM32RTC::HOUR_24);
/* Attach the callback function before enabling Interrupt */
_rtc.attachInterrupt(UTIL_TIMER_IRQ_MAP_PROCESS, STM32RTC::ALARM_B);
_rtc.attachSecondsInterrupt(TIMER_IF_SSRUCallback);
/* The subsecond alarm B is set during the StartTimerEvent */
UTIL_TIMER_Init(_rtc.getHandle());
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
Copy link

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

@fpistm
Copy link
Member

fpistm commented Nov 6, 2023

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
Copy link

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
Copy link
Member

fpistm commented Nov 6, 2023

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
Copy link

@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
Copy link
Author

janvrska commented Nov 8, 2023

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
Copy link
Member

fpistm commented Nov 20, 2023

@FRASTM
do you have any idea on this subject?

@slavendam
Copy link

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
Copy link
Contributor

FRASTM commented Feb 21, 2024

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
Copy link

slavendam commented Feb 25, 2024

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
Copy link
Contributor

FRASTM commented Feb 26, 2024

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
Copy link
Contributor

FRASTM commented Feb 26, 2024

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 stm32duino/STM32RTC#106

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants