/*** ***************************************************************************************** * @file lcd.c * @brief 使用STM32F29本身的控制器驱动液晶屏,一下代码移植于官方 *STM32F429I_DISCOVERY 实验板的例程,并作出相应的修改 ***************************************************************************************** * * * * ****************************************************************************************** ***/ #include "lcd_rgb.h" #include "mymem.h" #define COLOR565TO888(color) \ ((((color) & 0xf800) << 8) | ((color) & 0x07e0) << 5 | \ (((color) & 0x001f) << 3)) #define COLOR888TO565(color) \ ((((color) >> 8) & 0xf800) | (((color) >> 5) & 0x07e0) | \ (((color) >> 3) & 0x001f)) // 把RGB转化为565格式 #define RGB(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)) // RGB转灰度 #define RGB2GRAY(rgb16) \ (((((rgb16) & 0xf800) >> 8) + (((rgb16) & 0x07e0) >> 3) + \ (((rgb16) & 0x001f) << 3)) / \ 3) // 灰度转RGB #define GRAY2RGB(gray) \ ((((gray) >> 3) << 11) | (((gray) >> 2) << 5) | ((gray) >> 3)) // 函数:IO口初始化 void LCD_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHB1PeriphClockCmd(LCD_GPIO_CLK, ENABLE); GPIO_InitStruct.GPIO_Pin = LTDC_R0_PIN; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // LCD 颜色 R 引脚配置 GPIO_PinAFConfig(LTDC_R0_PORT, LTDC_R0_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R1_PORT, LTDC_R1_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R2_PORT, LTDC_R2_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R3_PORT, LTDC_R3_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R4_PORT, LTDC_R4_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R5_PORT, LTDC_R5_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R6_PORT, LTDC_R6_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_R7_PORT, LTDC_R7_PINSOURCE, GPIO_AF_LTDC); GPIO_InitStruct.GPIO_Pin = LTDC_R0_PIN; GPIO_Init(LTDC_R0_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R1_PIN; GPIO_Init(LTDC_R1_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R2_PIN; GPIO_Init(LTDC_R2_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R3_PIN; GPIO_Init(LTDC_R3_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R4_PIN; GPIO_Init(LTDC_R4_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R5_PIN; GPIO_Init(LTDC_R5_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R6_PIN; GPIO_Init(LTDC_R6_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_R7_PIN; GPIO_Init(LTDC_R7_PORT, &GPIO_InitStruct); // LCD 颜色 G 引脚配置 GPIO_PinAFConfig(LTDC_G0_PORT, LTDC_G0_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G1_PORT, LTDC_G1_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G2_PORT, LTDC_G2_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G3_PORT, LTDC_G3_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G4_PORT, LTDC_G4_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G5_PORT, LTDC_G5_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G6_PORT, LTDC_G6_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_G7_PORT, LTDC_G7_PINSOURCE, GPIO_AF_LTDC); GPIO_InitStruct.GPIO_Pin = LTDC_G0_PIN; GPIO_Init(LTDC_G0_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G1_PIN; GPIO_Init(LTDC_G1_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G2_PIN; GPIO_Init(LTDC_G2_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G3_PIN; GPIO_Init(LTDC_G3_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G4_PIN; GPIO_Init(LTDC_G4_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G5_PIN; GPIO_Init(LTDC_G5_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G6_PIN; GPIO_Init(LTDC_G6_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_G7_PIN; GPIO_Init(LTDC_G7_PORT, &GPIO_InitStruct); // LCD 颜色 B 引脚配置 GPIO_PinAFConfig(LTDC_B0_PORT, LTDC_B0_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B1_PORT, LTDC_B1_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B2_PORT, LTDC_B2_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B3_PORT, LTDC_B3_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B4_PORT, LTDC_B4_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B5_PORT, LTDC_B5_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B6_PORT, LTDC_B6_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_B7_PORT, LTDC_B7_PINSOURCE, GPIO_AF_LTDC); GPIO_InitStruct.GPIO_Pin = LTDC_B0_PIN; GPIO_Init(LTDC_B0_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B1_PIN; GPIO_Init(LTDC_B1_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B2_PIN; GPIO_Init(LTDC_B2_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B3_PIN; GPIO_Init(LTDC_B3_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B4_PIN; GPIO_Init(LTDC_B4_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B5_PIN; GPIO_Init(LTDC_B5_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B6_PIN; GPIO_Init(LTDC_B6_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_B7_PIN; GPIO_Init(LTDC_B7_PORT, &GPIO_InitStruct); // 控制线 GPIO_PinAFConfig(LTDC_CLK_PORT, LTDC_CLK_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_HSYNC_PORT, LTDC_HSYNC_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_VSYNC_PORT, LTDC_VSYNC_PINSOURCE, GPIO_AF_LTDC); GPIO_PinAFConfig(LTDC_DE_PORT, LTDC_DE_PINSOURCE, GPIO_AF_LTDC); GPIO_InitStruct.GPIO_Pin = LTDC_CLK_PIN; GPIO_Init(LTDC_CLK_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_HSYNC_PIN; GPIO_Init(LTDC_HSYNC_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_VSYNC_PIN; GPIO_Init(LTDC_VSYNC_PORT, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = LTDC_DE_PIN; GPIO_Init(LTDC_DE_PORT, &GPIO_InitStruct); // 背光 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_Pin = LTDC_Black_PIN; GPIO_Init(LTDC_Black_PORT, &GPIO_InitStruct); GPIO_SetBits(LTDC_Black_PORT, LTDC_Black_PIN); } void LCD_Backlight(u8 power) { if (power) { GPIO_SetBits(LTDC_Black_PORT, LTDC_Black_PIN); } else { GPIO_ResetBits(LTDC_Black_PORT, LTDC_Black_PIN); } } static u32 *LCD_ADDR = ((u32 *)(LCD_MemoryAdd + LCD_MemoryAdd_OFFSET * 0)); static u32 *LCD_ADDR1 = ((u32 *)(LCD_MemoryAdd + LCD_MemoryAdd_OFFSET * 1)); #define LCD_ADDR_BUFF0 \ ((u32)(LCD_MemoryAdd + (uint32_t)LCD_Width * LCD_Height * 4 * 0)) #define LCD_ADDR_BUFF1 \ ((u32)(LCD_MemoryAdd + (uint32_t)LCD_Width * LCD_Height * 4 * 1)) #define LCD_ADDR_BUFF2 \ ((u32)(LCD_MemoryAdd + (uint32_t)LCD_Width * LCD_Height * 4 * 2)) const static u32 g_lcdAddrTable[3] = { (u32)LCD_ADDR_BUFF0, (u32)LCD_ADDR_BUFF1, (u32)LCD_ADDR_BUFF2, }; static LCD_Struct g_lcd = {0}; // 函数:初始化LCD控制器 // 说明:在emWin初始化里被调用 // void LCD_Init(void) { u16 LCD_PLLSAIN = 0; // 用于倍频的PLLSAIN参数,可取范围为50~432 u8 LCD_PLLSAIR = 3; // 用于分频的PLLSAIR参数,可取范围为2~7 u8 LCD_CLKDIV = 8; // LCD时钟分频参数,默认设置为8分频,数值上等于RCC_PLLSAIDivR_Div8 LTDC_InitTypeDef LTDC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE); LCD_GPIO_Config(); // 初始化LCD引脚 LCD_PLLSAIN = LCD_CLK * LCD_PLLSAIR * LCD_CLKDIV; // 根据需要使用的LCD时钟计算PLLSAIN参数,可取范围为50~432 RCC_PLLSAIConfig(LCD_PLLSAIN, 7, LCD_PLLSAIR); // 时钟配置 RCC_LTDCCLKDivConfig( RCC_PLLSAIDivR_Div8); // LCD时钟分频设置,要和LCD_CLKDIV对应 RCC_PLLSAICmd(ENABLE); // 使能PLLSAI时钟 while (RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET) ; // 等待时钟配置完成 LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL; LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL; LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL; LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC; LTDC_InitStruct.LTDC_BackgroundRedValue = 0; LTDC_InitStruct.LTDC_BackgroundGreenValue = 0; LTDC_InitStruct.LTDC_BackgroundBlueValue = 0; LTDC_InitStruct.LTDC_HorizontalSync = HSW; LTDC_InitStruct.LTDC_VerticalSync = VSW; LTDC_InitStruct.LTDC_AccumulatedHBP = HBP; LTDC_InitStruct.LTDC_AccumulatedVBP = VBP; LTDC_InitStruct.LTDC_AccumulatedActiveW = LCD_Width + HBP; LTDC_InitStruct.LTDC_AccumulatedActiveH = LCD_Height + VBP; LTDC_InitStruct.LTDC_TotalWidth = LCD_Width + HBP + HFP; LTDC_InitStruct.LTDC_TotalHeigh = LCD_Height + VBP + VFP; LTDC_Init(<DC_InitStruct); // 初始化LCD控制器 LTDC_ITConfig(LTDC_IT_LI, ENABLE); NVIC_SetPriority(LTDC_IRQn, 0); NVIC_EnableIRQ(LTDC_IRQn); LTDC_Cmd(ENABLE); // 使能LCD控制器 LCD_LayerInit(); g_lcd.x_size = LCD_Width; g_lcd.y_size = LCD_Height; g_lcd.show = (u16 *)g_lcdAddrTable[0]; g_lcd.draw = (u16 *)g_lcdAddrTable[1]; LCD_SetWindow(0, 0, g_lcd.x_size, g_lcd.y_size); g_lcd.bkColor = 0x0; } // 函数:LCD层设置初始化 // void LCD_LayerInit(void) { LTDC_Layer_InitTypeDef LTDC_Layer_InitStruct; LTDC_Layer_InitStruct.LTDC_HorizontalStart = HBP + 1; LTDC_Layer_InitStruct.LTDC_HorizontalStop = (LCD_Width + HBP); LTDC_Layer_InitStruct.LTDC_VerticalStart = VBP + 1; LTDC_Layer_InitStruct.LTDC_VerticalStop = (LCD_Height + VBP); // LTDC_Layer_InitStruct.LTDC_PixelFormat = LTDC_Pixelformat_ARGB8888; // //像素格式设置 LTDC_Layer_InitStruct.LTDC_PixelFormat = LTDC_Pixelformat_RGB565; // 像素格式设置 LTDC_Layer_InitStruct.LTDC_ConstantAlpha = 255; LTDC_Layer_InitStruct.LTDC_DefaultColorBlue = 0; // 默认的颜色 LTDC_Layer_InitStruct.LTDC_DefaultColorGreen = 0; LTDC_Layer_InitStruct.LTDC_DefaultColorRed = 0; LTDC_Layer_InitStruct.LTDC_DefaultColorAlpha = 0; LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_CA; LTDC_Layer_InitStruct.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_CA; LTDC_Layer_InitStruct.LTDC_CFBLineNumber = LCD_Height; // 显示区域的行数 LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_MemoryAdd; // 第一层的起始地址 // 这里ARGB8888和RGB888使用相同的计算方式 { LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((LCD_Width * 2) + 3); // 每行的像素占的总字节数 LTDC_Layer_InitStruct.LTDC_CFBPitch = (LCD_Width * 2); // 行间距,某像素的起始处到下一行的起始处的增量 } LTDC_LayerInit(LTDC_Layer1, <DC_Layer_InitStruct); // 初始化层1 LTDC_LayerCmd(LTDC_Layer1, ENABLE); // 使能层1 #if (LCD_NUM_LAYERS == 2) // 当定义了双层时 LTDC_Layer_InitStruct.LTDC_PixelFormat = ColorMode_1; // 像素格式设置 LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_PAxCA; LTDC_Layer_InitStruct.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_PAxCA; LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_MemoryAdd + LCD_MemoryAdd_OFFSET; // 层2的起始地址 if (ColorMode_1 == LCD_RGB565 || ColorMode_1 == LCD_ARGB1555) // 判断颜色格式 { LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((LCD_Width * 2) + 3); // 每行的像素占的总字节数 LTDC_Layer_InitStruct.LTDC_CFBPitch = (LCD_Width * 2); // 行间距,某像素的起始处到下一行的起始处的增量 } else // 这里ARGB8888和RGB888使用相同的计算方式 { LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((LCD_Width * 4) + 3); // 每行的像素占的总字节数 LTDC_Layer_InitStruct.LTDC_CFBPitch = (LCD_Width * 4); // 行间距,某像素的起始处到下一行的起始处的增量 } LTDC_LayerInit(LTDC_Layer2, <DC_Layer_InitStruct); // 初始化层2 LTDC_LayerCmd(LTDC_Layer2, ENABLE); // 使能层2 #endif LTDC_ReloadConfig(LTDC_IMReload); // 重新载入参数 LTDC_DitherCmd( ENABLE); // 使能颜色抖动,24位色必须打开,否则无法达到24位色的效果 } void LTDC_ISR_Handler(void) { LTDC_ClearFlag(LTDC_FLAG_LI); if (g_lcd.LcdSwitchEn == 1) { g_lcd.LcdSwitchEn = 0; LTDC_Layer1->CFBAR = (u32)g_lcd.show; LTDC->SRCR = 1; } } static int LCD_UpDataWindow(void) { LCD_WindowStruct *win = &g_lcd.win; LCD_WindowStruct *draw = &g_lcd.realwin; int real = 1; if (win->xs >= 0 && win->xs < g_lcd.x_size) draw->xs = win->xs; else if (win->xs < 0) draw->xs = 0; else if (win->xs >= g_lcd.x_size) real = 0; // 在显示区域外 if (win->ys >= 0 && win->ys < g_lcd.y_size) draw->ys = win->ys; else if (win->ys < 0) draw->ys = 0; else if (win->ys >= g_lcd.y_size) real = 0; // 在显示区域外 if (win->xe >= 0 && win->xe < g_lcd.x_size) draw->xe = win->xe; else if (win->xe < 0) real = 0; // 在显示区域外 else if (win->xe >= g_lcd.x_size) draw->xe = g_lcd.x_size - 1; if (win->ye >= 0 && win->ye < g_lcd.y_size) draw->ye = win->ye; else if (win->ye < 0) real = 0; // 在显示区域外 else if (win->ye >= g_lcd.y_size) draw->ye = g_lcd.y_size - 1; if ((win->xs > win->xe) || (win->ys > win->ye)) real = 0; g_lcd.effective = real; return real; } // 设置活动窗口 void LCD_SetWindow(int x_s, int y_s, int x_size, int y_size) { g_lcd.win.xs = x_s; g_lcd.win.ys = y_s; g_lcd.win.xe = x_s + x_size - 1; g_lcd.win.ye = y_s + y_size - 1; LCD_UpDataWindow(); } int LCD_GetLcdSizeX(void) { return LCD_Width; } int LCD_GetLcdSizeY(void) { return LCD_Height; } // 获取图像显示地址 u32 *LCD_GetShowAddr(void) { uint32_t *ret = (u32 *)LTDC_Layer1->CFBAR; ret = (u32 *)g_lcd.show; return ret; } // 获取图像绘制地址 u32 *LCD_GetDrawAddr(void) { uint32_t *ret = 0; ret = (u32 *)g_lcd.draw; return ret; } // 设置屏幕显示地址,这个地址直接输出到屏幕上,返回上一个输出到屏幕的地址 u32 LCD_SetLayer(u32 AddrIndex) { uint32_t ret = LTDC_Layer1->CFBAR; if (AddrIndex < 3) { g_lcd.show = (u16 *)g_lcdAddrTable[AddrIndex]; LTDC_Layer1->CFBAR = g_lcdAddrTable[AddrIndex]; LTDC->SRCR = 1; } for (int i = 0; i < 3; i++) { if (ret == g_lcdAddrTable[i]) { ret = i; break; } } if (ret >= 3) ret = 0; return ret; } // 设置绘图地址,所有绘制操作在这个地址执行 u32 LCD_SetDrawLayer(u32 Index) { u32 ret = (u32)g_lcd.draw; if (Index < 3) { g_lcd.draw = (u16 *)g_lcdAddrTable[Index]; } for (int i = 0; i < 3; i++) { if (ret == g_lcdAddrTable[i]) { ret = i; break; } } if (ret >= 3) ret = 0; return ret; } u32 LCD_SetLcdColor(u32 color) { u32 ret = g_lcd.color; // g_lcd_struct.Color=color; g_lcd.color = COLOR888TO565(color); return ret; } u32 LCD_SetLcdBkColor(u32 color) { u32 ret = g_lcd.bkColor; // g_lcd_struct.BackColor=color; ret = g_lcd.bkColor = COLOR888TO565(color); return ret; } u32 LCD_SetLcdColor16(u32 color) { u32 ret = g_lcd.color; g_lcd.color = (color); return ret; } u32 LCD_SetLcdBkColor16(u32 color) { u32 ret = ret = g_lcd.bkColor; ret = g_lcd.bkColor = (color); return ret; } u32 LCD_GetLcdColor(void) { u32 ret = g_lcd.color; return COLOR565TO888(ret); } u32 LCD_GetLcdBkColor(void) { u32 ret = g_lcd.bkColor; return COLOR565TO888(ret); } u32 LCD_GetLcdColor16(void) { u32 ret = g_lcd.color; return ret; } u32 LCD_GetLcdBkColor16(void) { u32 ret = g_lcd.bkColor; return ret; } // 设置绘制模式,1,不绘制背景,0,绘制背景 void LCD_SetLcdDrawMode(int mode) { if (mode) { // g_lcd.DrawMode=1;//此时调用画点函数时不绘制背景色 } else { // g_lcd.DrawMode=0; } } static void LCD_DmaCopy(void *pSrc, void *pDst, uint32_t x_size, uint32_t y_size) { DMA2D_DeInit(); /* Set up mode */ DMA2D->CR = 0x00010000UL | (1 << 9); /* Control Register (Memory to memory with pixel format conversion and TCIE) */ /* Set up pointers */ DMA2D->FGMAR = (uint32_t)pSrc; /* Foreground Memory Address Register (Source address) */ DMA2D->OMAR = (uint32_t)pDst; /* Output Memory Address Register (Destination address) */ /* Set up offsets */ DMA2D->FGOR = 0; /* Foreground Offset Register (Source line offset) */ DMA2D->OOR = 0; /* Output Offset Register (Destination line offset) */ /* Set up pixel format */ DMA2D->FGPFCCR = LTDC_Pixelformat_RGB565; /* Foreground PFC Control Register (Defines the input pixel format) */ DMA2D->OPFCCR = LTDC_Pixelformat_RGB565; /* Output PFC Control Register (Defines the output pixel format) */ /* Set up size */ DMA2D->NLR = (uint32_t)(x_size << 16) | y_size; /* Number of Line Register (Size configuration of area to be transfered) */ /* Execute operation */ DMA2D->CR |= DMA2D_CR_START; while (DMA2D->CR & DMA2D_CR_START) { } } static void LCD_FillColor(void *pDst, int x, int y, int x_size, int y_size, u32 color) { DMA2D_DeInit(); DMA2D->OPFCCR = DMA2D_RGB565; DMA2D->CR = DMA2D_R2M; DMA2D->OCOLR = color; DMA2D->OMAR = (u32)pDst + (y * LCD_Width + x) * 2; DMA2D->OOR = LCD_Width - x_size; DMA2D->NLR = (x_size << 16) | y_size; /* Execute operation */ DMA2D->CR |= DMA2D_CR_START; while (DMA2D->CR & DMA2D_CR_START) { } } void LCD_FillImg(const u16 *pSurf, int x, int y, u16 w, u16 h, int width_bytes, const u8 *bits) { DMA2D_DeInit(); DMA2D->OPFCCR = DMA2D_RGB565; DMA2D->CR = DMA2D_M2M; DMA2D->OMAR = (u32)pSurf + (y * LCD_Width + x) * 2; DMA2D->OOR = LCD_Width - w; DMA2D->NLR = (w << 16) | h; DMA2D->FGPFCCR = CM_RGB565; DMA2D->FGMAR = (u32)bits; DMA2D->FGOR = (width_bytes >> 1) - w; /* Execute operation */ DMA2D->CR |= DMA2D_CR_START; while (DMA2D->CR & DMA2D_CR_START) { } } // 层复制 void LCD_LayerCopy(int dst, int src) { u32 *p_dst = 0; u32 *p_src = 0; if ((dst < 3) && (src < 3)) { p_dst = (u32 *)g_lcdAddrTable[dst]; p_src = (u32 *)g_lcdAddrTable[src]; LCD_DmaCopy(p_src, p_dst, LCD_Width, LCD_Height); } } // 开始在缓冲区绘制 void LCD_LayerBufferOn(void) { // 为了兼容以前的窗口,保留这个空函数,2019.12.26 } // 显示缓冲层 void LCD_LayerBuffShow(void) { // 为了兼容以前的窗口,保留这个空函数,2019.12.26 } // 进入缓冲区 void LCD_EnterLayerBuff(void) { if (g_lcd.LayerBuffEnter != 0) return; g_lcd.LayerBuffEnter++; // while(LCD_GetLayerUpdataStat()==0); if (g_lcd.LcdSwitchEn == 1) { // 如果上次更改还没来得及刷新,不刷新了,这次更改之后一起刷新 // 如果应用程序中屏幕刷新太快,会造成丢帧 g_lcd.LcdSwitchEn = 0; } else { // 刷新了之后,lcd显示区和绘图区是同一段内存,需要错开 if ((u32)g_lcd.show == g_lcdAddrTable[0]) { g_lcd.draw = (u16 *)g_lcdAddrTable[1]; LCD_LayerCopy(1, 0); } else if ((u32)g_lcd.show == g_lcdAddrTable[1]) { g_lcd.draw = (u16 *)g_lcdAddrTable[0]; LCD_LayerCopy(0, 1); } } } // 切换层,不用复制显示,播放视频时用 void LCD_SwitchLayerBuff(void) { if (g_lcd.LayerBuffEnter != 0) return; g_lcd.LayerBuffEnter++; if (g_lcd.LcdSwitchEn == 1) { // 如果上次更改还没来得及刷新,不刷新了,这次更改之后一起刷新 // 如果应用程序中屏幕刷新太快,会造成丢帧 g_lcd.LcdSwitchEn = 0; } else { // 刷新了之后,lcd显示区和绘图区是同一段内存,需要错开 if ((u32)g_lcd.show == g_lcdAddrTable[0]) { g_lcd.draw = (u16 *)g_lcdAddrTable[1]; } else if ((u32)g_lcd.show == g_lcdAddrTable[1]) { g_lcd.draw = (u16 *)g_lcdAddrTable[0]; } } } // 退出缓冲区 void LCD_ExitLayerBuff(void) { g_lcd.show = g_lcd.draw; g_lcd.LcdSwitchEn = 1; g_lcd.LayerBuffEnter = 0; } // 获取屏幕刷新状态,1,已刷新 int LCD_GetLayerUpdataStat(void) { return !g_lcd.LcdSwitchEn; } // 填充一条线,以窗口的起点为起点,最大填充到窗口的终点位置 static void LCD_FillLine16(int x, int y, int xe, u16 *buff, int xsize) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; xe += g_lcd.win.xs; if ((y < g_lcd.realwin.ys) || (y > g_lcd.realwin.ye)) return; if ((x + xsize - 1 < g_lcd.realwin.xs) || x > g_lcd.realwin.xe) return; int mx = x; if (mx < g_lcd.realwin.xs) mx = g_lcd.realwin.xs; buff += mx - x; xsize -= mx - x; // 不超过指定范围 // if (mx + xsize - 1 > xe) xsize=xe - mx + 1; if (xsize > g_lcd.realwin.xe - mx + 1) xsize = g_lcd.realwin.xe - mx + 1; for (int i = 0; i < xsize; i++) g_lcd.draw[mx + y * g_lcd.x_size + i] = (buff[i]); } // 把图像填充到屏幕的活动窗口中, // 参数xsize,图像的宽度 // 参数ysize,图像的高度 static void LCD_FillRect16(int xs, int ys, int xe, int ye, u16 *buff, int xsize, int ysize) { ys += g_lcd.win.ys; ye += g_lcd.win.ys; xs += g_lcd.win.xs; xe += g_lcd.win.xs; // for (int y = ys; y<=ye; y++) // { // LCD_FillLine16( xs,y,xe,buff, xsize); // buff += xsize; // } if (ye < g_lcd.realwin.ys || ys > g_lcd.realwin.ye) return; if (xe < g_lcd.realwin.xs || xs > g_lcd.realwin.xe) return; if (ys < g_lcd.realwin.ys) { buff += (g_lcd.realwin.ys - ys) * xsize; ysize -= g_lcd.realwin.ys - ys; if (ysize < 0) return; ys = g_lcd.realwin.ys; } if (xs < g_lcd.realwin.xs) { buff += (g_lcd.realwin.xs - xs); xsize -= g_lcd.realwin.xs - xs; if (xsize < 0) return; xs = g_lcd.realwin.xs; } int lcd_xsize = xe - xs + 1; if (lcd_xsize > xsize) lcd_xsize = xsize; if (ysize > ye - ys + 1) ysize = ye - ys + 1; if (lcd_xsize > 0 && ysize > 0) LCD_FillImg(g_lcd.draw, xs, ys, lcd_xsize, ysize, xsize * 2, (u8 *)buff); // DMA2D_DrawBitmap_RGB565(LCD_GetDrawAddr(),g_lcd_struct.WindowSrcX,g_lcd_struct.WindowSrcY,lcd_xsize,ysize,xsize*2,(u8*)buff); } // 把图像偏移之后填充到屏幕的活动窗口中, // 参数x_s,图像要显示的横向起始坐标 // 参数y_s,图像要显示的纵向起始坐标 // 参数xsize,图像的宽度 // 参数ysize,图像的高度 static void LCD_FillRectOff16(int xs, int ys, int xe, int ye, u16 *buff, int x_s, int y_s, int xsize, int ysize) { // 图像偏移 int offset = y_s * xsize + x_s; // 图像相对屏幕偏移 // offset += xs + ys*xsize; LCD_FillRect16(xs, ys, xe, ye, buff + offset, xsize, ysize - y_s); } void LCD_FillRectOff16At(int lcd_xs, int lcd_ys, int lcd_xsize, int lcd_ysize, u16 *buff, int xs, int ys, int xsize, int ysize) { // 绘图 LCD_FillRectOff16(lcd_xs, lcd_ys, lcd_xs + lcd_xsize - 1, lcd_ys + lcd_ysize - 1, buff, xs, ys, xsize, ysize); } static int LCD_FillImg_ARGB(const void *pSurf, int x, int y, u16 w, u16 h, int width_bytes, const u8 *bits, u32 color_format); // 把图像填充到屏幕的活动窗口中, // 参数xsize,图像的宽度 // 参数ysize,图像的高度 static void LCD_FillRectAlpha(int xs, int ys, int xe, int ye, u32 *buff, int xsize, int ysize) { ys += g_lcd.win.ys; ye += g_lcd.win.ys; xs += g_lcd.win.xs; xe += g_lcd.win.xs; if (ye < g_lcd.realwin.ys || ys > g_lcd.realwin.ye) return; if (xe < g_lcd.realwin.xs || xs > g_lcd.realwin.xe) return; if (ys < g_lcd.realwin.ys) { buff += (g_lcd.realwin.ys - ys) * xsize; ysize -= g_lcd.realwin.ys - ys; if (ysize < 0) return; ys = g_lcd.realwin.ys; } if (xs < g_lcd.realwin.xs) { buff += (g_lcd.realwin.xs - xs); xsize -= g_lcd.realwin.xs - xs; if (xsize < 0) return; xs = g_lcd.realwin.xs; } int lcd_xsize = xe - xs + 1; if (lcd_xsize > xsize) lcd_xsize = xsize; if (ysize > ye - ys + 1) ysize = ye - ys + 1; if (lcd_xsize > 0 && ysize > 0) LCD_FillImg_ARGB(g_lcd.draw, xs, ys, lcd_xsize, ysize, xsize * 4, (u8 *)buff, CM_ARGB8888); } static void LCD_FillRectOffAlpha(int xs, int ys, int xe, int ye, u32 *buff, int x_s, int y_s, int xsize, int ysize) { // 图像偏移 int offset = y_s * xsize + x_s; // 图像相对屏幕偏移 // offset += xs + ys*xsize; LCD_FillRectAlpha(xs, ys, xe, ye, buff + offset, xsize, ysize - y_s); } void LCD_FillRectOffAtAlpha(int lcd_xs, int lcd_ys, int lcd_xsize, int lcd_ysize, void *buff, int xs, int ys, int xsize, int ysize) { // 绘图 LCD_FillRectOffAlpha(lcd_xs, lcd_ys, lcd_xs + lcd_xsize - 1, lcd_ys + lcd_ysize - 1, buff, xs, ys, xsize, ysize); } // 画点,不会进行安全性检查,调用时要保证要画的点不会超出屏幕 // 参数mode,1,画前景色,0,画背景色 void LCD_DrawPoint(int x, int y, u32 mode) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; if (x < g_lcd.realwin.xs || x > g_lcd.realwin.xe) return; if (y < g_lcd.realwin.ys || y > g_lcd.realwin.ye) return; if (mode) g_lcd.draw[x + y * g_lcd.x_size] = g_lcd.color; } // 安全画点,以屏幕窗口的坐标为原点,并且画点不会超出窗口范围 void LCD_DrawPointSafe(int x, int y, u32 mode) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; if (x < g_lcd.realwin.xs || x > g_lcd.realwin.xe) return; if (y < g_lcd.realwin.ys || y > g_lcd.realwin.ye) return; if (mode) g_lcd.draw[x + y * g_lcd.x_size] = g_lcd.color; } // 安全画点,以屏幕窗口的坐标为原点,并且画点不会超出窗口范围 // 以指定颜色画点,而不是前景色 void LCD_DrawPointSafeColor(int x, int y, u16 color) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; if (x < g_lcd.realwin.xs || x > g_lcd.realwin.xe) return; if (y < g_lcd.realwin.ys || y > g_lcd.realwin.ye) return; g_lcd.draw[x + y * g_lcd.x_size] = (color); } // 快速ALPHA BLENDING算法. // src:源颜色 // dst:目标颜色 // alpha:透明程度(0~32) // 返回值:混合后的颜色. static u16 alpha_blend565(u16 src, u16 dst, u8 alpha) { u32 src2; u32 dst2; // Convert to 32bit |-----GGGGGG-----RRRRR------BBBBB| src2 = ((src << 16) | src) & 0x07E0F81F; dst2 = ((dst << 16) | dst) & 0x07E0F81F; // Perform blending R:G:B with alpha in range 0..32 // Note that the reason that alpha may not exceed 32 is that there are only // 5bits of space between each R:G:B value, any higher value will overflow // into the next component and deliver ugly result. dst2 = ((((dst2 - src2) * alpha) >> 5) + src2) & 0x07E0F81F; return (dst2 >> 16) | dst2; } // 以指定色透明度画点0~32 void LCD_DrawPointSafeColorAlpha(int x, int y, u16 color, u8 alpha) { if (g_lcd.effective == 0) return; if (alpha == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; if (x < g_lcd.realwin.xs || x > g_lcd.realwin.xe) return; if (y < g_lcd.realwin.ys || y > g_lcd.realwin.ye) return; u32 color_old = g_lcd.draw[x + y * g_lcd.x_size]; color_old = (color_old); color = alpha_blend565(color_old, color, alpha); g_lcd.draw[x + y * g_lcd.x_size] = (color); } // 填充矩形,已窗口坐标为原点 void LCD_FillRectByColor(int x, int y, int x_size, int y_size) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; int xe = x + x_size - 1; int ye = y + y_size - 1; if (x < g_lcd.realwin.xs) x = g_lcd.realwin.xs; if (y < g_lcd.realwin.ys) y = g_lcd.realwin.ys; if (xe > g_lcd.realwin.xe) xe = g_lcd.realwin.xe; if (ye > g_lcd.realwin.ye) ye = g_lcd.realwin.ye; x_size = xe - x + 1; y_size = ye - y + 1; if (x_size < 0 || y_size < 0) return; LCD_FillColor(g_lcd.draw, x, y, x_size, y_size, g_lcd.color); } static int LCD_MemSet(const void *pSurf, u16 w, u16 h, u32 color) { DMA2D_DeInit(); DMA2D->OPFCCR = DMA2D_ARGB8888; DMA2D->CR = DMA2D_R2M; // DMA2D->OPFCCR = DMA2D_RGB565; DMA2D->OCOLR = color; DMA2D->OMAR = (u32)pSurf; DMA2D->OOR = 0; DMA2D->NLR = (w << 16) | h; /* Execute operation */ DMA2D->CR |= DMA2D_CR_START; while (DMA2D->CR & DMA2D_CR_START) { } return 1; } static int LCD_FillImg_ARGB(const void *pSurf, int x, int y, u16 w, u16 h, int width_bytes, const u8 *bits, u32 color_format) { DMA2D_DeInit(); DMA2D->OPFCCR = DMA2D_RGB565; DMA2D->BGPFCCR = CM_RGB565; DMA2D->CR = DMA2D_M2M_BLEND; DMA2D->OMAR = (u32)pSurf + (y * LCD_Width + x) * 2; DMA2D->OOR = LCD_Width - w; DMA2D->NLR = (w << 16) | h; DMA2D->BGMAR = DMA2D->OMAR; DMA2D->BGOR = DMA2D->OOR; DMA2D->FGPFCCR = NO_MODIF_ALPHA_VALUE | color_format; DMA2D->FGMAR = (u32)bits; switch (color_format) { case CM_ARGB4444: DMA2D->FGOR = (width_bytes >> 1) - w; break; case CM_ARGB8888: DMA2D->FGOR = (width_bytes >> 2) - w; break; default: return 0; } DMA2D->CR |= DMA2D_CR_START; while (DMA2D->CR & DMA2D_CR_START) { } return 1; } // 以透明度填充矩形,已窗口坐标为原点 void LCD_FillRectByColorAlpha(int x, int y, int x_size, int y_size, u8 alpha) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; int xe = x + x_size - 1; int ye = y + y_size - 1; if (x < g_lcd.realwin.xs) x = g_lcd.realwin.xs; if (y < g_lcd.realwin.ys) y = g_lcd.realwin.ys; if (xe > g_lcd.realwin.xe) xe = g_lcd.realwin.xe; if (ye > g_lcd.realwin.ye) ye = g_lcd.realwin.ye; x_size = xe - x + 1; y_size = ye - y + 1; if (x_size < 0 || y_size < 0) return; u8 *fb = mymalloc(x_size * y_size * 4); LCD_MemSet(fb, x_size, y_size, COLOR565TO888(g_lcd.color) | (alpha << (24 + 3))); LCD_FillImg_ARGB(LCD_GetDrawAddr(), x, y, x_size, y_size, x_size * 4, fb, CM_ARGB8888); myfree(fb); } // 求矩形在屏幕中的显示区域 static int LCD_RectIntersection(LCD_WindowStruct *out, int x, int y, int xsize, int ysize) { // 取得新矩形的左上角 int x_s = g_lcd.realwin.xs; int y_s = g_lcd.realwin.ys; if (x_s < x) x_s = x; if (y_s < y) y_s = y; // 取得新矩形的右下角 int x_e = g_lcd.realwin.xe; int y_e = g_lcd.realwin.ye; if (x_e > x + xsize - 1) x_e = x + xsize - 1; if (y_e > y + ysize - 1) y_e = y + ysize - 1; out->xs = x_s; out->ys = y_s; out->xe = x_e; out->ye = y_e; if ((y_e >= y_s) && (x_e >= x_s)) { return 1; } else { return 0; } } // 清除矩形内的显示 void LCD_ClearRect(int x, int y, int xsize, int ysize) { if (g_lcd.effective == 0) return; x += g_lcd.win.xs; y += g_lcd.win.ys; LCD_WindowStruct out = {0}; if (LCD_RectIntersection(&out, x, y, xsize, ysize)) { LCD_FillColor(g_lcd.draw, out.xs, out.ys, out.xe - out.xs + 1, out.ye - out.ys + 1, g_lcd.bkColor); } } // 获取指定矩形空间的屏幕颜色,屏幕的绝对坐标 void LCD_GetColors(u16 *buff, int x_s, int y_s, int x_size, int y_size) { u16 *addr = g_lcd.draw; if (x_s < 0) x_s = 0; else if (x_s > LCD_Width - 1) x_s = LCD_Width - 1; if (y_s < 0) y_s = 0; else if (y_s > LCD_Height - 1) y_s = LCD_Height - 1; if (x_size > LCD_Width - x_s) x_size = LCD_Width - x_s; else if (x_size < 0) x_size = 0; if (y_size > LCD_Height - y_s) y_size = LCD_Height - y_s; else if (y_size < 0) y_size = 0; for (int y = y_s; y < y_size + y_s; y++) { for (int x = x_s; x < x_size + x_s; x++) { u32 temp = addr[(y * LCD_Width + x)]; //*buff=COLOR888TO565(temp); *buff = temp; buff++; } } }