Files
player/Project/Src/Drive/Source/lcd_rgb.c
2025-07-10 11:30:57 +08:00

1060 lines
31 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***
*****************************************************************************************
* @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(&LTDC_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, &LTDC_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, &LTDC_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++;
}
}
}