12.RGBLCD 屏幕
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 就能直接刷新显示,是因为
LCDIF->CUR_BUF和LCDIF->NEXT_BUF告诉了 LCDIF 控制器去哪里找显示数据(这个“哪里”就是tftlcd_dev.framebuffer指向的地址)。- 后续的绘图操作(如
lcd_drawpoint)实际上是修改了tftlcd_dev.framebuffer所指向内存区域里的像素数据。 - 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接口

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


所有评论(0)