From 50d12c7ceaedc0a3f0547c34bfb6b124ffb7e166 Mon Sep 17 00:00:00 2001 From: philmoz Date: Wed, 22 Jul 2026 09:38:29 +1000 Subject: [PATCH] chore(color): reduce busy wait time on LCD refresh (#7483) --- radio/src/boards/jumper-h750/lcd_driver.cpp | 20 +--- radio/src/boards/jumper-h750/lcd_driver.h | 6 +- radio/src/boards/rm-h750/lcd_driver_480.cpp | 48 ++------ radio/src/boards/rm-h750/lcd_driver_480.h | 14 +-- radio/src/boards/rm-h750/lcd_driver_800.cpp | 44 ++----- radio/src/boards/rm-h750/lcd_driver_800.h | 7 -- radio/src/gui/colorlcd/boot_lcd.cpp | 110 ++++++++---------- radio/src/gui/colorlcd/boot_menu.cpp | 97 ++++++++------- radio/src/gui/colorlcd/lcd.cpp | 91 ++++++--------- radio/src/gui/colorlcd/lcd.h | 9 +- radio/src/gui/common/stdlcd/lcd_common.h | 2 + radio/src/targets/horus/lcd_driver.cpp | 104 ++++++++--------- .../src/targets/horus/lcd_st7796s_driver.cpp | 13 +-- radio/src/targets/pa01/lcd_driver.cpp | 2 + radio/src/targets/pl18/lcd_driver.cpp | 14 +-- radio/src/targets/simu/simulib.cpp | 4 +- radio/src/targets/st16/lcd_driver.cpp | 12 +- .../src/targets/stm32h7s78-dk/lcd_driver.cpp | 12 +- radio/src/targets/taranis/board.h | 1 - 19 files changed, 230 insertions(+), 380 deletions(-) diff --git a/radio/src/boards/jumper-h750/lcd_driver.cpp b/radio/src/boards/jumper-h750/lcd_driver.cpp index 013e91ff6..e01c91dc7 100644 --- a/radio/src/boards/jumper-h750/lcd_driver.cpp +++ b/radio/src/boards/jumper-h750/lcd_driver.cpp @@ -24,9 +24,7 @@ #include "stm32_hal.h" #include "stm32_gpio_driver.h" #include "edgetx_types.h" -#include "dma2d.h" #include "hal.h" -#include "delays_driver.h" #include "debug.h" #include "lcd.h" #include "lcd_driver.h" @@ -35,15 +33,12 @@ #include "stm32_gpio.h" #include "hal/gpio.h" -uint8_t TouchControllerType = 0; // 0: other; 1: CST836U static volatile uint16_t lcd_phys_w = LCD_H; static volatile uint16_t lcd_phys_h = LCD_W; static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { @@ -54,16 +49,11 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, // faster than cleaning by address SCB_CleanDCache(); -// LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); LTDC_Layer1->CFBAR = (uint32_t)buffer; // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } lcdSpiInitFucPtr lcdInitFunction; @@ -71,8 +61,6 @@ lcdSpiInitFucPtr lcdOffFunction; lcdSpiInitFucPtr lcdOnFunction; uint32_t lcdPixelClock; -volatile uint8_t LCD_ReadBuffer[24] = { 0, 0 }; - static void LCD_Delay(void) { volatile unsigned int i; @@ -1884,7 +1872,6 @@ void LCD_Init_LTDC() { // Trigger on last line HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } void LCD_LayerInit() { @@ -2009,5 +1996,6 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; -} \ No newline at end of file + + lcdFlushed(); +} diff --git a/radio/src/boards/jumper-h750/lcd_driver.h b/radio/src/boards/jumper-h750/lcd_driver.h index 6ffeb1e9c..d42f435dd 100644 --- a/radio/src/boards/jumper-h750/lcd_driver.h +++ b/radio/src/boards/jumper-h750/lcd_driver.h @@ -19,8 +19,7 @@ * GNU General Public License for more details. */ -#ifndef __LCD_DRIVER_H__ -#define __LCD_DRIVER_H__ +#pragma once #define HBP ( 24 ) // TODO use names from FlySky #define VBP ( 10 ) @@ -66,12 +65,9 @@ extern lcdSpiInitFucPtr lcdOnFunction; #define LCD_READ_DATA_PIN() LL_GPIO_IsInputPinSet(LCD_SPI_GPIO, LCD_SPI_MOSI_GPIO_PIN) - #define HORIZONTAL_SYNC_WIDTH ( 4 ) #define HORIZONTAL_BACK_PORCH ( 24 ) #define HORIZONTAL_FRONT_PORCH ( 140 - HORIZONTAL_BACK_PORCH ) #define VERTICAL_SYNC_HEIGHT ( 2 ) #define VERTICAL_BACK_PORCH ( 10 ) #define VERTICAL_FRONT_PORCH ( 22 - VERTICAL_BACK_PORCH ) - -#endif \ No newline at end of file diff --git a/radio/src/boards/rm-h750/lcd_driver_480.cpp b/radio/src/boards/rm-h750/lcd_driver_480.cpp index c8b761289..593653654 100644 --- a/radio/src/boards/rm-h750/lcd_driver_480.cpp +++ b/radio/src/boards/rm-h750/lcd_driver_480.cpp @@ -22,9 +22,7 @@ #include "stm32_hal_ll.h" #include "stm32_hal.h" #include "edgetx_types.h" -#include "dma2d.h" #include "hal.h" -#include "delays_driver.h" #include "debug.h" #include "lcd.h" #include "lcd_driver_480.h" @@ -34,15 +32,9 @@ #include "stm32_gpio.h" #include "stm32_qspi.h" -uint8_t TouchControllerType = 0; // 0: other; 1: CST836U -static volatile uint16_t lcd_phys_w = LCD_PHYS_W; -static volatile uint16_t lcd_phys_h = LCD_PHYS_H; - static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { @@ -55,23 +47,11 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, LTDC_Layer1->CFBAR = (uint32_t)buffer; // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); - - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); } -lcdSpiInitFucPtr lcdInitFunction; -lcdSpiInitFucPtr lcdOffFunction; -lcdSpiInitFucPtr lcdOnFunction; -uint32_t lcdPixelClock; - -volatile uint8_t LCD_ReadBuffer[24] = { 0, 0 }; - static void LCD_Delay(void) { volatile unsigned int i; @@ -424,13 +404,13 @@ void LCD_Init_LTDC() { /* Configure accumulated vertical back porch */ hltdc.Init.AccumulatedVBP = VSH+VBP-1; /* Configure accumulated active width */ - hltdc.Init.AccumulatedActiveW = lcd_phys_w + HBP+HSW-1; + hltdc.Init.AccumulatedActiveW = LCD_PHYS_W + HBP+HSW-1; /* Configure accumulated active height */ - hltdc.Init.AccumulatedActiveH = lcd_phys_h + VBP+VSH-1; + hltdc.Init.AccumulatedActiveH = LCD_PHYS_H + VBP+VSH-1; /* Configure total width */ - hltdc.Init.TotalWidth = lcd_phys_w + HBP + HFP + HSW -1; + hltdc.Init.TotalWidth = LCD_PHYS_W + HBP + HFP + HSW -1; /* Configure total height */ - hltdc.Init.TotalHeigh = lcd_phys_h + VBP + VFP+VSH-1; + hltdc.Init.TotalHeigh = LCD_PHYS_H + VBP + VFP+VSH-1; HAL_LTDC_Init(&hltdc); @@ -439,8 +419,7 @@ void LCD_Init_LTDC() { NVIC_EnableIRQ(LTDC_IRQn); // Trigger on last line - HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); + HAL_LTDC_ProgramLineEvent(&hltdc, LCD_PHYS_H); } void LCD_LayerInit() { @@ -448,9 +427,9 @@ void LCD_LayerInit() { /* Windowing configuration */ layer.WindowX0 = 0; - layer.WindowX1 = lcd_phys_w; + layer.WindowX1 = LCD_PHYS_W; layer.WindowY0 = 0; - layer.WindowY1 = lcd_phys_h; + layer.WindowY1 = LCD_PHYS_H; /* Pixel Format configuration*/ layer.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; @@ -468,8 +447,8 @@ void LCD_LayerInit() { layer.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; layer.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; - layer.ImageWidth = lcd_phys_w; - layer.ImageHeight = lcd_phys_h; + layer.ImageWidth = LCD_PHYS_W; + layer.ImageHeight = LCD_PHYS_H; /* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */ layer.FBStartAdress = (intptr_t)initialFrameBuffer; @@ -508,12 +487,9 @@ void lcdInit(void) /* Send LCD initialization commands */ TRACE("LCD INIT (default): ST7365"); boardLcdType = "ST7365 (Default)"; - lcdInitFunction = LCD_ST7365_Init; - lcdOffFunction = LCD_ST7365_Off; - lcdOnFunction = LCD_ST7365_On; __HAL_RCC_LTDC_CLK_ENABLE(); - lcdInitFunction(); + LCD_ST7365_Init(); LCD_Init_LTDC(); LCD_LayerInit(); @@ -533,6 +509,6 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; -} + lcdFlushed(); +} diff --git a/radio/src/boards/rm-h750/lcd_driver_480.h b/radio/src/boards/rm-h750/lcd_driver_480.h index dbb2e52d1..c8debb930 100644 --- a/radio/src/boards/rm-h750/lcd_driver_480.h +++ b/radio/src/boards/rm-h750/lcd_driver_480.h @@ -19,10 +19,7 @@ * GNU General Public License for more details. */ -#ifndef __LCD_DRIVER_H__ -#define __LCD_DRIVER_H__ - -#include "bsp_io.h" +#pragma once #define HBP ( 20 ) #define VBP ( 10 ) @@ -35,9 +32,6 @@ #define LCD_DELAY() LCD_Delay() -typedef void (*lcdSpiInitFucPtr)(void); -typedef unsigned int LcdReadIDFucPtr( void ); - #define SET_IO_INPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_INPUT ) #define SET_IO_OUTPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_OUTPUT ) @@ -57,9 +51,3 @@ typedef unsigned int LcdReadIDFucPtr( void ); #define LCD_MOSI_AS_OUTPUT() SET_IO_OUTPUT( LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN ) #define LCD_READ_DATA_PIN() LL_GPIO_IsInputPinSet(LCD_SPI_MOSI_GPIO, LCD_SPI_MOSI_GPIO_PIN) - -#endif - - - - diff --git a/radio/src/boards/rm-h750/lcd_driver_800.cpp b/radio/src/boards/rm-h750/lcd_driver_800.cpp index d6790db74..8064d802c 100644 --- a/radio/src/boards/rm-h750/lcd_driver_800.cpp +++ b/radio/src/boards/rm-h750/lcd_driver_800.cpp @@ -22,9 +22,7 @@ #include "stm32_hal_ll.h" #include "stm32_hal.h" #include "edgetx_types.h" -#include "dma2d.h" #include "hal.h" -#include "delays_driver.h" #include "debug.h" #include "lcd.h" #include "lcd_driver_800.h" @@ -34,15 +32,9 @@ #include "stm32_gpio.h" #include "stm32_qspi.h" -uint8_t TouchControllerType = 0; // 0: other; 1: CST836U -static const uint16_t lcd_phys_w = LCD_PHYS_W; -static const uint16_t lcd_phys_h = LCD_PHYS_H; - static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { @@ -55,23 +47,11 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, LTDC_Layer1->CFBAR = (uint32_t)buffer; // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); - - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); } -lcdSpiInitFucPtr lcdInitFunction; -lcdSpiInitFucPtr lcdOffFunction; -lcdSpiInitFucPtr lcdOnFunction; -uint32_t lcdPixelClock; - -volatile uint8_t LCD_ReadBuffer[24] = { 0, 0 }; - static void LCD_AF_GPIOConfig(void) { const gpio_t _lcd_af_gpios[] = { @@ -121,8 +101,6 @@ static void lcdReset() { delay_ms(100); } - - void LCD_Init_LTDC() { hltdc.Instance = LTDC; @@ -166,13 +144,13 @@ void LCD_Init_LTDC() { /* Configure accumulated vertical back porch */ hltdc.Init.AccumulatedVBP = VSH+VBP-1; /* Configure accumulated active width */ - hltdc.Init.AccumulatedActiveW = lcd_phys_w + HBP+HSW-1; + hltdc.Init.AccumulatedActiveW = LCD_PHYS_W + HBP+HSW-1; /* Configure accumulated active height */ - hltdc.Init.AccumulatedActiveH = lcd_phys_h + VBP+VSH-1; + hltdc.Init.AccumulatedActiveH = LCD_PHYS_H + VBP+VSH-1; /* Configure total width */ - hltdc.Init.TotalWidth = lcd_phys_w + HBP + HFP + HSW -1; + hltdc.Init.TotalWidth = LCD_PHYS_W + HBP + HFP + HSW -1; /* Configure total height */ - hltdc.Init.TotalHeigh = lcd_phys_h + VBP + VFP+VSH-1; + hltdc.Init.TotalHeigh = LCD_PHYS_H + VBP + VFP+VSH-1; HAL_LTDC_Init(&hltdc); @@ -181,8 +159,7 @@ void LCD_Init_LTDC() { NVIC_EnableIRQ(LTDC_IRQn); // Trigger on last line - HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); + HAL_LTDC_ProgramLineEvent(&hltdc, LCD_PHYS_H); } void LCD_LayerInit() { @@ -190,9 +167,9 @@ void LCD_LayerInit() { /* Windowing configuration */ layer.WindowX0 = 0; - layer.WindowX1 = lcd_phys_w; + layer.WindowX1 = LCD_PHYS_W; layer.WindowY0 = 0; - layer.WindowY1 = lcd_phys_h; + layer.WindowY1 = LCD_PHYS_H; /* Pixel Format configuration*/ layer.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; @@ -210,8 +187,8 @@ void LCD_LayerInit() { layer.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; layer.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; - layer.ImageWidth = lcd_phys_w; - layer.ImageHeight = lcd_phys_h; + layer.ImageWidth = LCD_PHYS_W; + layer.ImageHeight = LCD_PHYS_H; /* Start Address configuration : the LCD Frame buffer is defined on SDRAM w/ Offset */ layer.FBStartAdress = (intptr_t)initialFrameBuffer; @@ -271,5 +248,6 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; + + lcdFlushed(); } diff --git a/radio/src/boards/rm-h750/lcd_driver_800.h b/radio/src/boards/rm-h750/lcd_driver_800.h index 9b700f931..3188a3ec4 100644 --- a/radio/src/boards/rm-h750/lcd_driver_800.h +++ b/radio/src/boards/rm-h750/lcd_driver_800.h @@ -32,13 +32,6 @@ #define HFP ( 16 ) #define VFP ( 8 ) -typedef void (*lcdSpiInitFucPtr)(void); -typedef unsigned int LcdReadIDFucPtr( void ); - -extern lcdSpiInitFucPtr lcdInitFunction; -extern lcdSpiInitFucPtr lcdOffFunction; -extern lcdSpiInitFucPtr lcdOnFunction; - #define SET_IO_INPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_INPUT ) #define SET_IO_OUTPUT( PORT, PIN ) LL_GPIO_SetPinMode( PORT, PIN, LL_GPIO_MODE_OUTPUT ) diff --git a/radio/src/gui/colorlcd/boot_lcd.cpp b/radio/src/gui/colorlcd/boot_lcd.cpp index d1fd67f75..f739f0eeb 100644 --- a/radio/src/gui/colorlcd/boot_lcd.cpp +++ b/radio/src/gui/colorlcd/boot_lcd.cpp @@ -33,46 +33,40 @@ #include "board.h" #include "etx_lv_theme.h" -pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; -pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; +pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM __ALIGNED(64); +pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM __ALIGNED(64); -BitmapBuffer lcdBuffer1(BMP_RGB565, LCD_W, LCD_H, - (uint16_t*)LCD_FIRST_FRAME_BUFFER); -BitmapBuffer lcdBuffer2(BMP_RGB565, LCD_W, LCD_H, - (uint16_t*)LCD_SECOND_FRAME_BUFFER); - -BitmapBuffer* lcdFront = &lcdBuffer1; -BitmapBuffer* lcd = &lcdBuffer2; +BitmapBuffer lcd(BMP_RGB565, LCD_W, LCD_H, (uint16_t*)LCD_FIRST_FRAME_BUFFER); static lv_disp_draw_buf_t disp_buf; static lv_disp_drv_t disp_drv; - static lv_disp_t disp; // Call backs static void (*lcd_flush_cb)(lv_disp_drv_t*, uint16_t* buffer, const rect_t& area) = nullptr; +extern "C" void lcdFlushed() +{ + lv_disp_flush_ready(&disp_drv); +} + void lcdSetFlushCb(void (*cb)(lv_disp_drv_t*, uint16_t*, const rect_t&)) { lcd_flush_cb = cb; } -static lv_disp_drv_t* refr_disp = nullptr; - static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) { if (lcd_flush_cb) { - refr_disp = disp_drv; - rect_t copy_area = {area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1}; lcd_flush_cb(disp_drv, (uint16_t*)color_p, copy_area); + } else { + lcdFlushed(); } - - lv_disp_flush_ready(disp_drv); } static void clear_frame_buffers() @@ -83,24 +77,27 @@ static void clear_frame_buffers() static void init_lvgl_disp_drv() { - lv_disp_draw_buf_init(&disp_buf, lcdFront->getData(), lcd->getData(), LCD_W * LCD_H); + int direct_mode = 1; +#if LCD_VERTICAL_INVERT +#if defined(RADIO_F16) + direct_mode = (hardwareOptions.pcbrev > 0) ? 1 : 0; +#else + direct_mode = 0; +#endif +#endif + + lv_disp_draw_buf_init(&disp_buf, + LCD_FIRST_FRAME_BUFFER, + direct_mode ? LCD_SECOND_FRAME_BUFFER : nullptr, + LCD_W * LCD_H); lv_disp_drv_init(&disp_drv); /*Basic initialization*/ disp_drv.draw_buf = &disp_buf; /*Set an initialized buffer*/ disp_drv.flush_cb = flushLcd; /*Set a flush callback to draw to the display*/ - disp_drv.wait_cb = nullptr; /*Set a wait callback*/ disp_drv.hor_res = LCD_W; /*Set the horizontal resolution in pixels*/ disp_drv.ver_res = LCD_H; /*Set the vertical resolution in pixels*/ - disp_drv.full_refresh = 0; - -#if !LCD_VERTICAL_INVERT - disp_drv.direct_mode = 1; -#elif defined(RADIO_F16) - disp_drv.direct_mode = (hardwareOptions.pcbrev > 0) ? 1 : 0; -#else - disp_drv.direct_mode = 0; -#endif + disp_drv.direct_mode = direct_mode; } void lcdInitDisplayDriver() @@ -119,7 +116,7 @@ void lcdInitDisplayDriver() // Clear buffers first clear_frame_buffers(); - lcdSetInitalFrameBuffer(lcdFront->getData()); + lcdSetInitalFrameBuffer(lcd.getData()); // Init hardware LCD driver lcdInit(); @@ -141,32 +138,24 @@ void lcdInitDisplayDriver() } lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; - lcd->setDrawCtx(draw_ctx); - lcdFront->setDrawCtx(draw_ctx); + lcd.setDrawCtx(draw_ctx); -#if defined(LCD_BACKLIGHT_INIT_DELAY_MS) - delay_ms(LCD_BACKLIGHT_INIT_DELAY_MS); -#endif - - backlightInit(); -} - -void lcdClear() { lcd->clear(); } - -// Direct drawing - used by boot loader - -void lcdInitDirectDrawing() -{ static lv_area_t screen_area = {0, 0, LCD_W - 1, LCD_H - 1}; - - lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; draw_ctx->buf = disp_drv.draw_buf->buf_act; draw_ctx->buf_area = &screen_area; draw_ctx->clip_area = &screen_area; - lcd->setData((pixel_t*)draw_ctx->buf); - lcd->reset(); + +#if defined(LCD_BACKLIGHT_INIT_DELAY_MS) + delay_ms(LCD_BACKLIGHT_INIT_DELAY_MS); +#endif + + backlightInit(); } +void lcdClear() { lcd.clear(); } + +// Direct drawing - used by boot loader + // // Private code copied and adapted from LVGL / lv_refr.c // (_call_flush_cb & _draw_buf_flush) @@ -182,21 +171,12 @@ static void _call_flush_cb(lv_disp_drv_t* drv, const lv_area_t* area, drv->flush_cb(drv, &offset_area, color_p); } -static void _draw_buf_flush(lv_disp_t* disp) +void lcdRefresh() { + /* Flush the rendered content to the display */ + lv_disp_t* disp = _lv_refr_get_disp_refreshing(); lv_disp_draw_buf_t* draw_buf = lv_disp_get_draw_buf(disp); - - /*Flush the rendered content to the display*/ lv_draw_ctx_t* draw_ctx = disp->driver->draw_ctx; - if (draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx); - - /* In double buffered mode wait until the other buffer is freed - * and driver is ready to receive the new buffer */ - if (draw_buf->buf1 && draw_buf->buf2) { - while (draw_buf->flushing) { - if (disp->driver->wait_cb) disp->driver->wait_cb(disp->driver); - } - } draw_buf->flushing = 1; draw_buf->flushing_last = 1; @@ -208,15 +188,17 @@ static void _draw_buf_flush(lv_disp_t* disp) /*If there are 2 buffers swap them. */ if (draw_buf->buf1 && draw_buf->buf2) { + /* In double buffered mode wait until the other buffer is freed + * and driver is ready to receive the new buffer */ + while (draw_buf->flushing); if (draw_buf->buf_act == draw_buf->buf1) draw_buf->buf_act = draw_buf->buf2; else draw_buf->buf_act = draw_buf->buf1; } -} -void lcdRefresh() -{ - lv_disp_t* d = _lv_refr_get_disp_refreshing(); - _draw_buf_flush(d); + // Update draw context and lcd bitmap + draw_ctx->buf = draw_buf->buf_act; + lcd.setData((pixel_t*)draw_buf->buf_act); + lcd.reset(); } diff --git a/radio/src/gui/colorlcd/boot_menu.cpp b/radio/src/gui/colorlcd/boot_menu.cpp index 74a9db750..ff174d41e 100644 --- a/radio/src/gui/colorlcd/boot_menu.cpp +++ b/radio/src/gui/colorlcd/boot_menu.cpp @@ -55,7 +55,7 @@ constexpr coord_t PROGRESS_W = LCD_W * 3 / 4; constexpr coord_t PROGRESS_X = (LCD_W - PROGRESS_W) / 2; LAYOUT_VAL_SCALED(PROGRESS_H, 31) -extern BitmapBuffer * lcd; +extern BitmapBuffer lcd; #if defined(USB_SW_GPIO) #include "hal/gpio.h" @@ -74,28 +74,28 @@ void blExit(void) static void bootloaderDrawTitle(const char* text) { - lcd->drawText(LCD_W / 2, TITLE_Y1, text, CENTERED | BL_FOREGROUND); - lcd->drawSolidFilledRect(PAD_LARGE, TITLE_Y2, LCD_W - PAD_LARGE * 2, LINE_H, BL_FOREGROUND); + lcd.drawText(LCD_W / 2, TITLE_Y1, text, CENTERED | BL_FOREGROUND); + lcd.drawSolidFilledRect(PAD_LARGE, TITLE_Y2, LCD_W - PAD_LARGE * 2, LINE_H, BL_FOREGROUND); } static void bootloaderDrawFooter() { - lcd->drawSolidFilledRect(PAD_LARGE, LCD_H - FOOTER_LY, LCD_W - PAD_LARGE * 2, LINE_H, BL_FOREGROUND); + lcd.drawSolidFilledRect(PAD_LARGE, LCD_H - FOOTER_LY, LCD_W - PAD_LARGE * 2, LINE_H, BL_FOREGROUND); } static void bootloaderDrawVerFooter() { bootloaderDrawFooter(); if (LCD_W < LCD_H) - lcd->drawText(LCD_W / 2, LCD_H - FOOTER_Y2 + PAD_TINY, TR_BL_CURRENT_FW, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H - FOOTER_Y2 + PAD_TINY, TR_BL_CURRENT_FW, CENTERED | BL_FOREGROUND); const char* fw_ver = getFirmwareVersion(); if (!fw_ver) fw_ver = TR_BL_NO_VERSION; - lcd->drawText(LCD_W / 2, LCD_H - FOOTER_Y1, fw_ver, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H - FOOTER_Y1, fw_ver, CENTERED | BL_FOREGROUND); } static void bootloaderDrawBackground() { - lcd->clear(BL_BACKGROUND); + lcd.clear(BL_BACKGROUND); } bool bootloaderRadioMenu(uint32_t menuItem, event_t event) @@ -157,14 +157,12 @@ void bootloaderInitScreen() void bootloaderDrawDFUScreen() { - lcdInitDirectDrawing(); bootloaderDrawBackground(); - lcd->drawText(LCD_W / 2, LCD_H / 2, TR_BL_DFU_MODE, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2, TR_BL_DFU_MODE, CENTERED | BL_FOREGROUND); } void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) { - lcdInitDirectDrawing(); bootloaderDrawBackground(); bootloaderDrawTitle(BOOTLOADER_TITLE); @@ -173,9 +171,9 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) const char* msg = (st == ST_START) ? TR_BL_PLUG_USB : TR_BL_COPY_UF2; - lcd->drawText(LCD_W / 2, LCD_H / 2 - TITLE_Y1, msg, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2 - TITLE_Y1, msg, CENTERED | BL_FOREGROUND); if (st != ST_USB) - lcd->drawText(LCD_W / 2, LCD_H / 2 + TITLE_Y1, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2 + TITLE_Y1, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, CENTERED | BL_FOREGROUND); bootloaderDrawVerFooter(); @@ -184,11 +182,11 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) const coord_t pb_y = (LCD_H - PROGRESS_H) / 2; const char* msg = (st == ST_FLASH_DONE) ? TR_BL_WRITING_COMPL : TR_BL_WRITING_FW; - lcd->drawText(PROGRESS_X, pb_y - TITLE_Y1, msg, BL_FOREGROUND); - lcd->drawRect(PROGRESS_X, pb_y, PROGRESS_W, PROGRESS_H, LINE_H, SOLID, BL_SELECTED); + lcd.drawText(PROGRESS_X, pb_y - TITLE_Y1, msg, BL_FOREGROUND); + lcd.drawRect(PROGRESS_X, pb_y, PROGRESS_W, PROGRESS_H, LINE_H, SOLID, BL_SELECTED); LcdFlags color = (st == ST_FLASH_DONE) ? BL_GREEN : BL_RED; - lcd->drawSolidFilledRect(PROGRESS_X + PAD_SMALL, pb_y + PAD_SMALL, ((PROGRESS_W - PAD_SMALL * 2) * opt) / 100, PROGRESS_H - PAD_SMALL * 2, color); + lcd.drawSolidFilledRect(PROGRESS_X + PAD_SMALL, pb_y + PAD_SMALL, ((PROGRESS_W - PAD_SMALL * 2) * opt) / 100, PROGRESS_H - PAD_SMALL * 2, color); } } @@ -247,8 +245,8 @@ void bootloaderInitScreen() void bootloaderDrawItem(const char* symbol, const char* text, coord_t& y, coord_t& lastX, coord_t symXO = 0) { - lcd->drawText(SYM_X - symXO, y, symbol, BL_FOREGROUND); - coord_t nx = lcd->drawText(LBL_X, y, text, BL_FOREGROUND) + BOX_GAP; + lcd.drawText(SYM_X - symXO, y, symbol, BL_FOREGROUND); + coord_t nx = lcd.drawText(LBL_X, y, text, BL_FOREGROUND) + BOX_GAP; if (nx > lastX) lastX = nx; y += SYM_H; } @@ -256,12 +254,11 @@ void bootloaderDrawItem(const char* symbol, const char* text, coord_t& y, coord_ void bootloaderDrawSelected(coord_t boxX2, int opt) { boxX2 -= OPTBOX_X; - lcd->drawSolidRect(OPTBOX_X, BOX_Y + (opt * SYM_H), boxX2, BOX_H, PAD_TINY, BL_SELECTED); + lcd.drawSolidRect(OPTBOX_X, BOX_Y + (opt * SYM_H), boxX2, BOX_H, PAD_TINY, BL_SELECTED); } void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) { - lcdInitDirectDrawing(); bootloaderDrawBackground(); coord_t y = SYM_Y, boxX2 = 0; @@ -286,9 +283,9 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) bootloaderDrawSelected(boxX2, opt); - lcd->drawBitmap(USB_ICN_X, LCD_H - USB_ICN_Y, (const BitmapBuffer*)&BMP_PLUG_USB); - lcd->drawText(USB_TXT_X, LCD_H - USB_TXT_Y1, TR_BL_USB_PLUGIN, USB_TXT_ALIGN | BL_FOREGROUND); - lcd->drawText(USB_TXT_X, LCD_H - USB_TXT_Y2, TR_BL_USB_MASS_STORE, USB_TXT_ALIGN | BL_FOREGROUND); + lcd.drawBitmap(USB_ICN_X, LCD_H - USB_ICN_Y, (const BitmapBuffer*)&BMP_PLUG_USB); + lcd.drawText(USB_TXT_X, LCD_H - USB_TXT_Y1, TR_BL_USB_PLUGIN, USB_TXT_ALIGN | BL_FOREGROUND); + lcd.drawText(USB_TXT_X, LCD_H - USB_TXT_Y2, TR_BL_USB_MASS_STORE, USB_TXT_ALIGN | BL_FOREGROUND); bootloaderDrawVerFooter(); } @@ -301,7 +298,7 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) bootloaderDrawSelected(boxX2, opt); bootloaderDrawFooter(); - int pos = lcd->drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_SD_CARD " " TR_BL_ERASE_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); + int pos = lcd.drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_SD_CARD " " TR_BL_ERASE_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); #if LANDSCAPE pos = 0; #else @@ -309,12 +306,12 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) pos = (pos - FOOTER_X1) / 2; } #endif - lcd->drawText(FOOTER_X2 - pos, LCD_H - FOOTER_Y2, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, FOOTER_ALIGN2 | BL_FOREGROUND); + lcd.drawText(FOOTER_X2 - pos, LCD_H - FOOTER_Y2, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, FOOTER_ALIGN2 | BL_FOREGROUND); } else if (st == ST_CLEAR_FLASH) { bootloaderDrawTitle(TR_BL_ERASE_INT_FLASH); - lcd->drawText(LCD_W / 2, SYM_Y, TR_BL_ERASE_FLASH_MSG, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, SYM_Y, TR_BL_ERASE_FLASH_MSG, CENTERED | BL_FOREGROUND); bootloaderDrawFooter(); } #endif @@ -327,7 +324,7 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) bootloaderDrawSelected(boxX2, opt); bootloaderDrawFooter(); - int pos = lcd->drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_USB " " TR_BL_TOGGLE_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); + int pos = lcd.drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_USB " " TR_BL_TOGGLE_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); #if LANDSCAPE pos = 0; #else @@ -335,13 +332,13 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) pos = (pos - FOOTER_X1) / 2; } #endif - lcd->drawText(FOOTER_X2 - pos, LCD_H - FOOTER_Y2, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, FOOTER_ALIGN2 | BL_FOREGROUND); + lcd.drawText(FOOTER_X2 - pos, LCD_H - FOOTER_Y2, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, FOOTER_ALIGN2 | BL_FOREGROUND); } #endif else if (st == ST_USB) { y = (LCD_H - BMP_USB_PLUGGED.height()) / 2; - lcd->drawBitmap(USB_PLG_X, y, (const BitmapBuffer*)&BMP_USB_PLUGGED); - lcd->drawText(USB_TXT_X, y + USB_PLG_TXT_YO, TR_BL_USB_CONNECTED, USB_TXT_ALIGN | BL_FOREGROUND); + lcd.drawBitmap(USB_PLG_X, y, (const BitmapBuffer*)&BMP_USB_PLUGGED); + lcd.drawText(USB_TXT_X, y + USB_PLG_TXT_YO, TR_BL_USB_CONNECTED, USB_TXT_ALIGN | BL_FOREGROUND); } else if (st == ST_FILE_LIST || st == ST_DIR_CHECK || st == ST_FLASH_CHECK || st == ST_FLASHING || st == ST_FLASH_DONE) { @@ -356,37 +353,37 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) opt = 100; // Completed > 100% } - lcd->drawRect(PROGRESS_X, (LCD_H - PROGRESS_H) / 2, PROGRESS_W, PROGRESS_H, LINE_H, SOLID, BL_SELECTED); - lcd->drawSolidFilledRect(PROGRESS_X + PAD_SMALL, (LCD_H - PROGRESS_H) / 2 + PAD_SMALL, ((PROGRESS_W - PAD_SMALL * 2) * opt) / 100, PROGRESS_H - PAD_SMALL * 2, color); + lcd.drawRect(PROGRESS_X, (LCD_H - PROGRESS_H) / 2, PROGRESS_W, PROGRESS_H, LINE_H, SOLID, BL_SELECTED); + lcd.drawSolidFilledRect(PROGRESS_X + PAD_SMALL, (LCD_H - PROGRESS_H) / 2 + PAD_SMALL, ((PROGRESS_W - PAD_SMALL * 2) * opt) / 100, PROGRESS_H - PAD_SMALL * 2, color); } else if (st == ST_DIR_CHECK) { if (opt == FR_NO_PATH) { - lcd->drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_DIR_MISSING, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_DIR_MISSING, CENTERED | BL_FOREGROUND); } else { - lcd->drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_DIR_EMPTY, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_DIR_EMPTY, CENTERED | BL_FOREGROUND); } } else if (st == ST_FLASH_CHECK) { bootloaderDrawFilename(str, 0, true); if (opt == FC_ERROR) { - lcd->drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE, CENTERED | BL_FOREGROUND); } else if (opt == FC_OK) { VersionTag tag; memset(&tag, 0, sizeof(tag)); getFileFirmwareVersion(&tag); if (strcmp(tag.flavour, FLAVOUR)) { - lcd->drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE, CENTERED | BL_FOREGROUND); + lcd.drawText(LCD_W / 2, LCD_H / 2, LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE, CENTERED | BL_FOREGROUND); } else { - lcd->drawText(VERCHK_X, VERCHK_Y, TR_BL_FORK, RIGHT | BL_FOREGROUND); - lcd->drawSizedText(VERCHK_X + PAD_MEDIUM, VERCHK_Y, tag.fork, 6, BL_FOREGROUND); + lcd.drawText(VERCHK_X, VERCHK_Y, TR_BL_FORK, RIGHT | BL_FOREGROUND); + lcd.drawSizedText(VERCHK_X + PAD_MEDIUM, VERCHK_Y, tag.fork, 6, BL_FOREGROUND); - lcd->drawText(VERCHK_X, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT, TR_BL_VERSION, RIGHT | BL_FOREGROUND); - lcd->drawText(VERCHK_X + PAD_MEDIUM, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT, tag.version, BL_FOREGROUND); + lcd.drawText(VERCHK_X, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT, TR_BL_VERSION, RIGHT | BL_FOREGROUND); + lcd.drawText(VERCHK_X + PAD_MEDIUM, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT, tag.version, BL_FOREGROUND); - lcd->drawText(VERCHK_X, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT * 2, TR_BL_RADIO, RIGHT | BL_FOREGROUND); - lcd->drawText(VERCHK_X + PAD_MEDIUM, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT * 2, tag.flavour, BL_FOREGROUND); + lcd.drawText(VERCHK_X, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT * 2, TR_BL_RADIO, RIGHT | BL_FOREGROUND); + lcd.drawText(VERCHK_X + PAD_MEDIUM, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT * 2, tag.flavour, BL_FOREGROUND); - lcd->drawText(VERCHK_ICN_X, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT, LV_SYMBOL_OK, BL_GREEN); + lcd.drawText(VERCHK_ICN_X, VERCHK_Y + EdgeTxStyles::STD_FONT_HEIGHT, LV_SYMBOL_OK, BL_GREEN); } } } @@ -397,16 +394,16 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) int align = FOOTER_ALIGN2; if ( st != ST_DIR_CHECK && (st != ST_FLASH_CHECK || opt == FC_OK)) { if (st == ST_FILE_LIST) { - pos = lcd->drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_SELECT_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); + pos = lcd.drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_SELECT_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); } else if (st == ST_FLASH_CHECK && opt == FC_OK) { - pos = lcd->drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_FLASH_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); + pos = lcd.drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_FLASH_KEY, FOOTER_ALIGN1 | BL_FOREGROUND); } else if (st == ST_FLASHING) { - pos = lcd->drawText(LCD_W / 2, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_WRITING_FW, CENTERED | BL_FOREGROUND); + pos = lcd.drawText(LCD_W / 2, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_WRITING_FW, CENTERED | BL_FOREGROUND); } else if (st == ST_FLASH_DONE) { - pos = lcd->drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_WRITING_COMPL, FOOTER_ALIGN1 | BL_FOREGROUND); + pos = lcd.drawText(FOOTER_X1, LCD_H - FOOTER_Y1, LV_SYMBOL_CHARGE " " TR_BL_WRITING_COMPL, FOOTER_ALIGN1 | BL_FOREGROUND); } } #if LANDSCAPE @@ -419,18 +416,18 @@ void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) } #endif if (st != ST_FLASHING) { - lcd->drawText(FOOTER_X2 - pos, LCD_H - FOOTER_Y2, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, align | BL_FOREGROUND); + lcd.drawText(FOOTER_X2 - pos, LCD_H - FOOTER_Y2, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, align | BL_FOREGROUND); } } } void bootloaderDrawFilename(const char* str, uint8_t line, bool selected) { - lcd->drawText(FILENAM_X1, FILENAM_Y1 + (line * FILENAM_H), LV_SYMBOL_FILE, BL_FOREGROUND); - lcd->drawText(FILENAM_X2, FILENAM_Y1 + (line * FILENAM_H), str, BL_FOREGROUND); + lcd.drawText(FILENAM_X1, FILENAM_Y1 + (line * FILENAM_H), LV_SYMBOL_FILE, BL_FOREGROUND); + lcd.drawText(FILENAM_X2, FILENAM_Y1 + (line * FILENAM_H), str, BL_FOREGROUND); if (selected) { - lcd->drawSolidRect(FILESEL_X, BOX_Y + (line * FILENAM_H), FILESEL_W, BOX_H, PAD_TINY, BL_SELECTED); + lcd.drawSolidRect(FILESEL_X, BOX_Y + (line * FILENAM_H), FILESEL_W, BOX_H, PAD_TINY, BL_SELECTED); } } diff --git a/radio/src/gui/colorlcd/lcd.cpp b/radio/src/gui/colorlcd/lcd.cpp index b4eb7c946..22a7d5666 100644 --- a/radio/src/gui/colorlcd/lcd.cpp +++ b/radio/src/gui/colorlcd/lcd.cpp @@ -40,49 +40,43 @@ char* get_lvgl_mem(int nbytes) } #endif -pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; -pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; - -BitmapBuffer lcdBuffer1(BMP_RGB565, LCD_W, LCD_H, - (uint16_t*)LCD_FIRST_FRAME_BUFFER); -BitmapBuffer lcdBuffer2(BMP_RGB565, LCD_W, LCD_H, - (uint16_t*)LCD_SECOND_FRAME_BUFFER); - -static BitmapBuffer* lcdFront = &lcdBuffer1; -static BitmapBuffer* lcd = &lcdBuffer2; +pixel_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM __ALIGNED(64); +pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM __ALIGNED(64); static lv_disp_draw_buf_t disp_buf; static lv_disp_drv_t disp_drv; // Call backs -static void (*lcd_wait_cb)(lv_disp_drv_t*) = nullptr; static void (*lcd_flush_cb)(lv_disp_drv_t*, uint16_t* buffer, const rect_t& area) = nullptr; -void lcdSetWaitCb(void (*cb)(lv_disp_drv_t*)) { lcd_wait_cb = cb; } - void lcdSetFlushCb(void (*cb)(lv_disp_drv_t*, uint16_t*, const rect_t&)) { lcd_flush_cb = cb; } -static lv_disp_drv_t* refr_disp = nullptr; +#if defined(SIMU) +// Only used in simulator to prevent lock up when closing simulator +// TODO: find a better way to handle this +static void (*lcd_wait_cb)(lv_disp_drv_t*) = nullptr; +void lcdSetWaitCb(void (*cb)(lv_disp_drv_t*)) { lcd_wait_cb = cb; } +#endif + +extern "C" void lcdFlushed() +{ + lv_disp_flush_ready(&disp_drv); +} + +void lcdRefresh() {} static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) { -#if !LCD_VERTICAL_INVERT || defined(RADIO_F16) -#if defined(RADIO_F16) - if (hardwareOptions.pcbrev > 0) -#endif - { - // we're only interested in the last flush in direct mode - if (!lv_disp_flush_is_last(disp_drv)) { - lv_disp_flush_ready(disp_drv); - return; - } + // we're only interested in the last flush in direct mode + if (disp_drv->direct_mode && !lv_disp_flush_is_last(disp_drv)) { + lv_disp_flush_ready(disp_drv); + return; } -#endif #if defined(DEBUG_WINDOWS) if (area->x1 != 0 || area->x2 != LCD_W - 1 || area->y1 != 0 || @@ -95,15 +89,13 @@ static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, #endif if (lcd_flush_cb) { - refr_disp = disp_drv; - rect_t copy_area = {area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1}; lcd_flush_cb(disp_drv, (uint16_t*)color_p, copy_area); + } else { + lcdFlushed(); } - - lv_disp_flush_ready(disp_drv); } static void clear_frame_buffers() @@ -114,25 +106,30 @@ static void clear_frame_buffers() static void init_lvgl_disp_drv() { - lv_disp_draw_buf_init(&disp_buf, lcdFront->getData(), lcd->getData(), + int direct_mode = 1; +#if LCD_VERTICAL_INVERT +#if defined(RADIO_F16) + direct_mode = (hardwareOptions.pcbrev > 0) ? 1 : 0; +#else + direct_mode = 0; +#endif +#endif + + lv_disp_draw_buf_init(&disp_buf, + LCD_FIRST_FRAME_BUFFER, + direct_mode ? LCD_SECOND_FRAME_BUFFER : nullptr, LCD_W * LCD_H); lv_disp_drv_init(&disp_drv); /*Basic initialization*/ disp_drv.draw_buf = &disp_buf; /*Set an initialized buffer*/ disp_drv.flush_cb = flushLcd; /*Set a flush callback to draw to the display*/ +#if defined(SIMU) disp_drv.wait_cb = lcd_wait_cb; /*Set a wait callback*/ +#endif disp_drv.hor_res = LCD_W; /*Set the horizontal resolution in pixels*/ disp_drv.ver_res = LCD_H; /*Set the vertical resolution in pixels*/ - disp_drv.full_refresh = 0; - -#if !LCD_VERTICAL_INVERT - disp_drv.direct_mode = 1; -#elif defined(RADIO_F16) - disp_drv.direct_mode = (hardwareOptions.pcbrev > 0) ? 1 : 0; -#else - disp_drv.direct_mode = 0; -#endif + disp_drv.direct_mode = direct_mode; } void lcdInitDisplayDriver() @@ -153,7 +150,7 @@ void lcdInitDisplayDriver() // Clear buffers first clear_frame_buffers(); - lcdSetInitalFrameBuffer(lcdFront->getData()); + lcdSetInitalFrameBuffer(LCD_FIRST_FRAME_BUFFER); // Init hardware LCD driver lcdInit(); @@ -167,17 +164,3 @@ void lcdInitDisplayDriver() // remove all styles on default screen (makes it transparent as well) lv_obj_remove_style_all(lv_scr_act()); } - -void lcdFlushed() -{ - // Only used in simulator - - // its possible to get here before flushLcd is ever called. - // so check for nullptr first. (Race condition if you put breakpoints in - // startup code) - if (refr_disp != nullptr) lv_disp_flush_ready(refr_disp); -} - -#if defined(SIMU) -void lcdRefresh() {} -#endif diff --git a/radio/src/gui/colorlcd/lcd.h b/radio/src/gui/colorlcd/lcd.h index 4b325ecfd..caef6dd19 100644 --- a/radio/src/gui/colorlcd/lcd.h +++ b/radio/src/gui/colorlcd/lcd.h @@ -39,17 +39,16 @@ struct _lv_disp_drv_t; typedef _lv_disp_drv_t lv_disp_drv_t; // Call backs -void lcdSetWaitCb(void (*cb)(lv_disp_drv_t *)); void lcdSetFlushCb(void (*cb)(lv_disp_drv_t *, uint16_t*, const rect_t&)); +#if defined(SIMU) +void lcdSetWaitCb(void (*cb)(lv_disp_drv_t *)); +#endif // Init LVGL and its display driver void lcdInitDisplayDriver(); void lcdClear(); -// Patch the draw context to allow for direct drawing -void lcdInitDirectDrawing(); - void lcdRefresh(); -void lcdFlushed(); +extern "C" void lcdFlushed(); diff --git a/radio/src/gui/common/stdlcd/lcd_common.h b/radio/src/gui/common/stdlcd/lcd_common.h index de0fb2754..7193b0bd1 100644 --- a/radio/src/gui/common/stdlcd/lcd_common.h +++ b/radio/src/gui/common/stdlcd/lcd_common.h @@ -173,3 +173,5 @@ void drawTelemetryTopBar(); void lcdDraw1bitBitmap(coord_t x, coord_t y, const unsigned char * img, uint8_t idx, LcdFlags att=0); uint8_t getTextWidth(const char * s, uint8_t len=0, LcdFlags flags=0); + +void lcdFlushed(); diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index 724808e0c..3f2b2e2f3 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -32,6 +32,7 @@ #include "lcd.h" #include +#include #if defined(RADIO_T18) #define HBP 43 @@ -60,17 +61,29 @@ static void* initialFrameBuffer = nullptr; #if LCD_VERTICAL_INVERT typedef uint16_t pixel_t; -static pixel_t _LCD_BUF_1[DISPLAY_BUFFER_SIZE] __SDRAM; -static pixel_t _LCD_BUF_2[DISPLAY_BUFFER_SIZE] __SDRAM; - -static pixel_t _line_buffer[LCD_W]; +static pixel_t _LCD_BUF_1[DISPLAY_BUFFER_SIZE] __SDRAM __ALIGNED(64); +#if defined(RADIO_F16) +// F16 can be either normal or inverted +static pixel_t _LCD_BUF_2[DISPLAY_BUFFER_SIZE] __SDRAM __ALIGNED(64); +#else +// LVGL will only use one buffer when display is inverted so reuse 2nd +// buffer here +extern pixel_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE]; +#define _LCD_BUF_2 LCD_SECOND_FRAME_BUFFER +#endif +// Frame buffer pointers static uint16_t* _front_buffer = _LCD_BUF_1; static uint16_t* _back_buffer = _LCD_BUF_2; +// Vector to save areas that need to be copied from front buffer to back buffer +static std::vector dma_areas; + // Copy 2 pixels at once to speed up a little static void _copy_rotate_180(uint16_t* dst, uint16_t* src, const rect_t& copy_area) { + static pixel_t _line_buffer[LCD_W]; + coord_t x1 = LCD_W - copy_area.w - copy_area.x; coord_t y1 = LCD_H - copy_area.h - copy_area.y; @@ -106,50 +119,44 @@ static void _copy_rotate_180(uint16_t* dst, uint16_t* src, const rect_t& copy_ar dst -= LCD_W; } } - -static void _rotate_area_180(lv_area_t& area) -{ - lv_coord_t tmp_coord; - tmp_coord = area.y2; - area.y2 = LCD_H - area.y1 - 1; - area.y1 = LCD_H - tmp_coord - 1; - tmp_coord = area.x2; - area.x2 = LCD_W - area.x1 - 1; - area.x1 = LCD_W - tmp_coord - 1; -} #endif -static volatile uint8_t _frame_addr_reloaded = 0; - static void _update_frame_buffer_addr(uint16_t* addr) { LTDC_Layer1->CFBAR = (uint32_t)addr; - // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { #if LCD_VERTICAL_INVERT -#if defined(RADIO_F16) - if(hardwareOptions.pcbrev > 0) { - // Direct mode + if (disp_drv->direct_mode) { + // Direct mode / not inverted _update_frame_buffer_addr(buffer); - } else -#endif - { + return; + } + + // Copy areas that were updated last frame to the back buffer + if (dma_areas.size() > 0) { + for (auto a: dma_areas) { + DMACopyBitmap(_back_buffer, LCD_W, LCD_H, a.x1, a.y1, + _front_buffer, LCD_W, LCD_H, a.x1, a.y1, + a.x2 - a.x1 + 1, a.y2 - a.y1 + 1); + } + dma_areas.clear(); + DMAWait(); + } + + // Copy changes from LVGL to LCD back buffer with 180 degree rotation _copy_rotate_180(_back_buffer, buffer, copy_area); + // Check for last LVGL update before we need to swap buffers if (lv_disp_flush_is_last(disp_drv)) { - - // swap back/front + // swap back/front buffers if (_front_buffer == _LCD_BUF_1) { _front_buffer = _LCD_BUF_2; _back_buffer = _LCD_BUF_1; @@ -161,30 +168,22 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, // Trigger async refresh _update_frame_buffer_addr(_front_buffer); - // Copy refreshed & rotated areas into new back buffer - uint16_t* src = _front_buffer; - uint16_t* dst = _back_buffer; - + // Save areas that need to be updated next time around lv_disp_t* disp = _lv_refr_get_disp_refreshing(); for(int i = 0; i < disp->inv_p; i++) { if(disp->inv_area_joined[i]) continue; + // Rotate area 180 degrees lv_area_t refr_area; - lv_area_copy(&refr_area, &disp->inv_areas[i]); + refr_area.x1 = LCD_W - disp->inv_areas[i].x2 - 1; + refr_area.x2 = LCD_W - disp->inv_areas[i].x1 - 1; + refr_area.y1 = LCD_H - disp->inv_areas[i].y2 - 1; + refr_area.y2 = LCD_H - disp->inv_areas[i].y1 - 1; - // TRACE("Vert invert refresh {%d,%d,%d,%d}", refr_area.x1, - // refr_area.y1, refr_area.x2 - refr_area.x1 + 1, refr_area.y2 - refr_area.y1 + 1); - - _rotate_area_180(refr_area); - - auto area_w = refr_area.x2 - refr_area.x1 + 1; - auto area_h = refr_area.y2 - refr_area.y1 + 1; - - DMACopyBitmap(dst, LCD_W, LCD_H, refr_area.x1, refr_area.y1, - src, LCD_W, LCD_H, refr_area.x1, refr_area.y1, - area_w, area_h); + dma_areas.push_back(refr_area); } - } + } else { + lv_disp_flush_ready(disp_drv); } #else // Direct mode @@ -337,7 +336,6 @@ void LCD_Init_LTDC() // Trigger on last line HAL_LTDC_ProgramLineEvent(&hltdc, LCD_PHYS_H); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); #if 0 DMA2D_ITConfig(DMA2D_CR_TCIE, ENABLE); @@ -425,8 +423,8 @@ void lcdInit() { #if LCD_VERTICAL_INVERT // Clear buffer first - memset(_LCD_BUF_1, 0, sizeof(_LCD_BUF_1)); - memset(_LCD_BUF_2, 0, sizeof(_LCD_BUF_2)); + memset(_LCD_BUF_1, 0, DISPLAY_BUFFER_SIZE * sizeof(pixel_t)); + memset(_LCD_BUF_2, 0, DISPLAY_BUFFER_SIZE * sizeof(pixel_t)); #endif // Initialize the LCD @@ -439,11 +437,11 @@ void lcdInit() lcdSetFlushCb(startLcdRefresh); } - extern "C" void LTDC_IRQHandler(void) { // clear interrupt flag __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); - _frame_addr_reloaded = 1; -} + __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + lcdFlushed(); +} diff --git a/radio/src/targets/horus/lcd_st7796s_driver.cpp b/radio/src/targets/horus/lcd_st7796s_driver.cpp index 7fabd4d6e..d1b2e8fae 100644 --- a/radio/src/targets/horus/lcd_st7796s_driver.cpp +++ b/radio/src/targets/horus/lcd_st7796s_driver.cpp @@ -36,24 +36,17 @@ static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t* disp_drv, uint16_t* buffer, const rect_t& copy_area) { (void)disp_drv; (void)copy_area; - LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); LTDC_Layer1->CFBAR = (uint32_t)buffer; // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while (_frame_addr_reloaded == 0); + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } uint32_t lcdPixelClock; @@ -389,7 +382,6 @@ void LCD_Init_LTDC() // Trigger on last line HAL_LTDC_ProgramLineEvent(&hltdc, LCD_W); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } void LCD_LayerInit() @@ -466,5 +458,6 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; + + lcdFlushed(); } diff --git a/radio/src/targets/pa01/lcd_driver.cpp b/radio/src/targets/pa01/lcd_driver.cpp index da2ede118..055d17ab3 100644 --- a/radio/src/targets/pa01/lcd_driver.cpp +++ b/radio/src/targets/pa01/lcd_driver.cpp @@ -120,6 +120,8 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, set_row_addr(y1, y2); memory_write(buffer, copy_area.w * copy_area.h); + + lcdFlushed(); } lcdSpiInitFucPtr lcdInitFunction; diff --git a/radio/src/targets/pl18/lcd_driver.cpp b/radio/src/targets/pl18/lcd_driver.cpp index 070bdb5f1..e597c5621 100644 --- a/radio/src/targets/pl18/lcd_driver.cpp +++ b/radio/src/targets/pl18/lcd_driver.cpp @@ -40,24 +40,17 @@ static void* initialFrameBuffer = nullptr; #define GPIO_AF_LTDC GPIO_AF14 -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { (void)disp_drv; (void)copy_area; - LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); LTDC_Layer1->CFBAR = (uint32_t)buffer; // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); + __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } lcdSpiInitFucPtr lcdInitFunction; @@ -2763,7 +2756,6 @@ void LCD_Init_LTDC() { // Trigger on last line HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } void LCD_LayerInit() { @@ -2887,6 +2879,6 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; -} + lcdFlushed(); +} diff --git a/radio/src/targets/simu/simulib.cpp b/radio/src/targets/simu/simulib.cpp index 82778f26d..64b313739 100644 --- a/radio/src/targets/simu/simulib.cpp +++ b/radio/src/targets/simu/simulib.cpp @@ -84,7 +84,6 @@ rotenc_t rotaryEncoderGetValue() extern const etx_hal_adc_driver_t simu_adc_driver; void lcdCopy(void * dest, void * src); -void lcdFlushed(); #if defined(AUX_SERIAL) || defined(AUX2_SERIAL) static void hostSerialInit(); @@ -733,7 +732,8 @@ void simuLuaReloadPermanentScripts() void simuLcdFlushed() { - ::lcdFlushed(); + if (simu_running) + lcdFlushed(); } uint8_t simuGetMaxTrainerChannels() diff --git a/radio/src/targets/st16/lcd_driver.cpp b/radio/src/targets/st16/lcd_driver.cpp index 941b50657..b647f5903 100644 --- a/radio/src/targets/st16/lcd_driver.cpp +++ b/radio/src/targets/st16/lcd_driver.cpp @@ -40,8 +40,6 @@ static volatile uint16_t lcd_phys_h = LCD_PHYS_H; static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { @@ -53,16 +51,10 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, SCB_CleanDCache(); LTDC_Layer1->CFBAR = (uint32_t)buffer; - // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); - - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); } lcdSpiInitFucPtr lcdInitFunction; @@ -2760,7 +2752,6 @@ void LCD_Init_LTDC() { // Trigger on last line HAL_LTDC_ProgramLineEvent(&hltdc, lcd_phys_h); - __HAL_LTDC_ENABLE_IT(&hltdc, LTDC_IT_LI); } void LCD_LayerInit() { @@ -2885,5 +2876,6 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; + + lcdFlushed(); } diff --git a/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp b/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp index 4139306c5..e5b0ec465 100644 --- a/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp +++ b/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp @@ -417,8 +417,6 @@ extern "C" void backlightInit() LPTIMx_PWM_Init(&hlcd_lptim); } -static volatile uint8_t _frame_addr_reloaded = 0; - static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { @@ -427,18 +425,11 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, SCB_CleanDCache(); - LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); LTDC_Layer1->CFBAR = (uint32_t)buffer; - // reload shadow registers on vertical blank - _frame_addr_reloaded = 0; LTDC->SRCR = LTDC_SRCR_VBR; __HAL_LTDC_ENABLE_IT(&hlcd_ltdc, LTDC_IT_LI); - - // wait for reload - // TODO: replace through some smarter mechanism without busy wait - while(_frame_addr_reloaded == 0); } extern "C" void lcdSetInitalFrameBuffer(void* fbAddress) @@ -460,5 +451,6 @@ extern "C" void LTDC_IRQHandler(void) // clear interrupt flag __HAL_LTDC_CLEAR_FLAG(&hlcd_ltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hlcd_ltdc, LTDC_IT_LI); - _frame_addr_reloaded = 1; + + lcdFlushed(); } diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 891462520..21b1eb9d0 100644 --- a/radio/src/targets/taranis/board.h +++ b/radio/src/targets/taranis/board.h @@ -312,7 +312,6 @@ void lcdSetInvert(bool invert); #ifdef __cplusplus void lcdSetContrast(bool useDefault = false); #endif -void lcdFlushed(); // Top LCD driver #if defined(TOPLCD_GPIO)