文章目录
LTDC/DMA2D——液晶显示
1.显示器介绍
常用的显示器有液晶LCD显示器、LED点阵显示器、OLED显示器、CRT显示器。
LED显示器是由LED点阵彩色显示器的点个像素点整合起来,显示整个面板图形,每一个像素点都是由一个LED灯实现RGB显示,所以一般来说,LED显示器体积比较大;
新一代的OLED单个的像素点是由发光二极管显示的,所以它的像素密度比较高;
显示器参数:
分辨率:行像素值×列像素值
色彩深度:每个像素点能表示多少种颜色,一般有位bit表示,单色显示屏只能表示亮、灭两种状态,所以为2bit,一般常见的是16bit、24bit
显示器尺寸:5寸、7寸
点距:两个相邻像素点之间的距离
2.液晶控制原理
(1)显示器由液晶显示面板、电容触摸面板、PCB底板组成。
(2)液晶面板的控制信号
信号名称 | 说明 |
---|---|
R[7:0] | 红色数据 |
G[7:0] | 绿色数据 |
B[7:0] | 蓝色数据 |
CLK | 像素同步时钟信号 |
HSYNC | 水平同步信号 |
VSYNC | 水平同步信号 |
DE | 数据使能信号 |
DISP | 液晶屏使能信号 |
BL | 液晶屏背光信号 |
(3)液晶数据传输时序图
(4)显存
在液晶显示中的每个像素点都是数据,实际应用中需要先将大量的数据缓存起来,然后一帧一帧的传输给液晶显示屏,这种存储显示数据的存储器就称为显存。一般最少要存储一帧数据。
例如分辨率为800×480的液晶屏,使用RGB888格式显示(24位),它存储一帧数据的大小为800*480×3=115200字节。
3.LTDC液晶控制器
(1)液晶显示屏支持2层数据的显示,前景层和背景层,在输出时LTDC控制器将两层数据叠加混合为一层数据进行输出。
(2)LTDC结构框图
主要包括信号线、图像处理单元、寄存器、时钟信号,具体设置可以根据需要进行配置
4.DMA2D图形加速器介绍
在使用LTDC控制器控制液晶面板时,LTDC控制器将显存里面缓存的数据搬运到液晶面板时,数据非常大,就想用DMA进行操作,可以提高速度,DMA2D可以快速绘制矩形、直线、分层数据混合、数据复制等,图形绘制的专用的DMA
5.LTDC初始化结构体
如何配置LTDC结构体
/**
* @brief 初始化控制LCD的IO
* @param 无
* @retval 无
*/
static void LCD_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 使能LCD相关的GPIO时钟 */
/*RGB信号线*/
RCC_AHB1PeriphClockCmd(LCD_R0_GPIO_CLK | LCD_R1_GPIO_CLK | LCD_R2_GPIO_CLK |
LCD_R3_GPIO_CLK | LCD_R4_GPIO_CLK | LCD_R5_GPIO_CLK |
LCD_R6_GPIO_CLK | LCD_R7_GPIO_CLK | LCD_G0_GPIO_CLK |
LCD_G1_GPIO_CLK | LCD_G2_GPIO_CLK | LCD_G3_GPIO_CLK |
LCD_G4_GPIO_CLK | LCD_G5_GPIO_CLK | LCD_G6_GPIO_CLK |
LCD_G7_GPIO_CLK | LCD_B0_GPIO_CLK | LCD_B1_GPIO_CLK |
LCD_B2_GPIO_CLK | LCD_B3_GPIO_CLK | LCD_B4_GPIO_CLK |
LCD_B5_GPIO_CLK | LCD_B6_GPIO_CLK | LCD_B7_GPIO_CLK |
/*控制信号线*/
LCD_CLK_GPIO_CLK | LCD_HSYNC_GPIO_CLK | LCD_VSYNC_GPIO_CLK |
LCD_DE_GPIO_CLK | LCD_DISP_GPIO_CLK | LCD_BL_GPIO_CLK,ENABLE);
/*-- GPIO 配置 --------------------------------------*/
/* 通用 GPIO 配置 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //配置为复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/*红色数据线GPIO配置*/
GPIO_InitStructure.GPIO_Pin = LCD_R0_GPIO_PIN;
GPIO_Init(LCD_R0_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(LCD_R0_GPIO_PORT, LCD_R0_PINSOURCE , LCD_R0_AF);
/*中间的数据线省略*/
//绿色数据线
GPIO_InitStruct.GPIO_Pin = LTDC_G0_GPIO_PIN;
GPIO_Init(LTDC_G0_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(LTDC_G0_GPIO_PORT, LTDC_G0_PINSOURCE, LTDC_G0_AF);
/*中间的数据线省略*/
//蓝色数据线
GPIO_InitStruct.GPIO_Pin = LTDC_B0_GPIO_PIN;
GPIO_Init(LTDC_B0_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(LTDC_B0_GPIO_PORT, LTDC_B0_PINSOURCE, LTDC_B0_AF);
//控制信号线
GPIO_InitStruct.GPIO_Pin = LTDC_CLK_GPIO_PIN;
GPIO_Init(LTDC_CLK_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(LTDC_CLK_GPIO_PORT, LTDC_CLK_PINSOURCE, LTDC_CLK_AF);
GPIO_InitStruct.GPIO_Pin = LTDC_HSYNC_GPIO_PIN;
GPIO_Init(LTDC_HSYNC_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(LTDC_HSYNC_GPIO_PORT, LTDC_HSYNC_PINSOURCE, LTDC_HSYNC_AF);
GPIO_InitStruct.GPIO_Pin = LTDC_VSYNC_GPIO_PIN;
GPIO_Init(LTDC_VSYNC_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(LTDC_VSYNC_GPIO_PORT, LTDC_VSYNC_PINSOURCE, LTDC_VSYNC_AF);
GPIO_InitStruct.GPIO_Pin = LTDC_DE_GPIO_PIN;
GPIO_Init(LTDC_DE_GPIO_PORT, &GPIO_InitStruct);
GPIO_PinAFConfig(LTDC_DE_GPIO_PORT, LTDC_DE_PINSOURCE, LTDC_DE_AF);
//背光BL及液晶使能信号DISP
GPIO_InitStruct.GPIO_Pin = LTDC_DISP_GPIO_PIN;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(LTDC_DISP_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = LTDC_BL_GPIO_PIN;
GPIO_Init(LTDC_BL_GPIO_PORT, &GPIO_InitStruct);
//拉高使能lcd
GPIO_SetBits(LTDC_DISP_GPIO_PORT,LTDC_DISP_GPIO_PIN);
GPIO_SetBits(LTDC_BL_GPIO_PORT,LTDC_BL_GPIO_PIN);
}
注意其中的背光BL及液晶使能信号DISP/拉高使能lcd 也需要进行初始化配置
6.LTDC层级初始化结构体
可以配合固件库手册对层级结构体进行配置(stm324x9i_eval_lcd.c.)
void LCD_Init(void)
{
LTDC_InitTypeDef LTDC_InitStruct;
LTDC_Layer_TypeDef LTDC_Layerx;
/* Enable the LTDC Clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE);
/* Enable the DMA2D Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE);
/* Configure the LCD Control pins */
LCD_AF_GPIOConfig();
/* Configure the FMC Parallel interface : SDRAM is used as Frame Buffer for LCD */
SDRAM_Init();
/* Check if the LCD is AMPIRE480272 or AMPIRE640480 */
LCD_CheckDevice();
/* Polarity configuration */
/* Initialize the horizontal synchronization polarity as active low */
LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL;
/* Initialize the vertical synchronization polarity as active low */
LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL;
/* Initialize the data enable polarity as active low */
LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL;
/* Initialize the pixel clock polarity as input pixel clock */
LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC;
/* Configure R,G,B component values for LCD background color */
LTDC_InitStruct.LTDC_BackgroundRedValue = 0;
LTDC_InitStruct.LTDC_BackgroundGreenValue = 0;
LTDC_InitStruct.LTDC_BackgroundBlueValue = 0;
/* LCD AMPIRE640480 is used */
if(CurrentLcd == USE_LCD_AM640480)
{
/* Initialise I2C for touch panel usage */
LCD_I2C_Config();
/* Initialize the LCD pixel width and pixel height */
LCD_PIXEL_WIDTH = 640;
LCD_PIXEL_HEIGHT = 480;
/* Configure PLLSAI prescalers for LCD */
/* Enable Pixel Clock */
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 192 Mhz */
/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAI_R = 192/2 = 96 Mhz */
/* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = 96/4 = 24 Mhz */
RCC_PLLSAIConfig(192, 7, 2);
RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div4);
/* Enable PLLSAI Clock */
RCC_PLLSAICmd(ENABLE);
/* Wait for PLLSAI activation */
while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET)
{
}
/* Timing configuration */
/* Configure horizontal synchronization width */
LTDC_InitStruct.LTDC_HorizontalSync = 29;
/* Configure vertical synchronization height */
LTDC_InitStruct.LTDC_VerticalSync = 2;
/* Configure accumulated horizontal back porch */
LTDC_InitStruct.LTDC_AccumulatedHBP = 143;
/* Configure accumulated vertical back porch */
LTDC_InitStruct.LTDC_AccumulatedVBP = 34;
/* Configure accumulated active width */
LTDC_InitStruct.LTDC_AccumulatedActiveW = 783;
/* Configure accumulated active height */
LTDC_InitStruct.LTDC_AccumulatedActiveH = 514;
/* Configure total width */
LTDC_InitStruct.LTDC_TotalWidth = 799;
/* Configure total height */
LTDC_InitStruct.LTDC_TotalHeigh = 524;
LTDC_Init(<DC_InitStruct);
}
/* LCD AMPIRE480272 is used */
else if(CurrentLcd == USE_LCD_AM480272)
{
/* Initialize the LCD pixel width and pixel height */
LCD_PIXEL_WIDTH = 480;
LCD_PIXEL_HEIGHT = 272;
/* Configure PLLSAI prescalers for LCD */
/* Enable Pixel Clock */
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 192 Mhz */
/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAI_R = 192/3 = 64 Mhz */
/* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDivR = 64/8 = 8 Mhz */
RCC_PLLSAIConfig(192, 7, 3);
RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);
/* Enable PLLSAI Clock */
RCC_PLLSAICmd(ENABLE);
/* Wait for PLLSAI activation */
while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET)
{
}
/* Timing configuration */
/* Configure horizontal synchronization width */
LTDC_InitStruct.LTDC_HorizontalSync = 40;
/* Configure vertical synchronization height */
LTDC_InitStruct.LTDC_VerticalSync = 9;
/* Configure accumulated horizontal back porch */
LTDC_InitStruct.LTDC_AccumulatedHBP = 42;
/* Configure accumulated vertical back porch */
LTDC_InitStruct.LTDC_AccumulatedVBP = 11;
/* Configure accumulated active width */
LTDC_InitStruct.LTDC_AccumulatedActiveW = 522;
/* Configure accumulated active height */
LTDC_InitStruct.LTDC_AccumulatedActiveH = 283;
/* Configure total width */
LTDC_InitStruct.LTDC_TotalWidth = 524;
/* Configure total height */
LTDC_InitStruct.LTDC_TotalHeigh = 285;
LTDC_Init(<DC_InitStruct);
}
}
7.DMA2D初始化结构体
这里以使用DMA2D画直线为例,可以在固件库手册里面调用关于LCD_DrawLine()函数,同样固件库里面含有画圆、矩形的函数等等,可以根据需要调用。
/**
* @brief Displays a line.
* @param Xpos: specifies the X position.
* @param Ypos: specifies the Y position.
* @param Length: line length.
* @param Direction: line direction.
* This parameter can be one of the following values: Vertical or Horizontal.
* @retval None
*/
void LCD_DrawLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length, uint8_t Direction)
{
DMA2D_InitTypeDef DMA2D_InitStruct;
uint32_t Xaddress = 0;
uint16_t Red_Value = 0, Green_Value = 0, Blue_Value = 0;
Xaddress = CurrentFrameBuffer + 2*((LCD_PIXEL_WIDTH*Ypos) + Xpos);
Red_Value = (0xF800 & CurrentTextColor) >> 11;
Blue_Value = 0x001F & CurrentTextColor;
Green_Value = (0x07E0 & CurrentTextColor) >> 5;
/* Configure DMA2D */
DMA2D_DeInit();
DMA2D_InitStruct.DMA2D_Mode = DMA2D_R2M;
DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB565;
DMA2D_InitStruct.DMA2D_OutputGreen = Green_Value;
DMA2D_InitStruct.DMA2D_OutputBlue = Blue_Value;
DMA2D_InitStruct.DMA2D_OutputRed = Red_Value;
DMA2D_InitStruct.DMA2D_OutputAlpha = 0x0F;
DMA2D_InitStruct.DMA2D_OutputMemoryAdd = Xaddress;
if(Direction == LCD_DIR_HORIZONTAL)
{
DMA2D_InitStruct.DMA2D_OutputOffset = 0;
DMA2D_InitStruct.DMA2D_NumberOfLine = 1;
DMA2D_InitStruct.DMA2D_PixelPerLine = Length;
}
else
{
DMA2D_InitStruct.DMA2D_OutputOffset = LCD_PIXEL_WIDTH - 1;
DMA2D_InitStruct.DMA2D_NumberOfLine = Length;
DMA2D_InitStruct.DMA2D_PixelPerLine = 1;
}
DMA2D_Init(&DMA2D_InitStruct);
/* Start Transfer */
DMA2D_StartTransfer();
/* Wait for CTC Flag activation */
while(DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET)
{
}
}