【LTDC】LTDC 相关寄存器

前言

此篇文章仅作笔记分享,内容来源为:

【正点原子】全是干货 | 手把手教你学STM32的LTDC

这篇文章就是为了了解 LTDC 其中的寄存器,以至于移植什么的更加清晰明了。

注意事项

  1. RGBLCD 其实也是 TFTLCD,只是接口不同。
  2. 控制 B7、G7、R7 引脚可以分辨 LCD 的模块 ID,例如:100 为 4.3 寸,800 * 480 分辨率 LCD。
  3. LTDC 是 STM32H7 的 TFTLCD 控制器。
  4. LTDC 控制器主要包含:信号线、图像处理单元、 AHB接口、配置和状态寄存器以及时钟部分,其框图如图。
  5. LTDC 有 24 位并行像素输出,每个像素8位数据(RGB888),但是为了节省 IO,提高速度,一般只用 RGB565,只需要16个 IO 口。
    即:LCD_R[7:3]、LCD_G[7:2]、LCD_B[7:3]。
  6. 一个像素需要2个字节的内存,一般的 16 位 RGB565 模式,800 * 480 的屏幕,则需要 800 * 480 * 2 = 768 KB,故要使用到外部SDRAM,
    而 SDRAM 是挂载在 AHB 总线上的,LTDC 的AHB 总线的功能就是将显存数据从 SDRAM 存储器传输到 FIFO 中。
  7. 对于 LTDC 控制器来说,屏幕的显示区域被称作为有效显示范围,即分辨率。其中一些无效显示范围包括以下部分:image-20251017151004943

寄存器

全局控制寄存器 LTDC_GCR (极性控制)

image-20251017151652439

  1. LTDCEN TFT LCD: 控制器使能位,也就是 LTDC 的开关,该位需要设置为 1。
  2. PCPOL: 像素时钟极性。控制像素时钟的极性,根据 LCD 面板的特性来设置,我们所用的 LCD 一般设置为 0 即可,表示低电平有效。
  3. DEPOL: 数据使能极性。控制 DE 信号的极性,根据 LCD 面板的特性来设置,我们所用的 LCD 一般设置为 0 即可,表示低电平有效。
  4. VSPOL: 垂直同步极性。控制 VSYNC 信号的极性,根据 LCD 面板的特性来设置,我们所用的 LCD 一般设置为 0 即可,表示低电平有效。
  5. HSPOL: 水平同步极性。控制 HSYNC 信号的极性,根据 LCD 面板的特性来设置,我们所用的 LCD 一般设置为 0 即可,表示低电平有效。

同步大小配置寄存器 LTDC_SSCR

image-20251017151926540

  1. VSH: 表示垂直同步高度(以水平扫描行为单位),表示垂直同步脉宽减 1 ,即 VSW-1。
  2. HSW: 表示水平同步宽度(以像素时钟为单位),表示 水平同步脉宽减 1,即 HSW-1。

后沿配置寄存器 LTDC_BPCR

image-20251017152019389

  1. AVBP: 加垂直后沿(以水平扫描行为单位),表示: VSW+VBP-1。
  2. AHBP:累加水平后沿(以像素时钟为单位),表示 HSW+HBP-1,下同。

有效宽度配置寄存器 LTDC_AWCR

image-20251017152128512

  1. AAH: 累加有效高度(以水平扫描行为单位),表示: VSW+VBP+有效高度 -1。

  2. AAW: 累加有效宽度(以像素时钟为单位),表示: HSW+HBP+有效宽度 -1。

    这里所说的有效高度和有效宽度,是指LCD 面板的宽度和高度(构成分辨率,下同)


总宽度配置寄存器 LTDC_TWCR

image-20251017152211018

  1. TOTALH: 总高度(以水平扫描行为单位),表示: VSW+VBP+有效高度 +VFP-1。
  2. TOTALW: 总宽度(以像素时钟为单位),表示: HSW+HBP+有效宽度 +HFP-1。

背景色配置寄存器 LTDC_BCC

image-20251017152303512

该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。


层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2)

image-20251017152351732

