Linux-Ubuntu之RGBLCD显示屏
一,实现原理
采用的是4.3寸 800×480显示屏,即每行有800个像素点,每列有480个像素点,外接时钟信号,控制刷新频率,每次刷新时,每一帧信号采用'Z'字型的方式,依次从第一行,第二行...往下面去刷,正常每个像素点由RGB三个通道来控制颜色,RGB三通道每一个通道用一个字节,这个显示屏采用ARGB,A是一个透明通道,因此颜色方面采用四个字节控制。
**显示原理:**电子枪打开,从左往右扫描,显示完一行后,电子枪关闭,水平同步信号HSYNC会打开,从电子枪关闭到水平同步信号打开的时间间隔叫HFP,然后电子枪移动到屏幕左边下一行,HSYNC结束到电子枪打开这个时间间隔是HBP,VSYNC是帧同步信号,当显示完整个屏幕即一帧后,电子枪关闭到VSYNC信号打开的时间间隔是VFP,等VSYNC关闭到电子枪重新从左上角打开的时间间隔是VBP。
时钟 :显示一帧图像用的时钟数: (VSPW+VBP+LINE+VFP) * (HSPW + HBP + HOZVAL + HFP)=(3+32+480+13)(48+88+800+40)=515328,显示60帧:515328 60=30919680≈31MHZ,因此时钟选择31MHZ即可满足该屏幕刷新。采用PPL5给LCD作为原始时钟源,然后经过选择器和分频器设置为31MHZ即可。
显存 :一个像素颜色用四个字节,800480 3=153600个字节约等于1.5MB内存。
最后是对寄存器进行配置:①初始化LCD使用的IO,设置复用功能和电器属性,对不同屏幕设置不同时钟。②设置CCM相应寄存器,尤其是关于扫描方面寄存器配置。③设置初始化地址,LCD的CTRL,CTRL1,CUR_BUF,TRANSFER_COUNT,NEXT_BUF寄存器。④编写响应的显示函数,清屏等。
二,驱动代码
需要先读这个LCD的ID,ID能说明长和宽,即对应的像素有多少,才能对屏幕进行设置。
c
/*LCD.h*/
#ifndef _DSP_LCD_H
#define _DSP_LCD_H
#include "imx6ul.h"
/*屏幕ID*/
#define ATK4342 0x4342
#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 SHOW_ADRESS (0x89000000)
/*颜色*/
#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
/**LCD屏幕信息结构体*/
struct tflcd_typedef{
unsigned short height;//屏幕高度
unsigned short width;//屏幕宽度
unsigned char pixsize;//每个像素占据第字节数字
unsigned short vspw;
unsigned short vbpd;
unsigned short vfpd;
unsigned short hspw;
unsigned short hbpd;
unsigned short hfpd;
unsigned int framebuffer;//屏幕显存地址
unsigned int forecolor;//前景色
unsigned int backcolor;//背景色
};
extern struct tflcd_typedef tftlcd_dev;
void lcd_init(void);//初始化
unsigned short lcd_read_panelid(void);//读取屏幕ID
void lcdgpio_init(void);//背光设置
void lcd_reset(void);/*复位*/
void lcd_noreset(void);/*停止复位*/
void lcd_enable(void);/*使能LCD控制器*/
void lcd_clock_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 int x,unsigned int y);//读点
void lcd_clear(unsigned int color);//清屏
void lcd_fill(unsigned short x0,unsigned short y0,unsigned short x1,unsigned short y1,unsigned int color);
#endif
/*LCD.c*/
#include "dcp_lcd.h"
#include "dsp_gpio.h"
#include "dsp_delay.h"
#include "stdio.h"
/*屏幕参数结构体变量*/
struct tflcd_typedef tftlcd_dev;
/*LCD初始化*/
void lcd_init(void)
{
unsigned short lcd_ID=0;
lcd_ID = lcd_read_panelid();
printf("屏幕ID为:%x \r\n",lcd_ID);
/*初始化ID*/
lcdgpio_init();
lcd_reset();
delay(10);
lcd_noreset();
/*根据不同屏幕设置*/
if(lcd_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;
lcd_clock_init(,4,8);//时钟频率 31.5MHZ
}else if(lcd_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;
lcd_clock_init(27,8,8);//时钟频率 10.1MHZ
}
tftlcd_dev.pixsize = 4;
tftlcd_dev.framebuffer = SHOW_ADRESS;
tftlcd_dev.forecolor = LCD_WHITE;
tftlcd_dev.backcolor = LCD_BLACK;
/*配置LCDIF控制器接口*/
LCDIF->CTRL = 0;
LCDIF->CTRL |= (1<<5) |(3<<8)|(3<<10)|(1<<17)|(1<<19);
LCDIF->CTRL1 = 0;
LCDIF->CTRL1 |=(7<<16);
LCDIF->TRANSFER_COUNT = 0;
LCDIF->TRANSFER_COUNT =(tftlcd_dev.height<<16)|(tftlcd_dev.width<<0);
LCDIF->VDCTRL0 =0;
LCDIF->VDCTRL0 = (tftlcd_dev.vspw<<0)|(1<<20)|(1<<21)|
(1<<24)|(0<<25)|(0<<26)|(0<<27)|(1<<28)|(0<<29);
LCDIF->VDCTRL1 = tftlcd_dev.vspw+tftlcd_dev.vbpd+tftlcd_dev.height+tftlcd_dev.vfpd;//一帧画面的总时间
LCDIF->VDCTRL2 = (tftlcd_dev.hspw+tftlcd_dev.hbpd+tftlcd_dev.width+tftlcd_dev.hfpd )|(tftlcd_dev.hspw<<18);
LCDIF->VDCTRL3 = (tftlcd_dev.vspw+tftlcd_dev.vbpd)|((tftlcd_dev.hspw+tftlcd_dev.hbpd)<<16);
LCDIF->VDCTRL4 = (tftlcd_dev.width)|(1<<18);
LCDIF->CUR_BUF = (unsigned int)tftlcd_dev.framebuffer;//放起始地址
LCDIF->NEXT_BUF = (unsigned int)tftlcd_dev.framebuffer;
lcd_enable();
delay(20);
lcd_clear(LCD_WHITE);
}
/*IO初始化*/
void lcdgpio_init(void)
{
/* 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);
/*GPIO电气属性*/
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_UART1_CTS_B_GPIO1_IO18,0xF080);
/*2.背光设置*/
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_GPIO1_IO08,0);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08,0XB9);
gpio_config_t bl_config;
bl_config.section= gpio_out;
bl_config.mode=1;
gpio_init(GPIO1,8,&bl_config);
}
/*像素时钟第初始化,LCD频率=24×loopDiv/prediv/div,后面两个都是分频值*/
void lcd_clock_init(unsigned char loopDiv,unsigned char prediv,unsigned char div)
{
/*不用小数分频器*/
CCM_ANALOG->PLL_VIDEO_NUM = 0;
CCM_ANALOG->PLL_VIDEO_DENOM = 0;
CCM_ANALOG->PLL_VIDEO =(1<<13)|(2<<19)|(loopDiv<<0);
CCM_ANALOG->MISC2 &=~(3<<30);
CCM_ANALOG->MISC2 = 0 << 30;
CCM->CSCDR2 &=~(7<<15);
CCM->CSCDR2 |=(2<<15);
CCM->CSCDR2 &=~(7<<12);
CCM->CSCDR2 |=(prediv-1)<<12;
CCM->CBCMR &=~(7<<23);
CCM->CBCMR |=(div-1)<<23;
CCM->CSCDR2 &=~(7<<9);
CCM->CSCDR2 |= (0 << 9);
}
/*复位*/
void lcd_reset(void)
{
LCDIF->CTRL =1<<31;
}
/*停止复位*/
void lcd_noreset(void)
{
LCDIF->CTRL = 0<<31;
}
/*使能LCD控制器*/
void lcd_enable(void)
{
LCDIF->CTRL |= 1<<0;
}
unsigned short lcd_read_panelid(void)
{
unsigned char idx = 0;
unsigned short idx_result = 0;
/*打开模拟开关*/
IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_GPIO3_IO03,0);
IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_GPIO3_IO03,0X10b0);
/*GPIO初始化*/
gpio_config_t lcd_config;
lcd_config.section= gpio_out;
lcd_config.mode=1;
gpio_init(GPIO3,3,&lcd_config);
/*读取屏幕ID*/
IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_GPIO3_IO12,0);//B7
IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_GPIO3_IO20,0);//G7
IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_GPIO3_IO28,0);//R7
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_GPIO3_IO12,0Xf080);//B7
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_GPIO3_IO20,0Xf080);//G7
IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_GPIO3_IO28,0Xf080);//R7
lcd_config.section= gpio_in;//设置为输入
gpio_init(GPIO3,12,&lcd_config);
gpio_init(GPIO3,20,&lcd_config);
gpio_init(GPIO3,28,&lcd_config);
idx = (unsigned char)gpio_read(GPIO3,28);//idx= R7: G7: B7:
idx |= (unsigned char)gpio_read(GPIO3,20)<<1;
idx |= (unsigned char)gpio_read(GPIO3,12)<<2;
switch(idx)
{
case 0:
idx_result = ATK4342;
break;
case 1:
idx_result = ATK7084;
break;
case 2:
idx_result = ATK7016;
break;
case 5:
idx_result = ATK1018;
break;
case 4:
idx_result = ATK4384;
break;
default:
break;
}
return idx_result;
}
/*画点函数*/
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 unsigned int lcd_readpoint(unsigned int x,unsigned int y)
{
return *(unsigned int *)((unsigned int)tftlcd_dev.framebuffer+tftlcd_dev.pixsize*(tftlcd_dev.width*y+x));
}
/*清除屏幕*/
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.height*tftlcd_dev.width);
for(i=0;i<num;i++)
{
startaddr[i]=color;
}
}
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);
}
}
主函数:
c
#include "main.h"
#include "dsp_clk.h"
#include "dsp_led.h"
#include "dsp_delay.h"
#include "beep.h"
#include "dsp_key.h"
#include "dsp_int.h"
#include "dsp_exti.h"
#include "dsp_epit.h"
#include "dsp_uart.h"
#include "stdio.h"
#include "dsp_lcd.h"
#include "dsp_lcdapi.h"
unsigned int show_color[8]={LCD_BLACK,LCD_YELLOW,LCD_BLUE,
LCD_GREEN,LCD_LIGHTRED,LCD_LIGHTYELLOW,
LCD_GRAY,LCD_ORANGE};
int main(void)
{
int b=0;
unsigned char kkkk=0;
int_init();//中断初始化
imx6u_clkinit();//时钟初始化
key_init();//按键初始化
clk_enable();//时钟初始化
uart_init();//串口初始化
beep_init();//凤鸣器初始化
led_init();//led初始化
lcd_init();//LCD读ID号
tftlcd_dev.forecolor = LCD_RED;
tftlcd_dev.backcolor = LCD_WHITE;
// lcd_show_string(10,40,260,32,32,(char *)"Fucking high");
while(1)
{
tftlcd_dev.forecolor = LCD_RED;
lcd_show_string(100,100,240,32,32,(char *)"2025.1.1");
// lcd_clear(show_color[b]);
// b++;
// if(b==8) b=0;
led_mode(kkkk);
delay(1000);
kkkk = !kkkk;
}
return 0;
}
三,总结
1.c语言知识
c
int aaaa= 0x11223344
*(unsigned int *)a=5
这个意思是先把aaaa强制类型转换成无符号整形指针,即地址为0X11223344,在前面再加*,意思就是这个指针指向的内容,即先强制转化为指针后,再往这个地址对应的内容进行赋值。