12.RGBLCD 屏幕

常见的屏幕接口有: 6800、8080、RGB、I2C、SPI、MIPI-SDI、LVDS等

中小屏接口I2C、SPI、UART

大屏接口RGB、LVDS、MIPI、EDP和DP

6ULL有专门的外设接口eLCDIF

寄存器设置

LCDIF_CTRLn

LCDIF_CTRLn[0]:使能位

LCDIF_CTRLn[1]:设置数据格式为24位有效

LCDIF_CTRLn[5]:设置LCDIF接口工作在主机模式下

LCDIF_CTRLn[9:8]:设置输入像素格式为24bit,写3

LCDIF_CTRLn[10:11]:设置数据传输宽度位24bit,写3

LCDIF_CTRLn[12:13]:设置数据交换,不需要

LCDIF_CTRLn[14:15]:设置输入数据交换,不需要

LCDIF_CTRLn[17]:设置LCDIF工作在DOTCLK模式下

LCDIF_CTRLn[19]:设置必须工作在DOTCLK模式下

LCDIF_CTRLn[31]:复位功能必须置0;


LCDIF_CTRL1n

LCDIF_CTRLn[19:16]:设置为7,24位的格式

LCDIF_TRANSFER_COUNT

LCDIF_TRANSFER_COUNT[15:0]是LCD的行像素数 置为1024

LCDIF_TRANSFER_COUNT[31:16]:是LCD的列像素数 置为800

LCDIF_VDCRL0n

LCDIF_VDCRL0n[17:0]:为vspw时序参数

LCDIF_VDCRL0n[20]:设置vsync信号的宽度单位

LCDIF_VDCRL0n[21]:设置1

LCDIF_VDCRL0n[24]:设置ENABLE极性,为0低电平有效,为1高电平有效设置为1

LCDIF_VDCRL0n[25]:设置CLK信号极性,设置为0;

LCDIF_VDCRL0n[26]:设置HSYNC信号极性,设置为0;

LCDIF_VDCRL0n[27]:设置VSYNC信号极性,设置为0;

LCDIF_VDCTRL1

LCDIF_VDCTRL1寄存器为两个VSYNC信号之间的长度,即VSPW+VBPD+HEIGHT+VFP

LCDIF_VDCTRL2

LCDIF_VDCTRL2[17:0]:设置两个HSYNC信号之间的长度,即HSPW+HBP+WIDTH+HFP

LCDIF_VDCTRL2[31:18]:设置HSPW

LCDIF_VDCTRL3

LCDIF_VDCTRL3[15:0]:设置BVP+VSPW

LCDIF_VDCTRL3[16:27]:设置HBP+HSPW

LCDIF_VDCTRL4

LCDIF_VDCTRL4[16:27]:设置一行的像素点

LCDIF_CUR_BUF

定义LCD缓存首地址

LCDIF_NEXT_BUF

LCD下一帧数据首地址

LDC的IO初始化

LCD的时钟数配置

LCD的CLK是由6ULL的CLK引脚发送给RGB_LCK的,比如7寸的屏幕需要51.2MHz的CLK

我需要配置CCM章节中的寄存器去配置相关时钟频率

将PLL5(Vedio PLL)作为时钟源

在这里插入图片描述

PLL_AUDIOn[20:19]为1分频 置2;

CCM_ANALOG_MISC2n[31:30]:配置为1分频 置0;

①设置PLL5时钟频率

PLL5 CLK = Fref * (DIV_SELECT + NUM/DENOM) -> 为了简化将后面的分子分母设为0

DIV_SELECT可以通过CCM_ANALOG_PLL_VIDEO[6:0]进行控制,可选范围:27—54

Fref为24Mhz的参考频率

分子分母设为0 CCM_ANALOG_PLL_VIDEO_NUM=0 CCM_ANALOG_PLL_VIDEO_DENOM=0

在这里插入图片描述

②设置进入LCDIF的时钟源

