From 82047b1ac6e56361abac0c4b01f06c405e941d19 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 1 Oct 2017 18:00:49 +1000 Subject: STM32LTDC 2nd layer support with alpha --- drivers/gdisp/STM32LTDC/board_STM32LTDC_template.h | 47 ++++++-- drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c | 134 +++++++++++++-------- drivers/gdisp/STM32LTDC/gdisp_lld_config.h | 20 ++- 3 files changed, 133 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/gdisp/STM32LTDC/board_STM32LTDC_template.h b/drivers/gdisp/STM32LTDC/board_STM32LTDC_template.h index 0596fe7b..8164c166 100644 --- a/drivers/gdisp/STM32LTDC/board_STM32LTDC_template.h +++ b/drivers/gdisp/STM32LTDC/board_STM32LTDC_template.h @@ -8,6 +8,8 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H +#define ALLOW_2ND_LAYER TRUE + static const ltdcConfig driverCfg = { 480, 272, // Width, Height (pixels) 41, 10, // Horizontal, Vertical sync (pixels) @@ -17,14 +19,14 @@ static const ltdcConfig driverCfg = { 0x000000, // Clear color (RGB888) { // Background layer config - (LLDCOLOR_TYPE *)SDRAM_DEVICE_ADDR, // Frame buffer address + (LLDCOLOR_TYPE *)SDRAM_DEVICE_ADDR, // Frame buffer address 480, 272, // Width, Height (pixels) 480 * LTDC_PIXELBYTES, // Line pitch (bytes) LTDC_PIXELFORMAT, // Pixel format 0, 0, // Start pixel position (x, y) 480, 272, // Size of virtual layer (cx, cy) - LTDC_COLOR_FUCHSIA, // Default color (ARGB8888) - 0x980088, // Color key (RGB888) + 0x00000000, // Default color (ARGB8888) + 0x000000, // Color key (RGB888) LTDC_BLEND_FIX1_FIX2, // Blending factors 0, // Palette (RGB888, can be NULL) 0, // Palette length @@ -32,28 +34,47 @@ static const ltdcConfig driverCfg = { LTDC_LEF_ENABLE // Layer configuration flags }, - LTDC_UNUSED_LAYER_CONFIG // Foreground layer config +#if ALLOW_2ND_LAYER + { // Foreground layer config (if turned on) + (LLDCOLOR_TYPE *)(SDRAM_DEVICE_ADDR+(480 * 272 * LTDC_PIXELBYTES)), // Frame buffer address + 480, 272, // Width, Height (pixels) + 480 * LTDC_PIXELBYTES, // Line pitch (bytes) + LTDC_PIXELFORMAT, // Pixel format + 0, 0, // Start pixel position (x, y) + 480, 272, // Size of virtual layer (cx, cy) + 0x00000000, // Default color (ARGB8888) + 0x000000, // Color key (RGB888) + LTDC_BLEND_MOD1_MOD2, // Blending factors + 0, // Palette (RGB888, can be NULL) + 0, // Palette length + 0xFF, // Constant alpha factor + LTDC_LEF_ENABLE // Layer configuration flags + } +#else + LTDC_UNUSED_LAYER_CONFIG +#endif }; static GFXINLINE void init_board(GDisplay* g) { - - // As we are not using multiple displays we set g->board to NULL as we don't use it. - g->board = 0; - - switch(g->controllerdisplay) { - case 0: // Set up for Display 0 - // Your init here - break; - } + // This is function only called once with the display for the background layer. + (void)g; } static GFXINLINE void post_init_board(GDisplay* g) { + // This is function may be called twice - once for the background display and once + // for the foreground display. + // Note: It doesn't get called for the foreground display unless gfxconf.h has been + // setup for two displays on this controller. (void)g; } static GFXINLINE void set_backlight(GDisplay* g, uint8_t percent) { + // This is function may be called with the display for either the foreground + // or the background layer. + // Note: It can't be called for the foreground display unless gfxconf.h has been + // setup for two displays on this controller. (void)g; (void)percent; } diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c index 37fe779f..1dedb22b 100644 --- a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c +++ b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c @@ -99,13 +99,15 @@ typedef struct ltdcConfig { /* Driver local routines. */ /*===========================================================================*/ -#define PIXIL_POS(g, x, y) ((y) * driverCfg.bglayer.pitch + (x) * LTDC_PIXELBYTES) -#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)((uint8_t *)driverCfg.bglayer.frame+pos)) +#define PIXIL_POS(g, x, y) ((y) * ((ltdcLayerConfig *)g->priv)->pitch + (x) * LTDC_PIXELBYTES) +#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)((uint8_t *)((ltdcLayerConfig *)g->priv)->frame+pos)) /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ +static const ltdcLayerConfig layerOff = LTDC_UNUSED_LAYER_CONFIG; + static void _ltdc_reload(void) { LTDC->SRCR |= LTDC_SRCR_IMR; while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) @@ -210,7 +212,7 @@ static void _ltdc_init(void) { _ltdc_layer_init(LTDC_Layer1, &driverCfg.bglayer); // Load the foreground layer - _ltdc_layer_init(LTDC_Layer2, &driverCfg.fglayer); + _ltdc_layer_init(LTDC_Layer2, &layerOff); // Interrupt handling // Possible flags - LTDC_IER_RRIE, LTDC_IER_LIE, LTDC_IER_FUIE, LTDC_IER_TERRIE etc @@ -227,26 +229,55 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { g->priv = 0; g->board = 0; - // Init the board - init_board(g); + switch(g->controllerdisplay) { + case 0: // Display 0 is the background layer + // Init the board + init_board(g); - // Initialise the LTDC controller - _ltdc_init(); + // Initialise the LTDC controller + _ltdc_init(); - // Initialise DMA2D - #if LTDC_USE_DMA2D - dma2d_init(); - #endif + // Initialise DMA2D + #if LTDC_USE_DMA2D + dma2d_init(); + #endif + + if (!(driverCfg.bglayer.layerflags & LTDC_LEF_ENABLE)) + return FALSE; + + g->priv = (void *)&driverCfg.bglayer; + + // Finish Init the board + post_init_board(g); + + // Turn on the back-light + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + break; + + case 1: // Display 1 is the foreground layer + + if (!(driverCfg.fglayer.layerflags & LTDC_LEF_ENABLE)) + return FALSE; - // Finish Init the board - post_init_board(g); + // Load the foreground layer + _ltdc_layer_init(LTDC_Layer2, &driverCfg.fglayer); + _ltdc_reload(); - // Turn on the back-light - set_backlight(g, GDISP_INITIAL_BACKLIGHT); + g->priv = (void *)&driverCfg.fglayer; + + // Finish Init the board + post_init_board(g); + + break; + + default: // There is only 1 LTDC in the CPU and only the 2 layers in the LTDC. + return FALSE; + } // Initialise the GDISP structure - g->g.Width = driverCfg.bglayer.width; - g->g.Height = driverCfg.bglayer.height; + g->g.Width = ((ltdcLayerConfig *)g->priv)->width; + g->g.Height = ((ltdcLayerConfig *)g->priv)->height; g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = GDISP_INITIAL_BACKLIGHT; @@ -282,7 +313,14 @@ LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g) { while(DMA2D->CR & DMA2D_CR_START); #endif - PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color); + #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 + // As we don't support ARGB pixel types in uGFX yet we will + // use RGB with an inverted alpha value for compatibility + // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white + PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color) ^ 0xFF000000; + #else + PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color); + #endif } LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { @@ -313,27 +351,21 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { while(DMA2D->CR & DMA2D_CR_START); #endif - color = PIXEL_ADDR(g, pos)[0]; - + #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 + // As we don't support ARGB pixel types in uGFX yet we will + // use RGB with an inverted alpha value for compatibility + // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white + color = PIXEL_ADDR(g, pos)[0] ^ 0xFF000000; + #else + color = PIXEL_ADDR(g, pos)[0]; + #endif + return gdispNative2Color(color); } #if GDISP_NEED_CONTROL LLDSPEC void gdisp_lld_control(GDisplay* g) { switch(g->p.x) { - case GDISP_CONTROL_POWER: - if (g->g.Powermode == (powermode_t)g->p.ptr) - return; - switch((powermode_t)g->p.ptr) { - case powerOff: case powerOn: case powerSleep: case powerDeepSleep: - // TODO - break; - default: - return; - } - g->g.Powermode = (powermode_t)g->p.ptr; - return; - case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; @@ -369,12 +401,6 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; - - case GDISP_CONTROL_CONTRAST: - if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - // TODO - g->g.Contrast = (unsigned)g->p.ptr; - return; } } #endif @@ -383,14 +409,14 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { static void dma2d_init(void) { // Enable DMA2D clock RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; - + // Output color format #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 DMA2D->OPFCCR = OPFCCR_RGB565; #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 DMA2D->OPFCCR = OPFCCR_ARGB8888; #endif - + // Foreground color format #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 DMA2D->FGPFCCR = FGPFCCR_CM_RGB565; @@ -401,14 +427,11 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { // Uses p.x,p.y p.cx,p.cy p.color LLDSPEC void gdisp_lld_fill_area(GDisplay* g) - { + { uint32_t pos; uint32_t lineadd; uint32_t shape; - // Wait until DMA2D is ready - while(DMA2D->CR & DMA2D_CR_START); - #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -438,13 +461,24 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { lineadd = g->g.Width - g->p.cx; shape = (g->p.cx << 16) | (g->p.cy); #endif - + + // Wait until DMA2D is ready + while(DMA2D->CR & DMA2D_CR_START); + // Start the DMA2D DMA2D->OMAR = (uint32_t)PIXEL_ADDR(g, pos); DMA2D->OOR = lineadd; DMA2D->NLR = shape; - DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color)); - DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START; + #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 + // As we don't support ARGB pixel types in uGFX yet we will + // use RGB with an inverted alpha value for compatibility + // ie. 0x00FFFFFF is fully opaque white, 0xFFFFFFFF is fully transparent white + DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color)) ^ 0xFF000000; + #else + DMA2D->OCOLR = (uint32_t)(gdispColor2Native(g->p.color)); + #endif + ; + DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START; } /* Oops - the DMA2D only supports GDISP_ROTATE_0. @@ -464,7 +498,7 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { * access to the framebuffer is fast - probably faster than DMA2D. * It just uses more CPU. */ - #if GDISP_HARDWARE_BITFILLS + #if GDISP_HARDWARE_BITFILLS // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) LLDSPEC void gdisp_lld_blit_area(GDisplay* g) { // Wait until DMA2D is ready @@ -473,7 +507,7 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) { // Source setup DMA2D->FGMAR = LTDC_PIXELBYTES * (g->p.y1 * g->p.x2 + g->p.x1) + (uint32_t)g->p.ptr; DMA2D->FGOR = g->p.x2 - g->p.cx; - + // Output setup DMA2D->OMAR = (uint32_t)PIXEL_ADDR(g, PIXIL_POS(g, g->p.x, g->p.y)); DMA2D->OOR = g->g.Width - g->p.cx; diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_config.h b/drivers/gdisp/STM32LTDC/gdisp_lld_config.h index 5c3b1883..1476b38b 100644 --- a/drivers/gdisp/STM32LTDC/gdisp_lld_config.h +++ b/drivers/gdisp/STM32LTDC/gdisp_lld_config.h @@ -21,8 +21,15 @@ // Both these pixel formats are supported - pick one. // RGB565 obviously is faster and uses less RAM but with lower color resolution than RGB888 -#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 -//#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 + +#if defined(GDISP_LTDC_USE_RGB565) && GDISP_LTDC_USE_RGB565 + #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 + #if GDISP_TOTAL_DISPLAYS > 1 + #error "LTDC: You must use RGB888 pixel format with LTDC when using dual layers as only RGB888 currently supports using alpha" + #endif +#else + #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#endif /*===========================================================================*/ @@ -35,9 +42,12 @@ // Accelerated bitfills are also possible but only for GDISP_ROTATE_0 // and if no color translation is required (for now) - #if !GDISP_NEED_CONTROL && GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT - #define GDISP_HARDWARE_BITFILLS TRUE - #endif + // Oops - this is not working and adds little performance benefit + // so we will just disable it for the near future. +// #if !GDISP_NEED_CONTROL && !defined(GDISP_PIXELFORMAT) +// #define GDISP_HARDWARE_BITFILLS TRUE +// #endif + #endif /* GDISP_USE_DMA2D */ #endif /* GFX_USE_GDISP */ -- cgit v1.2.3