正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-21.7讲 LCDIF控制接口初始化编写

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第21 讲” 的读书笔记。第21讲主要是介绍I.MX6U处理器的LCD液晶显示屏驱动的裸机开发,本节使用的是正点原子I.MX6U ALPHA/Mini 开发板配套的4.7英寸或7英寸 RGBLCD (RGB接口的LCD液晶显示屏)。本节将参考正点原子的视频教程第21讲和配套的正点原子开发指南文档进行学习。

正点原子第21讲I.MX6U ARM裸机RGBLCD液晶显示屏的视频教程比较长一共有8节视频教程,相对来说通过I.MX6U ARM 裸机寄存器来驱动RGBLCD涉及到的寄存器比较多,相对来说还是比较复杂的。

本节是正点原子第21.7讲RGBLCD视频教程, LCDIF控制接口初始化编写。

0. 概述

 LCDIF控制接口初始化编写

1. LCDIF 控制寄存器

1.1 LCDIF_CTR寄存器

LCDIF_CTR 控制寄存器,如下图所示:

  • RUN bit[0]:
  • MASTER bit[5]:
  • WORD_LENGTH[9:8]:
  • LCD_DATABUS_WIDTH[11:10]:
  • DOTCLK_MODE bit[17]:
  • BYPASS_COUNT[19]:
  • SFTRST bit[31]: 

1.2 LCDIF_CTRL1 寄存器

1.3 LCDIF_TRANSFER_COUNT 寄存器

设置LCD一帧中一行有多少数据,一列有多少数据。

1.4 LCDIF_VDCTRL0n 寄存器

LCDIF_VDCTRL0n 寄存器,我们需要关注的寄存器bit位如下,

1.5 LCDIF_VDCTRL1寄存器

LCDIF_VDCTRL1寄存器,只有一个位表示是LCD VSYNC的长度。

计算方法为:

(VSPW + VBP + VFP + 屏幕垂直宽度)

1.6 LCDIF_VDCTRL2

计算方法为:

(HSPW + HBP + HFP + 屏幕垂直高度)

1.7 LCDIF_VDCTRL3 寄存器

  • 水平等待宽度为 HSPW + HBP.
  • 垂直等待宽度为 VSPW + VBP

1.8 LCDIF_VDCTRL4 寄存器

水平方向像素的个数

1.9 LCDIF_CUR_BUF

当前帧缓冲区地址

 1.10 LCDIF_NEXT_BUF

下一帧缓冲区地址

2. 编写LCDIF控制接口初始化源码

编写LCDIF控制接口初始化源码,编写如下:

#include "bsp_lcd.h"
#include "bsp_gpio.h"
#include "stdio.h"
#include "bsp_delay.h"


/* 屏幕参数结构体变量 */
struct tftlcd_typedef tftlcd_dev;

/*
 * @description 	: LCD初始化
 * @param  			: 无
 * @return 			: 无
 */
