前言:
本文是根据哔哩哔哩网站上“正点原子[第二期]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. 结束
本文至此结束