Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(demos): add demo for the OSAL #6182

Merged
merged 2 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions docs/porting/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ Operating system and interrupts
LVGL is **not thread-safe** by default.

However, in the following conditions it's valid to call LVGL related
functions: - In *events*. Learn more in :ref:`events`. -
In *lv_timer*. Learn more in :ref:`timer`.
functions:

- In *events*. Learn more in :ref:`events`.
- In *lv_timer*. Learn more in :ref:`timer`.

Tasks and threads
-----------------
Expand All @@ -20,35 +22,42 @@ 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
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:

.. code:: c

static mutex_t lvgl_mutex;

void lvgl_thread(void)
{
while(1) {
uint32_t time_till_next;
mutex_lock(&lvgl_mutex);
time_till_next = lv_timer_handler();
mutex_unlock(&lvgl_mutex);
time_till_next = lv_timer_handler(); /*lv_lock/lv_unlock is called internally*/
thread_sleep(time_till_next); /* sleep for a while */
}
}

void other_thread(void)
{
/* 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());
mutex_unlock(&lvgl_mutex);
lv_unlock();

while(1) {
mutex_lock(&lvgl_mutex);
lv_lock();
/* change to the next image */
lv_image_set_src(img, next_image);
mutex_unlock(&lvgl_mutex);
lv_unlock();
thread_sleep(2000);
}
}
Expand Down
1 change: 1 addition & 0 deletions examples/lv_examples.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extern "C" {
#include "layouts/lv_example_layout.h"
#include "libs/lv_example_libs.h"
#include "others/lv_example_others.h"
#include "porting/osal/lv_example_osal.h"
#include "scroll/lv_example_scroll.h"
#include "styles/lv_example_style.h"
#include "widgets/lv_example_widgets.h"
Expand Down
95 changes: 95 additions & 0 deletions examples/porting/osal/lv_example_osal.c
Original file line number Diff line number Diff line change
@@ -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 changes: 38 additions & 0 deletions examples/porting/osal/lv_example_osal.h
Original file line number Diff line number Diff line change
@@ -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*/
1 change: 1 addition & 0 deletions lv_conf_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,7 @@

/*Vector graphic demo*/
#define LV_USE_DEMO_VECTOR_GRAPHIC 0

/*--END OF LV_CONF_H--*/

#endif /*LV_CONF_H*/
Expand Down
5 changes: 5 additions & 0 deletions src/core/lv_global.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extern "C" {
#include "../misc/lv_log.h"
#include "../misc/lv_style.h"
#include "../misc/lv_timer.h"
#include "../osal/lv_os.h"
#include "../others/sysmon/lv_sysmon.h"
#include "../stdlib/builtin/lv_tlsf.h"

Expand Down Expand Up @@ -212,6 +213,10 @@ typedef struct _lv_global_t {
struct _lv_nuttx_ctx_t * nuttx_ctx;
#endif

#if LV_USE_OS != LV_OS_NONE
lv_mutex_t lv_general_mutex;
#endif

void * user_data;
} lv_global_t;

Expand Down
1 change: 1 addition & 0 deletions src/lv_conf_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3321,6 +3321,7 @@
#endif



/*----------------------------------
* End of parsing lv_conf_template.h
-----------------------------------*/
Expand Down
4 changes: 4 additions & 0 deletions src/lv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "draw/lv_draw.h"
#include "misc/lv_async.h"
#include "misc/lv_fs.h"
#include "osal/lv_os_private.h"

#if LV_USE_DRAW_VGLITE
#include "draw/nxp/vglite/lv_draw_vglite.h"
#endif
Expand Down Expand Up @@ -160,6 +162,8 @@ void lv_init(void)
lv_profiler_builtin_init(&profiler_config);
#endif

lv_os_init();

_lv_timer_core_init();

_lv_fs_init();
Expand Down
5 changes: 5 additions & 0 deletions src/misc/lv_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
}

LV_PROFILER_BEGIN;
lv_lock();

uint32_t handler_start = lv_tick_get();

if(handler_start == 0) {
Expand Down Expand Up @@ -139,7 +141,10 @@ LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
state_p->already_running = false; /*Release the mutex*/

LV_TRACE_TIMER("finished (%" LV_PRIu32 " ms until the next timer call)", time_until_next);
lv_unlock();

LV_PROFILER_END;

return time_until_next;
}

Expand Down
71 changes: 71 additions & 0 deletions src/osal/lv_os.c
Original file line number Diff line number Diff line change
@@ -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
**********************/

23 changes: 23 additions & 0 deletions src/osal/lv_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,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);

/**
* 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
**********************/
Expand Down
Loading
Loading