本文主要是介绍手写GD32F450/F470 TLI-LCD接口驱动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
TLI-LCD接口开发(使用GD32F450/F470芯片开发)
简介
TLI(TFT-LCD接口)连接同步的LCD接口,并且为无源LCD显示屏提供像素数据,时钟以及时序
信号。它支持不同的完全可编程的时序参数显示。一个内嵌的DMA不断的从系统存储器搬移数
据到TLI然后输出到外部的LCD显示。TLI支持两个独立的显示层,并支持层窗口和层混叠功能。
-
主要特点
每像素最多24位并行数据输出;
支持高达2048*2048的分辨率;
完全可编程的时序参数;
内嵌DMA处理像素数据拷贝;
带有窗口和混合功能的两个独立的层;
支持多种像素格式:ARGB8888,RGB888,RGB565等;
支持CLUT(颜色查找表)和色键格式;
像素低位的抖动操作。 -
结构框图
在TLI模块有3个时钟域。寄存器工作在APB
时钟域,通过APB总线访问。像素DMA模块工作在AHB时钟域,从系统存储器获取像素数据需
要使用AHB总线。剩下的模块工作在TLI时钟域。TLI时钟由PLLSAI-R 分频而得到。PLLSAI参
数和分频因子在RCU模块配置。
- 时钟配置如下图:
使用到的寄存器如下:
简单介绍就到这里,需要详细了解请阅读官方文档。接下来,展示代码。
TIL驱动代码
- GD32的TIL有两个图层,这里只使用图层0,使用两个图层需要很大的显存。最好外扩RAM作为TLI的显存。
- TLI.h
/*
* TLI.h
* dasen, 2023/5/30
*/#ifndef _DS_TLI_H
#define _DS_TLI_H#include "gd32f4xx.h"#define HORIZONTAL_SYNCHRONOUS_PULSE 10
#define HORIZONTAL_BACK_PORCH 150
#define ACTIVE_WIDTH 480
#define HORIZONTAL_FRONT_PORCH 40#define VERTICAL_SYNCHRONOUS_PULSE 10
#define VERTICAL_BACK_PORCH 140
#define ACTIVE_HEIGHT 800
#define VERTICAL_FRONT_PORCH 15extern uint16_t *ltdc_framebuf[2];
//extern __IO uint16_t ltdc_lcd_framebuf0[800][480];
//extern __IO uint16_t ltdc_lcd_framebuf1[800][480]; extern __IO uint16_t ltdc_lcd_framebuf0[800*480]; void _TLI_gpio_init(void);
void _TLI_init(void); #endif
- TLI.c
/*
* TLI.c
* dasen, 2023/5/30
*/#include "TLI.h"
#include "sdram.h"uint16_t *ltdc_framebuf[2]; __IO uint16_t ltdc_lcd_framebuf0[800*480] __attribute__((at(SDRAM_DEVICE0_ADDR)));//图层0显存
//__IO uint16_t ltdc_lcd_framebuf1[800][480] __attribute__((at(SDRAM_DEVICE0_ADDR + 800 * 480 * 2))); //图层1显存 ---> 图层1不使用//TIL GPIO口配置函数
void _TLI_gpio_init(void)
{/* enable the periphral clock */rcu_periph_clock_enable(RCU_GPIOA);rcu_periph_clock_enable(RCU_GPIOB);rcu_periph_clock_enable(RCU_GPIOC);rcu_periph_clock_enable(RCU_GPIOD);rcu_periph_clock_enable(RCU_GPIOF);rcu_periph_clock_enable(RCU_GPIOG);/* TLI pins AF configure */gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);gpio_af_set(GPIOB, GPIO_AF_9, GPIO_PIN_0); // PB0gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_6 | GPIO_PIN_7);gpio_af_set(GPIOD, GPIO_AF_14, GPIO_PIN_3);gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_11);gpio_af_set(GPIOG, GPIO_AF_9, GPIO_PIN_10 | GPIO_PIN_12);/* configure TLI GPIO */gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_11 | GPIO_PIN_12);gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_0 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11);gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7);gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_6 | GPIO_PIN_7);gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_10);gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
} void _TLI_init(void)
{uint32_t temp;//rcu_periph_clock_enable(RCU_TLI);RCU_APB2EN |=(1<<26);//TLI 时钟使能_TLI_gpio_init();/*TLI 时钟配置*****************************************************///f=1M, CK_TLI=f*N/(DIV*R)=192*1MHZ/(3*2)=32MHZtemp=0;temp |=(3<<28);//R=3temp |=(0<<16);//P=2temp |=(192<<6);//N=192RCU_PLLSAI=temp;temp=RCU_CFG1;temp &=~(3<<16);temp |=(0<<16);//DIV=2RCU_CFG1=temp;RCU_CTL |=(1<<28);//PLLSAI使能while((RCU_CTL&(1<<29))==0);//等待PLLSAISTB=1,即PLLSAI稳定。if((RCU_CTL&(1<<29))==0)return;
/******************************************************************//*TLI_SPSZ同步脉冲宽度寄存器************************************************/temp=0;temp |=((HORIZONTAL_SYNCHRONOUS_PULSE-1)<<16);//HPSZ水平同步脉冲宽度temp |=((VERTICAL_SYNCHRONOUS_PULSE-1)<<0);//VPSZ垂直同步脉冲宽度TLI_SPSZ=temp;
/***************************************************************************//*TLI_BPSZ后沿宽度寄存器************************************************/temp=0;temp |=((HORIZONTAL_SYNCHRONOUS_PULSE+HORIZONTAL_BACK_PORCH-1)<<16);//HBPSZ水平后沿加同步脉冲的宽度temp |=((VERTICAL_SYNCHRONOUS_PULSE+VERTICAL_BACK_PORCH-1)<<0);//VBPSZ垂直后沿加同步脉冲的宽度TLI_BPSZ = temp;
/***************************************************************************//*TLI_ASZ有效宽度寄存器************************************************/temp=0;temp |=((HORIZONTAL_SYNCHRONOUS_PULSE+ACTIVE_WIDTH+HORIZONTAL_BACK_PORCH-1)<<16);//HASZtemp |=((VERTICAL_SYNCHRONOUS_PULSE+ACTIVE_HEIGHT+VERTICAL_BACK_PORCH-1)<<0);//VASZTLI_ASZ=temp;
/***************************************************************************//*TLI_TSZ总宽度寄存器************************************************/temp=0;temp |=((HORIZONTAL_SYNCHRONOUS_PULSE+ACTIVE_WIDTH+HORIZONTAL_BACK_PORCH+HORIZONTAL_FRONT_PORCH-1)<<16);//HTSZtemp |=((VERTICAL_SYNCHRONOUS_PULSE+ACTIVE_HEIGHT+VERTICAL_BACK_PORCH+VERTICAL_FRONT_PORCH-1)<<0);//VTSZTLI_TSZ=temp;
/***************************************************************************//*TLI_CTL控制寄存器************************************************/temp=TLI_CTL;temp &=~(1<<31);//HPPS水平脉冲极性选择: 0:水平同步脉冲低电平有效; 1:水平同步脉冲高电平有效temp &=~(1<<30);//VPPS垂直脉冲极性选择: 0:垂直同步脉冲低电平有效; 1:垂直同步脉冲高电平有效temp &=~(1<<29);//DEPS数据使能极性选择: 0:数据使能低电平有效; 1:数据使能高电平有效temp |=(1<<28);//CLKPS像素时钟极性选择: 0:像素时钟是TLI时钟; 1:像素时钟是TLI时钟翻转temp |=(1<<16);//DFEN抖动功能使能位;0-禁用;1-使能//temp |=(1<<0);//TLI使能位;0-禁止;1-使能TLI_CTL = temp;
/***************************************************************************//*TLI_BGC背景配置寄存器************************************************/temp=0;temp |=(0XFF<<16);//BVR-redtemp |=(0XFF<<8);//BVG-greentemp |=(0XFF<<0);//BVB-blueTLI_BGC =temp;
/***************************************************************************//*layer 0 配置************************************************///TLI_LxHPOS第x层水平位置参数寄存器配置/temp =0;temp |=((ACTIVE_WIDTH+HORIZONTAL_SYNCHRONOUS_PULSE+HORIZONTAL_BACK_PORCH-1)<<16);//WRP窗口右侧位置temp |=((HORIZONTAL_SYNCHRONOUS_PULSE+HORIZONTAL_BACK_PORCH)<<0);//WLP窗口左侧位置TLI_LxHPOS(LAYER0)=temp;////TLI_LxVPOS第x层垂直位置参数寄存器配置/temp =0;temp |=((ACTIVE_HEIGHT+VERTICAL_SYNCHRONOUS_PULSE+VERTICAL_BACK_PORCH-1)<<16);//WBP窗口底部位置temp |=((VERTICAL_SYNCHRONOUS_PULSE+VERTICAL_BACK_PORCH)<<0);//WTP窗口顶部位置TLI_LxVPOS(LAYER0)=temp;////TLI_LxPPF第x层像素格式寄存器配置/temp =0;temp |=(2<<0);//像素格式//这些位配置像素格式//000:ARGB8888//001:RGB888//010:RGB565//011:ARGB1555//100:ARGB4444//101:L8//110:AL44//111:AL88TLI_LxPPF(LAYER0)=temp;////TLI_LxSA第x层恒定alpha寄存器配置/temp =0;temp |=(0XFF<<0);//恒定Alpha, 可用于计算混合因子。TLI_LxSA(LAYER0)=temp;////TLI_LxDC第x层默认颜色寄存器配置/temp =0;temp |=(0<<24);//DCA默认颜色Alphatemp |=(0XFF<<16);//DCR默认颜色redtemp |=(0XFF<<8);//DCG默认颜色greentemp |=(0XFF<<0);//DCB默认颜色blueTLI_LxDC(LAYER0)=temp;////TLI_LxBLEND第x层混合寄存器配置/temp =0;temp |=LAYER_ACF1_SA;//ACM1: Alpha混合因子1计算方法//000:保留//001:保留//010:保留//011:保留//100:归一化的恒定Alpha//101:保留//110:归一化的像素Alpha乘以归一化的恒定Alpha//111:保留temp |=LAYER_ACF2_SA;//ACM2:Alpha混合因子2计算方法//000:保留//001:保留//010:保留//011:保留//100:保留//101:1-归一化的恒定Alpha//110:保留//111:1-归一化的像素Alpha乘以归一化的恒定AlphaTLI_LxBLEND(LAYER0)=temp;////TLI_LxFBADDR第x层帧基地址寄存器配置/ltdc_framebuf[0] = (uint16_t *)<dc_lcd_framebuf0;TLI_LxFBADDR(LAYER0)=(uint32_t)ltdc_framebuf[0];////TLI_LxFLLEN第x层长度寄存器配置/temp=0;temp |=((ACTIVE_WIDTH * 2)<<16);//步幅偏移: 这个值定义了从某行起始处到下一行起始处之间的字节数temp |=((ACTIVE_WIDTH * 2 +3)<<0);//行长度: 这个值为一行的字节数+3TLI_LxFLLEN(LAYER0)=temp;////TLI_LxFTLN第x层总行数寄存器配置/temp=0;temp |=(ACTIVE_HEIGHT <<0);//总行数: 这个值定义了一帧行数TLI_LxFTLN(LAYER0)=temp;////TLI_LxCTL第x层控制寄存器配置/temp=0;temp |=(0<<4);//LUTEN- 0:禁用LUT;1-使能LUTtemp |=(0<<1);//CKEYEN色键使能:0-禁用;1-使能temp |=(1<<0);//LEN层使能:0-禁止;1-使能TLI_LxCTL(LAYER0)=temp;//使能layer 0///***************************************************************************//*TLI_RL重载层配置寄存器************************************************/
//此寄存器配置需在layer层配置后面temp=0;temp |=(0<<1);//FBR帧消隐重载请求:0:禁止重载; 1:层配置将在帧消隐时被重载进入真正寄存器。temp |=(1<<0);//RQR立即重载请求:0:禁止重载; 1:层配置将在该位置位之后被重载进入真正寄存器。TLI_RL =temp;
/***************************************************************************////*layer 1 配置************************************************/
// //TLI_LxHPOS第x层水平位置参数寄存器配置/
// temp =0;
// temp |=((ACTIVE_WIDTH+HORIZONTAL_SYNCHRONOUS_PULSE+HORIZONTAL_BACK_PORCH-1)<<16);//WRP窗口右侧位置
// temp |=((HORIZONTAL_SYNCHRONOUS_PULSE+HORIZONTAL_BACK_PORCH)<<0);//WLP窗口左侧位置
// TLI_LxHPOS(LAYER1)=temp;
// //
//
// //TLI_LxVPOS第x层垂直位置参数寄存器配置/
// temp =0;
// temp |=((ACTIVE_HEIGHT+VERTICAL_SYNCHRONOUS_PULSE+VERTICAL_BACK_PORCH-1)<<16);//WBP窗口底部位置
// temp |=((VERTICAL_SYNCHRONOUS_PULSE+VERTICAL_BACK_PORCH)<<0);//WTP窗口顶部位置
// TLI_LxVPOS(LAYER1)=temp;
// //
//
// //TLI_LxPPF第x层像素格式寄存器配置/
// temp =0;
// temp |=(2<<0);//像素格式
// //这些位配置像素格式
// //000:ARGB8888
// //001:RGB888
// //010:RGB565
// //011:ARGB1555
// //100:ARGB4444
// //101:L8
// //110:AL44
// //111:AL88
// TLI_LxPPF(LAYER1)=temp;
// //
//
// //TLI_LxSA第x层恒定alpha寄存器配置/
// temp =0;
// temp |=(0XFF<<0);//恒定Alpha, 可用于计算混合因子。
// TLI_LxSA(LAYER1)=temp;
// //
//
// //TLI_LxDC第x层默认颜色寄存器配置/
// temp =0;
// temp |=(0<<24);//DCA默认颜色Alpha
// temp |=(0XFF<<16);//DCR默认颜色red
// temp |=(0XFF<<8);//DCG默认颜色green
// temp |=(0XFF<<0);//DCB默认颜色blue
// TLI_LxDC(LAYER1)=temp;
// //
//
// //TLI_LxBLEND第x层混合寄存器配置/
// temp =0;
// temp |=LAYER_ACF1_SA;//ACM1: Alpha混合因子1计算方法
// //000:保留
// //001:保留
// //010:保留
// //011:保留
// //100:归一化的恒定Alpha
// //101:保留
// //110:归一化的像素Alpha乘以归一化的恒定Alpha
// //111:保留
//
// temp |=LAYER_ACF2_SA;//ACM2:Alpha混合因子2计算方法
// //000:保留
// //001:保留
// //010:保留
// //011:保留
// //100:保留
// //101:1-归一化的恒定Alpha
// //110:保留
// //111:1-归一化的像素Alpha乘以归一化的恒定Alpha
// TLI_LxBLEND(LAYER1)=temp;
// //
//
// //TLI_LxFBADDR第x层帧基地址寄存器配置/
// ltdc_framebuf[1] = (uint16_t *)<dc_lcd_framebuf1;
// TLI_LxFBADDR(LAYER1)=(uint32_t)ltdc_framebuf[1];
// //
//
// //TLI_LxFLLEN第x层长度寄存器配置/
// temp=0;
// temp |=((ACTIVE_WIDTH * 2)<<16);//步幅偏移: 这个值定义了从某行起始处到下一行起始处之间的字节数
// temp |=((ACTIVE_WIDTH * 2 +3)<<0);//行长度: 这个值为一行的字节数+3
// TLI_LxFLLEN(LAYER1)=temp;
// //
//
// //TLI_LxFTLN第x层总行数寄存器配置/
// temp=0;
// temp |=(ACTIVE_HEIGHT <<0);//总行数: 这个值定义了一帧行数
// TLI_LxFTLN(LAYER1)=temp;
// //// //TLI_LxCTL第x层控制寄存器配置/
// temp=0;
// temp |=(0<<4);//LUTEN- 0:禁用LUT;1-使能LUT
// temp |=(0<<1);//CKEYEN色键使能:0-禁用;1-使能
// temp |=(0<<0);//LEN层使能:0-禁止;1-使能
// TLI_LxCTL(LAYER1)=temp;//禁用layer 1
// //
///***************************************************************************////*TLI_RL重载层配置寄存器************************************************/
此寄存器配置需在layer层配置后面
// temp=0;
// temp |=(0<<1);//FBR帧消隐重载请求:0:禁止重载; 1:层配置将在帧消隐时被重载进入真正寄存器。
// temp |=(1<<0);//RQR立即重载请求:0:禁止重载; 1:层配置将在该位置位之后被重载进入真正寄存器。
// TLI_RL =temp;
///***************************************************************************/TLI_CTL |=(1<<0);//TLI使能位;0-禁止;1-使能}
TLI驱动LCD实验现象
- 使用TIL驱动5寸屏480*800的LCD显示,这里还移植了LVGL图形库来做显示界面。这个LCD屏为梁山派的屏幕。显示效果如下:
- 实验效果视频如下:
这篇关于手写GD32F450/F470 TLI-LCD接口驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!