手写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

相关文章

Java8需要知道的4个函数式接口简单教程

《Java8需要知道的4个函数式接口简单教程》:本文主要介绍Java8中引入的函数式接口,包括Consumer、Supplier、Predicate和Function,以及它们的用法和特点,文中... 目录什么是函数是接口?Consumer接口定义核心特点注意事项常见用法1.基本用法2.结合andThen链

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

MyBatis-Flex BaseMapper的接口基本用法小结

《MyBatis-FlexBaseMapper的接口基本用法小结》本文主要介绍了MyBatis-FlexBaseMapper的接口基本用法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具... 目录MyBATis-Flex简单介绍特性基础方法INSERT① insert② insertSelec

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

Idea实现接口的方法上无法添加@Override注解的解决方案

《Idea实现接口的方法上无法添加@Override注解的解决方案》文章介绍了在IDEA中实现接口方法时无法添加@Override注解的问题及其解决方法,主要步骤包括更改项目结构中的Languagel... 目录Idea实现接China编程口的方法上无法添加@javascriptOverride注解错误原因解决方

Java function函数式接口的使用方法与实例

《Javafunction函数式接口的使用方法与实例》:本文主要介绍Javafunction函数式接口的使用方法与实例,函数式接口如一支未完成的诗篇,用Lambda表达式作韵脚,将代码的机械美感... 目录引言-当代码遇见诗性一、函数式接口的生物学解构1.1 函数式接口的基因密码1.2 六大核心接口的形态学

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

Java后端接口中提取请求头中的Cookie和Token的方法

《Java后端接口中提取请求头中的Cookie和Token的方法》在现代Web开发中,HTTP请求头(Header)是客户端与服务器之间传递信息的重要方式之一,本文将详细介绍如何在Java后端(以Sp... 目录引言1. 背景1.1 什么是 HTTP 请求头?1.2 为什么需要提取请求头?2. 使用 Spr

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果: 解密后的数据就是正常数据: 后端:使用的是spring-cloud框架,在gateway模块进行操作 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency> 编写一个AES加密