设置图中框选的4个寄存器(多路选择器和预分频器)

最后将时钟源选择固定,可通过参数配置预分频器的值封装成函数。

bsp_lcd.h

#ifndef __BSP_LCD_H
#define __BSP_LCD_H

#include "imx6ul.h"


/* 颜色 */ //采用argb8888编码方式对应(255,255,255,255)->(透明度,红,绿,蓝)
#define LCD_BLUE		  0x000000FF
#define LCD_GREEN		  0x0000FF00
#define LCD_RED 		  0x00FF0000
#define LCD_CYAN		  0x0000FFFF
#define LCD_MAGENTA 	  0x00FF00FF
#define LCD_YELLOW		  0x00FFFF00
#define LCD_LIGHTBLUE	  0x008080FF
#define LCD_LIGHTGREEN	  0x0080FF80
#define LCD_LIGHTRED	  0x00FF8080
#define LCD_LIGHTCYAN	  0x0080FFFF
#define LCD_LIGHTMAGENTA  0x00FF80FF
#define LCD_LIGHTYELLOW   0x00FFFF80
#define LCD_DARKBLUE	  0x00000080
#define LCD_DARKGREEN	  0x00008000
#define LCD_DARKRED 	  0x00800000
#define LCD_DARKCYAN	  0x00008080
#define LCD_DARKMAGENTA   0x00800080
#define LCD_DARKYELLOW	  0x00808000
#define LCD_WHITE		  0x00FFFFFF
#define LCD_LIGHTGRAY	  0x00D3D3D3
#define LCD_GRAY		  0x00808080
#define LCD_DARKGRAY	  0x00404040
#define LCD_BLACK		  0x00000000
#define LCD_BROWN		  0x00A52A2A
#define LCD_ORANGE		  0x00FFA500
#define LCD_TRANSPARENT   0x00000000

/* 屏幕ID */ //针对不同屏幕进行不同参数设置
#define ATK4342		0X4342	/* 4.3寸480*272 	*/
#define ATK4384		0X4384	/* 4.3寸800*480 	*/
#define ATK7084		0X7084	/* 7寸800*480 		*/
#define ATK7016		0X7016	/* 7寸1024*600 		*/
#define ATK1018		0X1018	/* 10.1寸1280*800 	*/
#define ATKVGA		0xff00 /* VGA */

/* LCD显存地址 */
#define LCD_FRAMEBUF_ADDR	(0x89000000)

/* LCD控制参数结构体 */
struct tftlcd_typedef{
	unsigned short height;		/* LCD屏幕高度 */
	unsigned short width;		/* LCD屏幕宽度 */
	unsigned char pixsize;		/* LCD每个像素所占字节大小 */

    //水平参数和垂直参数
	unsigned short vspw;
	unsigned short vbpd;
	unsigned short vfpd;
	unsigned short hspw;
	unsigned short hbpd;
	unsigned short hfpd;


    //其他参数设置
	unsigned int framebuffer; 	/* LCD显存首地址   	  */
	unsigned int forecolor;		/* 前景色 */
	unsigned int backcolor;		/* 背景色 */
	unsigned int id;  			/*	屏幕ID */
};

extern struct tftlcd_typedef tftlcd_dev;



void lcd_init(void);
void lcdgpio_init(void);

void lcd_reset(void);
void lcd_noreset(void);
void lcd_enable(void);
void lcdclk_init(unsigned char loopDiv, unsigned char prediv, unsigned char div);
inline void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color);
inline unsigned int lcd_readpoint(unsigned short x,unsigned short y);
void lcd_clear(unsigned int color);
unsigned short lcd_read_panelid(void);
void lcd_fill(unsigned    short x0, unsigned short y0, unsigned short x1, unsigned short y1, unsigned int color);

#endif

bsp_lcd.c