void lcd_init(void)
{
	unsigned short lcdid = 0;
	unsigned int reg = 0;

	lcdid = lcd_read_panelId();
	printf("LCD panelId=0X%X\r\n", lcdid);

	/* IO接口初始化, LCD_DATA0~LCD_DATA23, LCD_CLK, LCD_EN, LCD_VSYNC, LCD_HSYNC */
	lcd_gpio_init();


	lcd_reset();
	delay_ms(10);
	lcd_stopreset();



	/* 根据不同的屏幕ID来设置屏幕参数 */
	if(lcdid == ATK4342){
		tftlcd_dev.height = 272;
		tftlcd_dev.width = 480;
		tftlcd_dev.vspw = 0;
		tftlcd_dev.vbpd = 8;
		tftlcd_dev.vfpd = 8;
		tftlcd_dev.hspw = 0;
		tftlcd_dev.hbpd = 40;
		tftlcd_dev.hfpd = 5;
		lcdclk_init(27, 8, 8);	/* 初始化LCD时钟 10.1MHz */
	}
	else if(lcdid == 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(lcdid == 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(lcdid == 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;

		printf("lcdid == ATK7016, tftlcd_dev init\r\n");

		lcdclk_init(32, 3, 5);	/* 初始化LCD时钟 51.2MHz */
	} else if(lcdid == 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(lcdid == 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;							/* 每个像素4个字节 */
	tftlcd_dev.framebuffer = TFTLCD_FRAMEBUF_ADDR;
	tftlcd_dev.forecolor = LCD_BLACK;				/* 前景黑色 */
	tftlcd_dev.backcolor = LCD_WHITE;				/* 背景白色 */


	/* 配置LCDIF控制器接口 */
	printf("register LCDIF->CTRL=%08x\r\n", LCDIF->CTRL);
	LCDIF->CTRL = 0;				/* 清零 */
	LCDIF->CTRL |= (1 << 5);		/* 工作在主机模式 */
	LCDIF->CTRL	|= (3 << 8);		/* 输入数据格式24bit */
	LCDIF->CTRL	|= (3 << 10);		/* LCD Data BUS 数据格式24bit */
	LCDIF->CTRL	|= (1 << 17);		/* DOTCLK 模式 */
	LCDIF->CTRL	|= (1 << 19);		/* DOTCLK 模式下必须置1 */

	LCDIF->CTRL1 &= ~(0xF << 16);	
	LCDIF->CTRL1 |= (0x7 << 16);	/* 数据封装格式为24bit A-R-G-B */


	LCDIF->TRANSFER_COUNT = 0;
	LCDIF->TRANSFER_COUNT |= ((tftlcd_dev.width & 0xFFFF) << 0);	/* 一行的像素 */
	LCDIF->TRANSFER_COUNT |= ((tftlcd_dev.height & 0xFFFF) << 16);	/* 一列的像素 */


	printf("register LCDIF->VDCTRL0=%08x\r\n", LCDIF->VDCTRL0);
	LCDIF->VDCTRL0 = 0;
	reg = 0;
	reg |= (tftlcd_dev.vspw << 0);
	reg |= (1 << 20);
	reg |= (1 << 21);
	reg |= (1 << 24);	/* Enable极性 */
	reg |= (0 << 25);	/* DOTCLK极性 */
	reg |= (0 << 26);	/* VSYNC极性 */
	reg |= (0 << 27);	/* HSYNC极性*/
	reg |= (1 << 28);	/* 是否使用Enable信号 */
	reg |= (0 << 29);	/* SYNC作为输出 */
	LCDIF->VDCTRL0 = reg;



	//vsync的长度
	LCDIF->VDCTRL1 = (tftlcd_dev.vspw + tftlcd_dev.vbpd + tftlcd_dev.vfpd + tftlcd_dev.height);
	
	//(tftlcd_dev.hspw + tftlcd_dev.hbpd + tftlcd_dev.hfpd + hbpd.width)

	//LCDIF->VDCTRL2 &= ~(0x3FFFF << 0);
	LCDIF->VDCTRL2  = 0;
	LCDIF->VDCTRL2 |= (tftlcd_dev.hspw + tftlcd_dev.hbpd + tftlcd_dev.hfpd + tftlcd_dev.width);
	LCDIF->VDCTRL2 |= (tftlcd_dev.hspw << 18);


	LCDIF->VDCTRL3 = 0;
	LCDIF->VDCTRL3 |= ((tftlcd_dev.vspw + tftlcd_dev.vbpd) << 0);
	LCDIF->VDCTRL3 |= ((tftlcd_dev.hspw + tftlcd_dev.hbpd) << 16);


	LCDIF->VDCTRL4  = 0;
	LCDIF->VDCTRL4 |= (tftlcd_dev.width << 0);
	LCDIF->VDCTRL4 |= (1 << 18);

	// LCDIF->AS_BUF = (unsigned int)tftlcd_dev.framebuffer;				/* 当前帧缓冲区地址 */
	// LCDIF->AS_NEXT_BUF = (unsigned int)tftlcd_dev.framebuffer;			/* 下一帧缓冲区地址 */
	LCDIF->CUR_BUF = (unsigned int)tftlcd_dev.framebuffer;				/* 当前帧缓冲区地址 */
	LCDIF->NEXT_BUF = (unsigned int)tftlcd_dev.framebuffer;			/* 下一帧缓冲区地址 */

	/* 使能LCD Enable */
	lcd_enable();


	delay_ms(20);


	lcd_clean(LCD_WHITE);
}

/*
 * @description 	: 读取正点原子LCD液晶屏面板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 			: 正点原子LCD液晶屏面板id
 * 
 */
unsigned short lcd_read_panelId(void)
{
	unsigned short idx = 0;
	unsigned short panelId = 0;
	gpio_pin_config_t led_config;

	/* LCD_VSYNC 复用为GPIO3_IO03 输出模式 */
	IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_GPIO3_IO03, 0);			/* IO复用 */
	IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_GPIO3_IO03, 0x10B0);	/* IO电气特性 */

	led_config.direction = kGPIO_DigitalOutput;		
	led_config.outputLogic = 1;							
	//gpio_init(GPIO5, 1, &led_config);
	gpio_init(GPIO3, 3, &led_config);


	/* M0,M1,M2 IO 复用 */
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_GPIO3_IO28, 0);			/* M0(R7)  LCD_DATA23 GPIO输入模式 */
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_GPIO3_IO20, 0);			/* M1(G7) LCD_DATA15 GPIO输入模式 */
	IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_GPIO3_IO12, 0);			/* M2(B7) LCD_DATA07 GPIO输入模式 */

	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_GPIO3_IO28, 0xF080);	/* M0(R7) IO电气特性 */
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_GPIO3_IO20, 0xF080);	/* M1(G7) IO电气特性 */
	IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_GPIO3_IO12, 0xF080);	/* M2(B7) IO电气特性 */

	led_config.direction = kGPIO_DigitalInput;								
	gpio_init(GPIO3, 28, &led_config);							/* M0 */
	gpio_init(GPIO3, 20, &led_config);							/* M1 */
	gpio_init(GPIO3, 12, &led_config);							/* M2 */


	idx = gpio_pinread(GPIO3, 28);
	idx |= gpio_pinread(GPIO3, 20) << 1;
	idx |= gpio_pinread(GPIO3, 12) << 2;

	printf("idx=%d\r\n", idx);

	switch(idx)
	{
		case 0:
			panelId = ATK4342;
			break;
		case 1:
			panelId = ATK7084;
			break;
		case 2:
			panelId = ATK7016;
			break;
		case 4:
			panelId = ATK4384;
			break;
		case 5:
			panelId = ATK1018;
			break;
	}

	return panelId;
}

