jefftenney / LPTIM-Tick-U5

FreeRTOS Tick/Tickless via LPTIM for STM32U
3 stars 3 forks source link

Power Consumption is more than 5ma if system clock is made to 160MHz #3

Closed nilesh-dryad closed 2 years ago

nilesh-dryad commented 2 years ago

I have been testing this with STM32u575 board, it was working fine with 24mhz clock and consumption was around 850uA but when I changed the system clk to 160Mhz it just increased to 5ma-10ma.

Increasing the clock may result in higher power consumption. But this is a significant increase.

jefftenney commented 2 years ago

Your measurement of 850μA at 24MHz isn't expected. My own measurements at 24MHz show all three tests under 100μA. So the issue you are having at 24MHz is probably the same issue you are having at 160MHz.

Still I tried to duplicate your results at 160MHz. So I changed the clock config in CubeMX and regenerated code. Then I added #define SUPPORT_VREG_RANGES_1_THROUGH_3 at the top of ulp.c. Here are my results:

160MHz with lptimTick.c (STOP mode per ulp.c):

If I make these measurements while the STM32 is in debug mode, I still get under 500μA for all three tests.

Then out of curiosity I disabled the use of STOP modes by eliminating the definitions of configPRE_SLEEP_PROCESSING() and configPOST_SLEEP_PROCESSING() in FreeRTOSConfig.h. The current measurements are still less than your results:

So I'm not able to reproduce the issue. Have you modified the code?

nilesh-dryad commented 2 years ago

There are four things which I am doing different.

  1. I changed the branch to kernel PR.
  2. I change CubeMX version because I have the latest version.
  3. I am using STM32U575.
  4. I didn't use SUPPORT_VREG_RANGES_1_THROUGH_3 macro.

Let me try exactly the same board and same code with same cube ide version.

jefftenney commented 2 years ago

That makes more sense. The kernel PR 59 branch has configUSE_TICKLESS_IDLE set to 1. That means lptimTick.c is not used, nor is STOP mode used. And in this configuration, SUPPORT_VREG_RANGES_1_THROUGH_3 doesn't make a difference.

At 24 MHz, current is about 500μA. At 160 MHz, current is about 5mA.

However, my hardware is configured for the internal SMPS. Does your hardware support the internal SMPS? If your hardware uses the LDO, that would make the difference you are seeing in current consumption.

nilesh-dryad commented 2 years ago

I did some debugging and found that when configUSE_TICKLESS_IDLE set to 1, systick interrupt is coming at every 1 ms which is waking up the system every 1ms. May be that's why consumption is high.

Please note that I had to comment below line. Because of that line HAL_DELAY timing became wrong. Someone might need HAL_DELAY in their application for busy waiting.

TIM17->CR1 &= ~TIM_CR1_CEN; // wish CubeMX would generate a symbol for the HAL tick timer

I guess you need to define pre and post sleep function when configUSE_TICKLESS_IDLE set to 1.

When I added below code, system stopped waking up when was in tickless mode. and HAL_DELAY timing is almost accurate.

__weak void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{
    /* place for user code */
    HAL_SuspendTick();
    HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_RESET);
}

__weak void PostSleepProcessing(uint32_t ulExpectedIdleTime)
{
    /* place for user code */
    HAL_GPIO_WritePin(USER_LED1_GPIO_Port, USER_LED1_Pin, GPIO_PIN_SET);
    HAL_ResumeTick();
}
jefftenney commented 2 years ago

This repo illustrates the three choices you have for power consumption with FreeRTOS on STM32. These choices are the three values of configUSE_TICKLESS_IDLE.

0 - Tickless is disabled; tick provided by SysTick. Highest power consumption 1 - Tickless is enabled; tick provided by SysTick. The tickless code is from FreeRTOS. Medium power consumption. 2 - Tickless is enabled; tick provided by LPTIM. The tickless code is from me, in lptimTick.c. Lowest power consumption.

Effect on ST HAL: With 0, you could leave the HAL timer (TIM17 in this repo) running. No harm done to have two tick counters. The FreeRTOS tick is in SysTick, and the HAL tick is in TIM17. With 1 and 2, you would stop the HAL timer. Otherwise, it will wake the system from tickless periods every 1ms. Application code would use vTaskDelay() instead of HAL_Delay(). If application includes ST device drivers that require HAL_Delay(), application would provide a custom version of HAL_Delay() that uses the FreeRTOS tick. (Same with other HAL tick functions.) This repo does not provide a custom version of HAL_Delay() because this repo doesn't use the HAL tick once FreeRTOS is running.

Use of PreSleepProcessing() and PostSleepProcessing() In this repo, the purpose of these functions is to select a deeper level of sleep (aka STOP modes aka deep sleep) than standard sleep. With 1, there is no need to select STOP modes because they stop the SysTick. FreeRTOS cannot keep track of time and cannot wake itself up after a delay if SysTick stops. Therefore with 1, there's really no use for the pre/post sleep functions.