该寄存器用来定义一层显存的起始地址。STM32H743的 LTDC支持 2个层,所以总共两个寄存器,分别设置层 1和层 2的显存起始地址。


层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)

image-20251017152434844

该寄存器只有最低 3位有效,用于设置层颜色的像素格式:
000: ARGB8888
001: RGB888
010: RGB565
011: ARGB1555
100: ARGB4444
101: L8(8位 Luminance)
110: AL44(4位 Alpha 4位 Luminance)
111: AL88 (8位 Alpha 8位 Luminance)

我们一般使用 RGB565 格式,即该寄存器设置为: 010 即可。


层恒定 Alpha配置寄存器 LTDC_LxCACR(x=1/2)

image-20251017152827876

该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255分频。关于这个恒定 Alpha 的使用,我们将在介绍 LTDC_LxBFCR 寄存器的时候进行讲解。


层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)

image-20251017152930685

该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0即可。


层混合系数配置寄存器 LTDC_LxBFCR(x=1/2)

image-20251017153024076

该寄存器用于定义混合系数:BF1BF2

BF1 = 100: 使用恒定 Alpha混合系数(由 LTDC_LxCACR寄存器设置恒定 Alpha 值)
BF1 = 110: 使用像素 Alpha * 恒定 Alpha。像素 Alpha即 ARGB格式像素的 A值( Alpha值),仅限ARGB颜色格式时使用。
颜色格式时使用。在 RGB565格式下,我们设置 BF1 = 100 即可。

BF2 同 BF1类似。

BF2 = 101: 使用恒定 Alpha混合系数。
BF2 = 111: 使用像素 Alpha*恒定 Alpha。
在 RGB565格式下,我们设置 BF2 = 101 即可。

公式

通用的混合公式为:BC = BF1 * C + BF2 * Cs
BC: 混合后的颜色
BF1: 混合系数 1
C: 当前层颜色,即我们写入层显存的颜色值
BF2: 混合系数 2
Cs: 底层混合后的颜色,对于层 1 来说, Cs=背景层的颜色,对于层 2 来说, Cs=背景层和层 1 混合后的颜色。

举例

假设 Alpha 的值由 LTDC_LxCACR 寄存器设置,恒定 ALpha = LTDC_LxCACR 设置值 / 255。假设 LTDC_LxCACR 设置值= 240;C = 128;Cs = 48;那么计算得 恒定 Alpha = LTDC_LxCACR 设置值 / 255 = 0.94。通过以上混合公式:BC = BF1 * C + BF2 * Cs 计算得,BC = 122

注意

  1. BF1 和 BF2 的恒定 Alpha 值互补,他们之和为 1。
  2. 且 BF1 使用的是恒定 Alpha 值, BF2 使用的是互补值。
  3. 一般情况下,我们设置 LTDC_LxCACR 的值为 255,这样,在使用恒定 Alpha 值的时候,BF1 = 1、BF2 = 0,这样就可以得到 BC=C,即混合后的颜色,就是显存里面的颜色(不进行混色)。

层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)

image-20251017154816270

该寄存器定义第 1 层或第 2 层窗口的水平位置(第一个和最后一个像素),其中:

  1. WHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素。
  2. WHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素。

层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)

image-20251017155142166

该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行),其中:

  1. WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行,见图 27.1.2.15。
  2. WVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行,见图 27.1.2.15。

LTDC 的层支持窗口设置功能,通过 LTDC_LxWHPCR 和 LTDC_LxWVPCR 这上面两个寄存器设置,可以调整显示区域的大小,如图:

image-20251017155401514


层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)

image-20251017155629910

该寄存器定义颜色帧缓冲区的行长和行间距。其中:

  1. CFBLL:这些位定义一行像素的长度(以字节为单位) +3。行长的计算方法为:有效宽度 每像素的字节数 +3。比如, LCD 面板的分辨率为 800480 有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为: 8002+3=1603。
  2. CFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。这个设置,其实同样是一行像素的长度,对于 800480的 LCD 面板, RGB565 格式,设置 CFBP 为: 8002=1600 即可。

层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)

image-20251017155751101

该寄存器定义颜色帧缓冲区中的行数。

