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:
committed by
GitHub
parent
55faa53bcc
commit
9db0ee3d02
9
Kconfig
9
Kconfig
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 "atomic.h"
|
||||
|
||||
#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)
|
||||
{
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user