From b03756a24ad14832ff0233be824b37012809fe5d Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 25 Apr 2021 21:40:01 +0200 Subject: [PATCH] Add time measure to SPI display --- .../Adafruit_LvGL_Glue.cpp | 111 ++++++++---------- tasmota/xdrv_54_lvgl.ino | 57 ++++++++- 2 files changed, 107 insertions(+), 61 deletions(-) diff --git a/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp b/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp index dfabf2efa..250661600 100644 --- a/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp +++ b/lib/libesp32_lvgl/Adafruit_LvGL_Glue-shadinger/Adafruit_LvGL_Glue.cpp @@ -3,6 +3,8 @@ // ARCHITECTURE-SPECIFIC TIMER STUFF --------------------------------------- +extern void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p); + // Tick interval for LittlevGL internal timekeeping; 1 to 10 ms recommended static const int lv_tick_interval_ms = 10; @@ -51,63 +53,63 @@ static bool touchscreen_read(struct _lv_indev_drv_t *indev_drv, lv_indev_data_t #define LV_BUFFER_ROWS 60 // Most others have a bit more space -// This is the flush function required for LittlevGL screen updates. -// It receives a bounding rect and an array of pixel data (conveniently -// already in 565 format, so the Earth was lucky there). -static void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { - // Get pointer to glue object from indev user data - Adafruit_LvGL_Glue *glue = (Adafruit_LvGL_Glue *)disp->user_data; +// // This is the flush function required for LittlevGL screen updates. +// // It receives a bounding rect and an array of pixel data (conveniently +// // already in 565 format, so the Earth was lucky there). +// static void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { +// // Get pointer to glue object from indev user data +// Adafruit_LvGL_Glue *glue = (Adafruit_LvGL_Glue *)disp->user_data; - uint16_t width = (area->x2 - area->x1 + 1); - uint16_t height = (area->y2 - area->y1 + 1); +// uint16_t width = (area->x2 - area->x1 + 1); +// uint16_t height = (area->y2 - area->y1 + 1); - if (glue->getScreenshotFile() != nullptr) { - // save pixels to file - int32_t btw = (width * height * LV_COLOR_DEPTH + 7) / 8; - while (btw > 0) { - int32_t ret = glue->getScreenshotFile()->write((const uint8_t*) color_p, btw); - //Serial.printf(">>> btw %d, written %d\n", btw, ret); - if (ret >= 0) { - btw -= ret; - } else { - btw = 0; // abort - } - } - lv_disp_flush_ready(disp); - return; // ok - } +// // check if we are currently doing a screenshot +// if (glue->getScreenshotFile() != nullptr) { +// // save pixels to file +// int32_t btw = (width * height * LV_COLOR_DEPTH + 7) / 8; +// while (btw > 0) { +// int32_t ret = glue->getScreenshotFile()->write((const uint8_t*) color_p, btw); +// if (ret >= 0) { +// btw -= ret; +// } else { +// btw = 0; // abort +// } +// } +// lv_disp_flush_ready(disp); +// return; // ok +// // } - Renderer *display = glue->display; +// Renderer *display = glue->display; - if (!glue->first_frame) { - //display->dmaWait(); // Wait for prior DMA transfer to complete - //display->endWrite(); // End transaction from any prior call - } else { - glue->first_frame = false; - } +// if (!glue->first_frame) { +// //display->dmaWait(); // Wait for prior DMA transfer to complete +// //display->endWrite(); // End transaction from any prior call +// } else { +// glue->first_frame = false; +// } - display->setAddrWindow(area->x1, area->y1, area->x1+width, area->y1+height); - display->pushColors((uint16_t *)color_p, width * height, true); - display->setAddrWindow(0,0,0,0); +// display->setAddrWindow(area->x1, area->y1, area->x1+width, area->y1+height); +// display->pushColors((uint16_t *)color_p, width * height, true); +// display->setAddrWindow(0,0,0,0); - lv_disp_flush_ready(disp); +// lv_disp_flush_ready(disp); -} +// } -#if (LV_USE_LOG) -// Optional LittlevGL debug print function, writes to Serial if debug is -// enabled when calling glue begin() function. -static void lv_debug(lv_log_level_t level, const char *file, uint32_t line, const char *fname, - const char *dsc) { - Serial.print(file); - Serial.write('@'); - Serial.print(line); - Serial.print(":"); - Serial.print(fname); - Serial.write("->"); - Serial.println(dsc); -} -#endif +// #if (LV_USE_LOG) +// // Optional LittlevGL debug print function, writes to Serial if debug is +// // enabled when calling glue begin() function. +// static void lv_debug(lv_log_level_t level, const char *file, uint32_t line, const char *fname, +// const char *dsc) { +// Serial.print(file); +// Serial.write('@'); +// Serial.print(line); +// Serial.print(":"); +// Serial.print(fname); +// Serial.write("->"); +// Serial.println(dsc); +// } +// #endif // GLUE LIB FUNCTIONS ------------------------------------------------------ @@ -120,9 +122,6 @@ static void lv_debug(lv_log_level_t level, const char *file, uint32_t line, cons */ Adafruit_LvGL_Glue::Adafruit_LvGL_Glue(void) : first_frame(true), lv_pixel_buf(NULL) { -#if defined(ARDUINO_ARCH_SAMD) - zerotimer = NULL; -#endif } // Destructor @@ -133,9 +132,6 @@ Adafruit_LvGL_Glue::Adafruit_LvGL_Glue(void) */ Adafruit_LvGL_Glue::~Adafruit_LvGL_Glue(void) { delete[] lv_pixel_buf; -#if defined(ARDUINO_ARCH_SAMD) - delete zerotimer; -#endif // Probably other stuff that could be deallocated here } @@ -207,11 +203,6 @@ LvGLStatus Adafruit_LvGL_Glue::begin(Renderer *tft, void *touch, bool debug) { lv_init(); -// #if (LV_USE_LOG) -// if (debug) { -// lv_log_register_print_cb(lv_debug); // Register debug print function -// } -// #endif // Allocate LvGL display buffer (x2 because DMA double buffering) LvGLStatus status = LVGL_ERR_ALLOC; diff --git a/tasmota/xdrv_54_lvgl.ino b/tasmota/xdrv_54_lvgl.ino index 717d279e0..daddaf109 100644 --- a/tasmota/xdrv_54_lvgl.ino +++ b/tasmota/xdrv_54_lvgl.ino @@ -119,6 +119,61 @@ static void guiTask(void *pvParameter) { vTaskDelete(NULL); } + +/************************************************************ + * Main screen refresh function + ************************************************************/ +// This is the flush function required for LittlevGL screen updates. +// It receives a bounding rect and an array of pixel data (conveniently +// already in 565 format, so the Earth was lucky there). +void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p); +void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { + // Get pointer to glue object from indev user data + Adafruit_LvGL_Glue *glue = (Adafruit_LvGL_Glue *)disp->user_data; + + uint16_t width = (area->x2 - area->x1 + 1); + uint16_t height = (area->y2 - area->y1 + 1); + + // check if we are currently doing a screenshot + if (glue->getScreenshotFile() != nullptr) { + // save pixels to file + int32_t btw = (width * height * LV_COLOR_DEPTH + 7) / 8; + while (btw > 0) { + int32_t ret = glue->getScreenshotFile()->write((const uint8_t*) color_p, btw); + if (ret >= 0) { + btw -= ret; + } else { + btw = 0; // abort + } + } + lv_disp_flush_ready(disp); + return; // ok + } + + Renderer *display = glue->display; + + if (!glue->first_frame) { + //display->dmaWait(); // Wait for prior DMA transfer to complete + //display->endWrite(); // End transaction from any prior call + } else { + glue->first_frame = false; + } + + uint32_t pixels_len = width * height; + uint32_t chrono_start = millis(); + display->setAddrWindow(area->x1, area->y1, area->x1+width, area->y1+height); + display->pushColors((uint16_t *)color_p, pixels_len, true); + display->setAddrWindow(0,0,0,0); + uint32_t chrono_time = millis() - chrono_start; + + lv_disp_flush_ready(disp); + + if (pixels_len >= 10000) { + AddLog(LOG_LEVEL_DEBUG, D_LOG_LVGL "Refreshed %d pixels in %d ms (%i pix/ms)", pixels_len, chrono_time, + chrono_time > 0 ? pixels_len / chrono_time : -1); + } +} + /************************************************************ * Callbacks for file system access from LVGL * @@ -255,7 +310,7 @@ void start_lvgl(const char * uconfig) { } if (uconfig && !renderer) { -#ifdef USE_UNIVERSAL_DISPLAY +#ifdef USE_UNIVERSAL_DISPLAY // TODO - we will probably support only UNIV_DISPLAY renderer = Init_uDisplay((char*)uconfig, -1); if (!renderer) return; #else