#include "bsp_lcd.h"
#include "bsp_gpio.h"
#include "stdio.h"
#include "bsp_uart.h"
#include "bsp_delay.h"
#include "imx6ul.h"
struct tftlcd_typedef tftlcd_dev;


//初始化LCD
void lcd_init(void){
     
    //首先读取屏幕Id
    unsigned short ID = 0;
    ID = lcd_read_panelid();

    printf("LCD ID=%#X\r\n", ID);
    lcdgpio_init();
	lcd_reset();
	delay_ms(10);
	lcd_noreset();

	//根据不同的屏幕ID来设置屏幕参数
	/* TFTLCD参数结构体初始化 */
	if(ID == ATK4342) {
		tftlcd_dev.height = 272;	
		tftlcd_dev.width = 480;
		tftlcd_dev.vspw = 1;
		tftlcd_dev.vbpd = 8;
		tftlcd_dev.vfpd = 8;
		tftlcd_dev.hspw = 1;
		tftlcd_dev.hbpd = 40;
		tftlcd_dev.hfpd = 5; 	
		lcdclk_init(27, 8, 8);	/* 初始化LCD时钟 10.1MHz */
	} else if(ID == ATK4384) {
		tftlcd_dev.height = 480;	
		tftlcd_dev.width = 800;
		tftlcd_dev.vspw = 3;
		tftlcd_dev.vbpd = 32;
		tftlcd_dev.vfpd = 13;
		tftlcd_dev.hspw = 48;
		tftlcd_dev.hbpd = 88;
		tftlcd_dev.hfpd = 40;
		lcdclk_init(42, 4, 8);	/* 初始化LCD时钟 31.5MHz */
	} else if(ID == ATK7084) {
		tftlcd_dev.height = 480;	
		tftlcd_dev.width = 800;
		tftlcd_dev.vspw = 1;
		tftlcd_dev.vbpd = 23;
		tftlcd_dev.vfpd = 22;
		tftlcd_dev.hspw = 1;
		tftlcd_dev.hbpd = 46;
		tftlcd_dev.hfpd = 210;	
		lcdclk_init(30, 3, 7);	/* 初始化LCD时钟 34.2MHz */
	} else if(ID == ATK7016) {
		tftlcd_dev.height = 600;	
		tftlcd_dev.width = 1024;
		tftlcd_dev.vspw = 3;
		tftlcd_dev.vbpd = 20;
		tftlcd_dev.vfpd = 12;
		tftlcd_dev.hspw = 20;
		tftlcd_dev.hbpd = 140;
		tftlcd_dev.hfpd = 160;
		lcdclk_init(32, 3, 5);	/* 初始化LCD时钟 51.2MHz */
	} else if(ID == ATK1018) {
		tftlcd_dev.height = 800;	
		tftlcd_dev.width = 1280;
		tftlcd_dev.vspw = 3;
		tftlcd_dev.vbpd = 10;
		tftlcd_dev.vfpd = 10;
		tftlcd_dev.hspw = 10;
		tftlcd_dev.hbpd = 80;
		tftlcd_dev.hfpd = 70;
		lcdclk_init(35, 3, 5);	/* 初始化LCD时钟 56MHz */
	} else if(ID == ATKVGA) {  
		tftlcd_dev.height = 768;	
		tftlcd_dev.width = 1366;
		tftlcd_dev.vspw = 3;
		tftlcd_dev.vbpd = 24;
		tftlcd_dev.vfpd = 3;
		tftlcd_dev.hspw = 143;
		tftlcd_dev.hbpd = 213;
		tftlcd_dev.hfpd = 70;
		lcdclk_init(32, 3, 3);	/* 初始化LCD时钟 85MHz */
	}

	//共有参数 
	tftlcd_dev.pixsize = 4;				/* ARGB8888模式,每个像素4字节 */
	tftlcd_dev.framebuffer = LCD_FRAMEBUF_ADDR;	
	tftlcd_dev.backcolor = LCD_WHITE;	/* 背景色为白色 */
	tftlcd_dev.forecolor = LCD_BLACK;	/* 前景色为黑色 */



    
	/* 初始化ELCDIF的CTRL寄存器
     * bit [31] 0 : 停止复位
     * bit [19] 1 : 旁路计数器模式
     * bit [17] 1 : LCD工作在dotclk模式
     * bit [15:14] 00 : 输入数据不交换
     * bit [13:12] 00 : CSC不交换
     * bit [11:10] 11 : 24位总线宽度
     * bit [9:8]   11 : 24位数据宽度,也就是RGB888
     * bit [5]     1  : elcdif工作在主模式
     * bit [1]     0  : 所有的24位均有效
	 */
     LCDIF->CTRL = 0;
	 LCDIF->CTRL |= (1 << 19) | (1 << 17) | (0 << 14) | (0 << 12) |
	 				(3 << 10) | (3 << 8) | (1 << 5) | (0 << 1);
	/*
     * 初始化ELCDIF的寄存器CTRL1
     * bit [19:16]  : 0X7 ARGB模式下,传输24位数据,A通道不用传输
	 */	

	 LCDIF->CTRL1  = 0;
     LCDIF->CTRL1 |= (7<<16);

	 /*
      * 初始化ELCDIF的寄存器TRANSFER_COUNT寄存器
      * bit [31:16]  : 高度
      * bit [15:0]   : 宽度
	  */
	LCDIF->TRANSFER_COUNT = 0;
	LCDIF->TRANSFER_COUNT |= (tftlcd_dev.height << 16)| (tftlcd_dev.width);

	/*
     * 初始化ELCDIF的VDCTRL0寄存器
     * bit [29] 0 : VSYNC输出
     * bit [28] 1 : 使能ENABLE输出
     * bit [27] 0 : VSYNC低电平有效
     * bit [26] 0 : HSYNC低电平有效
     * bit [25] 0 : DOTCLK上升沿有效
     * bit [24] 1 : ENABLE信号高电平有效
     * bit [21] 1 : DOTCLK模式下设置为1
     * bit [20] 1 : DOTCLK模式下设置为1
     * bit [17:0] : vsw参数
	 */
	LCDIF->VDCTRL0 = 0;	//先清零
	if(lcdid == ATKVGA) {   //VGA需要特殊处理
		LCDIF->VDCTRL0 = (0 << 29) | (1 << 28) | (0 << 27) |
					 (0 << 26) | (1 << 25) | (0 << 24) |
					 (1 << 21) | (1 << 20) | (tftlcd_dev.vspw << 0);
	} else {
		LCDIF->VDCTRL0 = (0 << 29) | (1 << 28) | (0 << 27) |
					 (0 << 26) | (0 << 25) | (1 << 24) |
					 (1 << 21) | (1 << 20) | (tftlcd_dev.vspw << 0);
	}

	/*
	 * 初始化ELCDIF的VDCTRL1寄存器
	 * 设置VSYNC总周期
	 */  
	LCDIF->VDCTRL1 = tftlcd_dev.height + tftlcd_dev.vspw + tftlcd_dev.vfpd + tftlcd_dev.vbpd;  //VSYNC周期
	 
	 /*
	  * 初始化ELCDIF的VDCTRL2寄存器
	  * 设置HSYNC周期
	  * bit[31:18] :hsw
	  * bit[17:0]  : HSYNC总周期
	  */ 
	LCDIF->VDCTRL2 = (tftlcd_dev.hspw << 18) | (tftlcd_dev.width + tftlcd_dev.hspw + tftlcd_dev.hfpd + tftlcd_dev.hbpd);

	/*
	 * 初始化ELCDIF的VDCTRL3寄存器
	 * 设置HSYNC周期
	 * bit[27:16] :水平等待时钟数
	 * bit[15:0]  : 垂直等待时钟数
	 */ 
	LCDIF->VDCTRL3 = ((tftlcd_dev.hbpd + tftlcd_dev.hspw) << 16) | (tftlcd_dev.vbpd + tftlcd_dev.vspw);

	/*
	 * 初始化ELCDIF的VDCTRL4寄存器
	 * 设置HSYNC周期
	 * bit[18] 1 : 当使用VSHYNC、HSYNC、DOTCLK的话此为置1
	 * bit[17:0]  : 宽度
	 */ 
	
	LCDIF->VDCTRL4 = (1<<18) | (tftlcd_dev.width);

	/*
     * 初始化ELCDIF的CUR_BUF和NEXT_BUF寄存器
     * 设置当前显存地址和下一帧的显存地址
	 */
	LCDIF->CUR_BUF = (unsigned int)tftlcd_dev.framebuffer;
	LCDIF->NEXT_BUF = (unsigned int)tftlcd_dev.framebuffer;




	lcd_enable();			/* 使能LCD 	*/
	delay_ms(10);
	lcd_clear(LCD_BLUE);	/* 清屏 		*/
	




}

