mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
feat(demos): add demo for the OSAL (#6182)
Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
parent
4ab68c5dc1
commit
70ed004ef3
@ -7,8 +7,10 @@ Operating system and interrupts
|
|||||||
LVGL is **not thread-safe** by default.
|
LVGL is **not thread-safe** by default.
|
||||||
|
|
||||||
However, in the following conditions it's valid to call LVGL related
|
However, in the following conditions it's valid to call LVGL related
|
||||||
functions: - In *events*. Learn more in :ref:`events`. -
|
functions:
|
||||||
In *lv_timer*. Learn more in :ref:`timer`.
|
|
||||||
|
- In *events*. Learn more in :ref:`events`.
|
||||||
|
- In *lv_timer*. Learn more in :ref:`timer`.
|
||||||
|
|
||||||
Tasks and threads
|
Tasks and threads
|
||||||
-----------------
|
-----------------
|
||||||
@ -20,19 +22,26 @@ around every LVGL (``lv_...``) related function call and code. This way
|
|||||||
you can use LVGL in a real multitasking environment. Just make use of a
|
you can use LVGL in a real multitasking environment. Just make use of a
|
||||||
mutex to avoid the concurrent calling of LVGL functions.
|
mutex to avoid the concurrent calling of LVGL functions.
|
||||||
|
|
||||||
|
LVGL has a built-in mutex which can be used with:
|
||||||
|
- :cpp:func:`lv_lock()` and :cpp:func:`lv_lock_isr()`
|
||||||
|
- :cpp:func:`lv_unlock()`
|
||||||
|
|
||||||
|
These functions are called internally in :cpp:func:`lv_timer_handler`
|
||||||
|
and the users need to call them only from their own therads.
|
||||||
|
|
||||||
|
To enable ``lv_lock/lv_unlock`` ``LV_USE_OS`` needs to be set to other
|
||||||
|
than ``LV_OS_NONE``.
|
||||||
|
|
||||||
|
|
||||||
Here is some pseudocode to illustrate the concept:
|
Here is some pseudocode to illustrate the concept:
|
||||||
|
|
||||||
.. code:: c
|
.. code:: c
|
||||||
|
|
||||||
static mutex_t lvgl_mutex;
|
|
||||||
|
|
||||||
void lvgl_thread(void)
|
void lvgl_thread(void)
|
||||||
{
|
{
|
||||||
while(1) {
|
while(1) {
|
||||||
uint32_t time_till_next;
|
uint32_t time_till_next;
|
||||||
mutex_lock(&lvgl_mutex);
|
time_till_next = lv_timer_handler(); /*lv_lock/lv_unlock is called internally*/
|
||||||
time_till_next = lv_timer_handler();
|
|
||||||
mutex_unlock(&lvgl_mutex);
|
|
||||||
thread_sleep(time_till_next); /* sleep for a while */
|
thread_sleep(time_till_next); /* sleep for a while */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,15 +49,15 @@ Here is some pseudocode to illustrate the concept:
|
|||||||
void other_thread(void)
|
void other_thread(void)
|
||||||
{
|
{
|
||||||
/* You must always hold the mutex while using LVGL APIs */
|
/* You must always hold the mutex while using LVGL APIs */
|
||||||
mutex_lock(&lvgl_mutex);
|
lv_lock();
|
||||||
lv_obj_t *img = lv_image_create(lv_screen_active());
|
lv_obj_t *img = lv_image_create(lv_screen_active());
|
||||||
mutex_unlock(&lvgl_mutex);
|
lv_unlock();
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
mutex_lock(&lvgl_mutex);
|
lv_lock();
|
||||||
/* change to the next image */
|
/* change to the next image */
|
||||||
lv_image_set_src(img, next_image);
|
lv_image_set_src(img, next_image);
|
||||||
mutex_unlock(&lvgl_mutex);
|
lv_unlock();
|
||||||
thread_sleep(2000);
|
thread_sleep(2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ extern "C" {
|
|||||||
#include "layouts/lv_example_layout.h"
|
#include "layouts/lv_example_layout.h"
|
||||||
#include "libs/lv_example_libs.h"
|
#include "libs/lv_example_libs.h"
|
||||||
#include "others/lv_example_others.h"
|
#include "others/lv_example_others.h"
|
||||||
|
#include "porting/osal/lv_example_osal.h"
|
||||||
#include "scroll/lv_example_scroll.h"
|
#include "scroll/lv_example_scroll.h"
|
||||||
#include "styles/lv_example_style.h"
|
#include "styles/lv_example_style.h"
|
||||||
#include "widgets/lv_example_widgets.h"
|
#include "widgets/lv_example_widgets.h"
|
||||||
|
95
examples/porting/osal/lv_example_osal.c
Normal file
95
examples/porting/osal/lv_example_osal.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_example_osal.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "../../lv_examples.h"
|
||||||
|
|
||||||
|
#if LV_BUILD_EXAMPLES
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
static void counter_button_event_cb(lv_event_t * e);
|
||||||
|
static void increment_thread_entry(void * user_data);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
static lv_thread_sync_t press_sync;
|
||||||
|
static lv_thread_t increment_thread;
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void lv_example_osal(void)
|
||||||
|
{
|
||||||
|
lv_obj_t * counter_button;
|
||||||
|
|
||||||
|
counter_button = lv_button_create(lv_screen_active());
|
||||||
|
lv_obj_align(counter_button, LV_ALIGN_CENTER, 0, -15);
|
||||||
|
lv_obj_add_event_cb(counter_button, counter_button_event_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
|
if(lv_thread_sync_init(&press_sync) != LV_RESULT_OK) {
|
||||||
|
LV_LOG_ERROR("Error initializing thread sync");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lv_thread_init(&increment_thread, LV_THREAD_PRIO_MID, increment_thread_entry, 2048, NULL) != LV_RESULT_OK) {
|
||||||
|
LV_LOG_ERROR("Error initializing thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
static void counter_button_event_cb(lv_event_t * e)
|
||||||
|
{
|
||||||
|
LV_UNUSED(e);
|
||||||
|
if(lv_thread_sync_signal(&press_sync) != LV_RESULT_OK) {
|
||||||
|
LV_LOG_ERROR("Error signaling thread sync");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void increment_thread_entry(void * user_data)
|
||||||
|
{
|
||||||
|
LV_UNUSED(user_data);
|
||||||
|
lv_obj_t * counter_label;
|
||||||
|
uint32_t press_count = 0;
|
||||||
|
|
||||||
|
lv_lock();
|
||||||
|
counter_label = lv_label_create(lv_scr_act());
|
||||||
|
lv_obj_align(counter_label, LV_ALIGN_CENTER, 0, 0);
|
||||||
|
lv_label_set_text_fmt(counter_label, "Pressed %u times", press_count);
|
||||||
|
lv_unlock();
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
if(lv_thread_sync_wait(&press_sync) != LV_RESULT_OK) {
|
||||||
|
LV_LOG_ERROR("Error awaiting thread sync");
|
||||||
|
}
|
||||||
|
press_count += 1;
|
||||||
|
|
||||||
|
lv_lock();
|
||||||
|
lv_label_set_text_fmt(counter_label, "Pressed %u times", press_count);
|
||||||
|
lv_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
38
examples/porting/osal/lv_example_osal.h
Normal file
38
examples/porting/osal/lv_example_osal.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_example_osal.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LV_EXAMPLE_OSAL_H
|
||||||
|
#define LV_EXAMPLE_OSAL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
void lv_example_osal(void);
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*LV_EXAMPLE_OSAL_H*/
|
@ -1028,6 +1028,7 @@
|
|||||||
|
|
||||||
/*Vector graphic demo*/
|
/*Vector graphic demo*/
|
||||||
#define LV_USE_DEMO_VECTOR_GRAPHIC 0
|
#define LV_USE_DEMO_VECTOR_GRAPHIC 0
|
||||||
|
|
||||||
/*--END OF LV_CONF_H--*/
|
/*--END OF LV_CONF_H--*/
|
||||||
|
|
||||||
#endif /*LV_CONF_H*/
|
#endif /*LV_CONF_H*/
|
||||||
|
@ -27,6 +27,7 @@ extern "C" {
|
|||||||
#include "../misc/lv_log.h"
|
#include "../misc/lv_log.h"
|
||||||
#include "../misc/lv_style.h"
|
#include "../misc/lv_style.h"
|
||||||
#include "../misc/lv_timer.h"
|
#include "../misc/lv_timer.h"
|
||||||
|
#include "../osal/lv_os.h"
|
||||||
#include "../others/sysmon/lv_sysmon.h"
|
#include "../others/sysmon/lv_sysmon.h"
|
||||||
#include "../stdlib/builtin/lv_tlsf.h"
|
#include "../stdlib/builtin/lv_tlsf.h"
|
||||||
|
|
||||||
@ -210,6 +211,10 @@ typedef struct _lv_global_t {
|
|||||||
struct _lv_nuttx_ctx_t * nuttx_ctx;
|
struct _lv_nuttx_ctx_t * nuttx_ctx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LV_USE_OS != LV_OS_NONE
|
||||||
|
lv_mutex_t lv_general_mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
void * user_data;
|
void * user_data;
|
||||||
} lv_global_t;
|
} lv_global_t;
|
||||||
|
|
||||||
|
@ -3349,6 +3349,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------
|
/*----------------------------------
|
||||||
* End of parsing lv_conf_template.h
|
* End of parsing lv_conf_template.h
|
||||||
-----------------------------------*/
|
-----------------------------------*/
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "draw/lv_draw.h"
|
#include "draw/lv_draw.h"
|
||||||
#include "misc/lv_async.h"
|
#include "misc/lv_async.h"
|
||||||
#include "misc/lv_fs.h"
|
#include "misc/lv_fs.h"
|
||||||
|
#include "osal/lv_os_private.h"
|
||||||
|
|
||||||
#if LV_USE_DRAW_VGLITE
|
#if LV_USE_DRAW_VGLITE
|
||||||
#include "draw/nxp/vglite/lv_draw_vglite.h"
|
#include "draw/nxp/vglite/lv_draw_vglite.h"
|
||||||
#endif
|
#endif
|
||||||
@ -160,6 +162,8 @@ void lv_init(void)
|
|||||||
lv_profiler_builtin_init(&profiler_config);
|
lv_profiler_builtin_init(&profiler_config);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
lv_os_init();
|
||||||
|
|
||||||
_lv_timer_core_init();
|
_lv_timer_core_init();
|
||||||
|
|
||||||
_lv_fs_init();
|
_lv_fs_init();
|
||||||
|
@ -78,6 +78,8 @@ LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LV_PROFILER_BEGIN;
|
LV_PROFILER_BEGIN;
|
||||||
|
lv_lock();
|
||||||
|
|
||||||
uint32_t handler_start = lv_tick_get();
|
uint32_t handler_start = lv_tick_get();
|
||||||
|
|
||||||
if(handler_start == 0) {
|
if(handler_start == 0) {
|
||||||
@ -139,7 +141,10 @@ LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
|
|||||||
state_p->already_running = false; /*Release the mutex*/
|
state_p->already_running = false; /*Release the mutex*/
|
||||||
|
|
||||||
LV_TRACE_TIMER("finished (%" LV_PRIu32 " ms until the next timer call)", time_until_next);
|
LV_TRACE_TIMER("finished (%" LV_PRIu32 " ms until the next timer call)", time_until_next);
|
||||||
|
lv_unlock();
|
||||||
|
|
||||||
LV_PROFILER_END;
|
LV_PROFILER_END;
|
||||||
|
|
||||||
return time_until_next;
|
return time_until_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
71
src/osal/lv_os.c
Normal file
71
src/osal/lv_os.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_os.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
#include "lv_os.h"
|
||||||
|
#include "lv_os_private.h"
|
||||||
|
#include "../core/lv_global.h"
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
#define lv_general_mutex LV_GLOBAL_DEFAULT()->lv_general_mutex
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC VARIABLES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
void lv_os_init(void)
|
||||||
|
{
|
||||||
|
#if LV_USE_OS != LV_OS_NONE
|
||||||
|
lv_mutex_init(&lv_general_mutex);
|
||||||
|
#endif /*LV_USE_OS != LV_OS_NONE*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void lv_lock(void)
|
||||||
|
{
|
||||||
|
#if LV_USE_OS != LV_OS_NONE
|
||||||
|
lv_mutex_lock(&lv_general_mutex);
|
||||||
|
#endif /*LV_USE_OS != LV_OS_NONE*/
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_result_t lv_lock_isr(void)
|
||||||
|
{
|
||||||
|
#if LV_USE_OS != LV_OS_NONE
|
||||||
|
return lv_mutex_lock_isr(&lv_general_mutex);
|
||||||
|
#else /*LV_USE_OS != LV_OS_NONE*/
|
||||||
|
return LV_RESULT_OK;
|
||||||
|
#endif /*LV_USE_OS != LV_OS_NONE*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void lv_unlock(void)
|
||||||
|
{
|
||||||
|
#if LV_USE_OS != LV_OS_NONE
|
||||||
|
lv_mutex_unlock(&lv_general_mutex);
|
||||||
|
#endif /*LV_USE_OS != LV_OS_NONE*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* STATIC FUNCTIONS
|
||||||
|
**********************/
|
||||||
|
|
@ -145,6 +145,29 @@ lv_result_t lv_thread_sync_signal(lv_thread_sync_t * sync);
|
|||||||
*/
|
*/
|
||||||
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync);
|
lv_result_t lv_thread_sync_delete(lv_thread_sync_t * sync);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock LVGL's general mutex.
|
||||||
|
* LVGL is not thread safe, so a mutex is used to avoid executing multiple LVGL functions at the same time
|
||||||
|
* from different threads. It shall be called when calling LVGL functions from threads
|
||||||
|
* different than lv_timer_handler's thread. It doesn't need to be called in LVGL events because
|
||||||
|
* they are called from lv_timer_handler().
|
||||||
|
* It is called internally in lv_timer_handler().
|
||||||
|
*/
|
||||||
|
void lv_lock(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `lv_lock()` but can be called from an interrupt.
|
||||||
|
* @return LV_RESULT_OK: success; LV_RESULT_INVALID: failure
|
||||||
|
*/
|
||||||
|
lv_result_t lv_lock_isr(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pair of `lv_lock()` and `lv_lock_isr()`.
|
||||||
|
* It unlocks LVGL general mutex.
|
||||||
|
* It is called internally in lv_timer_handler().
|
||||||
|
*/
|
||||||
|
void lv_unlock(void);
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
**********************/
|
**********************/
|
||||||
|
47
src/osal/lv_os_private.h
Normal file
47
src/osal/lv_os_private.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* @file lv_os_private.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LV_OS_PRIVATE_H
|
||||||
|
#define LV_OS_PRIVATE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* OS OPTIONS
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* INCLUDES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DEFINES
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* TYPEDEFS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* GLOBAL PROTOTYPES
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the OS layer
|
||||||
|
*/
|
||||||
|
void lv_os_init(void);
|
||||||
|
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* MACROS
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /*extern "C"*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*LV_OS_PRIVATE_H*/
|
Loading…
x
Reference in New Issue
Block a user