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
Gabor Kiss-Vamosi
parent
53c846f4ac
commit
e633ea2931
9
Kconfig
9
Kconfig
@@ -162,6 +162,15 @@ menu "LVGL configuration"
|
|||||||
string "Custom OS include header"
|
string "Custom OS include header"
|
||||||
default "stdint.h"
|
default "stdint.h"
|
||||||
depends on LV_OS_CUSTOM
|
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
|
endmenu
|
||||||
|
|
||||||
menu "Rendering Configuration"
|
menu "Rendering Configuration"
|
||||||
|
|||||||
@@ -70,3 +70,9 @@ if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
|
|||||||
target_compile_definitions(${COMPONENT_LIB}
|
target_compile_definitions(${COMPONENT_LIB}
|
||||||
PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
|
PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
|
||||||
endif()
|
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()
|
||||||
@@ -95,6 +95,15 @@
|
|||||||
#if LV_USE_OS == LV_OS_CUSTOM
|
#if LV_USE_OS == LV_OS_CUSTOM
|
||||||
#define LV_OS_CUSTOM_INCLUDE <stdint.h>
|
#define LV_OS_CUSTOM_INCLUDE <stdint.h>
|
||||||
#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.
|
||||||
|
*/
|
||||||
|
#define LV_USE_FREERTOS_TASK_NOTIFY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*========================
|
/*========================
|
||||||
* RENDERING CONFIGURATION
|
* 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;
|
lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit;
|
||||||
draw_vglite_unit->wait_for_finish = true;
|
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)
|
if(draw_vglite_unit->inited)
|
||||||
lv_thread_sync_signal(&draw_vglite_unit->sync);
|
lv_thread_sync_signal(&draw_vglite_unit->sync);
|
||||||
|
|
||||||
|
/* Wait for finish now. */
|
||||||
|
lv_draw_dispatch_wait_for_request();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -266,6 +266,25 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#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
|
* RENDERING CONFIGURATION
|
||||||
|
|||||||
@@ -15,11 +15,7 @@
|
|||||||
#include "lv_os.h"
|
#include "lv_os.h"
|
||||||
#if LV_USE_OS == LV_OS_FREERTOS
|
#if LV_USE_OS == LV_OS_FREERTOS
|
||||||
|
|
||||||
#if (ESP_PLATFORM)
|
#include "atomic.h"
|
||||||
#include "freertos/atomic.h"
|
|
||||||
#else
|
|
||||||
#include "atomic.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "../tick/lv_tick.h"
|
#include "../tick/lv_tick.h"
|
||||||
#include "../misc/lv_log.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);
|
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,
|
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
|
||||||
uint32_t ulLocalWaitingThreads);
|
uint32_t ulLocalWaitingThreads);
|
||||||
#endif
|
#endif
|
||||||
@@ -74,9 +72,13 @@ static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
|
|||||||
#if (ESP_PLATFORM)
|
#if (ESP_PLATFORM)
|
||||||
#define _enter_critical() taskENTER_CRITICAL(&critSectionMux);
|
#define _enter_critical() taskENTER_CRITICAL(&critSectionMux);
|
||||||
#define _exit_critical() taskEXIT_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
|
#else
|
||||||
#define _enter_critical() taskENTER_CRITICAL();
|
#define _enter_critical() taskENTER_CRITICAL();
|
||||||
#define _exit_critical() taskEXIT_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
|
#endif
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
@@ -195,20 +197,20 @@ lv_result_t lv_thread_sync_wait(lv_thread_sync_t * pxCond)
|
|||||||
/* If the cond is uninitialized, perform initialization. */
|
/* If the cond is uninitialized, perform initialization. */
|
||||||
prvCheckCondInit(pxCond);
|
prvCheckCondInit(pxCond);
|
||||||
|
|
||||||
#if USE_FREERTOS_TASK_NOTIFY
|
#if LV_USE_FREERTOS_TASK_NOTIFY
|
||||||
TaskHandle_t current_task_handle = xTaskGetCurrentTaskHandle();
|
TaskHandle_t xCurrentTaskHandle = xTaskGetCurrentTaskHandle();
|
||||||
|
|
||||||
_enter_critical();
|
_enter_critical();
|
||||||
BaseType_t signal_sent = pxCond->xSyncSignal;
|
BaseType_t xSyncSygnal = pxCond->xSyncSignal;
|
||||||
pxCond->xSyncSignal = pdFALSE;
|
pxCond->xSyncSignal = pdFALSE;
|
||||||
if(signal_sent == pdFALSE) {
|
if(xSyncSygnal == pdFALSE) {
|
||||||
/* The signal hasn't been sent yet. Tell the sender to notify this task */
|
/* 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 */
|
/* If we have a signal from the other task, we should not ask to be notified */
|
||||||
_exit_critical();
|
_exit_critical();
|
||||||
|
|
||||||
if(signal_sent == pdFALSE) {
|
if(xSyncSygnal == pdFALSE) {
|
||||||
/* Wait for other task to notify this task. */
|
/* Wait for other task to notify this task. */
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
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. */
|
/* If the cond is uninitialized, perform initialization. */
|
||||||
prvCheckCondInit(pxCond);
|
prvCheckCondInit(pxCond);
|
||||||
|
|
||||||
#if USE_FREERTOS_TASK_NOTIFY
|
#if LV_USE_FREERTOS_TASK_NOTIFY
|
||||||
_enter_critical();
|
_enter_critical();
|
||||||
TaskHandle_t task_to_notify = pxCond->xTaskToNotify;
|
TaskHandle_t xTaskToNotify = pxCond->xTaskToNotify;
|
||||||
pxCond->xTaskToNotify = NULL;
|
pxCond->xTaskToNotify = NULL;
|
||||||
if(task_to_notify == NULL) {
|
if(xTaskToNotify == NULL) {
|
||||||
/* No task waiting to be notified. Send this signal for later */
|
/* No task waiting to be notified. Send this signal for later */
|
||||||
pxCond->xSyncSignal = pdTRUE;
|
pxCond->xSyncSignal = pdTRUE;
|
||||||
}
|
}
|
||||||
/* If a task is already waiting, there is no need to set the sync signal */
|
/* If a task is already waiting, there is no need to set the sync signal */
|
||||||
_exit_critical();
|
_exit_critical();
|
||||||
|
|
||||||
if(task_to_notify != NULL) {
|
if(xTaskToNotify != NULL) {
|
||||||
/* There is a task waiting. Send a notification to it */
|
/* 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. */
|
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
|
||||||
#else
|
#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)
|
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. */
|
/* Cleanup all resources used by the cond. */
|
||||||
vSemaphoreDelete(pxCond->xCondWaitSemaphore);
|
vSemaphoreDelete(pxCond->xCondWaitSemaphore);
|
||||||
vSemaphoreDelete(pxCond->xSyncMutex);
|
vSemaphoreDelete(pxCond->xSyncMutex);
|
||||||
pxCond->ulWaitingThreads = 0;
|
pxCond->ulWaitingThreads = 0;
|
||||||
pxCond->xSyncSignal = pdFALSE;
|
|
||||||
#endif
|
#endif
|
||||||
|
pxCond->xSyncSignal = pdFALSE;
|
||||||
pxCond->xIsInitialized = pdFALSE;
|
pxCond->xIsInitialized = pdFALSE;
|
||||||
|
|
||||||
return LV_RESULT_OK;
|
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;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
/* If the cond is uninitialized, perform initialization. */
|
/* If the cond is uninitialized, perform initialization. */
|
||||||
prvCheckCondInit(pxCond);
|
prvCheckCondInitIsr(pxCond);
|
||||||
|
|
||||||
#if USE_FREERTOS_TASK_NOTIFY
|
#if LV_USE_FREERTOS_TASK_NOTIFY
|
||||||
_enter_critical();
|
uint32_t mask = _enter_critical_isr();
|
||||||
TaskHandle_t task_to_notify = pxCond->xTaskToNotify;
|
TaskHandle_t xTaskToNotify = pxCond->xTaskToNotify;
|
||||||
pxCond->xTaskToNotify = NULL;
|
pxCond->xTaskToNotify = NULL;
|
||||||
if(task_to_notify == NULL) {
|
if(xTaskToNotify == NULL) {
|
||||||
/* No task waiting to be notified. Send this signal for later */
|
/* No task waiting to be notified. Send this signal for later */
|
||||||
pxCond->xSyncSignal = pdTRUE;
|
pxCond->xSyncSignal = pdTRUE;
|
||||||
}
|
}
|
||||||
/* If a task is already waiting, there is no need to set the sync signal */
|
/* 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 */
|
/* There is a task waiting. Send a notification to it */
|
||||||
vTaskNotifyGiveFromISR(task_to_notify, &xHigherPriorityTaskWoken);
|
vTaskNotifyGiveFromISR(xTaskToNotify, &xHigherPriorityTaskWoken);
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
|
/* If there was no task waiting to be notified, we sent a signal for it to see later. */
|
||||||
#else
|
#else
|
||||||
/* Enter critical section to prevent preemption. */
|
/* Enter critical section to prevent preemption. */
|
||||||
_enter_critical();
|
uint32_t mask = _enter_critical_isr();
|
||||||
|
|
||||||
pxCond->xSyncSignal = pdTRUE;
|
pxCond->xSyncSignal = pdTRUE;
|
||||||
BaseType_t xAnyHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xAnyHigherPriorityTaskWoken = pdFALSE;
|
||||||
@@ -378,7 +380,7 @@ lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond)
|
|||||||
xHigherPriorityTaskWoken |= xAnyHigherPriorityTaskWoken;
|
xHigherPriorityTaskWoken |= xAnyHigherPriorityTaskWoken;
|
||||||
}
|
}
|
||||||
|
|
||||||
_exit_critical();
|
_exit_critical_isr(mask);
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -470,7 +472,7 @@ static void prvCondInit(lv_thread_sync_t * pxCond)
|
|||||||
pxCond->xIsInitialized = pdTRUE;
|
pxCond->xIsInitialized = pdTRUE;
|
||||||
pxCond->xSyncSignal = pdFALSE;
|
pxCond->xSyncSignal = pdFALSE;
|
||||||
|
|
||||||
#if USE_FREERTOS_TASK_NOTIFY
|
#if LV_USE_FREERTOS_TASK_NOTIFY
|
||||||
pxCond->xTaskToNotify = NULL;
|
pxCond->xTaskToNotify = NULL;
|
||||||
#else
|
#else
|
||||||
pxCond->xCondWaitSemaphore = xSemaphoreCreateCounting(ulMAX_COUNT, 0U);
|
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,
|
static void prvTestAndDecrement(lv_thread_sync_t * pxCond,
|
||||||
uint32_t ulLocalWaitingThreads)
|
uint32_t ulLocalWaitingThreads)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,14 +37,6 @@ extern "C" {
|
|||||||
* DEFINES
|
* 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
|
* TYPEDEFS
|
||||||
**********************/
|
**********************/
|
||||||
@@ -64,7 +56,7 @@ typedef struct {
|
|||||||
BaseType_t
|
BaseType_t
|
||||||
xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */
|
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. */
|
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. */
|
TaskHandle_t xTaskToNotify; /**< The task waiting to be signalled. NULL if nothing is waiting. */
|
||||||
#else
|
#else
|
||||||
SemaphoreHandle_t xCondWaitSemaphore; /**< Threads block on this semaphore in lv_thread_sync_wait. */
|
SemaphoreHandle_t xCondWaitSemaphore; /**< Threads block on this semaphore in lv_thread_sync_wait. */
|
||||||
|
|||||||
Reference in New Issue
Block a user