/*
 * @description		: LCD时钟初始化, LCD时钟计算公式如下:
 *                	  LCD CLK = 24 * loopDiv / prediv / div
 * @param -	loopDiv	: loopDivider值
 * @param -	prediv  : lcdifprediv值
 * @param -	div		: lcdifdiv值
 * @return 			: 无
 */
void lcdclk_init(unsigned char loopDiv, unsigned char prediv, unsigned char div){
	//不使用小数分分频器
	CCM_ANALOG->PLL_VIDEO_NUM = 0;
	CCM_ANALOG->PLL_VIDEO_DENOM = 0;
/*
     * PLL_VIDEO寄存器设置
     * bit[13]:    1   使能VIDEO PLL时钟
     * bit[20:19]  2  设置postDivider为1分频
     * bit[6:0] : 32  设置loopDivider寄存器
	 */
	CCM_ANALOG->PLL_VIDEO =  (2 << 19) | (1 << 13) | (loopDiv << 0); 

	/*
     * MISC2寄存器设置
     * bit[31:30]: 0  VIDEO的post-div设置,时钟源来源于postDivider,1分频
	 */
	CCM_ANALOG->MISC2 &= ~(3 << 30);
	CCM_ANALOG->MISC2 = 0 << 30;

	/* LCD时钟源来源与PLL5,也就是VIDEO           PLL  */
	CCM->CSCDR2 &= ~(7 << 15);  	
	CCM->CSCDR2 |= (2 << 15);			/* 设置LCDIF_PRE_CLK使用PLL5 */

	/* 设置LCDIF_PRE分频 */
	CCM->CSCDR2 &= ~(7 << 12);		
	CCM->CSCDR2 |= (prediv - 1) << 12;	/* 设置分频  */

	/* 设置LCDIF分频 */
	CCM->CBCMR &= ~(7 << 23);					
	CCM->CBCMR |= (div - 1) << 23;				

	/* 设置LCD时钟源为LCDIF_PRE时钟 */
	CCM->CSCDR2 &= ~(7 << 9);					/* 清除原来的设置		 	*/
	CCM->CSCDR2 |= (0 << 9);					/* LCDIF_PRE时钟源选择LCDIF_PRE时钟 */
}
/*
 * 读取屏幕ID,
 * 描述:LCD_DATA23=R7(M0);LCD_DATA15=G7(M1);LCD_DATA07=B7(M2);
 * 		M2:M1:M0
 *		0 :0 :0	//4.3寸480*272 RGB屏,ID=0X4342
 *		0 :0 :1	//7寸800*480 RGB屏,ID=0X7084
 *	 	0 :1 :0	//7寸1024*600 RGB屏,ID=0X7016
 *  	1 :0 :1	//10.1寸1280*800,RGB屏,ID=0X1018
 *		1 :0 :0	//4.3寸800*480 RGB屏,ID=0X4384
 * @param 		: 无
 * @return 		: 屏幕ID
 */
