aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2015-11-25 12:20:56 +1000
committerinmarket <andrewh@inmarket.com.au>2015-11-25 12:20:56 +1000
commit6900dfc0abab86ffdee5aef34136bfc69d1521d4 (patch)
tree36b78dfc1e09b737e71936b0df8948fb37cb229a
parente5ec9415d1060010f45878a2f86afe0d942bbb74 (diff)
downloaduGFX-6900dfc0abab86ffdee5aef34136bfc69d1521d4.tar.gz
uGFX-6900dfc0abab86ffdee5aef34136bfc69d1521d4.tar.bz2
uGFX-6900dfc0abab86ffdee5aef34136bfc69d1521d4.zip
Fix STM32LTDC orientation and DMA2D acceleration
-rw-r--r--drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c169
-rw-r--r--drivers/gdisp/STM32LTDC/gdisp_lld_config.h25
2 files changed, 98 insertions, 96 deletions
diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
index 949088b5..9d1aafa0 100644
--- a/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
+++ b/drivers/gdisp/STM32LTDC/gdisp_lld_STM32LTDC.c
@@ -102,17 +102,13 @@ typedef struct ltdcConfig {
/* Driver exported functions. */
/*===========================================================================*/
-static void _ltdc_reload(void)
-{
+static void _ltdc_reload(void) {
LTDC->SRCR |= LTDC_SRCR_IMR;
-
- while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) {
+ while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR))
gfxYield();
- }
}
-static void _ltdc_layer_init(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* pCfg)
-{
+static void _ltdc_layer_init(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig* pCfg) {
static const uint8_t fmt2Bpp[] = {
4, /* LTDC_FMT_ARGB8888 */
3, /* LTDC_FMT_RGB888 */
@@ -151,8 +147,7 @@ static void _ltdc_layer_init(LTDC_Layer_TypeDef* pLayReg, const ltdcLayerConfig*
pLayReg->CR = (pLayReg->CR & ~LTDC_LEF_MASK) | ((uint32_t)pCfg->layerflags & LTDC_LEF_MASK);
}
-static void _ltdc_init(void)
-{
+static void _ltdc_init(void) {
// Set up the display scanning
uint32_t hacc, vacc;
@@ -161,9 +156,9 @@ static void _ltdc_init(void)
RCC->APB2RSTR = 0;
// Enable the LTDC clock
- #if defined(STM32F4)
+ #if defined(STM32F4) || defined(STM32F429_439xx) || defined(STM32F429xx)
RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (1 << 16);
- #elif defined(STM32F7)
+ #elif defined(STM32F7) || defined(STM32F746xx)
RCC->DCKCFGR1 = (RCC->DCKCFGR1 & ~RCC_DCKCFGR1_PLLSAIDIVR) | (1 << 16);
#else
#error STM32LTDC driver not implemented for your platform
@@ -219,8 +214,7 @@ static void _ltdc_init(void)
_ltdc_reload();
}
-LLDSPEC bool_t gdisp_lld_init(GDisplay* g)
-{
+LLDSPEC bool_t gdisp_lld_init(GDisplay* g) {
// Initialize the private structure
g->priv = 0;
g->board = 0;
@@ -253,8 +247,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g)
return TRUE;
}
-LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g)
-{
+LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g) {
unsigned pos;
#if GDISP_NEED_CONTROL
@@ -277,11 +270,14 @@ LLDSPEC void gdisp_lld_draw_pixel(GDisplay* g)
pos = PIXIL_POS(g, g->p.x, g->p.y);
#endif
- PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color);
+ #if LTDC_USE_DMA2D
+ while(DMA2D->CR & DMA2D_CR_START);
+ #endif
+
+ PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color);
}
-LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
-{
+LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g) {
unsigned pos;
LLDCOLOR_TYPE color;
@@ -305,24 +301,28 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
pos = PIXIL_POS(g, g->p.x, g->p.y);
#endif
+ #if LTDC_USE_DMA2D
+ while(DMA2D->CR & DMA2D_CR_START);
+ #endif
+
color = PIXEL_ADDR(g, pos)[0];
return gdispNative2Color(color);
}
#if GDISP_NEED_CONTROL
- LLDSPEC void gdisp_lld_control(GDisplay* g)
- {
+ LLDSPEC void gdisp_lld_control(GDisplay* g) {
switch(g->p.x) {
case GDISP_CONTROL_POWER:
- // Don't do anything if it is the same power mode
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;
@@ -353,7 +353,6 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
default:
return;
}
-
g->g.Orientation = (orientation_t)g->p.ptr;
return;
@@ -373,8 +372,7 @@ LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay* g)
#endif
#if LTDC_USE_DMA2D
- static void dma2d_init(void)
- {
+ static void dma2d_init(void) {
// Enable DMA2D clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
@@ -396,91 +394,88 @@ 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 reg_omar = 0;
- uint32_t reg_oor = 0;
- uint32_t reg_nlr = 0;
+ uint32_t pos;
+ uint32_t lineadd;
+ uint32_t shape;
// Wait until DMA2D is ready
- while (1) {
- if (!(DMA2D->CR & DMA2D_CR_START)) {
- break;
- }
- }
+ while(DMA2D->CR & DMA2D_CR_START);
- // Calculate pixel positions and stuff like that
#if GDISP_NEED_CONTROL
switch(g->g.Orientation) {
case GDISP_ROTATE_0:
default:
- reg_omar = g->p.y * g->g.Width * LTDC_PIXELBYTES + g->p.x * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
- reg_oor = g->g.Width - g->p.cx;
- reg_nlr = (g->p.cx << 16) | (g->p.cy);
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ lineadd = g->g.Width - g->p.cx;
+ shape = (g->p.cx << 16) | (g->p.cy);
break;
-
case GDISP_ROTATE_90:
+ pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-g->p.cx);
+ lineadd = g->g.Height - g->p.cy;
+ shape = (g->p.cy << 16) | (g->p.cx);
break;
-
case GDISP_ROTATE_180:
- reg_omar = g->g.Width * (g->g.Height - g->p.y - g->p.cy) * LTDC_PIXELBYTES + (g->g.Width - g->p.x - g->p.cx) * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
- reg_oor = g->g.Width - g->p.cx;
- reg_nlr = (g->p.cy << 16) | (g->p.cx);
+ pos = PIXIL_POS(g, g->g.Width-g->p.x-g->p.cx, g->g.Height-g->p.y-g->p.cy);
+ lineadd = g->g.Width - g->p.cx;
+ shape = (g->p.cx << 16) | (g->p.cy);
break;
-
case GDISP_ROTATE_270:
+ pos = PIXIL_POS(g, g->g.Height-g->p.y-g->p.cy, g->p.x);
+ lineadd = g->g.Height - g->p.cy;
+ shape = (g->p.cy << 16) | (g->p.cx);
break;
}
#else
- reg_omar = g->p.y * g->g.Width * LTDC_PIXELBYTES + g->p.x * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
- reg_oor = g->g.Width - g->p.cx;
- reg_nlr = (g->p.cx << 16) | (g->p.cy);
+ pos = PIXIL_POS(g, g->p.x, g->p.y);
+ lineadd = g->g.Width - g->p.cx;
+ shape = (g->p.cx << 16) | (g->p.cy);
#endif
-
- // Output memory address register
- DMA2D->OMAR = reg_omar;
-
- // Output offset register (in pixels)
- DMA2D->OOR = reg_oor;
-
- // PL (pixel per lines to be transferred); NL (number of lines)
- DMA2D->NLR = reg_nlr;
-
- // Output color register
+
+ // 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));
-
- // Set MODE to R2M and Start the process
DMA2D->CR = DMA2D_CR_MODE_R2M | DMA2D_CR_START;
}
- // 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
- while (1) {
- if (!(DMA2D->CR & DMA2D_CR_START)) {
- break;
- }
+ /* Oops - the DMA2D only supports GDISP_ROTATE_0.
+ *
+ * Where the width is 1 we can trick it for other orientations.
+ * That is worthwhile as a width of 1 is common. For other
+ * situations we need to fall back to pixel pushing.
+ *
+ * Additionally, although DMA2D can translate color formats
+ * it can only do it for a small range of formats. For any
+ * other formats we also need to fall back to pixel pushing.
+ *
+ * As the code to actually do all that for other than the
+ * simplest case (orientation == GDISP_ROTATE_0 and
+ * GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT) is very complex
+ * we will always pixel push for now. In practice that is OK as
+ * access to the framebuffer is fast - probably faster than DMA2D.
+ * It just uses more CPU.
+ */
+ #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
+ while(DMA2D->CR & DMA2D_CR_START);
+
+ // 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;
+ DMA2D->NLR = (g->p.cx << 16) | (g->p.cy);
+
+ // Set MODE to M2M and Start the process
+ DMA2D->CR = DMA2D_CR_MODE_M2M | DMA2D_CR_START;
}
-
- // Foreground memory address register
- DMA2D->FGMAR = g->p.y1 * g->p.x2 * LTDC_PIXELBYTES + g->p.x1 * LTDC_PIXELBYTES + (uint32_t)g->p.ptr;
-
- // Foreground offset register (expressed in pixels)
- DMA2D->FGOR = g->p.x2 - g->p.cx;
-
- // Output memory address register
- DMA2D->OMAR = g->p.y * g->g.Width * LTDC_PIXELBYTES + g->p.x * LTDC_PIXELBYTES + (uint32_t)driverCfg.bglayer.frame;
-
- // Output offset register (expressed in pixels)
- DMA2D->OOR = g->g.Width - g->p.cx;
-
- // PL (pixel per lines to be transferred); NL (number of lines)
- DMA2D->NLR = (g->p.cx << 16) | (g->p.cy);
-
- // Set MODE to M2M and Start the process
- DMA2D->CR = DMA2D_CR_MODE_M2M | DMA2D_CR_START;
- }
+ #endif
#endif /* LTDC_USE_DMA2D */
-
#endif /* GFX_USE_GDISP */
diff --git a/drivers/gdisp/STM32LTDC/gdisp_lld_config.h b/drivers/gdisp/STM32LTDC/gdisp_lld_config.h
index 846fc1f0..5c3b1883 100644
--- a/drivers/gdisp/STM32LTDC/gdisp_lld_config.h
+++ b/drivers/gdisp/STM32LTDC/gdisp_lld_config.h
@@ -14,11 +14,15 @@
/* Driver hardware support. */
/*===========================================================================*/
-#define LTDC_USE_DMA2D FALSE // Currently has display artifacts
-#define GDISP_HARDWARE_DRAWPIXEL TRUE
-#define GDISP_HARDWARE_PIXELREAD TRUE
-#define GDISP_HARDWARE_CONTROL TRUE
-#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565
+#define LTDC_USE_DMA2D TRUE
+#define GDISP_HARDWARE_DRAWPIXEL TRUE
+#define GDISP_HARDWARE_PIXELREAD TRUE
+#define GDISP_HARDWARE_CONTROL TRUE
+
+// 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
/*===========================================================================*/
@@ -26,11 +30,14 @@
/*===========================================================================*/
#if LTDC_USE_DMA2D
+ // DMA2D supports accelerated fills
#define GDISP_HARDWARE_FILLS TRUE
- #define GDISP_HARDWARE_BITFILLS TRUE
-#else
- #define GDISP_HARDWARE_FILLS FALSE
- #define GDISP_HARDWARE_BITFILLS FALSE
+
+ // 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
#endif /* GDISP_USE_DMA2D */
#endif /* GFX_USE_GDISP */