一、硬件环境
第一代野火F429开发板,MCU为stm32f429IGT6。板载IS42S16400J SDRAM,16bit位宽 8M容量。
TFT为RG888接口,分辨率为800*480。
二、LTCD初始化
(1)初始化GPIO与SDRAM
(2)初始化相关时钟
//2、LTDC相关时钟初始化
/* 配置 PLLSAI 分频器,它的输出作为像素同步时钟CLK*/
/* PLLSAI_VCO 输入时钟 = HSE_VALUE/PLL_M = 1 Mhz */
/* PLLSAI_VCO 输出时钟 = PLLSAI_VCO输入 * PLLSAI_N = 420 Mhz */
/* PLLLCDCLK = PLLSAI_VCO 输出/PLLSAI_R = 420/6 Mhz */
/* LTDC 时钟频率 = PLLLCDCLK / DIV = 420/6/8 = 8.75 Mhz */
/* LTDC时钟太高会导花屏,若对刷屏速度要求不高,降低时钟频率可减少花屏现象*/
/* 以下函数三个参数分别为:PLLSAIN,PLLSAIQ,PLLSAIR,其中PLLSAIQ与LTDC无关*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_LTDC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE);
RCC_PLLSAIConfig(420, 6, 6);
RCC_LTDCCLKDivConfig(RCC_PLLSAIDivR_Div8);
RCC_PLLSAICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET);
(3)初始化LTDC结构体
//背景色
LTDC_InitStruct.LTDC_BackgroundBlueValue = 0;
LTDC_InitStruct.LTDC_BackgroundGreenValue = 0;
LTDC_InitStruct.LTDC_BackgroundRedValue = 0;
//极性
LTDC_InitStruct.LTDC_DEPolarity = LTDC_DEPolarity_AL;
LTDC_InitStruct.LTDC_HSPolarity = LTDC_HSPolarity_AL;
LTDC_InitStruct.LTDC_PCPolarity = LTDC_PCPolarity_IPC;
LTDC_InitStruct.LTDC_VSPolarity = LTDC_VSPolarity_AL;
//横纵信号宽度
LTDC_InitStruct.LTDC_AccumulatedActiveW = HBP + HSW + LCD_PIXEL_WIDTH - 1;
LTDC_InitStruct.LTDC_AccumulatedActiveH = VBP + VSW + LCD_PIXEL_HEIGHT - 1;
LTDC_InitStruct.LTDC_AccumulatedVBP = VSW + VBP - 1;
LTDC_InitStruct.LTDC_AccumulatedHBP = HSW + HBP - 1;
LTDC_InitStruct.LTDC_VerticalSync = VSW - 1;
LTDC_InitStruct.LTDC_HorizontalSync = HSW - 1;
LTDC_InitStruct.LTDC_TotalHeigh = VBP + VSW + LCD_PIXEL_HEIGHT + VFP -1;
LTDC_InitStruct.LTDC_TotalWidth = HBP + HSW + LCD_PIXEL_WIDTH + HFP -1;
LTDC_Init(<DC_InitStruct);
LTDC_Cmd(ENABLE);
具体的HBP\VBP\HSW\VSW\HFP\VFP等参数,参考液晶的参考手册
(4)初始化层结构体
void LCD_LayerInit(void)
{
//使能2层,刷500次纯色5.5S
//使能1层,刷500次纯色4.3S
LTDC_Layer_InitTypeDef LTDC_Layer_InitStruct;
/* 层窗口配置 */
//起始像素点与结束像素点
LTDC_Layer_InitStruct.LTDC_HorizontalStart = HBP + HSW;
LTDC_Layer_InitStruct.LTDC_HorizontalStop = HSW+HBP+LCD_PIXEL_WIDTH-1;
LTDC_Layer_InitStruct.LTDC_VerticalStart = VBP + VSW;
LTDC_Layer_InitStruct.LTDC_VerticalStop = VSW+VBP+LCD_PIXEL_HEIGHT-1;
/* 像素格式配置*/
LTDC_Layer_InitStruct.LTDC_PixelFormat = LTDC_Pixelformat_RGB888;
LTDC_Layer_InitStruct.LTDC_ConstantAlpha = 255; //透明度
LTDC_Layer_InitStruct.LTDC_DefaultColorBlue = 0xFF;
LTDC_Layer_InitStruct.LTDC_DefaultColorGreen = 0xFF;
LTDC_Layer_InitStruct.LTDC_DefaultColorRed = 0xFF;
LTDC_Layer_InitStruct.LTDC_DefaultColorAlpha = 0xFF;
LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_CA; //背景层恒定Alpha值
LTDC_Layer_InitStruct.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_PAxCA; //第一层使用像素Alpha x
/* 该成员应写入(一行像素数据占用的字节数+3)
Line Lenth = 行有效像素个数 x 每个像素的字节数 + 3
行有效像素个数 = LCD_PIXEL_WIDTH
每个像素的字节数 = 2(RGB565/RGB1555)/ 3 (RGB888)/ 4(ARGB8888)
*/
LTDC_Layer_InitStruct.LTDC_CFBLineLength = ((LCD_PIXEL_WIDTH * 3) + 3);
/* 从某行的起始位置到下一行起始位置处的像素增量
LTDC_Layer_InitStruct.LTDC_CFBPitch = (LCD_PIXEL_WIDTH * 3);
/* 配置有效的行数 */
LTDC_Layer_InitStruct.LTDC_CFBLineNumber = LCD_PIXEL_HEIGHT;
/* 配置本层的显存首地址 */
LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_FRAME_BUFFER;
/* 以上面的配置初始化第 1 层*/
LTDC_LayerInit(LTDC_Layer1, <DC_Layer_InitStruct);
/*配置第 2 层,若没有重写某个成员的值,则该成员使用跟第1层一样的配置 */
/* 配置本层的显存首地址,这里配置它紧挨在第1层的后面*/
LTDC_Layer_InitStruct.LTDC_CFBStartAdress = LCD_FRAME_BUFFER + BUFFER_OFFSET;
/* 配置混合因子,使用像素Alpha参与混合 */
LTDC_Layer_InitStruct.LTDC_BlendingFactor_1 = LTDC_BlendingFactor1_PAxCA; //第一层像素Alpha x
LTDC_Layer_InitStruct.LTDC_BlendingFactor_2 = LTDC_BlendingFactor2_PAxCA; //第二层像素Alpha x
/* 初始化第2层 */
LTDC_LayerInit(LTDC_Layer2, <DC_Layer_InitStruct);
/* 立即重载配置 */
LTDC_ReloadConfig(LTDC_IMReload);
/*使能前景及背景层 */
LTDC_LayerCmd(LTDC_Layer1, ENABLE);
LTDC_LayerCmd(LTDC_Layer2, ENABLE);
/* 立即重载配置 */
LTDC_ReloadConfig(LTDC_IMReload);
/* 设定字体(英文) */
LCD_SetFont(&LCD_DEFAULT_FONT);
}
三、DMA2D的使用
网上很多教程只是简单地用了DMA2D的 R_M功能,其他功能的程序找了半天就找到个M_M模式的,其他都自己摸索。。。
提供如下代码供参考,基于野火的第19章节,LTDC显示程序。至于R_M模式的代码就不提供了。。。
(1)DMA2D M2M模式:
这个模式主要是用来从一个层把数据复制到另外一个层。不能进行颜色格式转换以及颜色混合
下面的程序实现了把数据从LTDC的层1复制到层2,层1为全红色,层2全蓝色。
void DMA2D_M2M_Config(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
DMA2D_InitTypeDef DMA2D_InitStruct;
DMA2D_FG_InitTypeDef DMA2D_FG_InitStruct;
//目标区域为LTDC的第二层,源区域为第一层
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2D, ENABLE);
DMA2D_DeInit();
DMA2D_InitStruct.DMA2D_Mode = DMA2D_M2M;
DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB888;
DMA2D_InitStruct.DMA2D_OutputMemoryAdd = 0xD0000000 + 800*480*3 + 3*(800*Ypos + Xpos);
DMA2D_InitStruct.DMA2D_NumberOfLine = Height;
DMA2D_InitStruct.DMA2D_PixelPerLine = Width;
DMA2D_InitStruct.DMA2D_OutputGreen = 0; //无影响
DMA2D_InitStruct.DMA2D_OutputBlue = 0; //无影响
DMA2D_InitStruct.DMA2D_OutputRed = 0; //无影响
DMA2D_InitStruct.DMA2D_OutputAlpha = 0; //无影响
DMA2D_InitStruct.DMA2D_OutputOffset = (800 - Width);
DMA2D_Init(&DMA2D_InitStruct);
DMA2D_FG_StructInit(&DMA2D_FG_InitStruct);
DMA2D_FG_InitStruct.DMA2D_FGCM = DMA2D_RGB888;
DMA2D_FG_InitStruct.DMA2D_FGMA = 0xD0000000+3*(800*Ypos + Xpos);
DMA2D_FGConfig(&DMA2D_FG_InitStruct);
/* Start Transfer */
DMA2D_StartTransfer();
/* Wait for CTC Flag activation */
while(DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET)
{
}
}
FPC模式与BLEND模式的主函数:
int main(void)
{
u32 i;
/* LED 端口初始化 */
LED_GPIO_Config();
/*初始化液晶屏*/
LCD_Init();
LCD_LayerInit();
LTDC_Cmd(ENABLE);
/*把背景层刷黑色*/
LCD_SetLayer(LCD_BACKGROUND_LAYER);
//LCD_SetTransparency(0xff);
LCD_Clear(LCD_COLOR_RED);
LCD_SetLayer(LCD_FOREGROUND_LAYER);
//LCD_SetTransparency(0xff);
LCD_Clear(LCD_COLOR_BLUE);
LED_RGBOFF;
Delay(0xfff);
for(i=0;i<1168000;i+=2)
{
*(u16*)(0xD0300000+i) = 0xFFE0; //黄色
*(u16*)(0xD0500000+i) = 0x07E0; //绿色
}
DMA2D_M2M_Config(100, 100, 200, 200);
while(1)
{
//LCD_Test();
}
}
(2)FPC模式DMA2D使用:
此模式主要是将图层颜色格式进行转换后,输出到目标地址
此模式是不能进行颜色混合的
void DMA2D_M2M_Config(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
DMA2D_InitTypeDef DMA2D_InitStruct;
DMA2D_FG_InitTypeDef DMA2D_FG_InitStruct;
DMA2D_DeInit();
DMA2D_InitStruct.DMA2D_Mode = DMA2D_M2M_PFC; //此模式可进行格式转换,不能进行颜色混合
DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB888;
DMA2D_InitStruct.DMA2D_OutputMemoryAdd = 0xD0000000 + 3*(800*Ypos + Xpos) + 800*480*3;
DMA2D_InitStruct.DMA2D_NumberOfLine = Height;
DMA2D_InitStruct.DMA2D_PixelPerLine = Width;
DMA2D_InitStruct.DMA2D_OutputAlpha = 0x00; //无影响
DMA2D_InitStruct.DMA2D_OutputGreen = 0;
DMA2D_InitStruct.DMA2D_OutputBlue = 0;
DMA2D_InitStruct.DMA2D_OutputRed = 0;
DMA2D_InitStruct.DMA2D_OutputOffset = (800 - Width);
DMA2D_Init(&DMA2D_InitStruct);
DMA2D_FG_StructInit(&DMA2D_FG_InitStruct); //填充默认值
DMA2D_FG_InitStruct.DMA2D_FGCM = DMA2D_RGB565;
DMA2D_FG_InitStruct.DMA2D_FGMA = 0xD0300000 + 2*(800*Ypos + Xpos);
DMA2D_FG_InitStruct.DMA2D_FGPFC_ALPHA_MODE = COMBINE_ALPHA_VALUE ; //无影响
DMA2D_FG_InitStruct.DMA2D_FGPFC_ALPHA_VALUE = 0x00;
DMA2D_FGConfig(&DMA2D_FG_InitStruct);
/* Start Transfer */
DMA2D_StartTransfer();
/* Wait for CTC Flag activation */
while(DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET)
{
}
}
(3)BLEND模式DMA2D使用:
此模式可以进行颜色格式转换以及颜色混合
颜色混合,指的是将前景与背景的颜色混合后输出到目标区域,所以这里需要初始化前景与背景的结构体
void DMA2D_M2M_Config(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height)
{
DMA2D_InitTypeDef DMA2D_InitStruct;
DMA2D_FG_InitTypeDef DMA2D_FG_InitStruct;
DMA2D_BG_InitTypeDef DMA2D_BG_InitStruct;
DMA2D_DeInit();
DMA2D_InitStruct.DMA2D_Mode = DMA2D_M2M_BLEND;
DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB888;
DMA2D_InitStruct.DMA2D_OutputMemoryAdd = 0xD0000000+ 3*(800*Ypos + Xpos) + BUFFER_OFFSET;
DMA2D_InitStruct.DMA2D_NumberOfLine = Height;
DMA2D_InitStruct.DMA2D_PixelPerLine = Width;
DMA2D_InitStruct.DMA2D_OutputAlpha = 0x00; //在DMA2D_M2M_BLEND下无影响
DMA2D_InitStruct.DMA2D_OutputGreen = 0;
DMA2D_InitStruct.DMA2D_OutputBlue = 0;
DMA2D_InitStruct.DMA2D_OutputRed = 0;
DMA2D_InitStruct.DMA2D_OutputOffset = (800- Width);
DMA2D_Init(&DMA2D_InitStruct);
DMA2D_FG_StructInit(&DMA2D_FG_InitStruct); //填充默认值
DMA2D_FG_InitStruct.DMA2D_FGCM = DMA2D_RGB565;
DMA2D_FG_InitStruct.DMA2D_FGMA = 0xD0300000 + 2*(800*Ypos + Xpos);
DMA2D_FG_InitStruct.DMA2D_FGPFC_ALPHA_MODE = COMBINE_ALPHA_VALUE ;
DMA2D_FG_InitStruct.DMA2D_FGPFC_ALPHA_VALUE = 0x10; //前景层的透明值
DMA2D_FGConfig(&DMA2D_FG_InitStruct);
DMA2D_BG_StructInit(&DMA2D_BG_InitStruct);
DMA2D_BG_InitStruct.DMA2D_BGCM = DMA2D_RGB565;
DMA2D_BG_InitStruct.DMA2D_BGMA = 0xD0500000 + 2*(800*Ypos + Xpos);
DMA2D_BG_InitStruct.DMA2D_BGPFC_ALPHA_MODE = COMBINE_ALPHA_VALUE;
DMA2D_BG_InitStruct.DMA2D_BGPFC_ALPHA_VALUE = 0x80; //背景层的透明值
DMA2D_BGConfig(&DMA2D_BG_InitStruct);
/* Start Transfer */
DMA2D_StartTransfer();
/* Wait for CTC Flag activation */
while(DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET)
{
}
}
实际效果:
(1)M_M
(2)FPC
(3)BLEND
因为前景黄色透明度0x10,背景绿色透明度0x80,所以实际图像绿中带一点黄
NOTE:(1)在进行图层数据的复制时,源区域与目标区域大小一致。
因为前景层与后景层的Height与Width取自DMA2D_InitTypeDef的结构体成员DMA2D_NumberOfLine与
DMA2D_PixelPerLine
(2)前景或者后景层源起始区域是可变的
通过以下结构体成员设置前景层偏移值。
uint32_t DMA2D_FGMA;
背景层偏移值:
uint32_t DMA2D_BGMA;
比如800*480的分辨率下,将RGB565格式坐标为100*100大小为50*50的前景层区域复制到RBG888格式坐标为
30*30大小为50*50的目标区域,前景层DMA2D_FGMA填充值为:前景层起始地址 + 2*(100*100)
目标地址DMA2D_OutputOffset填充:目标地址 + 3*(30*30)
DMA2D_NumberOfLine与DMA2D_PixelPerLine分别填充50的值即可。前景层Height与Width也是取自这两个结构体成员。