Skip to main content
Graduate
September 12, 2024
Solved

How to implement low-power support with tickless mode in FreeRTOS

  • September 12, 2024
  • 1 reply
  • 2721 views

Hello everyone,

I'm using Board NUCLEO-U031R8 for testing now.

I have an old FreeRTOS project designed for a power-saving application, and I am preparing to migrate it to a new IC STM32U031 series MCU.

In the old project, setting configUSE_TICKLESS_IDLE to 1 allowed the system to enter low-power mode when tasks were idle, and the low-power support feature provided by the manufacturer.

So I started with STM32CubeMX to create a simple project and install "X-CUBE-FREERTOS" middleware (CMSIS RTOS2), and set configUSE_TICKLESS_IDLE to 1. then using STM32CubeIDE to import the .ioc file, last adding a long-duration LED blink task to make sure the system would entry tickless idle mode.

The LED operates as expected, but I noticed that the current consumption averages around 5mA, which suggests that low-power features might not be functioning as intended. Do I missing something or wrong understanding?

Is there a recommended way to achieve low-power mode with tickless functionality in FreeRTOS?

Regards

Kein.

    This topic has been closed for replies.
    Best answer by kein

    I found the problem, here is the situation:

    // FreeRTOSConfig.h
    #define configPRE_SLEEP_PROCESSING(__x__) \
     do { \
     PreSleepProcessing(__x__); \
     __x__ = 0; \
     }while(0)
    // ------------------------------------------------------------------------------------
    // port.c
    __attribute__( ( weak ) ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {
     // .......
     xModifiableIdleTime = xExpectedIdleTime;
     configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
     if( xModifiableIdleTime > 0 )
     {
     // TODO: this region won't excute, because xModifiableIdleTime is set to 0 by macro configPRE_SLEEP_PROCESSING()
     __asm volatile ( "dsb" ::: "memory" );
     __asm volatile ( "wfi" );
     __asm volatile ( "isb" );
     }
     configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
     // .......
    }

     

     

     

    The solution is simple just add sleep function maybe HAL_PWR_EnterSTOPMode() in configPRE_SLEEP_PROCESSING() and the code looks like this:

     

    void PreSleepProcessing(uint32_t ulExpectedIdleTime) {
     RTC_StartWakeUpTimer(ulExpectedIdleTime);
     timeBeforeSleep = RTC_GetCount();
     LL_SYSTICK_DisableIT();
    
     {
     // ----------------------------- Sleep ------------------------------
     LL_LPUART_EnableInStopMode(LPUART1); // Set LPUART1->CR1.UESM
     Power_EnterSleep();
     LL_LPUART_DisableInStopMode(LPUART1); // Clear LPUART1->CR1.UESM
     // ------------------------------------------------------------------
     }
    }
    //======================================================================================
    void PostSleepProcessing(uint32_t ulExpectedIdleTime) {
     uint32_t sleepTime = (timeBeforeSleep - RTC_GetCount()) >> 5; // 32k LSI, convert counter to ms with /32
    
     RTC_StopWakeUpTimer();
     LL_SYSTICK_EnableIT(); // HAL_ResumeTick();
    
    // NOTE: call vTaskStepTick() here, must commit out the vTaskStepTick() in file port.c
     vTaskStepTick( sleepTime );
    }

     

     

    hope this would help someone.

    1 reply

    Technical Moderator
    September 12, 2024

    Hello,


    @kein wrote:

    The LED operates as expected, but I noticed that the current consumption averages around 5mA, which suggests that low-power features might not be functioning as intended.


    How are you measuring the power consumption as your are turning ON a LED?. It could be you are measuring the LED consumption. So don't turn it ON.- 

    Refer also to these videos:

    FreeRTOS on STM32 v2 - 21a Low power modes (tickless mode) 

    FreeRTOS on STM32 v2 - 21b Low power modes (tickless SLEEP mode)

     

    keinAuthor
    Graduate
    September 13, 2024

    Hi SofLit:

    Thanks for the reply, The LED ON time is very short, and the OFF time is a long delay to make sure system idle, and measure the current in the same time, so i think it won't be a problem, here's my task simple code:

     

     while(1) {
     // LED ON with 100ms.
     LL_GPIO_SetOutputPin(LED4_GPIO, LED4_PIN);
     HAL_Delay(100);
     LL_GPIO_ResetOutputPin(LED4_GPIO, LED4_PIN);
     // LED OFF with 5000ms, ensure system entry tickless state.
     osDelay(5000);
     }

     

    I follow the video and create LPTIM, and add the code in fucntion as below, the current is 400uA in LED OFF time, and the LED blink time as excepted.


     

    void PreSleepProcessing(uint32_t ulExpectedIdleTime) {
     HAL_SuspendTick();
     HAL_LPTIM_TimeOut_Start_IT(&hlptim1, ulExpectedIdleTime);
    }
    void PostSleepProcessing(uint32_t ulExpectedIdleTime) {
     HAL_LPTIM_TimeOut_Stop_IT(&hlptim1);
     HAL_ResumeTick();
    }​

     

    The next step is modify vPortSuppressTicksAndSleep().

    But when i commit out the restart systick part, It seems that osDelay(5000) been skipped, lead to LED working abnormally and it seems like always ON.

     

    // port.c
    __attribute__( ( weak ) ) void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {
     // ......
     /* Restart SysTick. */
     // TODO: commit out the restart systick, osDelay() would been skipped.
     // portNVIC_SYSTICK_CTRL_REG |= portNVIC_SYSTICK_ENABLE_BIT; 
    
     xModifiableIdleTime = xExpectedIdleTime;
     configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
    
     if( xModifiableIdleTime > 0 ) {
     __asm volatile ( "dsb" ::: "memory" );
     // __asm volatile ( "wfi" ); // using HAL function to instead of this.
     HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);
     __asm volatile ( "isb" );
     }
     // ......
    }

     

    Regards.

    Technical Moderator
    September 13, 2024

    Did you watch the videos I shared? they contain how to implement low-power mode in tickless mode in FreeRTOS as well as how to measure. Did you reproduce the hands-on?