LowPower.deepSleep conflict with RX1 serial port

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
dolfandringa
Posts: 20
Joined: Wed Jun 03, 2020 3:47 am

LowPower.deepSleep conflict with RX1 serial port

Post by dolfandringa »

Hi all,

There seems to be some conflict with the serial port and the LowPower.deepSleep/stop mode of my STM32F103C8. I have already struggled with this using the libMaple core viewtopic.php?f=63&t=464&p=3081#p3081. Since then I switched to the official stm32duino Arduino Core because it has the LowPower library and I thought it would be easier. But I am still struggling with an issue with LowPower.deepSleep and the RX1 serial port (using an FTDI usb->serial converter).

With the sketch below: if I don't add the `Serial.end()` in my_sleep, the device never goes to sleep. The my_sleep function is called, but I am guessing the FTDI converter or Serial library triggers an interrupt that makes it wakeup again straight away.
If I do add the Serial.end(), and put a Serial.begin straight after LowPower.deepSleep (line 42) the same behaviour happens: it never goes to sleep.
With Serial.begin in the alamMatch funciton, the device does go to sleep, and also prints the Sleeping and Wakeup lines (if I comment out lines 52-57), but hangs on line 55, with the backtrace showing it goes all the way down to HardwareSerial::write in HardwareSerial.cpp:474 and freezes there. I am guessing after waking up, the code reaches line 55 before the alarmMatch function is called, so the serial port isn't started yet, causing the code to freeze?

How can I solve this issue?

Code: Select all

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

STM32RTC& rtc = STM32RTC::getInstance();


#define LED_PIN PC13

static uint32_t cnt = 0;
static uint64_t prev_time;
static uint64_t now;
static uint64_t wakeup_time;
static volatile bool woken_up = false;

void alarmMatch(void* data) {
    *(uint32_t*)data++;
    wakeup_time = rtc.getEpoch();
    Serial.begin(115200);
    Serial.println("Wakeup");
}


void setup() {
    Serial.begin(115200);
    Serial.setTimeout(10);
    Serial.println("Setup");
    rtc.begin();
    pinMode(LED_PIN, OUTPUT);
    LowPower.begin();
    wakeup_time = prev_time = rtc.getEpoch();
}


void my_sleep(uint16_t sleep_time){
    Serial.println("Sleeping");
    Serial.flush();
    Serial.end();
    LowPower.enableWakeupFrom(&rtc, alarmMatch, &cnt);
    rtc.setAlarmEpoch(rtc.getEpoch() + sleep_time);
    LowPower.deepSleep();
    //Serial.begin(115200);
}

void loop() {
    now = rtc.getEpoch();
    if(now - wakeup_time > 20) {
        my_sleep(10);
    }
    if(prev_time != rtc.getEpoch()) {
        prev_time = rtc.getEpoch();
        if(Serial.availableForWrite()) {
            Serial.print("Time: ");
            Serial.print(prev_time);
            Serial.print(" Cnt: ");
            Serial.println(cnt);
        }
    }
    digitalWrite(LED_PIN, !digitalRead(LED_BUILTIN));
}
User avatar
fpiSTM
Posts: 1758
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: LowPower.deepSleep conflict with RX1 serial port

Post by fpiSTM »

IRQ prio of the Serial is higher than the one from RTC.
I would first try to remove Serial end and begin and flush the one in the loop after Serial.println(cnt);

For prio you can try to change them:
by default: RTC_IRQ_PRIO is 2 and UART_IRQ_PRIO is 1

https://github.com/stm32duino/wiki/wiki ... ity-values
dolfandringa
Posts: 20
Joined: Wed Jun 03, 2020 3:47 am

Re: LowPower.deepSleep conflict with RX1 serial port

Post by dolfandringa »

Thanks for the help @fpiSTM . This did help a lot.
The problem is indeed that the serial port triggers an interrupt which directly wakes up the device again. Adding a serial.flush after each serial.print statement does solve that, by making sure all data has been flushed, so no interrupts occur anymore. This then allows me to remove the Serial.end and Serial.begin statements. But it seems a bit annoying to have to put a Serial.flush after each Serial.print statement everywhere in the code (my real code is much more complicated and larger than this sample). Is there no way to just wakeup from RTC only? Not from any other source? It seems weird the LowPower library allows you to turn on wakeup from RTC, but not turn off any other wakeup source.... Can't I control what source should wake up my MCU?

Interesting to see that there are priorities I can change. But what are those priorities? What are the consequences of changing them?

Cheers
dolfandringa
Posts: 20
Joined: Wed Jun 03, 2020 3:47 am

Re: LowPower.deepSleep conflict with RX1 serial port

Post by dolfandringa »

To make the problem above clearer: In the small example that I gave, indeed issuing the Serial.flush() did solve the issue there, but in my real life code (too big to post here), I am making use of 3rd party libraries. There I have added Serial.flush() statements everywhere I debug print stuff, and I don't see any other Serial.prints, but still the code wakes up instantly. So somehow some interrupt is triggered there (by the serial or otherwise) that wakes up the device instantly.
So:
1. Is there any way to prevent any interrupt from waking up the device except for the rtc alarm?
2. How can I see what interrupt is causing the wakeup? That would allow me to debug the issue.
User avatar
fpiSTM
Posts: 1758
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: LowPower.deepSleep conflict with RX1 serial port

Post by fpiSTM »

You don't need to add flush after each print, only one before going to sleep mode.

You can also disable all IRQ excepts the one from RTC, I guess.
To know which one well you will have to debug and check registers states.

Maybe one of your issue is that you received some data ?
Post Reply

Return to “General discussion”