Conclusions Based on the above, you should not comment out the line that stops TIM17, and you should not add pre/post sleep functions when configUSE_TICKLESS_IDLE is 1.

jefftenney commented 2 years ago

Also - for what it's worth, I did confirm your experiment and results. If you leave TIM17 running by commenting out this line, and if you suspend/resume the HAL tick in the pre/post sleep functions, the system still works properly. The benefit being you have a HAL tick available for ST device drivers and other ST-provided code that calls HAL_Delay().

However, as I noted in the post immediately above, a preferred method would be to provide custom versions of HAL_Delay() and HAL_GetTick() that use vTaskDelay() and xTaskGetTickCount() internally.

A note regarding your current consumption. With configUSE_TICKLESS_IDLE set to 1, you should be around 500 μA at 3.3V. If you add the HAL tick waking the system every 1ms during tickless periods, the current goes up around 50 μA. So that wouldn't explain your high current readings. What hardware are you using? Nucleo? EV? Custom? If you are measuring current at 1.8V, that would explain the difference.

nilesh-dryad commented 2 years ago

Yes you are right. We can have custom versions of HAL* functions. I have 500uA at 3.3V now. Please see the image. Everything is working fine with Kernel PR branch. Current consumption is also in desired limit. But if you see into the image. It is waking up at every 1 seconds which I don't understand. When Blue line is low, STM32 is in tickless sleep mode and when it is high, it is out of the sleep mode. image

jefftenney commented 2 years ago

I wouldn't worry too much about very brief wake-ups. That's just FreeRTOS hitting the limit of the hardware timer and waking up just long enough to reset the timer and account for the time elapsed. These "intermediate" wakeups are pretty harmless from an energy perspective.

With configUSE_TICKLESS_IDLE set to 1, the tick uses SysTick, which is a 24-bit timer, thus able about to count to 16.7M before rolling over. With configUSE_TICKLESS_IDLE set to 2, the tick uses LPTIM which is a 16-bit timer, up to only 65535.

By the way -- any reason why you are going with configUSE_TICKLESS_IDLE set to 1? The reason I created this repo is to show how much better setting 2 is, using LPTIM and lptimTick.c, because you get access to the ultra-low power "STOP" modes.

nilesh-dryad commented 2 years ago

My application needs 160Mhz system clock to achieve a full performance and at the same time my device is running on a solar. therefore I need to save the power. There are several peripherals I am using in my application. 3 UARTs, 3 SPIs, 1 ADC. Out of all these peripherals, one UART is with the GSM module. GSM module should be able to wake up the STM32 from the Sleep or STOP mode when it receives any data from Internet. I am afraid I can't use the STOP mode because system can only clocked upto 24Mhz with the STOP mode.

Our application is to protect a forest from fire and there are many sensors sending data to STM32. The larger the forest, more the data coming to the stm. Therefore we need a more processing power and hence the bigger clock. We were able to do this with ESP32 in tickless idle mode. Current consumption in tickless idle was 700uA with ESP32 running at 160Mhz. Only problem with ESP32 was that we were loosing first few bytes after wake up. With STM32 there is much more flexibility with the peripherals selection in SLEEP/STOP mode.

One thing I can try is that I keep the system running on 160Mhz and use the stop mode (I can disable other peripherals which I don't need when in tickless mode) and before going into stop mode, I change the system clock to 24Mhz (in presleep macro) and after coming out of stop mode (in post sleep macro), I again set the system clock to 160Mhz.

jefftenney commented 2 years ago

I see. Note that you don't need to reduce the clock to 24 MHz before entering stop mode. The 'U5 correctly enters STOP mode either way, and then it wakes up to a maximum of 24 MHz automatically. Your wake-up code could restore the clock settings, as shown in ulp.c.

Keep in mind the UARTs do work in STOP mode, so you might eventually be able to integrate the STOP modes (and lptimTick.c) and reduce the idle current significantly. Good luck!

Closing this issue since 5mA is expected at 160 MHz with configUSE_TICKLESS_IDLE set to 1 (not 2).

nilesh-dryad commented 2 years ago

Just a quick question. When you did this test of 160Mhz with STOP mode. Did you just change IOC file or made other configuration (apart from the SUPPORT_VREG_RANGES_1_THROUGH_3 macro) as well?

jefftenney commented 2 years ago

For my tests at 160MHz, I modified the ioc file to use the PLL at 320 MHz sourced from MSI @ 16 MHz. I set PLLR for divide-by-2 so the system clock was 160MHz. I updated the Vcore range (range 1, the only choice listed), and I set the flash wait states (4 WS, the only choice listed).

Keep in mind at the time I was using lptimTick.c (configUSE_TICKLESS_IDLE set to 2). When I got an average current around 5mA, I had eliminated the pre/post sleep functions in order to eliminate the use of STOP mode. But with the pre/post sleep functions still in use, I got much lower current as you can see in my first response at the beginning of this thread.