手写GD32F450/F470 TLI-LCD接口驱动

2023-10-21 22:40

本文主要是介绍手写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 *)&ltdc_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 *)&ltdc_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接口驱动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/257422

相关文章

Linux之platform平台设备驱动详解

《Linux之platform平台设备驱动详解》Linux设备驱动模型中,Platform总线作为虚拟总线统一管理无物理总线依赖的嵌入式设备,通过platform_driver和platform_de... 目录platform驱动注册platform设备注册设备树Platform驱动和设备的关系总结在 l

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

MybatisPlus service接口功能介绍

《MybatisPlusservice接口功能介绍》:本文主要介绍MybatisPlusservice接口功能介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录Service接口基本用法进阶用法总结:Lambda方法Service接口基本用法MyBATisP

Java中的Closeable接口及常见问题

《Java中的Closeable接口及常见问题》Closeable是Java中的一个标记接口,用于表示可以被关闭的对象,它定义了一个标准的方法来释放对象占用的系统资源,下面给大家介绍Java中的Clo... 目录1. Closeable接口概述2. 主要用途3. 实现类4. 使用方法5. 实现自定义Clos

java对接第三方接口的三种实现方式

《java对接第三方接口的三种实现方式》:本文主要介绍java对接第三方接口的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录HttpURLConnection调用方法CloseableHttpClient调用RestTemplate调用总结在日常工作

Java 的 Condition 接口与等待通知机制详解

《Java的Condition接口与等待通知机制详解》在Java并发编程里,实现线程间的协作与同步是极为关键的任务,本文将深入探究Condition接口及其背后的等待通知机制,感兴趣的朋友一起看... 目录一、引言二、Condition 接口概述2.1 基本概念2.2 与 Object 类等待通知方法的区别

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R