rogerclarkmelbourne / Arduino_STM32

Arduino STM32. Hardware files to support STM32 boards, on Arduino IDE 1.8.x including LeafLabs Maple and other generic STM32F103 boards
Other
2.52k stars 1.26k forks source link

USART port stops working after STOP mode #797

Closed dolfandringa closed 3 years ago

dolfandringa commented 4 years ago

I am trying to implement the low power sleep, deepsleep (=stop) and standby modes using the libmaple core and builtin RTClock library. I am succeeding but am having an issue where the USART1 port stops working after waking up. Checking the hex output from the serial monitor, I do see data is being sent, but it just sends 3 NULL bytes per character, instead of the actual characters. And using a debugger I can see the wakeup function is getting called and the device does wake up (led starts blinking again). So it is definitely a usart issue. I tried Serial.flush() and Serial.end() before sleeping and Serial.begin when waking up again, but to no avail. I feel it is something to do with clock sources, and/or data being stuck in the buffer somewhere? But I can't seem to fix it. Any suggestions?

And as a side node, I'd be happy to contribute my code as a proper PR/library to the libmaple core once it works if you're interested.

This is my code:

#include <Arduino.h>
#include <RTClock.h>

#include <libmaple/pwr.h> // PWR_BASE ref
#include <libmaple/scb.h> // SCB_BASE ref
#include <libmaple/rcc.h>
#include <libmaple/stm32.h>
#include <libmaple/usart.h> //USART functions

#define SLEEP_TIME 10

enum sleep_t {DEEPSLEEP, SLEEP, STANDBY};
uint32 tt; 

uint16_t cnt = 0;

volatile static bool nappy_time = false;
volatile static bool woken_up = false;

#define LED_PIN PC13

void blink () 
{
    digitalWrite(LED_PIN,!digitalRead(LED_PIN));
}

void set_nappy_time() {
    nappy_time = true;
}

void nothing() {
    SCB_BASE->SCR &= ~SCB_SCR_SLEEPDEEP;
    SCB_BASE->SCR &= ~SCB_SCR_SLEEPONEXIT;
    woken_up = true;
}

void wakeup() {

    PWR_BASE->CR |= PWR_CR_CWUF; // clear the wakeup flag
    woken_up = false;
    Serial.begin(9600); 

    usart_putc(USART1, 0x61);
    usart_putc(USART1, 0x62);
    usart_putc(USART1, 0x63);
}

void deepsleep(uint32_t sleep_time) {

    uint16_t now = rtc_get_count();

    Serial.flush();
    Serial.end();
    rtc_detach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT);
    rtc_detach_interrupt(RTC_ALARM_GLOBAL_INTERRUPT);
    rtc_detach_interrupt(RTC_SECONDS_INTERRUPT);

    //Enable ABP1 bus, on which the RTC clock registers (and a ton of other stuff) are located
    RCC_BASE->APB1ENR |= RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;
    RCC_BASE->APB2ENR &= ~RCC_APB2ENR_USART1EN;

    //Disable external wakeup pin
    PWR_BASE->CSR &= ~PWR_CSR_EWUP;

    //clear Wakeup flag
    PWR_BASE->CR |= PWR_CR_CWUF;
    //Clear PPDS bit.
    PWR_BASE->CR &= ~PWR_CR_PDDS;
    //Low power regulator or normal regulator. Bit set=low power regulator.
    PWR_BASE->CR |= PWR_CR_LPDS;

    SCB_BASE->SCR |= SCB_SCR_SLEEPONEXIT; 
    SCB_BASE->SCR |= SCB_SCR_SLEEPDEEP;

    rtc_set_alarm(now + sleep_time);
    rtc_attach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT, nothing);

    asm("WFE");
}

void sleep(sleep_t sleep_mode, uint32_t sleep_time) {
    uint16_t now = rtc_get_count();
    switch(sleep_mode) {
        case DEEPSLEEP:
            Serial.print("Sleeping at ");
            Serial.print(now);
            Serial.print(" until ");
            Serial.println(now+sleep_time);
            Serial.flush();
            delay(5);
            deepsleep(sleep_time);
            break;
    }
}

void setup() 
{ 
    rtc_init(RTCSEL_LSI);
    rtc_set_prescaler_load(0x9C3F);
    Serial.begin(9600);
    Serial.println("Setup");
    Serial.print("USART1 clock: ");
    rcc_clk_domain domain = rcc_dev_clk(USART1->clk_id);
    Serial.println(domain);
    Serial.print("F_CPU: ");
    Serial.println(F_CPU);
    Serial.flush();
    pinMode(LED_PIN, OUTPUT);
    rtc_set_count(0);
    rtc_set_alarm(rtc_get_count() + SLEEP_TIME);
    rtc_attach_interrupt(RTC_ALARM_SPECIFIC_INTERRUPT, set_nappy_time);
}

void loop() 
{
    Serial.flush();

    if(nappy_time) {
        nappy_time = false;
        sleep(DEEPSLEEP, SLEEP_TIME);
    }
    else if(woken_up) {
        // detect wakeup
        wakeup();
    }

    if (rtc_get_count()!=tt)
    {
        cnt++;
        tt = rtc_get_count();
        blink();
    }
}
rogerclarkmelbourne commented 4 years ago

Issues are only used to report bugs

Try posting your question https://www.stm32duino.com

dolfandringa commented 4 years ago

I already did without any luck. Why are you sure this isn't a bug? By looking at the stm32 arduino core (the other core and its low power library), I think I am doing everything right. So I am wondering if there isn't an issue with this core and stop mode. Maybe a clock doesn't get set properly? Or there is an issue with interrupts somewhere?

rogerclarkmelbourne commented 4 years ago

Its hard to know whether this is bug in the USART Class or your code.

I'll leave this issue open. But there are no actively developers on this core.

You are better off using the official core if this core does not do what you want or has bugs

dolfandringa commented 4 years ago

Thanks for the help. Yeah, I am kind of feeling that too. It's hard to find good info on the difference between the cores and how they relate to each other. When I had to decide, people were saying that for the STM32F1 series specifically, this one was more mature. And by now, I have a bunch of code (including unittests) that is based on your core. So switching is going to be a pain now.

rogerclarkmelbourne commented 4 years ago

This core was developed about 12 years ago by LeafLabs or their "Maple" board, which used the STM32F1. At that time, third party cores were not supported by the Arduino IDE, so LeafLabs wrote a customised version of the IDE which included their core.

However by 2015 they had abandoned their IDE / Core, but by that time, the Arduino IDE stated to support 3rd party external cores, and Bob Cousins did the initial port of the Maple core to the bare bones of this core.

Bob abandoned his initial conversion, a few months after he created it, and I took it over..

But it 2018/19 STM developed their own core, which uses the STM32 Cube/ HAL as its internal API.

I'm quite surprised this core is still as active as it is, considering there are no active devs on it and STM now fully support their own core.

stevstrong commented 4 years ago

The example you posted in the forum is different from this one. Here you are mixing USB serial (Serial) with USART1 (Serial1). I think you should initialize Serial1 before using usart_putc(USART1, 0x61);

stevstrong commented 3 years ago

Closed due to inactivity, also the forum query is also not active.