/*
 * IO引脚: 	LCD_DATA00 -> LCD_B0
 *			LCD_DATA01 -> LCD_B1
 *			LCD_DATA02 -> LCD_B2
 *			LCD_DATA03 -> LCD_B3
 *			LCD_DATA04 -> LCD_B4
 *			LCD_DATA05 -> LCD_B5
 *			LCD_DATA06 -> LCD_B6
 *			LCD_DATA07 -> LCD_B7
 *
 *			LCD_DATA08 -> LCD_G0
 *			LCD_DATA09 -> LCD_G1
 *			LCD_DATA010 -> LCD_G2
 *			LCD_DATA011 -> LCD_G3
 *			LCD_DATA012 -> LCD_G4
 *			LCD_DATA012 -> LCD_G4
 *			LCD_DATA013 -> LCD_G5
 *			LCD_DATA014 -> LCD_G6
 *			LCD_DATA015 -> LCD_G7
 *
 *			LCD_DATA016 -> LCD_R0
 *			LCD_DATA017 -> LCD_R1
 *			LCD_DATA018 -> LCD_R2 
 *			LCD_DATA019 -> LCD_R3
 *			LCD_DATA020 -> LCD_R4
 *			LCD_DATA021 -> LCD_R5
 *			LCD_DATA022 -> LCD_R6
 *			LCD_DATA023 -> LCD_R7
 *
 *			LCD_CLK -> LCD_CLK
 *			LCD_VSYNC -> LCD_VSYNC
 *			LCD_HSYNC -> LCD_HSYNC
 *			LCD_DE -> LCD_DE
 *			LCD_BL -> GPIO1_IO08 
 */
/*
 * @description 	: LCD IO初始化
 *					  LCD_DATA0~LCD_DATA23,LCD_CLK,LCD_EN,LCD_HYSNC,LCD_VSYNC,LCD_PWM
 *					  这些IO完成初始化,并默认点亮LCD背光
 * @param  			: 无
 * @return 			: 正点原子LCD液晶屏面板id
 * 
 */
void lcd_gpio_init(void)
{
	/* LCD_DATA 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);			/* LCD_CLK */
	IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0);	/* LCD_ENABLE */
	IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0);		/* LCD_HSYNC */
	IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0);		/* LCD_VSYNC */


	
	/* 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 高转换率
	 */
	/* LCD_DATA IO 电气属性 */
	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);			/* LCD_CLK */
	IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0xB9);	/* LCD_ENABLE */
	IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0xB9);		/* LCD_HSYNC */
	IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0xB9);		/* LCD_VSYNC */

	/* LCD背光点亮,背光GPIO初始化, LCD_PWM (Pulse Width Modulatization) */
	IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0);
	IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0xB9);

	gpio_pin_config_t led_config;
	led_config.direction = kGPIO_DigitalOutput;		
	led_config.outputLogic = 1;										/* 默认输出高电平 */
	gpio_init(GPIO1, 8, &led_config);
	gpio_pinwrite(GPIO1, 8, 1);										/* 输出高电平点亮LCD */
}