unsigned short lcd_read_panelid(void){

    unsigned char ID = 0;
 	IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_GPIO3_IO03, 0); //复用为GPIO3_IO3
	IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_GPIO3_IO03, 0X10B0); //设置输出电气属性
   	
    gpio_pin_config_t pin_config;
    pin_config.direction  = kGPIO_DigitalOutput;
    pin_config.outputLogic = 1;
    gpio_init(GPIO3,3,&pin_config);
    //读取IO值
    IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_GPIO3_IO12, 0); //复用为B7
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_GPIO3_IO20, 0);  //复用为M1
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_GPIO3_IO28, 0);//复用M0

    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_GPIO3_IO12, 0XF080); //设置输入电气属性
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_GPIO3_IO20, 0XF080); //设置输入电气属性
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_GPIO3_IO28, 0XF080); //设置输入电气属性

    pin_config.direction = kGPIO_DigitalInput;
    gpio_init(GPIO3,12,&pin_config);
    gpio_init(GPIO3,20,&pin_config);
    gpio_init(GPIO3,28,&pin_config);

        ID |=(unsigned char)gpio_pinRead(GPIO3,12)<<2;
        ID |=(unsigned char)gpio_pinRead(GPIO3,20)<<1;
        ID |=(unsigned char)gpio_pinRead(GPIO3,28);


    if (ID == 0)
    {
        return ATK4342;
    }else if (ID==1)
    {
        return ATK7084;
    }else if (ID==2)
    {
        return ATK7016;
    }else if (ID==5)
    {
        return ATK1018;
    }else if (ID==4)
    {
        return ATK4384;
    }else{

        return 0;
    }
    
}


