check ThisThread::sleep_for() + json MBED_TICKLESS function for CPU IDD reduction

/users/kenjiArai/notebook/standby-mode-current-consumption-on-nucleo-f446re/

IDD Jumper(JP6)
ModeMbed-OSBoardIDD Current(sleep)IDD Current(Normal(*1))
DeepSleep0s5.15.1Nucleo-L152RE4.23uA5mA to 8mA
^0s6.6.0^4.22uA4mA to 7mA
StandBy0s5.15.1^3.90uA4mA to 7mA
^0s6.6.0^3.90uA4mA to 7mA
DeepSleep0s5.15.1Nucleo-L476RG2.13uA7mA to 10mA
^0s6.6.0^2.23uA7mA to 10mA
StandBy0s5.15.1^-uA(*2)-mA(*2)
^0s6.6.0^-uA(*2)-mA(*2)
DeepSleep0s5.15.1Nucleo-F411RE1.91mA(*3)7mA to 10mA
^0s6.6.0^1.65mA(*3)7mA to 10mA
StandBy0s5.15.1^3.35uA7mA to 10mA
^0s6.6.0^3.40uA7mA to 9mA
DeepSleep0s5.15.1Nucleo-F446RE1.67mA(*3)14mA to 17mA
^0s6.6.0^1.76mA(*3)14mA to 16mA
StandBy0s5.15.1^3.42uA14mA to 17mA
^0s6.6.0^3.42uA14mA to 16mA

(*1)-> LED1 Blinky every 1sec and change LED1 current
(*2)-> Could NOT make proper program and could NOT measure
(*3)-> NOT uA but mA
All Nucleo boards are stand alone condition(not additional circuit).
Equipment: DMM6500

/users/kenjiArai/code/Check_DeepSleep_os5/
/users/kenjiArai/code/Check_DeepSleep_os6/
/users/kenjiArai/code/Check_StandBy_os5/
/users/kenjiArai/code/Check_StandBy_os6/

main.cpp

Committer:
kenjiArai
Date:
2021-01-15
Revision:
1:d6abda61923b
Parent:
0:f8c5c7d19d9a

File content as of revision 1:d6abda61923b:

/*
 * Mbed Application program
 *  Check Deep Sleep Mode
 *
 * Copyright (c) 2020,'21 Kenji Arai / JH1PJL
 *  http://www7b.biglobe.ne.jp/~kenjia/
 *  https://os.mbed.com/users/kenjiArai/
 *      Revised:    March     12th, 2020
 *      Revised:    January   15th, 2021
 */

/*
    Reference information:
        https://forums.mbed.com/t/how-to-deep-sleep/7551

    Tested on
        Nucleo-L152RE       -> 4.23uA (Normal run = 5mA to 8mA)
        Nucleo-L476RG       -> 2.13uA (Normal run = 7mA to 10mA)
        Nucleo-F411RE       -> 1.91mA (not uA)(Normal run = 7mA to 10mA)
        Nucleo-F446RE       -> 1.67mA (not uA)(Normal run = 14mA to 17mA)

    ---> same results within MODE1,2 and 3
 */

//  Include --------------------------------------------------------------------
#include "mbed.h"

//  Definition -----------------------------------------------------------------
#define MODE    1

//  Constructor ----------------------------------------------------------------
DigitalIn   my_sw(USER_BUTTON);
DigitalOut  myled(LED1,1);
Serial      pc(USBTX, USBRX);
AnalogIn    a_in(A0);
Timer       t;

//  RAM ------------------------------------------------------------------------

//  ROM / Constant data --------------------------------------------------------

//  Function prototypes --------------------------------------------------------
void sw_irq(void);
void LowPowerConfiguration(void);
void time_enter_mode(void);
void chk_and_set_time(char *ptr);
int32_t  xatoi (char **str, int32_t *res);
void get_line (char *buff, int32_t len);
void print_revision(void);

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
int main()
{
    time_t seconds;
    char buf[64];
    uint32_t t_pass = 0;
    uint32_t loop_count = 1;
    float ain;

    printf("\r\nCheck current consumption at Deep-sleep mode.\r\n");
    print_revision();
#if   MODE == 1
    printf("-->MODE=1 --> Use ThisThread::sleep_for() function.\r\n");
#elif MODE == 2
    printf("-->MODE=2 --> Use thread_sleep_for() function.\r\n");
#elif MODE == 3
    printf("-->MODE=3 --> Use wait_ms() function.\r\n");
#endif
    seconds = time(NULL);
    while (my_sw == 0) {;}
    //ThisThread::sleep_for(10);    // without "bare-metal" in mbed_app.json
    thread_sleep_for(10);           // with "bare-metal"
    while (true) {
        t.reset();
        t.start();
        if ((my_sw == 0) || (loop_count > 10)) {
            LowPowerConfiguration();
            InterruptIn my_irq(USER_BUTTON);
            while (my_irq.read() == 0) {;}
            //ThisThread::sleep_for(100);
            thread_sleep_for(100);
            my_irq.fall(sw_irq);
            t.stop();
#if   MODE == 1
            ThisThread::sleep_for(10000);
#elif MODE == 2
            thread_sleep_for(10000);
#elif MODE == 3
            wait_ms(10000);
#endif
            system_reset();
        }
        ain = a_in.read();
        myled = !myled;
        seconds = time(NULL);
        strftime(buf, 50, "%H:%M:%S -> ", localtime(&seconds));
        pc.printf("%s", buf);
        pc.printf(
            "analog = %4.3f, loop_time=%3d, counter=%4d\r\n",
            ain, t_pass, loop_count++
        );
        t_pass = t.read_ms();
        //ThisThread::sleep_for(1000 - t_pass);
        thread_sleep_for(1000 - t_pass);
        if (pc.readable()) {
            strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
            pc.printf("[Time] %s\r\n", buf);
            time_enter_mode();
        }
    }
}


