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
+9
View File
@@ -162,6 +162,15 @@ menu "LVGL configuration"
Unblocking an RTOS task with a direct notification is 45% faster and uses less RAM 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. 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. 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 endmenu
menu "Rendering Configuration" menu "Rendering Configuration"
+64
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_IN() lv_freertos_task_switch_in(pxCurrentTCB->pcTaskName);
#define traceTASK_SWITCHED_OUT() lv_freertos_task_switch_out(); #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 */
}
+3
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. * 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 #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 #endif
/*======================== /*========================
+3
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. * 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 #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 #endif
/*======================== /*========================
+9
View File
@@ -312,6 +312,15 @@
#define LV_USE_FREERTOS_TASK_NOTIFY 1 #define LV_USE_FREERTOS_TASK_NOTIFY 1
#endif #endif
#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 #endif
/*======================== /*========================
+2
View File
@@ -403,6 +403,7 @@ void lv_freertos_task_switch_out(void)
else globals->freertos_non_idle_time_sum += elaps; else globals->freertos_non_idle_time_sum += elaps;
} }
#if LV_OS_IDLE_PERCENT_CUSTOM == 0
uint32_t lv_os_get_idle_percent(void) uint32_t lv_os_get_idle_percent(void)
{ {
if(globals->freertos_non_idle_time_sum + globals->freertos_idle_time_sum == 0) { 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; return pct;
} }
#endif
void lv_sleep_ms(uint32_t ms) void lv_sleep_ms(uint32_t ms)
{ {
+3 -1
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. * 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 #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 * RENDERING CONFIGURATION
*========================*/ *========================*/