CFBLNBR: 用于定义帧缓冲区行数,比如, LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可。

时钟域

LTDC 有三个时钟域: AXI 时钟域( ltdc_aclk)APB3 时钟域( ltdc_plck)像素时钟域( ltdc_ker_ck)

AXI 时钟域( ltdc_aclk):用于驱动接口读取寄存器的数据到FIFO中。

APB3 时钟域( ltdc_plck):配置寄存器。

像素时钟域( ltdc_ker_ck):生成LCD接口信号( LCD_HSYNC、 LCD_VSYNC和 LCD_CLK等),这些时钟信号需根据 LCD面板的要求进行配置。


LCD_CLK配置过程

LCD_CLK的时钟 源来自 ltdc_ker_ck 而 ltdc_ker_ck 则来自 PLL3的 R分频。下图则是配置过程:

image-20251017160229503

由图可知,ltdc_ker_ck 的来源 为 clk_in 一般 为外部晶振(假定外部晶振作为系统时钟源),经过 DIVM3分频器分频, 输入锁相环进行倍频( DIVN3)和分频 DIVR3),输出 pll3_r_ck 然后通过 PKSU和 PKEU得到 ltdc_ker_ck,最终输出到 LTDC,产生 LCD_CK,驱动液晶面板。

配置 LTDC

点击查看代码
/* LTDC 配置 */

#define LTDC_PIXFORMAT           LTDC_PIXEL_FORMAT_RGB565

/**
 * @brief       LTDC初始化函数
 * @param       无
 * @retval      无
 */
void ltdc_init(void)
{
    uint16_t 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(300, 25, 33);              /* 设置像素时钟 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(300, 25, 9);               /* 设置像素时钟 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(300, 25, 6);               /* 设置像素时钟  40Mhz 6 */
        /* 其他参数待定.*/
    }
    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(300, 25, 9);               /* 设置像素时钟 33M */
        /* 其他参数待定. */
    }
    else if (lcdid == 0X1018)
    {
        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(300, 25, 6);               /* 设置像素时钟  45Mhz */
    } 

    lcddev.width = lcdltdc.pwidth;
    lcddev.height = lcdltdc.pheight;
    
#if LTDC_PIXFORMAT == LTDC_PIXFORMAT_ARGB8888 || LTDC_PIXFORMAT == LTDC_PIXFORMAT_RGB888 
    g_ltdc_framebuf[0] = (uint32_t*) &ltdc_lcd_framebuf;
    lcdltdc.pixsize = 4;                        /* 每个像素占4个字节 */
#else 
    lcdltdc.pixsize = 2;                        /* 每个像素占2个字节 */
    g_ltdc_framebuf[0] = (uint32_t*)&ltdc_lcd_framebuf;
//    g_ltdc_framebuf[1] = (uint32_t*)&ltdc_lcd_framebuf1;
#endif 
    /* LTDC配置 */
    g_ltdc_handle.Instance = LTDC;
    g_ltdc_handle.Init.HSPolarity = LTDC_HSPOLARITY_AL;         /* 水平同步极性 */
    g_ltdc_handle.Init.VSPolarity = LTDC_VSPOLARITY_AL;         /* 垂直同步极性 */
    g_ltdc_handle.Init.DEPolarity = LTDC_DEPOLARITY_AL;         /* 数据使能极性 */
    g_ltdc_handle.State = HAL_LTDC_STATE_RESET;
    
    if (lcdid == 0X1018)
    {
        g_ltdc_handle.Init.PCPolarity = LTDC_PCPOLARITY_IIPC;   /* 像素时钟极性 */
    }
    else 
    {
        g_ltdc_handle.Init.PCPolarity = LTDC_PCPOLARITY_IPC;    /* 像素时钟极性 */
    }

    g_ltdc_handle.Init.HorizontalSync = lcdltdc.hsw - 1;                                            /* 水平同步宽度 */
    g_ltdc_handle.Init.VerticalSync = lcdltdc.vsw - 1;                                              /* 垂直同步宽度 */
    g_ltdc_handle.Init.AccumulatedHBP = lcdltdc.hsw + lcdltdc.hbp - 1;                              /* 水平同步后沿宽度 */
    g_ltdc_handle.Init.AccumulatedVBP = lcdltdc.vsw + lcdltdc.vbp - 1;                              /* 垂直同步后沿高度 */
    g_ltdc_handle.Init.AccumulatedActiveW = lcdltdc.hsw + lcdltdc.hbp + lcdltdc.pwidth - 1;         /* 有效宽度 */
    g_ltdc_handle.Init.AccumulatedActiveH = lcdltdc.vsw + lcdltdc.vbp + lcdltdc.pheight - 1;        /* 有效高度 */
    g_ltdc_handle.Init.TotalWidth = lcdltdc.hsw + lcdltdc.hbp + lcdltdc.pwidth + lcdltdc.hfp - 1;   /* 总宽度 */
    g_ltdc_handle.Init.TotalHeigh = lcdltdc.vsw + lcdltdc.vbp + lcdltdc.pheight + lcdltdc.vfp - 1;  /* 总高度 */
    g_ltdc_handle.Init.Backcolor.Red = 0;                                                           /* 屏幕背景层红色部分 */
    g_ltdc_handle.Init.Backcolor.Green = 0;                                                         /* 屏幕背景层绿色部分 */
    g_ltdc_handle.Init.Backcolor.Blue = 0;                                                          /* 屏幕背景色蓝色部分 */
    HAL_LTDC_Init(&g_ltdc_handle);

