From 172aa55cdb1d757c0f448b68fe067d9644e34243 Mon Sep 17 00:00:00 2001 From: Ivan <35629915+zmeiresearch@users.noreply.github.com> Date: Mon, 13 May 2024 21:07:35 +0300 Subject: [PATCH] Update to LVGL9.1 (#64) * Update PlatformIO demo to LVGL9.1 * Update ci.yml Trying to fix a ``` Run actions/setup-python@v1 Error: Version 3.x with arch x64 not found ``` failure on MacOS * Add a build script that automatically tries to adjust SDL2 include and library paths. Fixes compilation failure on MacOS 14 --- .github/workflows/ci.yml | 3 +- hal/sdl2/app_hal.c | 74 +++++++++++++--------------------- hal/stm32f429_disco/tft.c | 74 ++++++++++++++++++++++------------ hal/stm32f429_disco/touchpad.c | 12 +++--- platformio.ini | 18 +++------ support/sdl2_paths.py | 27 +++++++++++++ 6 files changed, 116 insertions(+), 92 deletions(-) create mode 100644 support/sdl2_paths.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc2e841..461d247 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,7 @@ name: CI on: push: pull_request: + workflow_dispatch: schedule: - cron: '0 0 * * 3' @@ -61,7 +62,7 @@ jobs: HOMEBREW_NO_AUTO_UPDATE=1 brew install sdl2 - uses: actions/checkout@v2 - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v5 - name: Install PlatformIO run: | diff --git a/hal/sdl2/app_hal.c b/hal/sdl2/app_hal.c index 490dbf2..392e344 100644 --- a/hal/sdl2/app_hal.c +++ b/hal/sdl2/app_hal.c @@ -1,29 +1,26 @@ #include #define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/ #include -#include "display/monitor.h" -#include "indev/mouse.h" -#include "indev/mousewheel.h" -#include "indev/keyboard.h" -#include "sdl/sdl.h" +#include "drivers/sdl/lv_sdl_mouse.h" +#include "drivers/sdl/lv_sdl_mousewheel.h" +#include "drivers/sdl/lv_sdl_keyboard.h" -/** - * A task to measure the elapsed time for LittlevGL - * @param data unused - * @return never return - */ -static int tick_thread(void * data) -{ - (void)data; - while(1) { - SDL_Delay(5); /*Sleep for 5 millisecond*/ - lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/ - } - return 0; +static lv_display_t *lvDisplay; +static lv_indev_t *lvMouse; +static lv_indev_t *lvMouseWheel; +static lv_indev_t *lvKeyboard; + + +#if LV_USE_LOG != 0 +static void lv_log_print_g_cb(lv_log_level_t level, const char * buf) +{ + LV_UNUSED(level); + LV_UNUSED(buf); } +#endif void hal_setup(void) @@ -34,43 +31,28 @@ void hal_setup(void) setenv("DBUS_FATAL_WARNINGS", "0", 1); #endif + #if LV_USE_LOG != 0 + lv_log_register_print_cb(lv_log_print_g_cb); + #endif + /* Add a display * Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/ - static lv_disp_draw_buf_t disp_buf; - static lv_color_t buf[SDL_HOR_RES * 10]; /*Declare a buffer for 10 lines*/ - lv_disp_draw_buf_init(&disp_buf, buf, NULL, SDL_HOR_RES * 10); /*Initialize the display buffer*/ - - static lv_disp_drv_t disp_drv; - lv_disp_drv_init(&disp_drv); /*Basic initialization*/ - disp_drv.flush_cb = sdl_display_flush; /*Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing)*/ - disp_drv.draw_buf = &disp_buf; - disp_drv.hor_res = SDL_HOR_RES; - disp_drv.ver_res = SDL_VER_RES; - //disp_drv.disp_fill = monitor_fill; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/ - //disp_drv.disp_map = monitor_map; /*Used when `LV_VDB_SIZE == 0` in lv_conf.h (unbuffered drawing)*/ - lv_disp_drv_register(&disp_drv); - - /* Add the mouse as input device - * Use the 'mouse' driver which reads the PC's mouse*/ - static lv_indev_drv_t indev_drv; - lv_indev_drv_init(&indev_drv); /*Basic initialization*/ - indev_drv.type = LV_INDEV_TYPE_POINTER; - indev_drv.read_cb = sdl_mouse_read; /*This function will be called periodically (by the library) to get the mouse position and state*/ - lv_indev_drv_register(&indev_drv); - - sdl_init(); - /* Tick init. - * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed - * Create an SDL thread to do this*/ - SDL_CreateThread(tick_thread, "tick", NULL); + lvDisplay = lv_sdl_window_create(SDL_HOR_RES, SDL_VER_RES); + lvMouse = lv_sdl_mouse_create(); + lvMouseWheel = lv_sdl_mousewheel_create(); + lvKeyboard = lv_sdl_keyboard_create(); } void hal_loop(void) { + Uint32 lastTick = SDL_GetTicks(); while(1) { SDL_Delay(5); - lv_task_handler(); + Uint32 current = SDL_GetTicks(); + lv_tick_inc(current - lastTick); // Update the tick timer. Tick is new for LVGL 9 + lastTick = current; + lv_timer_handler(); // Update the UI- } } diff --git a/hal/stm32f429_disco/tft.c b/hal/stm32f429_disco/tft.c index 07798d2..60360af 100644 --- a/hal/stm32f429_disco/tft.c +++ b/hal/stm32f429_disco/tft.c @@ -9,6 +9,7 @@ #include #include "tft.h" +#include #include "stm32f4xx.h" #include "stm32f429i_discovery_lcd.h" #include "ili9341.h" @@ -19,6 +20,8 @@ #define SDRAM_BANK_ADDR ((uint32_t)0xD0000000) +#define LV_BUFFER_SIZE (TFT_HOR_RES * TFT_VER_RES / 8 * (LV_COLOR_DEPTH / 8)) + #define DMA_STREAM DMA2_Stream0 #define DMA_CHANNEL DMA_CHANNEL_0 #define DMA_STREAM_IRQ DMA2_Stream0_IRQn @@ -32,7 +35,7 @@ * STATIC PROTOTYPES **********************/ -static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p); +static void tft_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map); /********************** * STATIC VARIABLES @@ -55,18 +58,22 @@ static void DMA_TransferComplete(DMA_HandleTypeDef *han); static void DMA_TransferError(DMA_HandleTypeDef *han); DMA_HandleTypeDef DmaHandle; -static lv_disp_drv_t disp_drv; +static lv_display_t * lvDisplay; + +static uint8_t lvBuffer[LV_BUFFER_SIZE]; static int32_t x1_flush; static int32_t y1_flush; static int32_t x2_flush; static int32_t y2_fill; static int32_t y_fill_act; -static const lv_color_t *buf_to_flush; +static const uint8_t *buf_to_flush; /********************** * MACROS **********************/ + + /********************** * GLOBAL FUNCTIONS **********************/ @@ -75,32 +82,47 @@ static const lv_color_t *buf_to_flush; */ void tft_init(void) { - static lv_color_t disp_buf1[TFT_HOR_RES * 40]; - static lv_disp_draw_buf_t buf; - lv_disp_draw_buf_init(&buf, disp_buf1, NULL, TFT_HOR_RES * 40); - - lv_disp_drv_init(&disp_drv); - - BSP_LCD_Init(); - BSP_LCD_LayerDefaultInit(0, (uint32_t)my_fb); - HAL_LTDC_SetPixelFormat(&LtdcHandler, LTDC_PIXEL_FORMAT_RGB565, 0); - DMA_Config(); - disp_drv.draw_buf = &buf; - disp_drv.flush_cb = tft_flush; - disp_drv.hor_res = TFT_HOR_RES; - disp_drv.ver_res = TFT_VER_RES; -#if TFT_USE_GPU != 0 - DMA2D_Config(); - disp_drv.gpu_blend_cb = gpu_mem_blend; - disp_drv.gpu_fill_cb = gpu_mem_fill; -#endif - lv_disp_drv_register(&disp_drv); + #if LV_USE_LOG != 0 + lv_log_register_print_cb(lv_log_print_g_cb); + #endif + + lvDisplay = lv_display_create(TFT_HOR_RES, TFT_VER_RES); + if (lvDisplay) + { + BSP_LCD_Init(); + BSP_LCD_LayerDefaultInit(0, (uint32_t)my_fb); + HAL_LTDC_SetPixelFormat(&LtdcHandler, LTDC_PIXEL_FORMAT_RGB565, 0); + DMA_Config(); + + lv_display_set_color_format(lvDisplay, LV_COLOR_FORMAT_RGB565); + lv_display_set_flush_cb(lvDisplay, tft_flush); + lv_display_set_buffers(lvDisplay, lvBuffer, NULL, LV_BUFFER_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL); + + #if TFT_USE_GPU != 0 + DMA2D_Config(); + disp_drv.gpu_blend_cb = gpu_mem_blend; + disp_drv.gpu_fill_cb = gpu_mem_fill; + #endif + } } /********************** * STATIC FUNCTIONS **********************/ +/** + * LVGL Log print callback + * @param level log message level + * @param buf string to print + */ +#if LV_USE_LOG != 0 +static void lv_log_print_g_cb(lv_log_level_t level, const char * buf) +{ + LV_UNUSED(level); + LV_UNUSED(buf); +} +#endif + /** * Flush a color buffer * @param x1 left coordinate of the rectangle @@ -109,7 +131,7 @@ void tft_init(void) * @param y2 bottom coordinate of the rectangle * @param color_p pointer to an array of colors */ -static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) +static void tft_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) { /*Return if the area is out the screen*/ if (area->x2 < 0) @@ -132,7 +154,7 @@ static void tft_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *col x2_flush = act_x2; y2_fill = act_y2; y_fill_act = act_y1; - buf_to_flush = color_p; + buf_to_flush = px_map; /*##-7- Start the DMA transfer using the interrupt mode #*/ /* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */ @@ -197,7 +219,7 @@ static void DMA_TransferComplete(DMA_HandleTypeDef *han) if (y_fill_act > y2_fill) { - lv_disp_flush_ready(&disp_drv); + lv_disp_flush_ready(lvDisplay); } else { diff --git a/hal/stm32f429_disco/touchpad.c b/hal/stm32f429_disco/touchpad.c index b16d581..7aeae08 100644 --- a/hal/stm32f429_disco/touchpad.c +++ b/hal/stm32f429_disco/touchpad.c @@ -24,7 +24,7 @@ /********************** * STATIC PROTOTYPES **********************/ -static void touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t *data); +static void touchpad_read(lv_indev_t * drv, lv_indev_data_t *data); static bool touchpad_get_xy(int16_t *x, int16_t *y); /********************** @@ -47,11 +47,9 @@ void touchpad_init(void) stmpe811_Init(TS_I2C_ADDRESS); stmpe811_TS_Start(TS_I2C_ADDRESS); - lv_indev_drv_t indev_drv; - lv_indev_drv_init(&indev_drv); - indev_drv.read_cb = touchpad_read; - indev_drv.type = LV_INDEV_TYPE_POINTER; - lv_indev_drv_register(&indev_drv); + lv_indev_t * indev_drv = lv_indev_create(); + lv_indev_set_read_cb(indev_drv, touchpad_read); + lv_indev_set_type(indev_drv, LV_INDEV_TYPE_POINTER); } /********************** @@ -65,7 +63,7 @@ void touchpad_init(void) * @param y put the y coordinate here * @return true: the device is pressed, false: released */ -static void touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t *data) +static void touchpad_read(lv_indev_t * dev, lv_indev_data_t *data) { static int16_t last_x = 0; static int16_t last_y = 0; diff --git a/platformio.ini b/platformio.ini index e515483..153fee1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,14 +22,15 @@ build_flags = ; Add more defines below to overide lvgl:/src/lv_conf_simple.h lib_deps = ; Use direct URL, because package registry is unstable - ;lvgl@~7.11.0 - lvgl=https://github.com/lvgl/lvgl/archive/refs/tags/v8.2.0.zip + lvgl@9.1 lib_archive = false [env:emulator_64bits] platform = native@^1.1.3 -extra_scripts = support/sdl2_build_extra.py +extra_scripts = + pre:support/sdl2_paths.py ; Tries to find SDL2 include and lib paths on your system - specifically for MacOS w/ Homebrew + post:support/sdl2_build_extra.py build_flags = ${env.build_flags} ; -D LV_LOG_LEVEL=LV_LOG_LEVEL_INFO @@ -40,25 +41,18 @@ build_flags = ; SDL drivers options -D LV_LVGL_H_INCLUDE_SIMPLE -D LV_DRV_NO_CONF - -D USE_SDL + -D LV_USE_SDL -D SDL_HOR_RES=480 -D SDL_VER_RES=320 -D SDL_ZOOM=1 - -D SDL_INCLUDE_PATH="\"SDL2/SDL.h\"" + -D LV_SDL_INCLUDE_PATH="\"SDL2/SDL.h\"" ; LVGL memory options, setup for the demo to run properly -D LV_MEM_CUSTOM=1 -D LV_MEM_SIZE="(128U * 1024U)" - - ; SDL2 includes, uncomment the next two lines on MAC OS if you intalled sdl via homebrew - ; !find /opt/homebrew/Cellar/sdl2 -name "include" | sed "s/^/-I /" - ; !find /opt/homebrew/Cellar/sdl2 -name "libSDL2.a" | xargs dirname | sed "s/^/-L /" lib_deps = ${env.lib_deps} - ; Use direct URL, because package registry is unstable - ;lv_drivers@~7.9.0 - lv_drivers=https://github.com/lvgl/lv_drivers/archive/refs/tags/v8.2.0.zip build_src_filter = +<*> +<../hal/sdl2> diff --git a/support/sdl2_paths.py b/support/sdl2_paths.py new file mode 100644 index 0000000..be6aa94 --- /dev/null +++ b/support/sdl2_paths.py @@ -0,0 +1,27 @@ +Import("env") +import sys +import os +import glob + +if sys.platform.startswith("darwin"): + #sdl_include_path = !find /opt/homebrew/Cellar/sdl2 -name "include" | sed "s/^/-I /" + sdl_include = glob.glob("/opt/homebrew/Cellar/sdl2/*/include", recursive=True) + if sdl_include: + print(f"Found Homebrew SDL include path: {sdl_include[0]}") + env.Append( + CPPPATH=sdl_include[0] + ) + sdl_lib = glob.glob("/opt/homebrew/Cellar/sdl2/**/libSDL2.a", recursive=True) + if sdl_lib: + print(f"Found Homebrew SDL lib path: {sdl_lib[0]}") + env.Append( + LIBPATH=os.path.dirname(sdl_lib[0]) + ) + + +#breakpoint() + +#print('NewENV=====================================') +#print(env.Dump()) +#print('DefaultENV=====================================') +#print(DefaultEnvironment().Dump())