/* LCD 复位 */
void lcd_reset(void)
{
	LCDIF->CTRL |= (1 << 31);
}

/* LCD 停止复位 */
void lcd_stopreset(void)
{
	LCDIF->CTRL &= ~(1 << 31);
}

/* LCD 使能 */
void lcd_enable(void)
{
	LCDIF->CTRL |= (1 << 0);
}

/* 像素时钟初始化 
 * @loopDiv 的合法值范围为27~54
 * @prediv 范围为1~8
 * @div 范围为1~8
 * LCD_CLK=24MHz*loopDiv/prediv/div
 * */
void lcdclk_init(unsigned char loopDiv, unsigned char prediv, unsigned char div)
{
	unsigned int reg = 0;

	CCM_ANALOG->PLL_VIDEO_NUM = 0;		/* 不使用小数分频器 */
	CCM_ANALOG->PLL_VIDEO_DENOM = 0;	/* 不使用小数分频器 */

	CCM_ANALOG->PLL_VIDEO  = 0;
	reg = 0;
	reg |= (1 << 13);					/* Enable PLL4 PLL_VIDEO */
	reg |= (2 << 19);					/* POST_DIV_SELECT 1分频 */
	reg |= ((loopDiv & 0x7f) << 0);		/* DIV_SELECT */
	CCM_ANALOG->PLL_VIDEO = reg;

	CCM_ANALOG->MISC2 &= ~(3 << 30);	/* CCM_ANLOG_MISC2->VIDEO_DIV 1分频 */
	CCM_ANALOG->MISC2 |= (0 << 30);

	/* video_clk 第一级时钟源选择 */
	CCM->CSCDR2 &= ~(7 << 15); 			/* 清零 */
	CCM->CSCDR2 |= (2 << 15);			/* 时钟源PLL5 */
	

	/* video_clk 分频 */
	CCM->CSCDR2 &= ~(7 << 12);			/* 清零 */
	// CCM->CSCDR2 &= ~(((prediv - 1) & 0x7) << 12);
	CCM->CSCDR2 |= (((prediv - 1) & 0x7) << 12);

	CCM->CBCMR &= ~(7 << 23);			/* 清零 */
	// CCM->CBCMR &= ~(((div - 1) & 0x7) << 23);
	CCM->CBCMR |= (((div - 1) & 0x7) << 23);


	/* video_clk 第二级时钟源选择 */
	CCM->CSCDR2 &= ~(7 << 9);			/* 时钟源LCDIF1 */

}


/* API 画点函数 */
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;
}

/* API 读点函数 */
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));
}

/* 清屏函数 */
void lcd_clean(unsigned int color)
{
	unsigned int size =(unsigned int)(tftlcd_dev.width * tftlcd_dev.height);
	unsigned int i = 0;
	unsigned int *startAddr = (unsigned int *)tftlcd_dev.framebuffer;

	for(i=0; i < size; i++){
		startAddr[i] = color;
	}
}

3. 编译烧写SD卡验证实验结果

译修改主频后源码烧录SD卡验证本节的 I.MX6U LCD(RGB)液晶屏驱动实验。预期烧录SD卡后正点原子I.MX6ULL ALPHA/Mini 开发板后, LCD(RGB)液晶屏能够刷新为白色。

我本地验证的结果是烧录SD卡后LCD液晶显示屏不能刷新为白色,经过反复的调试并且和正点原子提供的示例源码进行比对,并且注释源码并且替换为正点原子的示例源码,才最后成功点亮LCD显示屏并刷新为白色。问题原因的详情记录下下面的实验问题记录里。

4. 总结和实验遇到的问题记录

4.1 问题1:烧录LCD.bin并上电之后,LCD显示屏不能刷新为白色。

问题1 原因是这里没有清零,bit[30] clock_gate 使用printf打印出来查看默认值是1,1的时候关闭LCD CLK Gate 就是没有输出。

见如下《I.MX6ULL参考手册》中寄存器的说明,可printf打印到串口里的 LCDIF->CTRL 寄存器的默认值。

所以这里需要注意:

一定需要先清零 LCDIF->CTRL 寄存器,不启用CLKGATE也就是输出LCD CLK 时钟源。

4.2 问题2:LCD初始化函数中时钟源初始化时代码写错,应该使用“或运算”的错写成了“与运算”

LCD初始化函数中时钟源初始化时代码写错,应该使用“或运算”的错写成了“与运算”

4.3 问题3:LCDIF 的当前帧寄存器名字写错了,应该是 "LCDIF->CUR_BUF" 错写成了 "LCDIF->AS_BUF"

5. 结束

本文至此结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值