Files
player/Project/Src/Drive/Source/lcd_rgb.c
andy 045cff4cc6 整理代码
1.解决一些编译警告
2.发现png因为文件api不支持而不能使用
2025-10-18 13:58:40 +08:00

1073 lines
31 KiB
C
Raw Permalink 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"
#include "stm32f4xx.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(uint8_t power) {
if (power) {
GPIO_SetBits(LTDC_Black_PORT, LTDC_Black_PIN);
} else {
GPIO_ResetBits(LTDC_Black_PORT, LTDC_Black_PIN);
}
}
static uint32_t *LCD_ADDR =
((uint32_t *)(LCD_MemoryAdd + LCD_MemoryAdd_OFFSET * 0));
static uint32_t *LCD_ADDR1 =
((uint32_t *)(LCD_MemoryAdd + LCD_MemoryAdd_OFFSET * 1));
#define LCD_ADDR_BUFF0 \
((uint32_t)(LCD_MemoryAdd + (uint32_t)LCD_Width * LCD_Height * 4 * 0))
#define LCD_ADDR_BUFF1 \
((uint32_t)(LCD_MemoryAdd + (uint32_t)LCD_Width * LCD_Height * 4 * 1))
#define LCD_ADDR_BUFF2 \
((uint32_t)(LCD_MemoryAdd + (uint32_t)LCD_Width * LCD_Height * 4 * 2))
const static uint32_t g_lcdAddrTable[3] = {
(uint32_t)LCD_ADDR_BUFF0,
(uint32_t)LCD_ADDR_BUFF1,
(uint32_t)LCD_ADDR_BUFF2,
};
static LCD_Struct g_lcd = {0};
// 函数初始化LCD控制器
void LCD_Init(void) {
// 用于倍频的PLLSAIN参数可取范围为50~432
uint16_t LCD_PLLSAIN = 0;
// 用于分频的PLLSAIR参数可取范围为2~7
uint8_t LCD_PLLSAIR = 3;
// LCD时钟分频参数默认设置为8分频数值上等于RCC_PLLSAIDivR_Div8
uint8_t LCD_CLKDIV = 8;
LTDC_InitTypeDef LTDC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE);
LCD_GPIO_Config(); // 初始化LCD引脚
// 根据需要使用的LCD时钟计算PLLSAIN参数可取范围为50~432
LCD_PLLSAIN = LCD_CLK * LCD_PLLSAIR * LCD_CLKDIV;
// 时钟配置
RCC_PLLSAIConfig(LCD_PLLSAIN, 7, LCD_PLLSAIR);
// LCD时钟分频设置要和LCD_CLKDIV对应
RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);
// 使能PLLSAI时钟
RCC_PLLSAICmd(ENABLE);
// 等待时钟配置完成
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 = (uint16_t *)g_lcdAddrTable[0];
g_lcd.draw = (uint16_t *)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);
}
// 初始化层1
LTDC_LayerInit(LTDC_Layer1, &LTDC_Layer_InitStruct);
// 使能层1
LTDC_LayerCmd(LTDC_Layer1, ENABLE);
#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;
// 层2的起始地址
LTDC_Layer_InitStruct.LTDC_CFBStartAdress =
LCD_MemoryAdd + LCD_MemoryAdd_OFFSET;
// 判断颜色格式
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);
}
// 初始化层2
LTDC_LayerInit(LTDC_Layer2, &LTDC_Layer_InitStruct);
// 使能层2
LTDC_LayerCmd(LTDC_Layer2, ENABLE);
#endif
// 重新载入参数
LTDC_ReloadConfig(LTDC_IMReload);
// 使能颜色抖动24位色必须打开否则无法达到24位色的效果
LTDC_DitherCmd(ENABLE);
}
void LTDC_ISR_Handler(void) {
LTDC_ClearFlag(LTDC_FLAG_LI);
if (g_lcd.LcdSwitchEn == 1) {
g_lcd.LcdSwitchEn = 0;
LTDC_Layer1->CFBAR = (uint32_t)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; }
// 获取图像显示地址
uint32_t *LCD_GetShowAddr(void) {
uint32_t *ret = (uint32_t *)LTDC_Layer1->CFBAR;
ret = (uint32_t *)g_lcd.show;
return ret;
}
// 获取图像绘制地址
uint32_t *LCD_GetDrawAddr(void) {
uint32_t *ret = 0;
ret = (uint32_t *)g_lcd.draw;
return ret;
}
// 设置屏幕显示地址,这个地址直接输出到屏幕上,返回上一个输出到屏幕的地址
uint32_t LCD_SetLayer(uint32_t AddrIndex) {
uint32_t ret = LTDC_Layer1->CFBAR;
if (AddrIndex < 3) {
g_lcd.show = (uint16_t *)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;
}
// 设置绘图地址,所有绘制操作在这个地址执行
uint32_t LCD_SetDrawLayer(uint32_t Index) {
uint32_t ret = (uint32_t)g_lcd.draw;
if (Index < 3) {
g_lcd.draw = (uint16_t *)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;
}
uint32_t LCD_SetLcdColor(uint32_t color) {
uint32_t ret = g_lcd.color;
// g_lcd_struct.Color=color;
g_lcd.color = COLOR888TO565(color);
return ret;
}
uint32_t LCD_SetLcdBkColor(uint32_t color) {
uint32_t ret = g_lcd.bkColor;
// g_lcd_struct.BackColor=color;
ret = g_lcd.bkColor = COLOR888TO565(color);
return ret;
}
uint32_t LCD_SetLcdColor16(uint32_t color) {
uint32_t ret = g_lcd.color;
g_lcd.color = (color);
return ret;
}
uint32_t LCD_SetLcdBkColor16(uint32_t color) {
uint32_t ret = ret = g_lcd.bkColor;
ret = g_lcd.bkColor = (color);
return ret;
}
uint32_t LCD_GetLcdColor(void) {
uint32_t ret = g_lcd.color;
return COLOR565TO888(ret);
}
uint32_t LCD_GetLcdBkColor(void) {
uint32_t ret = g_lcd.bkColor;
return COLOR565TO888(ret);
}
uint32_t LCD_GetLcdColor16(void) {
uint32_t ret = g_lcd.color;
return ret;
}
uint32_t LCD_GetLcdBkColor16(void) {
uint32_t 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 */
/* Control Register (Memory to memory with pixel format conversion and TCIE) */
DMA2D->CR = 0x00010000UL | (1 << 9);
/* Set up pointers */
/* Foreground Memory Address Register (Source address) */
DMA2D->FGMAR = (uint32_t)pSrc;
/* Output Memory Address Register (Destination address) */
DMA2D->OMAR = (uint32_t)pDst;
/* Set up offsets */
/* Foreground Offset Register (Source line offset) */
DMA2D->FGOR = 0;
/* Output Offset Register (Destination line offset) */
DMA2D->OOR = 0;
/* Set up pixel format */
/* Foreground PFC Control Register (Defines the input pixel format) */
DMA2D->FGPFCCR = LTDC_Pixelformat_RGB565;
/* Output PFC Control Register (Defines the output pixel format) */
DMA2D->OPFCCR = LTDC_Pixelformat_RGB565;
/* Set up size */
/* Number of Line Register (Size configuration of area to be transfered) */
DMA2D->NLR = (uint32_t)(x_size << 16) | y_size;
/* 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,
uint32_t color) {
DMA2D_DeInit();
DMA2D->OPFCCR = DMA2D_RGB565;
DMA2D->CR = DMA2D_R2M;
DMA2D->OCOLR = color;
DMA2D->OMAR = (uint32_t)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 uint16_t *pSurf, int x, int y, uint16_t w, uint16_t h,
int width_bytes, const uint8_t *bits) {
DMA2D_DeInit();
DMA2D->OPFCCR = DMA2D_RGB565;
DMA2D->CR = DMA2D_M2M;
DMA2D->OMAR = (uint32_t)pSurf + (y * LCD_Width + x) * 2;
DMA2D->OOR = LCD_Width - w;
DMA2D->NLR = (w << 16) | h;
DMA2D->FGPFCCR = CM_RGB565;
DMA2D->FGMAR = (uint32_t)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) {
uint32_t *p_dst = 0;
uint32_t *p_src = 0;
if ((dst < 3) && (src < 3)) {
p_dst = (uint32_t *)g_lcdAddrTable[dst];
p_src = (uint32_t *)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 ((uint32_t)g_lcd.show == g_lcdAddrTable[0]) {
g_lcd.draw = (uint16_t *)g_lcdAddrTable[1];
LCD_LayerCopy(1, 0);
} else if ((uint32_t)g_lcd.show == g_lcdAddrTable[1]) {
g_lcd.draw = (uint16_t *)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 ((uint32_t)g_lcd.show == g_lcdAddrTable[0]) {
g_lcd.draw = (uint16_t *)g_lcdAddrTable[1];
} else if ((uint32_t)g_lcd.show == g_lcdAddrTable[1]) {
g_lcd.draw = (uint16_t *)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, uint16_t *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, uint16_t *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,
(uint8_t *)buff);
// DMA2D_DrawBitmap_RGB565(LCD_GetDrawAddr(),g_lcd_struct.WindowSrcX,g_lcd_struct.WindowSrcY,lcd_xsize,ysize,xsize*2,(uint8_t*)buff);
}
// 把图像偏移之后填充到屏幕的活动窗口中,
// 参数x_s,图像要显示的横向起始坐标
// 参数y_s图像要显示的纵向起始坐标
// 参数xsize,图像的宽度
// 参数ysize,图像的高度
static void LCD_FillRectOff16(int xs, int ys, int xe, int ye, uint16_t *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,
uint16_t *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, uint16_t w,
uint16_t h, int width_bytes, const uint8_t *bits,
uint32_t color_format);
// 把图像填充到屏幕的活动窗口中,
// 参数xsize,图像的宽度
// 参数ysize,图像的高度
static void LCD_FillRectAlpha(int xs, int ys, int xe, int ye, uint32_t *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,
(uint8_t *)buff, CM_ARGB8888);
}
static void LCD_FillRectOffAlpha(int xs, int ys, int xe, int ye, uint32_t *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, uint32_t 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, uint32_t 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, uint16_t 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 uint16_t alpha_blend565(uint16_t src, uint16_t dst, uint8_t alpha) {
uint32_t src2;
uint32_t 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, uint16_t color, uint8_t 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;
uint32_t 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, uint16_t w, uint16_t h,
uint32_t color) {
DMA2D_DeInit();
DMA2D->OPFCCR = DMA2D_ARGB8888;
DMA2D->CR = DMA2D_R2M;
// DMA2D->OPFCCR = DMA2D_RGB565;
DMA2D->OCOLR = color;
DMA2D->OMAR = (uint32_t)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, uint16_t w,
uint16_t h, int width_bytes, const uint8_t *bits,
uint32_t color_format) {
DMA2D_DeInit();
DMA2D->OPFCCR = DMA2D_RGB565;
DMA2D->BGPFCCR = CM_RGB565;
DMA2D->CR = DMA2D_M2M_BLEND;
DMA2D->OMAR = (uint32_t)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 = (uint32_t)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,
uint8_t 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;
uint8_t *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(uint16_t *buff, int x_s, int y_s, int x_size, int y_size) {
uint16_t *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++) {
uint32_t temp = addr[(y * LCD_Width + x)];
//*buff=COLOR888TO565(temp);
*buff = temp;
buff++;
}
}
}