/* 层配置:LTDC(LCD-TFT显示控制器)支持多层显示,通过配置不同层实现图像叠加等效果 */

/* 
 * 配置LTDC第0层的参数
 * 参数说明:
 *   第一个参数:0          - 层索引,指定配置第0层(LTDC通常支持多层,此处配置第1层)
 *   第二个参数:(uint32_t)g_ltdc_framebuf[0] - 该层的帧缓冲区地址,g_ltdc_framebuf[0]为存储第0层图像数据的数组
 *   第三个参数:LTDC_PIXFORMAT              - 像素格式(如RGB565、ARGB8888等,由宏定义具体指定)
 *   第四个参数:255                         - 图层透明度(0-255,255表示完全不透明,0表示完全透明)
 *   第五个参数:0                           - 混合因子(通常用于图层叠加计算,0表示不使用特殊混合规则)
 *   第六个参数:6                            - 水平同步后沿(HSYNC之后的无效像素数,根据LCD时序特性配置)
 *   第七个参数:7                            - 垂直同步后沿(VSYNC之后的无效行数,根据LCD时序特性配置)
 *   第八个参数:0X000000                     - 背景色(当图层无有效数据时显示的颜色,此处为黑色)
 */
ltdc_layer_parameter_config(0, (uint32_t)g_ltdc_framebuf[0], LTDC_PIXFORMAT, 255, 0, 6, 7, 0X000000);   /* 层参数配置 */

/* 
 * 配置LTDC第0层的显示窗口
 * 参数说明:
 *   第一个参数:0                  - 层索引,指定配置第0层
 *   第二个参数:0                  - 窗口左上角X坐标(以LCD面板坐标系为原点,横向起始位置)
 *   第三个参数:0                  - 窗口左上角Y坐标(以LCD面板坐标系为原点,纵向起始位置)
 *   第四个参数:lcdltdc.pwidth     - 窗口宽度(等于LCD面板的实际宽度,确保全屏显示)
 *   第五个参数:lcdltdc.pheight    - 窗口高度(等于LCD面板的实际高度,确保全屏显示)
 * 注意:窗口坐标以LCD面板原生坐标系为基准,直接影响图像在屏幕上的显示位置,非特殊需求请勿修改
 */
ltdc_layer_window_config(0, 0, 0, lcdltdc.pwidth, lcdltdc.pheight);                                     /* 层窗口配置,以LCD面板坐标系为基准,不要随便修改! */

/* 
 * 以下为第1层的配置示例(当前被注释禁用)
 * 第1层可用于叠加在第0层上方显示额外内容(如UI控件、状态信息等)
 */
