feat(freertos): allow overriding idle percentage calculation (#9647)

This commit is contained in:
Akash
2026-02-26 23:17:30 +05:30
committed by GitHub
parent 65192290e6
commit 586a25ed6f
7 changed files with 93 additions and 1 deletions

View File

@@ -162,6 +162,15 @@ menu "LVGL configuration"
Unblocking an RTOS task with a direct notification is 45% faster and uses less RAM
than unblocking a task using an intermediary object such as a binary semaphore.
RTOS task notifications can only be used when there is only one task that can be the recipient of the event.
config LV_OS_IDLE_PERCENT_CUSTOM
bool "Custom idle percentage calculation"
default n
depends on LV_OS_FREERTOS
help
Enable this to provide a custom implementation of lv_os_get_idle_percent.
This is useful for multi-core systems where the default
FreeRTOS implementation might not sufficiently track idle time across all cores.
endmenu
menu "Rendering Configuration"

View File

@@ -31,3 +31,67 @@ the idle function. To enable this, the following needs to be added in
#define traceTASK_SWITCHED_IN() lv_freertos_task_switch_in(pxCurrentTCB->pcTaskName);
#define traceTASK_SWITCHED_OUT() lv_freertos_task_switch_out();
Alternatively, on multi-core environments (like the ESP32 SMP), this default
implementation can be insufficient or inaccurate. In this case, you can set
``LV_OS_IDLE_PERCENT_CUSTOM`` to ``1`` in ``lv_conf.h`` to disable the default
implementation. Then, you can provide a custom implementation of
:cpp:expr:`lv_os_get_idle_percent` tailored to your environment
(e.g., using ``uxTaskGetSystemState()``) without modifying LVGL source files.
Example: Custom implementation for ESP32 SMP
********************************************
For multi-core environments like the ESP32 (which uses dual-core SMP), the default
implementation might not track all idle tasks. Below is an example of a custom
implementation using ``uxTaskGetSystemState()``. This requires
``configGENERATE_RUN_TIME_STATS`` and ``configUSE_TRACE_FACILITY`` to be enabled
in your ``FreeRTOSConfig.h`` (or via menuconfig for ESP-IDF).
.. code-block:: c
#include "FreeRTOS.h"
#include "task.h"
#include <string.h>
uint32_t lv_os_get_idle_percent(void) {
static uint32_t last_idle_time = 0;
static uint32_t last_total_time = 0;
uint32_t ulTotalRunTime;
uint32_t ulIdleTime = 0;
TaskStatus_t *pxTaskStatusArray;
UBaseType_t uxArraySize, x;
uxArraySize = uxTaskGetNumberOfTasks();
pxTaskStatusArray = pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));
if (pxTaskStatusArray == NULL) {
return 0;
}
uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime);
for (x = 0; x < uxArraySize; x++) {
/* ESP32 has IDLE0 and IDLE1 tasks */
if (strcmp(pxTaskStatusArray[x].pcTaskName, "IDLE0") == 0 ||
strcmp(pxTaskStatusArray[x].pcTaskName, "IDLE1") == 0) {
ulIdleTime += pxTaskStatusArray[x].ulRunTimeCounter;
}
}
vPortFree(pxTaskStatusArray);
uint32_t idle_diff = ulIdleTime - last_idle_time;
uint32_t total_diff = ulTotalRunTime - last_total_time;
last_idle_time = ulIdleTime;
last_total_time = ulTotalRunTime;
if (total_diff == 0) return 0;
/* Combined idle percentage across both cores (0-200 on dual-core) */
uint32_t idle_pct = (idle_diff * 100) / total_diff;
/* For Sysmon, we usually want average load across all cores (0-100) */
return idle_pct / 2; /* Adjust divisor based on your CPU core count */
}

View File

@@ -127,6 +127,9 @@
* RTOS task notifications can only be used when there is only one task that can be the recipient of the event.
*/
#define LV_USE_FREERTOS_TASK_NOTIFY 1
/* Enable this to provide a custom implementation of lv_os_get_idle_percent. */
#define LV_OS_IDLE_PERCENT_CUSTOM 0
#endif
/*========================

View File

@@ -119,6 +119,9 @@
* RTOS task notifications can only be used when there is only one task that can be the recipient of the event.
*/
#define LV_USE_FREERTOS_TASK_NOTIFY 1
/* Enable this to provide a custom implementation of lv_os_get_idle_percent. */
#define LV_OS_IDLE_PERCENT_CUSTOM 0
#endif
/*========================

View File

@@ -312,6 +312,15 @@
#define LV_USE_FREERTOS_TASK_NOTIFY 1
#endif
#endif
/* Enable this to provide a custom implementation of lv_os_get_idle_percent. */
#ifndef LV_OS_IDLE_PERCENT_CUSTOM
#ifdef CONFIG_LV_OS_IDLE_PERCENT_CUSTOM
#define LV_OS_IDLE_PERCENT_CUSTOM CONFIG_LV_OS_IDLE_PERCENT_CUSTOM
#else
#define LV_OS_IDLE_PERCENT_CUSTOM 0
#endif
#endif
#endif
/*========================

View File

@@ -403,6 +403,7 @@ void lv_freertos_task_switch_out(void)
else globals->freertos_non_idle_time_sum += elaps;
}
#if LV_OS_IDLE_PERCENT_CUSTOM == 0
uint32_t lv_os_get_idle_percent(void)
{
if(globals->freertos_non_idle_time_sum + globals->freertos_idle_time_sum == 0) {
@@ -418,6 +419,7 @@ uint32_t lv_os_get_idle_percent(void)
return pct;
}
#endif
void lv_sleep_ms(uint32_t ms)
{

View File

@@ -121,8 +121,10 @@
* RTOS task notifications can only be used when there is only one task that can be the recipient of the event.
*/
#define LV_USE_FREERTOS_TASK_NOTIFY 1
#endif
/* Enable this to provide a custom implementation of lv_os_get_idle_percent. */
#define LV_OS_IDLE_PERCENT_CUSTOM 0
#endif
/*========================
* RENDERING CONFIGURATION
*========================*/