display_gif_embedded: 15.4 -> 20.6 fps
- FPS/refresh/decode counter via LVGL monitor_cb (printed once per second) - LVGL logging off, per-loop memory prints removed, loop delay 5 -> 1 ms - double draw buffer (render while previous chunk is flushed) - compile with -O2 instead of -Os Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e63fb65c6
commit
70114f73aa
5 files changed
+70
-39
No files matched your search
@@ -201,7 +201,7 @@
|
|||||||
*-----------*/
|
*-----------*/
|
||||||
|
|
||||||
/*Enable the log module*/
|
/*Enable the log module*/
|
||||||
#define LV_USE_LOG 1
|
#define LV_USE_LOG 0
|
||||||
#if LV_USE_LOG
|
#if LV_USE_LOG
|
||||||
|
|
||||||
/*How important log should be added:
|
/*How important log should be added:
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define SCREEN_RES_VER 360
|
#define SCREEN_RES_VER 360
|
||||||
|
|
||||||
static lv_color_t *disp_draw_buf;
|
static lv_color_t *disp_draw_buf;
|
||||||
|
static lv_color_t *disp_draw_buf2; // second buffer: LVGL renders into one while the other is sent to the LCD
|
||||||
static lv_disp_draw_buf_t draw_buf;
|
static lv_disp_draw_buf_t draw_buf;
|
||||||
static lv_disp_drv_t disp_drv;
|
static lv_disp_drv_t disp_drv;
|
||||||
static lv_indev_t *indev_touchpad;
|
static lv_indev_t *indev_touchpad;
|
||||||
@@ -418,8 +419,9 @@ void scr_lvgl_init()
|
|||||||
size_t lv_cache_rows = 72;
|
size_t lv_cache_rows = 72;
|
||||||
|
|
||||||
disp_draw_buf = (lv_color_t *)heap_caps_malloc(lv_cache_rows * SCREEN_RES_HOR * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
disp_draw_buf = (lv_color_t *)heap_caps_malloc(lv_cache_rows * SCREEN_RES_HOR * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
|
disp_draw_buf2 = (lv_color_t *)heap_caps_malloc(lv_cache_rows * SCREEN_RES_HOR * 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
lv_init();
|
lv_init();
|
||||||
lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, NULL, SCREEN_RES_HOR * lv_cache_rows);
|
lv_disp_draw_buf_init(&draw_buf, disp_draw_buf, disp_draw_buf2, SCREEN_RES_HOR * lv_cache_rows);
|
||||||
|
|
||||||
lv_disp_drv_init(&disp_drv);
|
lv_disp_drv_init(&disp_drv);
|
||||||
disp_drv.hor_res = SCREEN_RES_HOR;
|
disp_drv.hor_res = SCREEN_RES_HOR;
|
||||||
|
|||||||
@@ -1,29 +1,32 @@
|
|||||||
; JC3636W518 — ESP32-S3R8, 16 MB QIO flash, 8 MB OPI PSRAM, 360x360 ST77916 QSPI + CST816S
|
; JC3636W518 — ESP32-S3R8, 16 MB QIO flash, 8 MB OPI PSRAM, 360x360 ST77916 QSPI + CST816S
|
||||||
; Settings mirror the vendor Arduino IDE setup (2-Program Example/Demo_Arduino/docs/Arduino set up.png)
|
; Settings mirror the vendor Arduino IDE setup (2-Program Example/Demo_Arduino/docs/Arduino set up.png)
|
||||||
|
|
||||||
[env:jc3636w518]
|
[env:jc3636w518]
|
||||||
; pioarduino = Arduino core 3.0.5 (ESP32_Display_Panel 0.1.4 needs core 3.x)
|
; pioarduino = Arduino core 3.0.5 (ESP32_Display_Panel 0.1.4 needs core 3.x)
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
board_build.arduino.memory_type = qio_opi
|
board_build.arduino.memory_type = qio_opi
|
||||||
board_build.flash_mode = qio
|
board_build.flash_mode = qio
|
||||||
board_upload.flash_size = 16MB
|
board_upload.flash_size = 16MB
|
||||||
; GIF compiled into firmware -> 3.4 MB, too big for huge_app (3 MB); 6.25 MB app slots
|
; GIF compiled into firmware -> 3.4 MB, too big for huge_app (3 MB); 6.25 MB app slots
|
||||||
board_build.partitions = default_16MB.csv
|
board_build.partitions = default_16MB.csv
|
||||||
|
|
||||||
build_flags =
|
; optimise for speed instead of size (faster GIF decoding)
|
||||||
-DBOARD_HAS_PSRAM
|
build_unflags = -Os
|
||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
build_flags =
|
||||||
; LVGL (also when compiled as a library) picks up include/lv_conf.h of this project
|
-O2
|
||||||
-DLV_CONF_INCLUDE_SIMPLE
|
-DBOARD_HAS_PSRAM
|
||||||
-Iinclude
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
; LVGL (also when compiled as a library) picks up include/lv_conf.h of this project
|
||||||
; vendor-bundled libraries: ESP32_Display_Panel 0.1.4, ESP32_IO_Expander 0.0.2, lvgl 8.3.11
|
-DLV_CONF_INCLUDE_SIMPLE
|
||||||
lib_extra_dirs = ../../2-Program Example/Demo_Arduino/library
|
-Iinclude
|
||||||
|
|
||||||
upload_port = COM21
|
; vendor-bundled libraries: ESP32_Display_Panel 0.1.4, ESP32_IO_Expander 0.0.2, lvgl 8.3.11
|
||||||
monitor_port = COM21
|
lib_extra_dirs = ../../2-Program Example/Demo_Arduino/library
|
||||||
monitor_speed = 115200
|
|
||||||
monitor_filters = esp32_exception_decoder
|
upload_port = COM21
|
||||||
|
monitor_port = COM21
|
||||||
|
monitor_speed = 115200
|
||||||
|
monitor_filters = esp32_exception_decoder
|
||||||
@@ -12,6 +12,30 @@ const char* password = "123456789";
|
|||||||
|
|
||||||
String httpGETRequest(const char* serverName);
|
String httpGETRequest(const char* serverName);
|
||||||
|
|
||||||
|
// FPS measurement: LVGL calls this after every screen refresh (= one GIF frame here)
|
||||||
|
static volatile uint32_t refr_count = 0;
|
||||||
|
static volatile uint32_t refr_time_ms = 0;
|
||||||
|
static uint32_t busy_us = 0; // time spent inside lv_timer_handler()
|
||||||
|
|
||||||
|
static void refr_monitor_cb(lv_disp_drv_t* drv, uint32_t time, uint32_t px) {
|
||||||
|
refr_count++;
|
||||||
|
refr_time_ms += time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_fps() {
|
||||||
|
static uint32_t last_ms = 0;
|
||||||
|
uint32_t now = millis();
|
||||||
|
if (now - last_ms < 1000) return;
|
||||||
|
// decode = busy time not spent refreshing the screen (mostly GIF decoding)
|
||||||
|
Serial.printf("FPS: %.1f avg refresh: %lu ms avg decode: %lu ms\n", refr_count * 1000.0f / (now - last_ms),
|
||||||
|
refr_count ? refr_time_ms / refr_count : 0,
|
||||||
|
refr_count ? (busy_us / 1000 - refr_time_ms) / refr_count : 0);
|
||||||
|
refr_count = 0;
|
||||||
|
refr_time_ms = 0;
|
||||||
|
busy_us = 0;
|
||||||
|
last_ms = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void my_print(const char* buf) {
|
void my_print(const char* buf) {
|
||||||
Serial.println(buf); // Print logs to the serial monitor
|
Serial.println(buf); // Print logs to the serial monitor
|
||||||
@@ -106,6 +130,7 @@ void setup() {
|
|||||||
delay(200);
|
delay(200);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
scr_lvgl_init();
|
scr_lvgl_init();
|
||||||
|
lv_disp_get_default()->driver->monitor_cb = refr_monitor_cb;
|
||||||
|
|
||||||
lv_init();
|
lv_init();
|
||||||
|
|
||||||
@@ -143,15 +168,11 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
uint32_t t0 = micros();
|
||||||
lv_timer_handler();
|
lv_timer_handler();
|
||||||
vTaskDelay(5);
|
busy_us += micros() - t0;
|
||||||
|
vTaskDelay(1);
|
||||||
lv_mem_monitor_t mem_mon;
|
print_fps();
|
||||||
lv_mem_monitor(&mem_mon);
|
|
||||||
printf("Free memory: %d bytes\n", mem_mon.free_size);
|
|
||||||
|
|
||||||
Serial.print("Available Heap: ");
|
|
||||||
Serial.println(esp_get_free_heap_size());
|
|
||||||
|
|
||||||
|
|
||||||
// if (WiFi.status() == WL_CONNECTED) {
|
// if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ Cheap dual-mode clones typically expose BLE service `FFF0` (notify `FFF1`, write
|
|||||||
## Gotchas / observations
|
## Gotchas / observations
|
||||||
- **LVGL GIF bug (patched locally):** LVGL 8.3.11 `gifdec.c` (`gd_open_gif`) filled the canvas *opaque* with the GIF's background color. GIFs with a transparent background (e.g. `loligod.gif`, bg = RGB 28,29,49) showed that dark gray except where "restore to background" frames had cleared to transparent (→ screen black). **Patched** in the vendor copy `2-Program Example/Demo_Arduino/library/lvgl/src/extra/libs/gif/gifdec.c`: initial canvas alpha 0x00 (marked `LOCAL PATCH`). Re-apply if LVGL is ever replaced/upgraded.
|
- **LVGL GIF bug (patched locally):** LVGL 8.3.11 `gifdec.c` (`gd_open_gif`) filled the canvas *opaque* with the GIF's background color. GIFs with a transparent background (e.g. `loligod.gif`, bg = RGB 28,29,49) showed that dark gray except where "restore to background" frames had cleared to transparent (→ screen black). **Patched** in the vendor copy `2-Program Example/Demo_Arduino/library/lvgl/src/extra/libs/gif/gifdec.c`: initial canvas alpha 0x00 (marked `LOCAL PATCH`). Re-apply if LVGL is ever replaced/upgraded.
|
||||||
- Most GIFs in `assets/gifs` are optimized (transparent unchanged pixels, disposal 1/2); `loligod.gif` has a fully transparent background (~84 % of each frame).
|
- Most GIFs in `assets/gifs` are optimized (transparent unchanged pixels, disposal 1/2); `loligod.gif` has a fully transparent background (~84 % of each frame).
|
||||||
|
- **GIF performance** (360×360 loligod, embedded, measured with a `monitor_cb` FPS counter in `display_gif_embedded`):
|
||||||
|
baseline 15.4 fps (decode 27 ms + refresh 31 ms) → no LVGL log / no per-loop prints: no change → `vTaskDelay(1)`: 16.5 → **double draw buffer** (2×72 rows internal RAM): 19.5 (refresh 21 ms) → **`-O2`** instead of `-Os`: **20.6 fps** (refresh 19 ms, decode ~24 ms). GIF's own rate is 23.7 fps. From SD card it was only ~1.4 fps.
|
||||||
|
Remaining limit is LVGL's single-threaded GIF decode; going further would need decoding on the other core or a lighter format (e.g. pre-converted frames/MJPEG).
|
||||||
|
- **SD card (user's 487 MB SDSC)** intermittently fails to init (`sdmmc_init_ocr ... 0x107`) after resets; once stuck only a power cycle helps (card VDD is hard-wired to 3V3). Recommend a newer SDHC card.
|
||||||
|
- Reading boot logs: USB-CDC — reset via DTR=0/RTS pulse, then reopen the port (it re-enumerates).
|
||||||
- LVGL version: all JC3636W518 projects use the vendor-bundled **LVGL 8.3.11**. LVGL 9 would require porting `scr_st77916.h` (display/touch driver glue).
|
- LVGL version: all JC3636W518 projects use the vendor-bundled **LVGL 8.3.11**. LVGL 9 would require porting `scr_st77916.h` (display/touch driver glue).
|
||||||
- Display is round: corners of the 360×360 framebuffer are not visible — design UI within a 360 px circle.
|
- Display is round: corners of the 360×360 framebuffer are not visible — design UI within a 360 px circle.
|
||||||
- Compiling a 13.9 MB GIF into the firmware will not fit "Huge APP" (3 MB); large media should live on SD (or in a custom partition).
|
- Compiling a 13.9 MB GIF into the firmware will not fit "Huge APP" (3 MB); large media should live on SD (or in a custom partition).
|
||||||
|
|||||||
Reference in new issue
Block a user