// /* 
//  * 配置LTDC第1层的参数
//  * 与第0层相比,主要差异在于透明度设为127(半透明),帧缓冲区使用g_ltdc_framebuf[1]
//  */
// ltdc_layer_parameter_config(1,(uint32_t)g_ltdc_framebuf[1],LTDC_PIXFORMAT,127,0,6,7,0X000000);        /* 层参数配置 */
// 
// /* 
//  * 配置LTDC第1层的显示窗口
//  * 窗口大小与第0层一致,默认全屏叠加(可根据需求修改为局部区域显示)
//  */
// ltdc_layer_window_config(1,0,0,lcdltdc.pwidth,lcdltdc.pheight);                                       /* 层窗口配置,以LCD面板坐标系为基准,不要随便修改! */

//    ltdc_display_dir(0);                 /* 默认竖屏 */
    ltdc_select_layer(0);                  /* 选择第1层 */
    LTDC_BL(1);                            /* 点亮背光 */
    ltdc_clear(0XFFFFFFFF);                /* 清屏 */
}

/**
 * @brief       LTDC层基本参数设置
 * @note        此函数,必须在ltdc_layer_window_config之前设置.
 * @param       layerx      : 0,第一层; 1,第二层;
 * @param       bufaddr     : 层颜色帧缓存起始地址
 * @param       pixformat   : 颜色格式. 0,ARGB8888; 1,RGB888; 2,RGB565; 3,ARGB1555; 4,ARGB4444; 5,L8; 6;AL44; 7;AL88
 * @param       alpha       : 层颜色Alpha值, 0,全透明;255,不透明
 * @param       alpha0      : 默认颜色Alpha值, 0,全透明;255,不透明
 * @param       bfac1       : 混合系数1, 4(100),恒定的Alpha; 6(101),像素Alpha*恒定Alpha
 * @param       bfac2       : 混合系数2, 5(101),恒定的Alpha; 7(111),像素Alpha*恒定Alpha
 * @param       bkcolor     : 层默认颜色,32位,低24位有效,RGB888格式
 * @retval      无
 */
void ltdc_layer_parameter_config(uint8_t layerx, uint32_t bufaddr, uint8_t pixformat, uint8_t alpha, uint8_t alpha0, uint8_t bfac1, uint8_t bfac2, uint32_t 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 = (uint32_t)bfac1 << 8;                  /* 设置层混合系数 */
    playercfg.BlendingFactor2 = (uint32_t)bfac2;                       /* 设置层混合系数 */
    playercfg.FBStartAdress = bufaddr;                                 /* 设置层颜色帧缓存起始地址 */
    playercfg.ImageWidth = lcdltdc.pwidth;                             /* 设置颜色帧缓冲区的宽度 */
    playercfg.ImageHeight = lcdltdc.pheight;                           /* 设置颜色帧缓冲区的高度 */
    playercfg.Backcolor.Red = (uint8_t)(bkcolor & 0X00FF0000) >> 16;   /* 背景颜色红色部分 */
    playercfg.Backcolor.Green = (uint8_t)(bkcolor & 0X0000FF00) >> 8;  /* 背景颜色绿色部分 */
    playercfg.Backcolor.Blue = (uint8_t)bkcolor & 0X000000FF;          /* 背景颜色蓝色部分 */
    HAL_LTDC_ConfigLayer(&g_ltdc_handle, &playercfg, layerx);          /* 设置所选中的层 */
}  

/**
 * @brief       LTDC层窗口设置, 窗口以LCD面板坐标系为基准
 * @note        此函数必须在ltdc_layer_parameter_config之后再设置.另外,当设置的窗口值不等于面板的尺
 *              寸时,GRAM的操作(读/写点函数),也要根据窗口的宽高来进行修改,否则显示不正常(本例程就未做修改).
 * @param       layerx      : 0,第一层; 1,第二层;
 * @param       sx, sy      : 起始坐标
 * @param       width,height: 宽度和高度
 * @retval      无
 */
void ltdc_layer_window_config(uint8_t layerx, uint16_t sx, uint16_t sy, uint16_t width, uint16_t height)
{
    HAL_LTDC_SetWindowPosition(&g_ltdc_handle, sx, sy, layerx);     /* 设置窗口的位置 */
    HAL_LTDC_SetWindowSize(&g_ltdc_handle, width, height, layerx);  /* 设置窗口大小 */
}