/*
 * @description	: LCD GPIO初始化
 * @param 		: 无
 * @return 		: 无
 */
void lcdgpio_init(void)
{
	gpio_pin_config_t gpio_config;
	

	/* 1、IO初始化复用功能 */
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA03_LCDIF_DATA03,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA04_LCDIF_DATA04,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA05_LCDIF_DATA05,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA06_LCDIF_DATA06,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_LCDIF_DATA07,0);
	
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA08_LCDIF_DATA08,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA09_LCDIF_DATA09,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA10_LCDIF_DATA10,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA11_LCDIF_DATA11,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA12_LCDIF_DATA12,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA13_LCDIF_DATA13,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA14_LCDIF_DATA14,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_LCDIF_DATA15,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA16_LCDIF_DATA16,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA17_LCDIF_DATA17,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA18_LCDIF_DATA18,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA19_LCDIF_DATA19,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA20_LCDIF_DATA20,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA21_LCDIF_DATA21,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA22_LCDIF_DATA22,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK,0);	
	IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE,0);	
	IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC,0);
	IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC,0);

	IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08,0);			/* 背光BL引脚      */
	IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);
					

	/* 2、配置LCD IO属性	
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 0 默认22K上拉
	 *bit [13]: 0 pull功能
	 *bit [12]: 0 pull/keeper使能 
	 *bit [11]: 0 关闭开路输出
	 *bit [7:6]: 10 速度100Mhz
	 *bit [5:3]: 111 驱动能力为R0/7
	 *bit [0]: 1 高转换率
	 */
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA03_LCDIF_DATA03,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA04_LCDIF_DATA04,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA05_LCDIF_DATA05,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA06_LCDIF_DATA06,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_LCDIF_DATA07,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA08_LCDIF_DATA08,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA09_LCDIF_DATA09,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA10_LCDIF_DATA10,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA11_LCDIF_DATA11,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA12_LCDIF_DATA12,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA13_LCDIF_DATA13,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA14_LCDIF_DATA14,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_LCDIF_DATA15,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA16_LCDIF_DATA16,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA17_LCDIF_DATA17,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA18_LCDIF_DATA18,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA19_LCDIF_DATA19,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA20_LCDIF_DATA20,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA21_LCDIF_DATA21,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA22_LCDIF_DATA22,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23,0xB9);

	IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC,0xB9);
	IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC,0xB9);

	IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08,0x10b0);	/* 背光BL引脚 		*/

	/* GPIO初始化 */
	gpio_config.direction = kGPIO_DigitalOutput;			/* 输出 			*/
	gpio_config.outputLogic = 1; 							/* 默认关闭背光 */
	gpio_init(GPIO1, 8, &gpio_config);						/* 背光默认打开 */
	gpio_pinWrite(GPIO1, 8, 1);								/* 打开背光     */
}


