From 4e8282a64b95e1d017f71a8084d438e753e6e778 Mon Sep 17 00:00:00 2001 From: Timo Niemann Date: Wed, 1 Jul 2026 13:03:58 +0200 Subject: [PATCH] + rearranged files + improved ui log + added image browser - image loading fails at the moment - arrangement of ui in image browser not checked --- README.md | 22 +++ main/CMakeLists.txt | 4 +- main/{ => include}/lcd/lcd.h | 0 main/include/lcd/ui.h | 12 ++ main/{ => include}/sd/sd.h | 0 main/lcd/lcd.c | 19 +-- main/lcd/ui.c | 294 +++++++++++++++++++++++++++++++++++ main/main.c | 71 ++------- main/sd/sd.c | 6 +- sdkconfig | 10 +- 10 files changed, 358 insertions(+), 80 deletions(-) create mode 100644 README.md rename main/{ => include}/lcd/lcd.h (100%) create mode 100644 main/include/lcd/ui.h rename main/{ => include}/sd/sd.h (100%) create mode 100644 main/lcd/ui.c diff --git a/README.md b/README.md new file mode 100644 index 0000000..5794677 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# ESP32 Image Viewer on LCD from SD + +## Introduction + +This project utilizes an ELECROW ESP32 Display to read images from SD card and display them. + +## Usage + +Insert SD card into the TF slot on the board. Flash the project to the ESP32. Use touch to switch between UI-Log and Image-Browser. + +## Hardware + +- ELECROW ESP32 5" HMI Display (800x480) RGB TFT Touchscreen compatible with LVGL +- USB-C cable to flash firmware +- optional but recommended: + - SD card + +## Software + +- ESP-IDF +- optional but recommended: + - VS Code with ESP-IDF extension \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 348a222..7bab7b2 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ -idf_component_register(SRCS main.c lcd/lcd.c sd/sd.c +idf_component_register(SRCS main.c lcd/lcd.c sd/sd.c lcd/ui.c PRIV_REQUIRES spi_flash esp_psram esp_lcd esp_driver_gpio esp_driver_i2c esp_driver_sdspi esp_driver_spi esp_lvgl_port esp_lcd_touch_gt911 fatfs sdmmc - INCLUDE_DIRS ".") + INCLUDE_DIRS "." "include") diff --git a/main/lcd/lcd.h b/main/include/lcd/lcd.h similarity index 100% rename from main/lcd/lcd.h rename to main/include/lcd/lcd.h diff --git a/main/include/lcd/ui.h b/main/include/lcd/ui.h new file mode 100644 index 0000000..9b20810 --- /dev/null +++ b/main/include/lcd/ui.h @@ -0,0 +1,12 @@ +#pragma once + +typedef enum { + UI_VIEW_LOG, + UI_VIEW_IMAGE_BROWSER, +} ui_view_t; + +void ui_log_append(const char *text); +void create_log_ui(void); +void create_image_browser_ui(void); + +void ui_switch_view_to(ui_view_t view); \ No newline at end of file diff --git a/main/sd/sd.h b/main/include/sd/sd.h similarity index 100% rename from main/sd/sd.h rename to main/include/sd/sd.h diff --git a/main/lcd/lcd.c b/main/lcd/lcd.c index 344c0c5..95e4971 100644 --- a/main/lcd/lcd.c +++ b/main/lcd/lcd.c @@ -71,8 +71,7 @@ static esp_lcd_touch_handle_t touch_handle; static lv_display_t *lvgl_display; static lv_indev_t *lvgl_touch_indev; -static esp_err_t init_backlight(void) -{ +static esp_err_t init_backlight(void){ const gpio_config_t backlight_config = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = 1ULL << LCD_GPIO_BACKLIGHT, @@ -83,17 +82,16 @@ static esp_err_t init_backlight(void) return ESP_OK; } -static esp_err_t probe_gt911_address(i2c_master_bus_handle_t i2c_handle, uint32_t *dev_addr) -{ +static esp_err_t probe_gt911_address(i2c_master_bus_handle_t i2c_handle, uint32_t *dev_addr){ const uint8_t addresses[] = { ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP, }; - for (size_t address_index = 0; address_index < sizeof(addresses) / sizeof(addresses[0]); address_index++) { + for(size_t address_index = 0; address_index < sizeof(addresses) / sizeof(addresses[0]); address_index++){ const uint8_t address = addresses[address_index]; const esp_err_t probe_ret = i2c_master_probe(i2c_handle, address, 100); - if (probe_ret == ESP_OK) { + if(probe_ret == ESP_OK){ *dev_addr = address; ESP_LOGI(TAG, "GT911 found at I2C address 0x%02x", address); return ESP_OK; @@ -257,7 +255,7 @@ static esp_err_t init_lvgl(void){ lv_display_set_rotation(lvgl_display, LCD_LVGL_ROTATION); ESP_LOGI(TAG, "LVGL display rotation set to %d", LCD_LVGL_ROTATION); - if (touch_handle) { + if(touch_handle){ const lvgl_port_touch_cfg_t touch_config = { .disp = lvgl_display, .handle = touch_handle, @@ -265,9 +263,8 @@ static esp_err_t init_lvgl(void){ lvgl_touch_indev = lvgl_port_add_touch(&touch_config); ESP_RETURN_ON_FALSE(lvgl_touch_indev, ESP_FAIL, TAG, "LVGL touch add failed"); ESP_LOGI(TAG, "LVGL touch input ready"); - } else { - ESP_LOGW(TAG, "LVGL touch input disabled"); } + else ESP_LOGW(TAG, "LVGL touch input disabled"); ESP_LOGI(TAG, "LVGL ready"); @@ -277,9 +274,7 @@ static esp_err_t init_lvgl(void){ esp_err_t lcd_init(void){ ESP_RETURN_ON_ERROR(init_rgb_panel(), TAG, "LCD panel init failed"); const esp_err_t touch_ret = init_touch(); - if (touch_ret != ESP_OK) { - ESP_LOGW(TAG, "Continuing without touch: %s", esp_err_to_name(touch_ret)); - } + if(touch_ret != ESP_OK) ESP_LOGW(TAG, "Continuing without touch: %s", esp_err_to_name(touch_ret)); return init_lvgl(); } diff --git a/main/lcd/ui.c b/main/lcd/ui.c new file mode 100644 index 0000000..0cd2eb0 --- /dev/null +++ b/main/lcd/ui.c @@ -0,0 +1,294 @@ +#include +#include +#include +#include + +#include "lvgl.h" +#include "lcd/lcd.h" +#include "esp_lvgl_port.h" +#include "esp_log.h" +#include "lcd/ui.h" +#include "sd/sd.h" + +#define UI_LOG_MAX_LINES 41 +#define UI_IMAGE_PATH_PREFIX "A:/sdcard/" +#define UI_IMAGE_PATH_MAX_LENGTH 160 +#define UI_IMAGE_INFO_BAR_HEIGHT 42 + +static lv_obj_t *log_textarea = NULL; +static lv_obj_t *image_tileview = NULL; +static size_t log_line_length = 0; +static size_t image_browser_image_count = 0; +static size_t image_browser_current_index = 0; +static const char *TAG = "ui"; + +static ui_view_t current_view = UI_VIEW_LOG; + +static void ui_reset_active_screen_locked(void){ + lv_obj_t *screen = lv_screen_active(); + lv_obj_clean(screen); + log_textarea = NULL; + image_tileview = NULL; + image_browser_image_count = 0; + image_browser_current_index = 0; +} + +static void ui_image_browser_set_index_locked(size_t image_index, lv_anim_enable_t anim_en){ + if(image_tileview == NULL || image_browser_image_count == 0) return; + + image_browser_current_index = image_index % image_browser_image_count; + lv_tileview_set_tile_by_index(image_tileview, 0, (uint32_t)image_browser_current_index, anim_en); +} + +static void ui_image_browser_touch_event_cb(lv_event_t *event){ + if(lv_event_get_code(event) != LV_EVENT_CLICKED) return; + ui_image_browser_set_index_locked(image_browser_current_index + 1, LV_ANIM_ON); +} + +static void ui_image_browser_value_changed_event_cb(lv_event_t *event){ + if(lv_event_get_code(event) != LV_EVENT_VALUE_CHANGED) return; + + lv_obj_t *tileview = lv_event_get_current_target(event); + lv_obj_t *active_tile = lv_tileview_get_tile_active(tileview); + if(active_tile == NULL) return; + + image_browser_current_index = (size_t)(uintptr_t)lv_obj_get_user_data(active_tile); +} + +static bool ui_char_equals_ignore_case(char left_char, char right_char){ + if(left_char >= 'A' && left_char <= 'Z') left_char = (char)(left_char + ('a' - 'A')); + if(right_char >= 'A' && right_char <= 'Z') right_char = (char)(right_char + ('a' - 'A')); + return left_char == right_char; +} + +static bool ui_has_extension(const char *filename, const char *extension){ + if(filename == NULL || extension == NULL) return false; + + const size_t filename_length = strlen(filename); + const size_t extension_length = strlen(extension); + if(filename_length < extension_length) return false; + + const char *filename_extension = filename + filename_length - extension_length; + for(size_t char_index = 0; char_index < extension_length; char_index++){ + if(!ui_char_equals_ignore_case(filename_extension[char_index], extension[char_index])) return false; + } + + return true; +} + +static bool ui_is_image_file(const char *filename){ + return ui_has_extension(filename, ".bmp") || + ui_has_extension(filename, ".jpg") || + ui_has_extension(filename, ".jpeg") || + ui_has_extension(filename, ".png"); +} + +static size_t ui_count_sd_images(void){ + const size_t file_count = sd_get_file_count(); + size_t image_count = 0; + + for(size_t file_index = 0; file_index < file_count; file_index++){ + const char *filename = sd_get_next_file(); + if(ui_is_image_file(filename)) image_count++; + } + + return image_count; +} + +static void ui_create_empty_image_browser_locked(lv_obj_t *screen){ + lv_obj_t *label = lv_label_create(screen); + lv_label_set_text(label, "No images found on SD card"); + lv_obj_set_style_text_color(label, lv_color_hex(0xdde7ef), 0); + lv_obj_center(label); +} + +static lv_dir_t ui_get_tile_directions(size_t image_index, size_t image_count){ + if(image_count <= 1) return LV_DIR_NONE; + if(image_index == 0) return LV_DIR_BOTTOM; + if(image_index + 1 == image_count) return LV_DIR_TOP; + return (lv_dir_t)(LV_DIR_TOP | LV_DIR_BOTTOM); +} + +static void ui_create_image_tile_locked(lv_obj_t *tile, const char *filename, size_t image_index, size_t image_count){ + lv_obj_set_style_bg_color(tile, lv_color_hex(0x070a0d), 0); + lv_obj_set_style_pad_all(tile, 0, 0); + lv_obj_remove_flag(tile, LV_OBJ_FLAG_SCROLLABLE); + + lv_obj_t *image_frame = lv_obj_create(tile); + lv_obj_set_size(image_frame, LV_PCT(100), LV_PCT(100)); + lv_obj_set_style_bg_color(image_frame, lv_color_black(), 0); + lv_obj_set_style_border_width(image_frame, 0, 0); + lv_obj_set_style_radius(image_frame, 0, 0); + lv_obj_set_style_pad_all(image_frame, 0, 0); + lv_obj_remove_flag(image_frame, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_center(image_frame); + + lv_obj_t *image = lv_image_create(image_frame); + lv_obj_set_size(image, LV_PCT(100), LV_PCT(100)); + lv_image_set_inner_align(image, LV_IMAGE_ALIGN_CONTAIN); + + char image_source[UI_IMAGE_PATH_MAX_LENGTH]; + snprintf(image_source, sizeof(image_source), "%s%s", UI_IMAGE_PATH_PREFIX, filename); + lv_image_set_src(image, image_source); + lv_obj_center(image); + + lv_obj_t *info_bar = lv_obj_create(tile); + lv_obj_set_size(info_bar, LV_PCT(100), UI_IMAGE_INFO_BAR_HEIGHT); + lv_obj_align(info_bar, LV_ALIGN_BOTTOM_MID, 0, 0); + lv_obj_set_style_bg_color(info_bar, lv_color_hex(0x101418), 0); + lv_obj_set_style_bg_opa(info_bar, LV_OPA_80, 0); + lv_obj_set_style_border_width(info_bar, 0, 0); + lv_obj_set_style_radius(info_bar, 0, 0); + lv_obj_set_style_pad_hor(info_bar, 14, 0); + lv_obj_set_style_pad_ver(info_bar, 0, 0); + lv_obj_remove_flag(info_bar, LV_OBJ_FLAG_SCROLLABLE); + + lv_obj_t *caption = lv_label_create(info_bar); + lv_label_set_long_mode(caption, LV_LABEL_LONG_DOT); + lv_obj_set_width(caption, LV_PCT(100)); + lv_obj_set_style_text_color(caption, lv_color_hex(0xdde7ef), 0); + lv_label_set_text_fmt(caption, "%u/%u %s", (unsigned int)(image_index + 1), (unsigned int)image_count, filename); + lv_obj_center(caption); + + if(lv_image_get_src_width(image) <= 0 || lv_image_get_src_height(image) <= 0){ + lv_obj_t *error_label = lv_label_create(tile); + lv_label_set_text(error_label, "Image cannot be loaded"); + lv_obj_set_style_text_color(error_label, lv_color_hex(0xffd166), 0); + lv_obj_align(error_label, LV_ALIGN_CENTER, 0, -18); + } +} + +static void ui_create_image_browser_tiles_locked(size_t image_count){ + const size_t file_count = sd_get_file_count(); + size_t image_index = 0; + + for(size_t file_index = 0; file_index < file_count && image_index < image_count; file_index++){ + const char *filename = sd_get_next_file(); + if(!ui_is_image_file(filename)) continue; + + lv_obj_t *tile = lv_tileview_add_tile(image_tileview, 0, (uint32_t)image_index, ui_get_tile_directions(image_index, image_count)); + lv_obj_set_user_data(tile, (void *)(uintptr_t)image_index); + lv_obj_add_flag(tile, LV_OBJ_FLAG_CLICKABLE); + lv_obj_add_event_cb(tile, ui_image_browser_touch_event_cb, LV_EVENT_CLICKED, NULL); + ui_create_image_tile_locked(tile, filename, image_index, image_count); + image_index++; + } +} + +static void ui_log_delete_first_line(void){ + lvgl_port_lock(0); + size_t cursor_pos = lv_textarea_get_cursor_pos(log_textarea); + lv_textarea_set_cursor_pos(log_textarea, 0); + + while(1){ + const char *log_text = lv_textarea_get_text(log_textarea); + if(log_text[0] == '\0') break; + + char first_char = log_text[0]; + lv_textarea_delete_char_forward(log_textarea); + + if(first_char == '\n') break; + } + + lv_textarea_set_cursor_pos(log_textarea, cursor_pos); + + lvgl_port_unlock(); +} + +void ui_log_append(const char *text){ + if(log_textarea == NULL || text == NULL) return; + + lvgl_port_lock(0); + lv_textarea_add_text(log_textarea, text); + lv_textarea_add_text(log_textarea, "\n"); + lv_textarea_set_cursor_pos(log_textarea, LV_TEXTAREA_CURSOR_LAST); + lvgl_port_unlock(); + + log_line_length++; + + while(log_line_length > UI_LOG_MAX_LINES){ + ui_log_delete_first_line(); + log_line_length--; + } +} + +void create_log_ui(void){ + ESP_LOGI(TAG, "Creating log UI"); + lvgl_port_lock(0); + ui_reset_active_screen_locked(); + + lv_obj_t *screen = lv_screen_active(); + lv_obj_set_style_bg_color(screen, lv_color_hex(0x101418), 0); + + lv_obj_t *title = lv_label_create(screen); + lv_label_set_text(title, "SD Image Viewer"); + lv_obj_set_style_text_color(title, lv_color_white(), 0); + lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 14); + + if(log_textarea == NULL){ + log_textarea = lv_textarea_create(screen); + lv_obj_set_size(log_textarea, 440, 730); + lv_obj_align(log_textarea, LV_ALIGN_TOP_LEFT, 20, 40); + lv_textarea_set_one_line(log_textarea, false); + lv_textarea_set_cursor_click_pos(log_textarea, false); + lv_textarea_set_text(log_textarea, ""); + lv_obj_set_style_bg_color(log_textarea, lv_color_hex(0x182028), 0); + lv_obj_set_style_text_color(log_textarea, lv_color_hex(0xdde7ef), 0); + lv_obj_set_style_border_color(log_textarea, lv_color_hex(0x4b6478), 0); + lv_obj_set_style_radius(log_textarea, 4, 0); + lv_obj_set_style_pad_all(log_textarea, 12, 0); + } + + lvgl_port_unlock(); + + ui_log_append("Boot UI ready"); + current_view = UI_VIEW_LOG; + ESP_LOGI(TAG, "Log UI created"); +} + +void create_image_browser_ui(void){ + ESP_LOGI(TAG, "Creating image browser UI"); + const size_t image_count = ui_count_sd_images(); + + lvgl_port_lock(0); + ui_reset_active_screen_locked(); + + lv_obj_t *screen = lv_screen_active(); + lv_obj_set_style_bg_color(screen, lv_color_hex(0x070a0d), 0); + + if(image_count == 0) ui_create_empty_image_browser_locked(screen); + else{ + image_tileview = lv_tileview_create(screen); + lv_obj_set_size(image_tileview, LV_PCT(100), LV_PCT(100)); + lv_obj_set_style_bg_color(image_tileview, lv_color_hex(0x070a0d), 0); + lv_obj_set_style_border_width(image_tileview, 0, 0); + lv_obj_set_style_pad_all(image_tileview, 0, 0); + lv_obj_set_scrollbar_mode(image_tileview, LV_SCROLLBAR_MODE_OFF); + lv_obj_add_event_cb(image_tileview, ui_image_browser_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL); + image_browser_image_count = image_count; + + ui_create_image_browser_tiles_locked(image_count); + ui_image_browser_set_index_locked(0, LV_ANIM_OFF); + } + + current_view = UI_VIEW_IMAGE_BROWSER; + lvgl_port_unlock(); + + ESP_LOGI(TAG, "Image browser UI created with %u images", (unsigned int)image_count); +} + +void ui_switch_view_to(ui_view_t view){ + if(view == current_view) return; + + switch(view){ + case UI_VIEW_LOG: + create_log_ui(); + break; + case UI_VIEW_IMAGE_BROWSER: + create_image_browser_ui(); + break; + default: + ESP_LOGW(TAG, "Unknown UI view: %d", view); + break; + } +} \ No newline at end of file diff --git a/main/main.c b/main/main.c index 7930eb1..e8e9b67 100644 --- a/main/main.c +++ b/main/main.c @@ -1,67 +1,28 @@ #include "esp_check.h" #include "esp_log.h" -#include "esp_lvgl_port.h" -#include "lcd/lcd.h" #include "sd/sd.h" -#include "lvgl.h" +#include "lcd/lcd.h" +#include "lcd/ui.h" + +#include "freertos/FreeRTOS.h" static const char *TAG = "app"; -static lv_obj_t *log_textarea = NULL; -static void ui_log_append(const char *text) -{ - if(log_textarea == NULL || text == NULL) return; - - lvgl_port_lock(0); - lv_textarea_add_text(log_textarea, text); - lv_textarea_add_text(log_textarea, "\n"); - lv_textarea_set_cursor_pos(log_textarea, LV_TEXTAREA_CURSOR_LAST); - lvgl_port_unlock(); -} - -static void create_log_ui(void) -{ - lv_obj_t *screen = lv_screen_active(); - lv_obj_set_style_bg_color(screen, lv_color_hex(0x101418), 0); - - lv_obj_t *title = lv_label_create(screen); - lv_label_set_text(title, "SD Image Viewer"); - lv_obj_set_style_text_color(title, lv_color_white(), 0); - lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 14); - - log_textarea = lv_textarea_create(screen); - lv_obj_set_size(log_textarea, lv_pct(92), lv_pct(84)); - lv_obj_align(log_textarea, LV_ALIGN_BOTTOM_MID, 0, -14); - lv_textarea_set_one_line(log_textarea, false); - lv_textarea_set_cursor_click_pos(log_textarea, false); - lv_textarea_set_text(log_textarea, ""); - lv_obj_set_style_bg_color(log_textarea, lv_color_hex(0x182028), 0); - lv_obj_set_style_text_color(log_textarea, lv_color_hex(0xdde7ef), 0); - lv_obj_set_style_border_color(log_textarea, lv_color_hex(0x4b6478), 0); - lv_obj_set_style_radius(log_textarea, 4, 0); - lv_obj_set_style_pad_all(log_textarea, 12, 0); - - lv_textarea_add_text(log_textarea, "Boot UI ready\n"); - lv_textarea_set_cursor_pos(log_textarea, LV_TEXTAREA_CURSOR_LAST); -} - -void app_main(void) -{ +void app_main(void){ ESP_LOGI(TAG, "Start display application"); ESP_ERROR_CHECK(lcd_init()); ESP_LOGI(TAG, "Creating log UI"); - lvgl_port_lock(0); create_log_ui(); - lvgl_port_unlock(); ESP_LOGI(TAG, "Initializing SD card"); - ui_log_append("Initializing SD card..."); + ui_log_append("\nInitializing SD card..."); sd_init(); print_sd_card_info(); ui_log_append("SD initialization done"); ESP_LOGI(TAG, "SD card initialization complete"); + ui_log_append("\nListing files in root directory:"); size_t file_count = sd_get_file_count(); ESP_LOGI(TAG, "Found %d files in root directory", file_count); const char* filename = NULL; @@ -71,19 +32,13 @@ void app_main(void) char line[96]; snprintf(line, sizeof(line), "Found file: %s", filename); ui_log_append(line); + vTaskDelay(pdMS_TO_TICKS(1)); } - /* - FILE* file = sd_open_write("test.txt"); - if(file != NULL){ - fprintf(file, "Hello, SD card!\n"); - sd_close_file(file); - ui_log_append("Wrote test.txt"); - } else { - ui_log_append("Failed to open test.txt for writing"); - } - */ + ui_log_append("Done listing files in root directory"); - sd_destroy(); - ui_log_append("SD card unmounted"); + ui_switch_view_to(UI_VIEW_IMAGE_BROWSER); + + // sd_destroy(); + // ui_log_append("\nSD card unmounted"); } diff --git a/main/sd/sd.c b/main/sd/sd.c index 0414eef..32c4399 100644 --- a/main/sd/sd.c +++ b/main/sd/sd.c @@ -71,16 +71,14 @@ void sd_init(void){ ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); if(ret != ESP_OK){ - if(ret == ESP_FAIL) ESP_LOGE(TAG, "Failed to mount filesystem."); - else ESP_LOGE(TAG, "Failed to initialize the card (%s). ", esp_err_to_name(ret)); + if(ret == ESP_FAIL) ESP_LOGE(TAG, "Failed to mount filesystem."); else ESP_LOGE(TAG, "Failed to initialize the card (%s). ", esp_err_to_name(ret)); spi_bus_free(host.slot); return; } ESP_LOGI(TAG, "SD card initialized"); - if(get_top_level_files() == ESP_OK) ESP_LOGI(TAG, "Found %d files in root directory", _file_count); - else ESP_LOGW(TAG, "No files found in root directory"); + if(get_top_level_files() == ESP_OK) ESP_LOGI(TAG, "Found %d files in root directory", _file_count); else ESP_LOGW(TAG, "No files found in root directory"); } void print_sd_card_info(void){ diff --git a/sdkconfig b/sdkconfig index eed8e65..8743cdf 100644 --- a/sdkconfig +++ b/sdkconfig @@ -3180,9 +3180,12 @@ CONFIG_LV_USE_GRID=y # 3rd Party Libraries # # default: -CONFIG_LV_FS_DEFAULT_DRIVER_LETTER=0 +CONFIG_LV_FS_DEFAULT_DRIVER_LETTER=65 +CONFIG_LV_USE_FS_STDIO=y # default: -# CONFIG_LV_USE_FS_STDIO is not set +CONFIG_LV_FS_STDIO_LETTER=65 +CONFIG_LV_FS_STDIO_PATH="" +CONFIG_LV_FS_STDIO_CACHE_SIZE=0 # default: # CONFIG_LV_USE_FS_POSIX is not set # default: @@ -3207,8 +3210,7 @@ CONFIG_LV_FS_DEFAULT_DRIVER_LETTER=0 # CONFIG_LV_USE_LIBPNG is not set # default: # CONFIG_LV_USE_BMP is not set -# default: -# CONFIG_LV_USE_TJPGD is not set +CONFIG_LV_USE_TJPGD=y # default: # CONFIG_LV_USE_LIBJPEG_TURBO is not set # default: