/* * This file is subject to the terms of the GFX License. If a copy of * the license was not distributed with this file, you can obtain one at: * * http://ugfx.org/license.html */ #include "gfx.h" #if GFX_USE_GDISP #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GISP_SCREEN_HEIGHT #endif #if defined(GDISP_SCREEN_WIDTH) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_WIDTH #endif #define GDISP_DRIVER_VMT GDISPVMT_STM32F429iDiscovery #include "drivers/gdisp/STM32F429iDiscovery/gdisp_lld_config.h" #include "src/gdisp/driver.h" #include "stm32_ltdc.h" typedef struct ltdcLayerConfig { // frame LLDCOLOR_TYPE *frame; // Frame buffer address coord_t width, height; // Frame size in pixels coord_t pitch; // Line pitch, in bytes uint16_t fmt; // Pixel format in LTDC format // window coord_t x, y; // Start pixel position of the virtual layer coord_t cx, cy; // Size of the virtual layer uint32_t defcolor; // Default color, ARGB8888 uint32_t keycolor; // Color key, RGB888 uint32_t blending; // Blending factors const uint32_t *palette; // The palette, RGB888 (can be NULL) uint16_t palettelen; // Palette length uint8_t alpha; // Constant alpha factor uint8_t layerflags; // Layer configuration } ltdcLayerConfig; #define LTDC_UNUSED_LAYER_CONFIG { 0, 1, 1, 1, LTDC_FMT_L8, 0, 0, 1, 1, 0x000000, 0x000000, LTDC_BLEND_FIX1_FIX2, 0, 0, 0, 0 } typedef struct ltdcConfig { coord_t width, height; // Screen size coord_t hsync, vsync; // Horizontal and Vertical sync pixels coord_t hbackporch, vbackporch; // Horizontal and Vertical back porch pixels coord_t hfrontporch, vfrontporch; // Horizontal and Vertical front porch pixels uint8_t syncflags; // Sync flags uint32_t bgcolor; // Clear screen color RGB888 ltdcLayerConfig bglayer; // Background layer config ltdcLayerConfig fglayer; // Foreground layer config } ltdcConfig; #if GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 #define LTDC_PIXELFORMAT LTDC_FMT_RGB565 #define LTDC_PIXELBYTES 2 #define LTDC_PIXELBITS 16 #elif GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 #define LTDC_PIXELFORMAT LTDC_FMT_RGB888 #define LTDC_PIXELBYTES 3 #define LTDC_PIXELBITS 24 #else #error "GDISP: STM32F4iDiscovery - unsupported pixel format" #endif #include "board_STM32F429iDiscovery.h" #include "ili9341.h" /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ #ifndef GDISP_INITIAL_CONTRAST #define GDISP_INITIAL_CONTRAST 50 #endif #ifndef GDISP_INITIAL_BACKLIGHT #define GDISP_INITIAL_BACKLIGHT 100 #endif /*===========================================================================*/ /* 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)) /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ static void InitController(GDisplay *g) { #define REG_TYPEMASK 0xFF00 #define REG_DATAMASK 0x00FF #define REG_DATA 0x0000 #define REG_COMMAND 0x0100 #define REG_DELAY 0x0200 static const uint16_t initdata[] = { REG_COMMAND | ILI9341_CMD_RESET, REG_DELAY | 5, REG_COMMAND | ILI9341_CMD_DISPLAY_OFF, REG_COMMAND | ILI9341_SET_FRAME_CTL_NORMAL, 0x00, 0x1B, REG_COMMAND | ILI9341_SET_FUNCTION_CTL, 0x0A, 0xA2, REG_COMMAND | ILI9341_SET_POWER_CTL_1, 0x10, REG_COMMAND | ILI9341_SET_POWER_CTL_2, 0x10, REG_COMMAND | ILI9341_SET_VCOM_CTL_1, 0x45, 0x15, REG_COMMAND | ILI9341_SET_VCOM_CTL_2, 0x90, REG_COMMAND | ILI9341_SET_MEM_ACS_CTL, 0xC8, REG_COMMAND | ILI9341_SET_RGB_IF_SIG_CTL, 0xC2, REG_COMMAND | ILI9341_SET_FUNCTION_CTL, 0x0A, 0xA7, 0x27, 0x04, REG_COMMAND | ILI9341_SET_COL_ADDR, 0x00, 0x00, 0x00, 0xEF, REG_COMMAND | ILI9341_SET_PAGE_ADDR, 0x00, 0x00, 0x01, 0x3F, REG_COMMAND | ILI9341_SET_IF_CTL, 0x01, 0x00, 0x06, REG_COMMAND | ILI9341_SET_GAMMA, 0x01, REG_COMMAND | ILI9341_SET_PGAMMA, 0x0F, 0x29, 0x24, 0x0C, 0x0E, 0x09, 0x4E, 0x78, 0x3C, 0x09, 0x13, 0x05, 0x17, 0x11, 0x00, REG_COMMAND | ILI9341_SET_NGAMMA, 0x00, 0x16, 0x1B, 0x04, 0x11, 0x07, 0x31, 0x33, 0x42, 0x05, 0x0C, 0x0A, 0x28, 0x2F, 0x0F, REG_COMMAND | ILI9341_CMD_SLEEP_OFF, REG_DELAY | 10, REG_COMMAND | ILI9341_CMD_DISPLAY_ON, REG_COMMAND | ILI9341_SET_MEM }; const uint16_t *p; acquire_bus(g); for(p = initdata; p < &initdata[sizeof(initdata)/sizeof(initdata[0])]; p++) { switch(*p & REG_TYPEMASK) { case REG_DATA: write_data(g, *p); break; case REG_COMMAND: write_index(g, *p); break; case REG_DELAY: gfxSleepMilliseconds(*p & 0xFF); break; } } release_bus(g); } static void LTDC_Reload(void) { LTDC->SRCR |= LTDC_SRCR_IMR; while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) gfxYield(); } static void LTDC_LayerInit(LTDC_Layer_TypeDef *pLayReg, const ltdcLayerConfig * pCfg) { static const uint8_t fmt2Bpp[] = { 4, /* LTDC_FMT_ARGB8888 */ 3, /* LTDC_FMT_RGB888 */ 2, /* LTDC_FMT_RGB565 */ 2, /* LTDC_FMT_ARGB1555 */ 2, /* LTDC_FMT_ARGB4444 */ 1, /* LTDC_FMT_L8 */ 1, /* LTDC_FMT_AL44 */ 2 /* LTDC_FMT_AL88 */ }; uint32_t start, stop; // Set the framebuffer dimensions and format pLayReg->PFCR = (pLayReg->PFCR & ~LTDC_LxPFCR_PF) | ((uint32_t)pCfg->fmt & LTDC_LxPFCR_PF); pLayReg->CFBAR = (uint32_t)pCfg->frame & LTDC_LxCFBAR_CFBADD; pLayReg->CFBLR = ((((uint32_t)pCfg->pitch << 16) & LTDC_LxCFBLR_CFBP) | (((uint32_t)fmt2Bpp[pCfg->fmt] * pCfg->width + 3) & LTDC_LxCFBLR_CFBLL)); pLayReg->CFBLNR = (uint32_t)pCfg->height & LTDC_LxCFBLNR_CFBLNBR; // Set the display window boundaries start = (uint32_t)pCfg->x + driverCfg.hsync + driverCfg.hbackporch; stop = start + pCfg->cx - 1; pLayReg->WHPCR = ((start << 0) & LTDC_LxWHPCR_WHSTPOS) | ((stop << 16) & LTDC_LxWHPCR_WHSPPOS); start = (uint32_t)pCfg->y + driverCfg.vsync + driverCfg.vbackporch; stop = start + pCfg->cy - 1; pLayReg->WVPCR = ((start << 0) & LTDC_LxWVPCR_WVSTPOS) | ((stop << 16) & LTDC_LxWVPCR_WVSPPOS); // Set colors pLayReg->DCCR = pCfg->defcolor; pLayReg->CKCR = (pLayReg->CKCR & ~0x00FFFFFF) | (pCfg->keycolor & 0x00FFFFFF); pLayReg->CACR = (pLayReg->CACR & ~LTDC_LxCACR_CONSTA) | ((uint32_t)pCfg->alpha & LTDC_LxCACR_CONSTA); pLayReg->BFCR = (pLayReg->BFCR & ~(LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2)) | ((uint32_t)pCfg->blending & (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2)); for (start = 0; start < pCfg->palettelen; start++) pLayReg->CLUTWR = ((uint32_t)start << 24) | (pCfg->palette[start] & 0x00FFFFFF); // Final flags pLayReg->CR = (pLayReg->CR & ~LTDC_LEF_MASK) | ((uint32_t)pCfg->layerflags & LTDC_LEF_MASK); } static void LTDC_Init(void) { // Set up the display scanning uint32_t hacc, vacc; /* Reset the LTDC hardware module.*/ RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST; RCC->APB2RSTR = 0; /* Enable the LTDC clock.*/ RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (2 << 16); /* /8 */ // Enable the module RCC->APB2ENR |= RCC_APB2ENR_LTDCEN; // Turn off the controller and its interrupts. LTDC->GCR = 0; LTDC->IER = 0; LTDC_Reload(); // Set synchronization params hacc = driverCfg.hsync - 1; vacc = driverCfg.vsync - 1; LTDC->SSCR = ((hacc << 16) & LTDC_SSCR_HSW) | ((vacc << 0) & LTDC_SSCR_VSH); // Set accumulated back porch params hacc += driverCfg.hbackporch; vacc += driverCfg.vbackporch; LTDC->BPCR = ((hacc << 16) & LTDC_BPCR_AHBP) | ((vacc << 0) & LTDC_BPCR_AVBP); // Set accumulated active params hacc += driverCfg.width; vacc += driverCfg.height; LTDC->AWCR = ((hacc << 16) & LTDC_AWCR_AAW) | ((vacc << 0) & LTDC_AWCR_AAH); // Set accumulated total params hacc += driverCfg.hfrontporch; vacc += driverCfg.vfrontporch; LTDC->TWCR = ((hacc << 16) & LTDC_TWCR_TOTALW) | ((vacc << 0) & LTDC_TWCR_TOTALH); // Set signal polarities and other flags LTDC->GCR = driverCfg.syncflags & (LTDC_EF_MASK & ~LTDC_EF_ENABLE); // Set background color LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (driverCfg.bgcolor & 0x00FFFFFF); // Load the background layer LTDC_LayerInit(LTDC_Layer1, &driverCfg.bglayer); // Load the foreground layer LTDC_LayerInit(LTDC_Layer2, &driverCfg.fglayer); // Interrupt handling //nvicEnableVector(STM32_LTDC_EV_NUMBER, CORTEX_PRIORITY_MASK(STM32_LTDC_EV_IRQ_PRIORITY)); //nvicEnableVector(STM32_LTDC_ER_NUMBER, CORTEX_PRIORITY_MASK(STM32_LTDC_ER_IRQ_PRIORITY)); // Possible flags - LTDC_IER_RRIE, LTDC_IER_LIE, LTDC_IER_FUIE, LTDC_IER_TERRIE etc LTDC->IER = 0; // Set everything going LTDC_Reload(); LTDC->GCR |= LTDC_GCR_LTDCEN; LTDC_Reload(); } LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { // Initialize the private structure g->priv = 0; g->board = 0; //if (!(g->priv = gfxAlloc(sizeof(fbPriv)))) // gfxHalt("GDISP Framebuffer: Failed to allocate private memory"); // Init the board init_board(g); //((fbPriv *)g->priv)->fbi.cfg = init_board(g); // Initialise the ILI9341 controller InitController(g); // Initialise the LTDC controller LTDC_Init(); // Initialise DMA2D //dma2dStart(&DMA2DD1, &dma2d_cfg); //dma2d_test(); // Finish Init the board post_init_board(g); /* Turn on the back-light */ set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = driverCfg.bglayer.width; g->g.Height = driverCfg.bglayer.height; g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = GDISP_INITIAL_BACKLIGHT; g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { unsigned pos; #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: default: pos = PIXIL_POS(g, g->p.x, g->p.y); break; case GDISP_ROTATE_90: pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1); break; case GDISP_ROTATE_180: pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1); break; case GDISP_ROTATE_270: pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x); break; } #else pos = PIXIL_POS(g, g->p.x, g->p.y); #endif PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color); } LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { unsigned pos; LLDCOLOR_TYPE color; #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: default: pos = PIXIL_POS(g, g->p.x, g->p.y); break; case GDISP_ROTATE_90: pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1); break; case GDISP_ROTATE_180: pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1); break; case GDISP_ROTATE_270: pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x); break; } #else pos = PIXIL_POS(g, g->p.x, g->p.y); #endif color = PIXEL_ADDR(g, pos)[0]; 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: board_power(g, (powermode_t)g->p.ptr); 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; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) { coord_t tmp; tmp = g->g.Width; g->g.Width = g->g.Height; g->g.Height = tmp; } break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) { coord_t tmp; tmp = g->g.Width; g->g.Width = g->g.Height; g->g.Height = tmp; } break; default: return; } g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; board_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; board_contrast(g, (unsigned)g->p.ptr); g->g.Contrast = (unsigned)g->p.ptr; return; } } #endif #endif /* GFX_USE_GDISP */