void sw_irq(void)
{
    system_reset();
}

void LowPowerConfiguration(void)
{
#if defined(TARGET_NUCLEO_L152RE)
    RCC->AHBENR |=
        (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN |
         RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOHEN);
#elif defined(TARGET_NUCLEO_L476RG)

#elif defined(TARGET_NUCLEO_F446RE)
    RCC->AHB1ENR |=
        (RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN |
         RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOHEN);
#endif
    GPIO_InitTypeDef GPIO_InitStruct;
    // All other ports are analog input mode
    GPIO_InitStruct.Pin = GPIO_PIN_All;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
#if defined(TARGET_NUCLEO_L152RE)
    RCC->AHBENR &=
        ~(RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN |RCC_AHBENR_GPIOCEN |
          RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOHEN);
#elif defined(TARGET_NUCLEO_L476RG)
    RCC->AHB1ENR = 0;
    RCC->AHB2ENR = 0;
    RCC->AHB3ENR = 0;
    RCC->APB1ENR2 = 0;
    RCC->APB2ENR = 0;
#elif defined(TARGET_NUCLEO_F446RE)
    RCC->AHB1ENR = 0;
    RCC->AHB2ENR = 0;
    RCC->AHB3ENR = 0;
    RCC->APB1ENR = 0x8;     // alive TIM5
    RCC->APB2ENR = 0;
    RCC->AHB1LPENR = 0;
    RCC->AHB2LPENR = 0;
    RCC->APB1LPENR = 0x8;   // alive TIM5
    RCC->APB2LPENR = 0;
#endif
}

void time_enter_mode(void)
{
    char *ptr;
    char linebuf[64];

    if (pc.readable()) {
        pc.getc();    // dummy read
    }
    pc.printf("\r\nSet time into RTC\r\n");
    pc.printf(" e.g. >21 1 12 13 14 15 -> January 12,'21, 13:14:14\r\n");
    pc.putc('>');
    ptr = linebuf;
    get_line(ptr, sizeof(linebuf));
    pc.printf("\r");
    chk_and_set_time(ptr);
}

void get_line (char *buff, int len)
{
    char c;
    uint32_t idx = 0;

    while(true) {
        c = pc.getc();
        if (c == '\r') {
            buff[idx++] = c;
            break;
        }
        if ((c == '\b') && idx) {
            idx--;
            pc.putc(c);
            pc.putc(' ');
            pc.putc(c);
        }
        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
            buff[idx++] = c;
            pc.putc(c);
        }
    }
    buff[idx] = 0;
    pc.puts("\r\n");
}

void chk_and_set_time(char *ptr)
{
    int32_t p1;
    struct tm t;
    time_t seconds;

    if (xatoi(&ptr, &p1)) {
        t.tm_year       = (uint8_t)p1 + 100;
        pc.printf("Year:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_mon        = (uint8_t)p1 - 1;
        pc.printf("Month:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_mday       = (uint8_t)p1;
        pc.printf("Day:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_hour       = (uint8_t)p1;
        pc.printf("Hour:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_min        = (uint8_t)p1;
        pc.printf("Min:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_sec        = (uint8_t)p1;
        pc.printf("Sec: %d \r\n",p1);
    } else {
        return;
    }
    seconds = mktime(&t);
    set_time(seconds);
    pc.printf(
        "Date: %04d/%02d/%02d, %02d:%02d:%02d\r\n",
        t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec
    );
}

int32_t xatoi (char **str, int32_t *res)
{
    int32_t val;
    uint8_t c, radix, s = 0;

    while ((c = **str) == ' ') {
        (*str)++;
    }
    if (c == '-') {
        s = 1;
        c = *(++(*str));
    }
    if (c == '0') {
        c = *(++(*str));
        if (c <= ' ') {
            *res = 0;
            return 1;
        }
        if (c == 'x') {
            radix = 16;
            c = *(++(*str));
        } else {
            if (c == 'b') {
                radix = 2;
                c = *(++(*str));
            } else {
                if ((c >= '0')&&(c <= '9')) {
                    radix = 8;
                } else {
                    return 0;
                }
            }
        }
    } else {
        if ((c < '1')||(c > '9')) {
            return 0;
        }
        radix = 10;
    }
    val = 0;
    while (c > ' ') {
        if (c >= 'a') {
            c -= 0x20;
        }
        c -= '0';
        if (c >= 17) {
            c -= 7;
            if (c <= 9) {
                return 0;
            }
        }
        if (c >= radix) {
            return 0;
        }
        val = val * radix + c;
        c = *(++(*str));
    }
    if (s) {
        val = -val;
    }
    *res = val;
    return 1;
}