/*
 * @description	: 复位ELCDIF接口
 * @param 		: 无
 * @return 		: 无
 */
void lcd_reset(void)
{
	LCDIF->CTRL  = 1<<31; /* 强制复位 */
}

/*
 * @description	: 结束复位ELCDIF接口
 * @param 		: 无
 * @return 		: 无
 */
void lcd_noreset(void)
{
	LCDIF->CTRL  = 0<<31; /* 取消强制复位 */
}

/*
 * @description	: 使能ELCDIF接口
 * @param 		: 无
 * @return 		: 无
 */
void lcd_enable(void)
{
	LCDIF->CTRL |= 1<<0; /* 使能ELCDIF */
}


/*
 * @description		: 画点函数 
 * @param - x		: x轴坐标
 * @param - y		: y轴坐标
 * @param - color	: 颜色值
 * @return 			: 无
 */
inline void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color)
{ 
  	*(unsigned int*)((unsigned int)tftlcd_dev.framebuffer + 
		             tftlcd_dev.pixsize * (tftlcd_dev.width * y+x))=color;
}

/*
 * @description		: 读取指定点的颜色值
 * @param - x		: x轴坐标
 * @param - y		: y轴坐标
 * @return 			: 读取到的指定点的颜色值
 */
inline unsigned int lcd_readpoint(unsigned short x,unsigned short y)
{ 
	return *(unsigned int*)((unsigned int)tftlcd_dev.framebuffer + 
		   tftlcd_dev.pixsize * (tftlcd_dev.width * y + x));
}



/*
 * @description		: 清屏
 * @param - color	: 颜色值
 * @return 			: 读取到的指定点的颜色值
 */
void lcd_clear(unsigned int color)
{
	unsigned int num;
	unsigned int i = 0; 

	unsigned int *startaddr=(unsigned int*)tftlcd_dev.framebuffer;	//指向帧缓存首地址
	num=(unsigned int)tftlcd_dev.width * tftlcd_dev.height;			//缓冲区总长度
	for(i = 0; i < num; i++)
	{
		startaddr[i] = color;
	}		
}

/*
 * @description		: 以指定的颜色填充一块矩形
 * @param - x0		: 矩形起始点坐标X轴
 * @param - y0		: 矩形起始点坐标Y轴
 * @param - x1		: 矩形终止点坐标X轴
 * @param - y1		: 矩形终止点坐标Y轴
 * @param - color	: 要填充的颜色
 * @return 			: 读取到的指定点的颜色值
 */
void lcd_fill(unsigned    short x0, unsigned short y0, 
                 unsigned short x1, unsigned short y1, unsigned int color)
{ 
    unsigned short x, y;

	if(x0 < 0) x0 = 0;
	if(y0 < 0) y0 = 0;
	if(x1 >= tftlcd_dev.width) x1 = tftlcd_dev.width - 1;
	if(y1 >= tftlcd_dev.height) y1 = tftlcd_dev.height - 1;
	
    for(y = y0; y <= y1; y++)
    {
        for(x = x0; x <= x1; x++)
			lcd_drawpoint(x, y, color);
    }
}

基本步骤

初始化IO,初始化LCD屏幕,初始化时钟频率,使用结构体设置屏幕参数,将结构体的参数写入寄存器或寄存器相关配置

重点

- 1.使用单缓冲区配置显示内容,

