diff --git a/radio/src/boards/jumper-h750/lcd_driver.cpp b/radio/src/boards/jumper-h750/lcd_driver.cpp index 013e91ff61a..ba0330f905a 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,14 +33,15 @@ #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; +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) @@ -54,16 +53,20 @@ 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); +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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 +#if defined(BOOT) + // wait for reload to finish - required for bootloader while(_frame_addr_reloaded == 0); +#endif } lcdSpiInitFucPtr lcdInitFunction; @@ -71,8 +74,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 +1885,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 +2009,10 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; -} \ No newline at end of file +#else + lvglFlushed(); +#endif +} diff --git a/radio/src/boards/jumper-h750/lcd_driver.h b/radio/src/boards/jumper-h750/lcd_driver.h index 6ffeb1e9c14..d42f435ddee 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 c8b7612896f..d3eb4ccec92 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,14 +32,12 @@ #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; +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) @@ -53,25 +49,22 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, // faster than cleaning by address SCB_CleanDCache(); +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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 +#if defined(BOOT) + // wait for reload to finish - required for bootloader while(_frame_addr_reloaded == 0); +#endif } -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 +417,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 +432,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 +440,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 +460,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 +500,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 +522,10 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } - diff --git a/radio/src/boards/rm-h750/lcd_driver_480.h b/radio/src/boards/rm-h750/lcd_driver_480.h index dbb2e52d1dc..c8debb9309c 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 d6790db7491..ca2b22efa52 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,14 +32,12 @@ #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; +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) @@ -53,25 +49,22 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, // faster than cleaning by address SCB_CleanDCache(); +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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 +#if defined(BOOT) + // wait for reload to finish - required for bootloader while(_frame_addr_reloaded == 0); +#endif } -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 +114,6 @@ static void lcdReset() { delay_ms(100); } - - void LCD_Init_LTDC() { hltdc.Instance = LTDC; @@ -166,13 +157,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 +172,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 +180,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 +200,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 +261,10 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } diff --git a/radio/src/boards/rm-h750/lcd_driver_800.h b/radio/src/boards/rm-h750/lcd_driver_800.h index 9b700f931e4..3188a3ec4e1 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 0ce2ca9d55f..835eb8c9da8 100644 --- a/radio/src/gui/colorlcd/boot_lcd.cpp +++ b/radio/src/gui/colorlcd/boot_lcd.cpp @@ -33,16 +33,10 @@ #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; @@ -58,14 +52,10 @@ 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}; @@ -83,7 +73,19 @@ 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 defined(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*/ @@ -93,14 +95,7 @@ static void init_lvgl_disp_drv() 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 !defined(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 +114,7 @@ void lcdInitDisplayDriver() // Clear buffers first clear_frame_buffers(); - lcdSetInitalFrameBuffer(lcdFront->getData()); + lcdSetInitalFrameBuffer(lcd.getData()); // Init hardware LCD driver lcdInit(); @@ -142,11 +137,10 @@ void lcdInitDisplayDriver() } lv_draw_ctx_t* draw_ctx = disp_drv.draw_ctx; - lcd->setDrawCtx(draw_ctx); - lcdFront->setDrawCtx(draw_ctx); + lcd.setDrawCtx(draw_ctx); } -void lcdClear() { lcd->clear(); } +void lcdClear() { lcd.clear(); } // Direct drawing - used by boot loader @@ -158,8 +152,8 @@ void lcdInitDirectDrawing() 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(); + lcd.setData((pixel_t*)draw_ctx->buf); + lcd.reset(); } // diff --git a/radio/src/gui/colorlcd/boot_menu.cpp b/radio/src/gui/colorlcd/boot_menu.cpp index 74a9db75062..3e9e22a13f9 100644 --- a/radio/src/gui/colorlcd/boot_menu.cpp +++ b/radio/src/gui/colorlcd/boot_menu.cpp @@ -38,6 +38,9 @@ #define BL_FOREGROUND COLOR_WHITE #define BL_SELECTED COLOR2FLAGS(RGB(11, 65, 244)) // deep blue +// Patch the draw context to allow for direct drawing +extern void lcdInitDirectDrawing(); + static constexpr coord_t LINE_H = 2; LAYOUT_VAL_SCALED(TITLE_Y1, 28) @@ -55,7 +58,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 +77,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) @@ -159,7 +162,7 @@ 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) @@ -173,9 +176,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 +187,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 +250,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,7 +259,7 @@ 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) @@ -286,9 +289,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 +304,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 +312,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 +330,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 +338,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 +359,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 +400,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 +422,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 e554305167a..ecdd9241f47 100644 --- a/radio/src/gui/colorlcd/lcd.cpp +++ b/radio/src/gui/colorlcd/lcd.cpp @@ -40,49 +40,40 @@ 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; +#if defined(SIMU) +static void (*lcd_wait_cb)(lv_disp_drv_t*) = nullptr; void lcdSetWaitCb(void (*cb)(lv_disp_drv_t*)) { lcd_wait_cb = cb; } +static lv_disp_drv_t* refr_disp = nullptr; +#endif + +extern "C" void lvglFlushed() +{ + 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 !defined(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 +86,17 @@ static void flushLcd(lv_disp_drv_t* disp_drv, const lv_area_t* area, #endif if (lcd_flush_cb) { +#if defined(SIMU) refr_disp = disp_drv; +#endif 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 { + lvglFlushed(); } - - lv_disp_flush_ready(disp_drv); } static void clear_frame_buffers() @@ -114,25 +107,31 @@ 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 defined(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 !defined(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 +152,7 @@ void lcdInitDisplayDriver() // Clear buffers first clear_frame_buffers(); - lcdSetInitalFrameBuffer(lcdFront->getData()); + lcdSetInitalFrameBuffer(LCD_FIRST_FRAME_BUFFER); // Init hardware LCD driver lcdInit(); @@ -168,6 +167,7 @@ void lcdInitDisplayDriver() lv_obj_remove_style_all(lv_scr_act()); } +#if defined(SIMU) void lcdFlushed() { // Only used in simulator @@ -178,6 +178,5 @@ void lcdFlushed() 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 4b325ecfd24..ce17c86985d 100644 --- a/radio/src/gui/colorlcd/lcd.h +++ b/radio/src/gui/colorlcd/lcd.h @@ -39,17 +39,17 @@ 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 *)); +void lcdFlushed(); +#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 lvglFlushed(); diff --git a/radio/src/gui/common/stdlcd/lcd_common.cpp b/radio/src/gui/common/stdlcd/lcd_common.cpp index 893f9ff951f..58fa3f34ebd 100644 --- a/radio/src/gui/common/stdlcd/lcd_common.cpp +++ b/radio/src/gui/common/stdlcd/lcd_common.cpp @@ -41,7 +41,9 @@ coord_t lcdLastRightPos; coord_t lcdLastLeftPos; coord_t lcdNextPos; +#if defined(SIMU) void lcdFlushed() {} +#endif void lcdClear() { diff --git a/radio/src/gui/common/stdlcd/lcd_common.h b/radio/src/gui/common/stdlcd/lcd_common.h index de0fb2754df..645379a78b7 100644 --- a/radio/src/gui/common/stdlcd/lcd_common.h +++ b/radio/src/gui/common/stdlcd/lcd_common.h @@ -173,3 +173,7 @@ 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); + +#if defined(SIMU) +void lcdFlushed(); +#endif diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index c6aab824fe3..2b4a3c2a3e9 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,24 @@ static void* initialFrameBuffer = nullptr; #if defined(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); +// 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 +// 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 +114,57 @@ 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 +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void _update_frame_buffer_addr(uint16_t* addr) { - LTDC_Layer1->CFBAR = (uint32_t)addr; +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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); + +#if defined(BOOT) + // wait for reload to finish - required for bootloader & inverted LCD radios + while (_frame_addr_reloaded == 0); +#endif } static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) { #if defined(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 +176,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]); - - // 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); + 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; - _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 +344,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 +431,8 @@ void lcdInit() { #if defined(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 +445,15 @@ void lcdInit() lcdSetFlushCb(startLcdRefresh); } - extern "C" void LTDC_IRQHandler(void) { // clear interrupt flag __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); + __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } - diff --git a/radio/src/targets/horus/lcd_st7796s_driver.cpp b/radio/src/targets/horus/lcd_st7796s_driver.cpp index 7fabd4d6eab..64eb77041b8 100644 --- a/radio/src/targets/horus/lcd_st7796s_driver.cpp +++ b/radio/src/targets/horus/lcd_st7796s_driver.cpp @@ -36,7 +36,9 @@ static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t* disp_drv, uint16_t* buffer, const rect_t& copy_area) @@ -44,16 +46,20 @@ static void startLcdRefresh(lv_disp_drv_t* disp_drv, uint16_t* buffer, (void)disp_drv; (void)copy_area; - LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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); +#if defined(BOOT) + // wait for reload to finish - required for bootloader + while(_frame_addr_reloaded == 0); +#endif } uint32_t lcdPixelClock; @@ -389,7 +395,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 +471,10 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } diff --git a/radio/src/targets/pa01/lcd_driver.cpp b/radio/src/targets/pa01/lcd_driver.cpp index da2ede11821..de0a8b41526 100644 --- a/radio/src/targets/pa01/lcd_driver.cpp +++ b/radio/src/targets/pa01/lcd_driver.cpp @@ -120,6 +120,10 @@ 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); + +#if !defined(BOOT) + lvglFlushed(); +#endif } lcdSpiInitFucPtr lcdInitFunction; diff --git a/radio/src/targets/pl18/lcd_driver.cpp b/radio/src/targets/pl18/lcd_driver.cpp index 070bdb5f19a..f548f47e01a 100644 --- a/radio/src/targets/pl18/lcd_driver.cpp +++ b/radio/src/targets/pl18/lcd_driver.cpp @@ -40,7 +40,9 @@ static void* initialFrameBuffer = nullptr; #define GPIO_AF_LTDC GPIO_AF14 +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) @@ -48,16 +50,20 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, (void)disp_drv; (void)copy_area; - LTDC_Layer1->CFBAR &= ~(LTDC_LxCFBAR_CFBADD); +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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 +#if defined(BOOT) + // wait for reload to finish - required for bootloader while(_frame_addr_reloaded == 0); +#endif } lcdSpiInitFucPtr lcdInitFunction; @@ -2763,7 +2769,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 +2892,10 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } - diff --git a/radio/src/targets/simu/simulib.cpp b/radio/src/targets/simu/simulib.cpp index d5ae5f222c5..7cdcfc5c751 100644 --- a/radio/src/targets/simu/simulib.cpp +++ b/radio/src/targets/simu/simulib.cpp @@ -70,7 +70,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(); @@ -721,7 +720,7 @@ void simuLuaReloadPermanentScripts() void simuLcdFlushed() { - ::lcdFlushed(); + lcdFlushed(); } uint8_t simuGetMaxTrainerChannels() diff --git a/radio/src/targets/st16/lcd_driver.cpp b/radio/src/targets/st16/lcd_driver.cpp index 941b506576c..14453ba15a2 100644 --- a/radio/src/targets/st16/lcd_driver.cpp +++ b/radio/src/targets/st16/lcd_driver.cpp @@ -40,7 +40,9 @@ static volatile uint16_t lcd_phys_h = LCD_PHYS_H; static LTDC_HandleTypeDef hltdc; static void* initialFrameBuffer = nullptr; +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) @@ -52,17 +54,20 @@ static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, // faster than cleaning by address SCB_CleanDCache(); - LTDC_Layer1->CFBAR = (uint32_t)buffer; +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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 +#if defined(BOOT) + // wait for reload to finish - required for bootloader while(_frame_addr_reloaded == 0); +#endif } lcdSpiInitFucPtr lcdInitFunction; @@ -2760,7 +2765,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 +2889,10 @@ extern "C" void LTDC_IRQHandler(void) { __HAL_LTDC_CLEAR_FLAG(&hltdc, LTDC_FLAG_LI); __HAL_LTDC_DISABLE_IT(&hltdc, LTDC_IT_LI); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } diff --git a/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp b/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp index 4139306c57d..dfb19d75f7d 100644 --- a/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp +++ b/radio/src/targets/stm32h7s78-dk/lcd_driver.cpp @@ -417,7 +417,9 @@ extern "C" void backlightInit() LPTIMx_PWM_Init(&hlcd_lptim); } +#if defined(BOOT) static volatile uint8_t _frame_addr_reloaded = 0; +#endif static void startLcdRefresh(lv_disp_drv_t *disp_drv, uint16_t *buffer, const rect_t ©_area) @@ -427,18 +429,20 @@ 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; +#if defined(BOOT) + _frame_addr_reloaded = 0; +#endif + 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 +#if defined(BOOT) + // wait for reload to finish - required for bootloader while(_frame_addr_reloaded == 0); +#endif } extern "C" void lcdSetInitalFrameBuffer(void* fbAddress) @@ -460,5 +464,10 @@ 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); + +#if defined(BOOT) _frame_addr_reloaded = 1; +#else + lvglFlushed(); +#endif } diff --git a/radio/src/targets/taranis/board.h b/radio/src/targets/taranis/board.h index 7cecc6749e5..554b88c543a 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)