/**
 * @brief       LTDC底层IO初始化和时钟使能
 * @note        此函数会被HAL_LTDC_Init()调用
 * @param       hltdc:LTDC句柄
 * @retval      无
 */
void HAL_LTDC_MspInit(LTDC_HandleTypeDef *hltdc)
{
    GPIO_InitTypeDef gpio_init_struct;

    __HAL_RCC_LTDC_CLK_ENABLE();                      /* 使能LTDC时钟 */
    __HAL_RCC_DMA2D_CLK_ENABLE();                     /* 使能DMA2D时钟 */

    /* 以下是LTDC信号控制引脚 BL/DE/VSYNC/HSYNC/CLK等的配置 */
    LTDC_BL_GPIO_CLK_ENABLE();                        /* LTDC_BL脚时钟使能 */
    LTDC_DE_GPIO_CLK_ENABLE();                        /* LTDC_DE脚时钟使能 */
    LTDC_VSYNC_GPIO_CLK_ENABLE();                     /* LTDC_VSYNC脚时钟使能 */
    LTDC_HSYNC_GPIO_CLK_ENABLE();                     /* LTDC_HSYNC脚时钟使能 */
    LTDC_CLK_GPIO_CLK_ENABLE();                       /* LTDC_CLK脚时钟使能 */
    __HAL_RCC_GPIOH_CLK_ENABLE();                     /* GPIOH时钟使能 */
    
    /* 初始化PB5,背光引脚 */
    gpio_init_struct.Pin = LTDC_BL_GPIO_PIN;          /* LTDC_BL引脚模式设置 */
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;      /* 推挽输出 */
    gpio_init_struct.Pull = GPIO_PULLUP;              /* 上拉 */
    gpio_init_struct.Speed = GPIO_SPEED_HIGH;         /* 高速 */
    HAL_GPIO_Init(LTDC_BL_GPIO_PORT, &gpio_init_struct);
    
    gpio_init_struct.Pin = LTDC_DE_GPIO_PIN;          /* LTDC_DE引脚模式设置 */
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;          /* 复用 */
    gpio_init_struct.Pull = GPIO_NOPULL;
    gpio_init_struct.Speed = GPIO_SPEED_HIGH;
    gpio_init_struct.Alternate = GPIO_AF14_LTDC;      /* 复用为LTDC */
    HAL_GPIO_Init(LTDC_DE_GPIO_PORT, &gpio_init_struct);
    
    gpio_init_struct.Pin = LTDC_VSYNC_GPIO_PIN;       /* LTDC_VSYNC引脚模式设置 */
    HAL_GPIO_Init(LTDC_VSYNC_GPIO_PORT, &gpio_init_struct);
    
    gpio_init_struct.Pin = LTDC_HSYNC_GPIO_PIN;       /* LTDC_HSYNC引脚模式设置 */
    HAL_GPIO_Init(LTDC_HSYNC_GPIO_PORT, &gpio_init_struct);
    
    gpio_init_struct.Pin = LTDC_CLK_GPIO_PIN;         /* LTDC_CLK引脚模式设置 */
    HAL_GPIO_Init(LTDC_CLK_GPIO_PORT, &gpio_init_struct);

    /* 初始化PG6,11 */
    gpio_init_struct.Pin = GPIO_PIN_6 | GPIO_PIN_11;
    HAL_GPIO_Init(GPIOG, &gpio_init_struct);
    
    /* 初始化PH9,10,11,12,13,14,15 */
    gpio_init_struct.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_init_struct);
    
    /* 初始化PI0,1,2,4,5,6,7 */
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5| \
                     GPIO_PIN_6 | GPIO_PIN_7;
    HAL_GPIO_Init(GPIOI, &gpio_init_struct); 
}

通过以上几个步骤,我们就完成了 LTDC 的配置,可以控制 RGBLCD 显示了。

博客导航

博客导航

posted @ 2025-10-24 15:40  膝盖中箭卫兵  阅读(7)  评论(0)    收藏  举报
ORCID iD icon https://orcid.org/0000-0001-5102-772X