fix(freertos): sync signal from isr fixed (#6793)

Signed-off-by: Nicușor Cîțu <nicusor.citu@nxp.com>
Signed-off-by: Cosmin-Daniel Radu <cosmin.radu_1@nxp.com>
Co-authored-by: Nicușor Cîțu <nicusor.citu@nxp.com>
This commit is contained in:
Cosmin-Daniel Radu
2024-09-24 14:35:39 +03:00
committed by GitHub
parent 55faa53bcc
commit 9db0ee3d02
7 changed files with 101 additions and 40 deletions

View File

@@ -162,6 +162,15 @@ menu "LVGL configuration"
string "Custom OS include header"
default "stdint.h"
depends on LV_OS_CUSTOM
config LV_USE_FREERTOS_TASK_NOTIFY
bool "Use RTOS task with a direct notification for synchronization"
default y
depends on LV_OS_FREERTOS
help
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.
endmenu
menu "Rendering Configuration"

View File

@@ -70,3 +70,9 @@ if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
target_compile_definitions(${COMPONENT_LIB}
PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
endif()
if(CONFIG_FREERTOS_SMP)
target_include_directories(${COMPONENT_LIB} PRIVATE "${IDF_PATH}/components/freertos/FreeRTOS-Kernel-SMP/include/freertos/")
else()
target_include_directories(${COMPONENT_LIB} PRIVATE "${IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos/")
endif()

View File

@@ -111,6 +111,15 @@
#if LV_USE_OS == LV_OS_CUSTOM
#define LV_OS_CUSTOM_INCLUDE <stdint.h>
#endif
#if LV_USE_OS == LV_OS_FREERTOS
/*
* 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.
*/
#define LV_USE_FREERTOS_TASK_NOTIFY 1
#endif
/*========================
* RENDERING CONFIGURATION

View File

@@ -340,9 +340,13 @@ static int32_t _vglite_wait_for_finish(lv_draw_unit_t * draw_unit)
lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit;
draw_vglite_unit->wait_for_finish = true;
/* Signal draw unit to finish its tasks and return READY state after completion. */
if(draw_vglite_unit->inited)
lv_thread_sync_signal(&draw_vglite_unit->sync);
/* Wait for finish now. */
lv_draw_dispatch_wait_for_request();
return 1;
}
#endif

View File

@@ -282,6 +282,25 @@
#endif
#endif
#endif
#if LV_USE_OS == LV_OS_FREERTOS
/*
* 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.
*/
#ifndef LV_USE_FREERTOS_TASK_NOTIFY
#ifdef LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_USE_FREERTOS_TASK_NOTIFY
#define LV_USE_FREERTOS_TASK_NOTIFY CONFIG_LV_USE_FREERTOS_TASK_NOTIFY
#else
#define LV_USE_FREERTOS_TASK_NOTIFY 0
#endif
#else
#define LV_USE_FREERTOS_TASK_NOTIFY 1
#endif
#endif
#endif
/*========================
* RENDERING CONFIGURATION

View File

@@ -15,11 +15,7 @@
#include "lv_os.h"
#if LV_USE_OS == LV_OS_FREERTOS
#if (ESP_PLATFORM)
#include "freertos/atomic.h"
#else
#include "atomic.h"
#endif
#include "../tick/lv_tick.h"
#include "../misc/lv_log.h"
@@ -54,7 +50,9 @@ static void prvCondInit(lv_thread_sync_t * pxCond);
static void prvCheckCondInit(lv_thread_sync_t * pxCond);
#if !USE_FREERTOS_TASK_NOTIFY
static void prvCheckCondInitIsr(lv_thread_sync_t * pxCond);
#if !LV_USE_FREERTOS_TASK_NOTIFY
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads);
#endif
@@ -74,9 +72,13 @@ static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
#if (ESP_PLATFORM)
#define _enter_critical() taskENTER_CRITICAL(&critSectionMux);
#define _exit_critical() taskEXIT_CRITICAL(&critSectionMux);
#define _enter_critical_isr() taskENTER_CRITICAL_FROM_ISR();
#define _exit_critical_isr(x) taskEXIT_CRITICAL_FROM_ISR(x);
#else
#define _enter_critical() taskENTER_CRITICAL();
#define _exit_critical() taskEXIT_CRITICAL();
#define _enter_critical_isr() taskENTER_CRITICAL_FROM_ISR();
#define _exit_critical_isr(x) taskEXIT_CRITICAL_FROM_ISR(x);
#endif
/**********************
@@ -195,20 +197,20 @@ lv_result_t lv_thread_sync_wait(lv_thread_sync_t * pxCond)
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond);
#if USE_FREERTOS_TASK_NOTIFY
TaskHandle_t current_task_handle = xTaskGetCurrentTaskHandle();
#if LV_USE_FREERTOS_TASK_NOTIFY
TaskHandle_t xCurrentTaskHandle = xTaskGetCurrentTaskHandle();
_enter_critical();
BaseType_t signal_sent = pxCond->xSyncSignal;
BaseType_t xSyncSygnal = pxCond->xSyncSignal;
pxCond->xSyncSignal = pdFALSE;
if(signal_sent == pdFALSE) {
if(xSyncSygnal == pdFALSE) {
/* The signal hasn't been sent yet. Tell the sender to notify this task */
pxCond->xTaskToNotify = current_task_handle;
pxCond->xTaskToNotify = xCurrentTaskHandle;
}
/* If we have a signal from the other task, we should not ask to be notified */
_exit_critical();
if(signal_sent == pdFALSE) {
if(xSyncSygnal == pdFALSE) {
/* Wait for other task to notify this task. */
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
@@ -275,20 +277,20 @@ lv_result_t lv_thread_sync_signal(lv_thread_sync_t * pxCond)
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond);
#if USE_FREERTOS_TASK_NOTIFY
#if LV_USE_FREERTOS_TASK_NOTIFY
_enter_critical();
TaskHandle_t task_to_notify = pxCond->xTaskToNotify;
TaskHandle_t xTaskToNotify = pxCond->xTaskToNotify;
pxCond->xTaskToNotify = NULL;
if(task_to_notify == NULL) {
if(xTaskToNotify == NULL) {
/* No task waiting to be notified. Send this signal for later */
pxCond->xSyncSignal = pdTRUE;
}
/* If a task is already waiting, there is no need to set the sync signal */
_exit_critical();
if(task_to_notify != NULL) {
if(xTaskToNotify != NULL) {
/* There is a task waiting. Send a notification to it */
xTaskNotifyGive(task_to_notify);
xTaskNotifyGive(xTaskToNotify);
}
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
#else
@@ -329,13 +331,13 @@ lv_result_t lv_thread_sync_signal(lv_thread_sync_t * pxCond)
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * pxCond)
{
#if !USE_FREERTOS_TASK_NOTIFY
#if !LV_USE_FREERTOS_TASK_NOTIFY
/* Cleanup all resources used by the cond. */
vSemaphoreDelete(pxCond->xCondWaitSemaphore);
vSemaphoreDelete(pxCond->xSyncMutex);
pxCond->ulWaitingThreads = 0;
pxCond->xSyncSignal = pdFALSE;
#endif
pxCond->xSyncSignal = pdFALSE;
pxCond->xIsInitialized = pdFALSE;
return LV_RESULT_OK;
@@ -346,28 +348,28 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond)
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* If the cond is uninitialized, perform initialization. */
prvCheckCondInit(pxCond);
prvCheckCondInitIsr(pxCond);
#if USE_FREERTOS_TASK_NOTIFY
_enter_critical();
TaskHandle_t task_to_notify = pxCond->xTaskToNotify;
#if LV_USE_FREERTOS_TASK_NOTIFY
uint32_t mask = _enter_critical_isr();
TaskHandle_t xTaskToNotify = pxCond->xTaskToNotify;
pxCond->xTaskToNotify = NULL;
if(task_to_notify == NULL) {
if(xTaskToNotify == NULL) {
/* No task waiting to be notified. Send this signal for later */
pxCond->xSyncSignal = pdTRUE;
}
/* If a task is already waiting, there is no need to set the sync signal */
_exit_critical();
_exit_critical_isr(mask);
if(task_to_notify != NULL) {
if(xTaskToNotify != NULL) {
/* There is a task waiting. Send a notification to it */
vTaskNotifyGiveFromISR(task_to_notify, &xHigherPriorityTaskWoken);
vTaskNotifyGiveFromISR(xTaskToNotify, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
#else
/* Enter critical section to prevent preemption. */
_enter_critical();
uint32_t mask = _enter_critical_isr();
pxCond->xSyncSignal = pdTRUE;
BaseType_t xAnyHigherPriorityTaskWoken = pdFALSE;
@@ -378,7 +380,7 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond)
xHigherPriorityTaskWoken |= xAnyHigherPriorityTaskWoken;
}
_exit_critical();
_exit_critical_isr(mask);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#endif
@@ -470,7 +472,7 @@ static void prvCondInit(lv_thread_sync_t * pxCond)
pxCond->xIsInitialized = pdTRUE;
pxCond->xSyncSignal = pdFALSE;
#if USE_FREERTOS_TASK_NOTIFY
#if LV_USE_FREERTOS_TASK_NOTIFY
pxCond->xTaskToNotify = NULL;
#else
pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U);
@@ -516,7 +518,27 @@ static void prvCheckCondInit(lv_thread_sync_t * pxCond)
}
}
#if !USE_FREERTOS_TASK_NOTIFY
static void prvCheckCondInitIsr(lv_thread_sync_t * pxCond)
{
/* Check if the condition variable needs to be initialized. */
if(pxCond->xIsInitialized == pdFALSE) {
/* Cond initialization must be in a critical section to prevent two
* threads from initializing it at the same time. */
uint32_t mask = _enter_critical_isr();
/* Check again that the condition is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if(pxCond->xIsInitialized == pdFALSE) {
prvCondInit(pxCond);
}
/* Exit the critical section. */
_exit_critical_isr(mask);
}
}
#if !LV_USE_FREERTOS_TASK_NOTIFY
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
uint32_t ulLocalWaitingThreads)
{

View File

@@ -37,14 +37,6 @@ extern "C" {
* DEFINES
*********************/
/*
* 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.
*/
#define USE_FREERTOS_TASK_NOTIFY 1
/**********************
* TYPEDEFS
**********************/
@@ -64,7 +56,7 @@ typedef struct {
BaseType_t
xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */
BaseType_t xSyncSignal; /**< Set to pdTRUE if the thread is signaled, pdFALSE otherwise. */
#if USE_FREERTOS_TASK_NOTIFY
#if LV_USE_FREERTOS_TASK_NOTIFY
TaskHandle_t xTaskToNotify; /**< The task waiting to be signalled. NULL if nothing is waiting. */
#else
SemaphoreHandle_t xCondWaitSemaphore; /**< Threads block on this semaphore in lv_thread_sync_wait. */