Files
stm32-cnn/HARDWARE/LCD/ltdc.c
2024-11-01 22:38:48 +08:00

526 lines
18 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.

#include "ltdc.h"
#include "lcd.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32开发板
//LTDC驱动
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/7/13
//版本V1.2
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//********************************************************************************
//修改说明
//V1.1 20161026
//在LTDC_PanelID_Read函数加入delay解决-O2优化读ID可能出错的BUG
//V1.2 20170606
//新增10.1寸RGB屏的支持
//////////////////////////////////////////////////////////////////////////////////
LTDC_HandleTypeDef LTDC_Handler; //LTDC句柄
DMA2D_HandleTypeDef DMA2D_Handler; //DMA2D句柄
//根据不同的颜色格式,定义帧缓存数组
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
u32 ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR))); //定义最大屏分辨率时,LCD所需的帧缓存数组大小
#else
u16 ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR))); //定义最大屏分辨率时,LCD所需的帧缓存数组大小
#endif
u32 *ltdc_framebuf[2]; //LTDC LCD帧缓存数组指针,必须指向对应大小的内存区域
_ltdc_dev lcdltdc; //管理LCD LTDC的重要参数
//打开LCD开关
//lcd_switch:1 打开,0关闭
void LTDC_Switch(u8 sw)
{
if(sw==1) __HAL_LTDC_ENABLE(&LTDC_Handler);
else if(sw==0)__HAL_LTDC_DISABLE(&LTDC_Handler);
}
//开关指定层
//layerx:层号,0,第一层; 1,第二层
//sw:1 打开;0关闭
void LTDC_Layer_Switch(u8 layerx,u8 sw)
{
if(sw==1) __HAL_LTDC_LAYER_ENABLE(&LTDC_Handler,layerx);
else if(sw==0) __HAL_LTDC_LAYER_DISABLE(&LTDC_Handler,layerx);
__HAL_LTDC_RELOAD_CONFIG(&LTDC_Handler);
}
//选择层
//layerx:层号;0,第一层;1,第二层;
void LTDC_Select_Layer(u8 layerx)
{
lcdltdc.activelayer=layerx;
}
//设置LCD显示方向
//dir:0,竖屏1,横屏
void LTDC_Display_Dir(u8 dir)
{
lcdltdc.dir=dir; //显示方向
if(dir==0) //竖屏
{
lcdltdc.width=lcdltdc.pheight;
lcdltdc.height=lcdltdc.pwidth;
}else if(dir==1) //横屏
{
lcdltdc.width=lcdltdc.pwidth;
lcdltdc.height=lcdltdc.pheight;
}
}
//画点函数
//x,y:写入坐标
//color:颜色值
void LTDC_Draw_Point(u16 x,u16 y,u32 color)
{
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
if(lcdltdc.dir) //横屏
{
*(u32*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x))=color;
}else //竖屏
{
*(u32*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x)+y))=color;
}
#else
if(lcdltdc.dir) //横屏
{
*(u16*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x))=color;
}else //竖屏
{
*(u16*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y))=color;
}
#endif
}
//读点函数
//x,y:读取点的坐标
//返回值:颜色值
u32 LTDC_Read_Point(u16 x,u16 y)
{
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
if(lcdltdc.dir) //横屏
{
return *(u32*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x));
}else //竖屏
{
return *(u32*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x)+y));
}
#else
if(lcdltdc.dir) //横屏
{
return *(u16*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x));
}else //竖屏
{
return *(u16*)((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y));
}
#endif
}
//LTDC填充矩形,DMA2D填充
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
//有时候需要频繁的调用填充函数,所以为了速度,填充函数采用寄存器版本,
//不过下面有对应的库函数版本的代码。
void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)
{
u32 psx,psy,pex,pey; //以LCD面板为基准的坐标系,不随横竖屏变化而变化
u32 timeout=0;
u16 offline;
u32 addr;
//坐标系转换
if(lcdltdc.dir) //横屏
{
psx=sx;psy=sy;
pex=ex;pey=ey;
}else //竖屏
{
psx=sy;psy=lcdltdc.pheight-ex-1;
pex=ey;pey=lcdltdc.pheight-sx-1;
}
offline=lcdltdc.pwidth-(pex-psx+1);
addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
__HAL_RCC_DMA2D_CLK_ENABLE(); //使能DM2D时钟
DMA2D->CR&=~(DMA2D_CR_START); //先停止DMA2D
DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
DMA2D->OPFCCR=LCD_PIXFORMAT; //设置颜色格式
DMA2D->OOR=offline; //设置行偏移
DMA2D->OMAR=addr; //输出存储器地址
DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16); //设定行数寄存器
DMA2D->OCOLR=color; //设定输出颜色寄存器
DMA2D->CR|=DMA2D_CR_START; //启动DMA2D
while((DMA2D->ISR&(DMA2D_FLAG_TC))==0) //等待传输完成
{
timeout++;
if(timeout>0X1FFFFF)break; //超时退出
}
DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
}
//在指定区域内填充单个颜色
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//color:要填充的颜色
//void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)
//{
// u32 psx,psy,pex,pey; //以LCD面板为基准的坐标系,不随横竖屏变化而变化
// u32 timeout=0;
// u16 offline;
// u32 addr;
// if(ex>=lcdltdc.width)ex=lcdltdc.width-1;
// if(ey>=lcdltdc.height)ey=lcdltdc.height-1;
// //坐标系转换
// if(lcdltdc.dir) //横屏
// {
// psx=sx;psy=sy;
// pex=ex;pey=ey;
// }else //竖屏
// {
// psx=sy;psy=lcdltdc.pheight-ex-1;
// pex=ey;pey=lcdltdc.pheight-sx-1;
// }
// offline=lcdltdc.pwidth-(pex-psx+1);
// addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
// if(LCD_PIXFORMAT==LCD_PIXEL_FORMAT_RGB565) //如果是RGB565格式的话需要进行颜色转换将16bit转换为32bit的
// {
// color=((color&0X0000F800)<<8)|((color&0X000007E0)<<5)|((color&0X0000001F)<<3);
// }
// //配置DMA2D的模式
// DMA2D_Handler.Instance=DMA2D;
// DMA2D_Handler.Init.Mode=DMA2D_R2M; //内存到存储器模式
// DMA2D_Handler.Init.ColorMode=LCD_PIXFORMAT; //设置颜色格式
// DMA2D_Handler.Init.OutputOffset=offline; //输出偏移
// HAL_DMA2D_Init(&DMA2D_Handler); //初始化DMA2D
// HAL_DMA2D_ConfigLayer(&DMA2D_Handler,lcdltdc.activelayer); //层配置
// HAL_DMA2D_Start(&DMA2D_Handler,color,(u32)addr,pex-psx+1,pey-psy+1);//开启传输
// HAL_DMA2D_PollForTransfer(&DMA2D_Handler,1000);//传输数据
// while((__HAL_DMA2D_GET_FLAG(&DMA2D_Handler,DMA2D_FLAG_TC)==0)&&(timeout<0X5000))//等待DMA2D完成
// {
// timeout++;
// }
// __HAL_DMA2D_CLEAR_FLAG(&DMA2D_Handler,DMA2D_FLAG_TC); //清除传输完成标志
//}
//在指定区域内填充指定颜色块,DMA2D填充
//此函数仅支持u16,RGB565格式的颜色数组填充.
//(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
//注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
//color:要填充的颜色数组首地址
void LTDC_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{
u32 psx,psy,pex,pey; //以LCD面板为基准的坐标系,不随横竖屏变化而变化
u32 timeout=0;
u16 offline;
u32 addr;
//坐标系转换
if(lcdltdc.dir) //横屏
{
psx=sx;psy=sy;
pex=ex;pey=ey;
}else //竖屏
{
psx=sy;psy=lcdltdc.pheight-ex-1;
pex=ey;pey=lcdltdc.pheight-sx-1;
}
offline=lcdltdc.pwidth-(pex-psx+1);
addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
__HAL_RCC_DMA2D_CLK_ENABLE(); //使能DM2D时钟
DMA2D->CR&=~(DMA2D_CR_START); //先停止DMA2D
DMA2D->CR=DMA2D_M2M; //存储器到存储器模式
DMA2D->FGPFCCR=LCD_PIXFORMAT; //设置颜色格式
DMA2D->FGOR=0; //前景层行偏移为0
DMA2D->OOR=offline; //设置行偏移
DMA2D->FGMAR=(u32)color; //源地址
DMA2D->OMAR=addr; //输出存储器地址
DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16); //设定行数寄存器
DMA2D->CR|=DMA2D_CR_START; //启动DMA2D
while((DMA2D->ISR&(DMA2D_FLAG_TC))==0) //等待传输完成
{
timeout++;
if(timeout>0X1FFFFF)break; //超时退出
}
DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
}
//LCD清屏
//color:颜色值
void LTDC_Clear(u32 color)
{
LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);
}
//LTDC时钟(Fdclk)设置函数
//Fvco=Fin*pllsain;
//Fdclk=Fvco/pllsair/2*2^pllsaidivr=Fin*pllsain/pllsair/2*2^pllsaidivr;
//Fvco:VCO频率
//Fin:输入时钟频率一般为1Mhz(来自系统时钟PLLM分频后的时钟,见时钟树图)
//pllsain:SAI时钟倍频系数N,取值范围:50~432.
//pllsair:SAI时钟的分频系数R,取值范围:2~7
//pllsaidivr:LCD时钟分频系数,取值范围:RCC_PLLSAIDIVR_2/4/8/16,对应分频2~16
//假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
//例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=RCC_PLLSAIDIVR_4
//Fdclk=1*400/5/4=400/20=20Mhz
//返回值:0,成功;1,失败。
u8 LTDC_Clk_Set(u32 pllsain,u32 pllsair,u32 pllsaidivr)
{
RCC_PeriphCLKInitTypeDef PeriphClkIniture;
//LTDC输出像素时钟需要根据自己所使用的LCD数据手册来配置
PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC; //LTDC时钟
PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;
PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
PeriphClkIniture.PLLSAIDivR=pllsaidivr;
if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkIniture)==HAL_OK) //配置像素时钟
{
return 0; //成功
}
else return 1; //失败
}
//LTDC,层颜窗口设置,窗口以LCD面板坐标系为基准
//注意:此函数必须在LTDC_Layer_Parameter_Config之后再设置.
//layerx:层值,0/1.
//sx,sy:起始坐标
//width,height:宽度和高度
void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)
{
HAL_LTDC_SetWindowPosition(&LTDC_Handler,sx,sy,layerx); //设置窗口的位置
HAL_LTDC_SetWindowSize(&LTDC_Handler,width,height,layerx);//设置窗口大小
}
//LTDC,基本参数设置.
//注意:此函数,必须在LTDC_Layer_Window_Config之前设置.
//layerx:层值,0/1.
//bufaddr:层颜色帧缓存起始地址
//pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
//alpha:层颜色Alpha值,0,全透明;255,不透明
//alpha0:默认颜色Alpha值,0,全透明;255,不透明
//bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
//bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
//bkcolor:层默认颜色,32位,低24位有效,RGB888格式
//返回值:无
void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)
{
LTDC_LayerCfgTypeDef pLayerCfg;
pLayerCfg.WindowX0=0; //窗口起始X坐标
pLayerCfg.WindowY0=0; //窗口起始Y坐标
pLayerCfg.WindowX1=lcdltdc.pwidth; //窗口终止X坐标
pLayerCfg.WindowY1=lcdltdc.pheight; //窗口终止Y坐标
pLayerCfg.PixelFormat=pixformat; //像素格式
pLayerCfg.Alpha=alpha; //Alpha值设置0~255,255为完全不透明
pLayerCfg.Alpha0=alpha0; //默认Alpha值
pLayerCfg.BlendingFactor1=(u32)bfac1<<8; //设置层混合系数
pLayerCfg.BlendingFactor2=(u32)bfac2<<8; //设置层混合系数
pLayerCfg.FBStartAdress=bufaddr; //设置层颜色帧缓存起始地址
pLayerCfg.ImageWidth=lcdltdc.pwidth; //设置颜色帧缓冲区的宽度
pLayerCfg.ImageHeight=lcdltdc.pheight; //设置颜色帧缓冲区的高度
pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16; //背景颜色红色部分
pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8; //背景颜色绿色部分
pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF; //背景颜色蓝色部分
HAL_LTDC_ConfigLayer(&LTDC_Handler,&pLayerCfg,layerx); //设置所选中的层
}
//读取面板参数
//PG6=R7(M0);PI2=G7(M1);PI7=B7(M2);
//M2:M1:M0
//0 :0 :0 //4.3寸480*272 RGB屏,ID=0X4342
//0 :0 :1 //7寸800*480 RGB屏,ID=0X7084
//0 :1 :0 //7寸1024*600 RGB屏,ID=0X7016
//0 :1 :1 //7寸1280*800 RGB屏,ID=0X7018
//1 :0 :0 //4.3寸800*480 RGB屏,ID=0X4384
//1 :0 :1 //10.1寸1280*800 RGB屏,ID=0X1018
//返回值:LCD ID:0,非法;其他值,ID;
u16 LTDC_PanelID_Read(void)
{
u8 idx=0;
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIOG时钟
__HAL_RCC_GPIOI_CLK_ENABLE(); //使能GPIOI时钟
GPIO_Initure.Pin=GPIO_PIN_6; //PG6
GPIO_Initure.Mode=GPIO_MODE_INPUT; //输入
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOG,&GPIO_Initure); //初始化
GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_7; //PI2,7
HAL_GPIO_Init(GPIOI,&GPIO_Initure); //初始化
idx=(u8)HAL_GPIO_ReadPin(GPIOG,GPIO_PIN_6); //读取M0
idx|=(u8)HAL_GPIO_ReadPin(GPIOI,GPIO_PIN_2)<<1;//读取M1
idx|=(u8)HAL_GPIO_ReadPin(GPIOI,GPIO_PIN_7)<<2;//读取M2
switch(idx)
{
case 0:return 0X4342; //4.3寸屏,480*272分辨率
case 1:return 0X7084; //7寸屏,800*480分辨率
case 2:return 0X7016; //7寸屏,1024*600分辨率
case 3:return 0X7018; //7寸屏,1280*800分辨率
case 4:return 0X4384; //4.3寸屏,800*480分辨率
case 5:return 0X1018; //10.1寸屏,1280*800分辨率
default:return 0;
}
}
//LCD初始化函数
void LTDC_Init(void)
{
u16 lcdid=0;
lcdid=LTDC_PanelID_Read(); //读取LCD面板ID
if(lcdid==0X4342)
{
lcdltdc.pwidth=480; //面板宽度,单位:像素
lcdltdc.pheight=272; //面板高度,单位:像素
lcdltdc.hsw=1; //水平同步宽度
lcdltdc.vsw=1; //垂直同步宽度
lcdltdc.hbp=40; //水平后廊
lcdltdc.vbp=8; //垂直后廊
lcdltdc.hfp=5; //水平前廊
lcdltdc.vfp=8; //垂直前廊
LTDC_Clk_Set(288,4,RCC_PLLSAIDIVR_8); //设置像素时钟 9Mhz
//其他参数待定.
}else if(lcdid==0X7084)
{
lcdltdc.pwidth=800; //面板宽度,单位:像素
lcdltdc.pheight=480; //面板高度,单位:像素
lcdltdc.hsw=1; //水平同步宽度
lcdltdc.vsw=1; //垂直同步宽度
lcdltdc.hbp=46; //水平后廊
lcdltdc.vbp=23; //垂直后廊
lcdltdc.hfp=210; //水平前廊
lcdltdc.vfp=22; //垂直前廊
LTDC_Clk_Set(396,3,RCC_PLLSAIDIVR_4); //设置像素时钟 33M(如果开双显,需要降低DCLK到:18.75Mhz 300/4/4,才会比较好)
}else if(lcdid==0X7016)
{
lcdltdc.pwidth=1024; //面板宽度,单位:像素
lcdltdc.pheight=600; //面板高度,单位:像素
lcdltdc.hsw=20; //水平同步宽度
lcdltdc.vsw=3; //垂直同步宽度
lcdltdc.hbp=140; //水平后廊
lcdltdc.vbp=20; //垂直后廊
lcdltdc.hfp=160; //水平前廊
lcdltdc.vfp=12; //垂直前廊
LTDC_Clk_Set(360,2,RCC_PLLSAIDIVR_4);//设置像素时钟 45Mhz
//其他参数待定.
}else if(lcdid==0X7018)
{
lcdltdc.pwidth=1280; //面板宽度,单位:像素
lcdltdc.pheight=800; //面板高度,单位:像素
//其他参数待定.
}else if(lcdid==0X4384)
{
lcdltdc.pwidth=800; //面板宽度,单位:像素
lcdltdc.pheight=480; //面板高度,单位:像素
lcdltdc.hbp=88; //水平后廊
lcdltdc.hfp=40; //水平前廊
lcdltdc.hsw=48; //水平同步宽度
lcdltdc.vbp=32; //垂直后廊
lcdltdc.vfp=13; //垂直前廊
lcdltdc.vsw=3; //垂直同步宽度
LTDC_Clk_Set(396,3,RCC_PLLSAIDIVR_4); //设置像素时钟 33M
//其他参数待定.
}else if(lcdid==0X1018) //10.1寸1280*800 RGB屏
{
lcdltdc.pwidth=1280; //面板宽度,单位:像素
lcdltdc.pheight=800; //面板高度,单位:像素
lcdltdc.hbp=140; //水平后廊
lcdltdc.hfp=10; //水平前廊
lcdltdc.hsw=10; //水平同步宽度
lcdltdc.vbp=10; //垂直后廊
lcdltdc.vfp=10; //垂直前廊
lcdltdc.vsw=3; //垂直同步宽度
LTDC_Clk_Set(360,2,RCC_PLLSAIDIVR_4);//设置像素时钟 45Mhz
}
lcddev.width=lcdltdc.pwidth;
lcddev.height=lcdltdc.pheight;
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
ltdc_framebuf[0]=(u32*)&ltdc_lcd_framebuf;
lcdltdc.pixsize=4; //每个像素占4个字节
#else
lcdltdc.pixsize=2; //每个像素占2个字节
ltdc_framebuf[0]=(u32*)&ltdc_lcd_framebuf;
#endif
//LTDC配置
LTDC_Handler.Instance=LTDC;
LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL; //水平同步极性
LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL; //垂直同步极性
LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL; //数据使能极性
if(lcdid==0X1018)LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IIPC;//像素时钟极性
else LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC; //像素时钟极性
LTDC_Handler.Init.HorizontalSync=lcdltdc.hsw-1; //水平同步宽度
LTDC_Handler.Init.VerticalSync=lcdltdc.vsw-1; //垂直同步宽度
LTDC_Handler.Init.AccumulatedHBP=lcdltdc.hsw+lcdltdc.hbp-1; //水平同步后沿宽度
LTDC_Handler.Init.AccumulatedVBP=lcdltdc.vsw+lcdltdc.vbp-1; //垂直同步后沿高度
LTDC_Handler.Init.AccumulatedActiveW=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth-1;//有效宽度
LTDC_Handler.Init.AccumulatedActiveH=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight-1;//有效高度
LTDC_Handler.Init.TotalWidth=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth+lcdltdc.hfp-1; //总宽度
LTDC_Handler.Init.TotalHeigh=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight+lcdltdc.vfp-1; //总高度
LTDC_Handler.Init.Backcolor.Red=0; //屏幕背景层红色部分
LTDC_Handler.Init.Backcolor.Green=0; //屏幕背景层绿色部分
LTDC_Handler.Init.Backcolor.Blue=0; //屏幕背景色蓝色部分
HAL_LTDC_Init(&LTDC_Handler);
//层配置
LTDC_Layer_Parameter_Config(0,(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);//层参数配置
LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight); //层窗口配置,以LCD面板坐标系为基准,不要随便修改!
LTDC_Display_Dir(0); //默认竖屏
LTDC_Select_Layer(0); //选择第1层
LCD_LED=1; //点亮背光
LTDC_Clear(0XFFFFFFFF); //清屏
}
//LTDC底层IO初始化和时钟使能
//此函数会被HAL_LTDC_Init()调用
//hltdc:LTDC句柄
void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_LTDC_CLK_ENABLE(); //使能LTDC时钟
__HAL_RCC_DMA2D_CLK_ENABLE(); //使能DMA2D时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
__HAL_RCC_GPIOF_CLK_ENABLE(); //使能GPIOF时钟
__HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIOG时钟
__HAL_RCC_GPIOH_CLK_ENABLE(); //使能GPIOH时钟
__HAL_RCC_GPIOI_CLK_ENABLE(); //使能GPIOI时钟
//初始化PB5背光引脚
GPIO_Initure.Pin=GPIO_PIN_5; //PB5推挽输出控制背光
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
//初始化PF10
GPIO_Initure.Pin=GPIO_PIN_10;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用
GPIO_Initure.Pull=GPIO_NOPULL;
GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速
GPIO_Initure.Alternate=GPIO_AF14_LTDC; //复用为LTDC
HAL_GPIO_Init(GPIOF,&GPIO_Initure);
//初始化PG6,7,11
GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;
HAL_GPIO_Init(GPIOG,&GPIO_Initure);
//初始化PH9,10,11,12,13,14,15
GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\
GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
HAL_GPIO_Init(GPIOH,&GPIO_Initure);
//初始化PI0,1,2,4,5,6,7,9,10
GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;
HAL_GPIO_Init(GPIOI,&GPIO_Initure);
}