LCDIF->CUR_BUF  = (unsigned int)tftlcd_dev.framebuffer;
LCDIF->NEXT_BUF = (unsigned int)tftlcd_dev.framebuffer;

后面通过改变 tftlcd_dev.framebuffer 就能直接刷新显示,是因为

  1. LCDIF->CUR_BUFLCDIF->NEXT_BUF 告诉了 LCDIF 控制器去哪里找显示数据(这个“哪里”就是 tftlcd_dev.framebuffer 指向的地址)。
  2. 后续的绘图操作(如 lcd_drawpoint)实际上是修改了 tftlcd_dev.framebuffer 所指向内存区域里的像素数据
  3. LCDIF 控制器持续读取这块内存并刷新屏幕,从而将内存中的数据变化实时地呈现在屏幕上。

这就是一个典型的单缓冲区 (Single Buffering) 显示模式。在这种模式下,绘图和显示都在同一块内存区域进行,所以你写进去的数据会立即被显示出来。不过,这种模式可能会出现屏幕撕裂 (tearing) 的现象,尤其是在快速动画时,因为显示控制器可能在绘图完成之前就读取了部分数据。在一些对显示质量要求更高的场景下,会使用双缓冲区 (Double Buffering) 甚至多缓冲区 (Triple Buffering) 来避免这个问题。

- 2.只用内联函数实现画点函数

/*
 * @description		: 画点函数 
 * @param - x		: x轴坐标
 * @param - y		: y轴坐标
 * @param - color	: 颜色值
 * @return 			: 无
 */
inline void lcd_drawpoint(unsigned short x,unsigned short y,unsigned int color)
{ 
  	*(unsigned int*)((unsigned int)tftlcd_dev.framebuffer + 
		             tftlcd_dev.pixsize * (tftlcd_dev.width * y+x))=color;
}
  • inline

这是一个 C/C++ 关键字,建议编译器将此函数进行内联展开。这意味着在调用 lcd_drawpoint 的地方,函数体的内容可能会直接插入到调用点,而不是通过传统的函数调用机制。这样做可以减少函数调用的开销,提高执行效率,尤其对于像绘制点这样频繁调用的函数很有用。

在这里插入图片描述

接着将指向该地址进行解引用,得到其指向的值,改为颜色值即可,完成画点函数。

- 3.移植lcd的api库函数、字库函数

api库函数均调用了画点函数lcd_drawpoint() 使用时将参数color设置为了前景色

- 4配置寄存器的原则:

①配置整个寄存器:

先清除寄存器的值 在使用|=来置1。在置位前一定要检查是否将这几位的值清除一遍!!!!

	LCDIF->CTRL1  = 0;
	LCDIF->CTRL1 |= (7<<16);

②配置某位寄存器

先清除该位(多位),再置一

	//19-16位
	LCDIF->CTRL1  &=~ (0xF<<16);
	LCDIF->CTRL1  |=  (7<<16);

对于寄存器的修改能一步到位就一步到位

	//19-16位 不建议采用下面的方式
	LCDIF->CTRL1  =0;
	LCDIF->CTRL1  |=  (7<<16);
	LCDIF->CTRL1  |=  (5<<12);
	LCDIF->CTRL1  |=  (5<<8);

//采用下面方式
	LCDIF->CTRL1  |=  (7<<16) | (5<<12) | (5<<8);
//实在需要分开的可以先用中间变量保存寄存器中的值,在中间变量中进行修改,最后统一写入寄存器
	unsigned int reg = LCDIF->CTRL1;
	reg |=  (7<<16);
	//中间处理其他事情
	reg |=  (5<<12);
    reg |=  (5<<8);     
	LCDIF->CTRL1 = reg;  

其他接口

6800接口

在这里插入图片描述

8080接口

在这里插入图片描述

DP接口

在这里插入图片描述

EDP接口

在这里插入图片描述

DSI接口

在这里插入图片描述

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