LCD是怎么驱动的

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCD是怎么驱动的相关的知识,希望对你有一定的参考价值。

LCD的工作原理

我们很早就知道物质有固态、液态、气态三种型态。液体分子质心的排列虽然不具有任何规律性,但是如果这些分子是长形的(或扁形的),它们的分子指向就可能有规律性。于是我们就可将液态又细分为许多型态。分子方向没有规律性的液体我们直接称为液体,而分子具有方向性的液体则称之为“液态晶体”,又简称“液晶”。液晶产品其实对我们来说并不陌生,我们常见到的手机、计算器都是属于液晶产品。液晶是在1888年,由奥地利植物学家Reinitzer发现的,是一种介于固体与液体之间,具有规则性分子排列的有机化合物。一般最常用的液晶型态为向列型液晶,分子形状为细长棒形,长宽约1nm~10nm,在不同电流电场作用下,液晶分子会做规则旋转90度排列,产生透光度的差别,如此在电源ON/OFF下产生明暗的区别,依此原理控制每个像素,便可构成所需图像。
1. 被动矩阵式LCD工作原理
TN-LCD、STN-LCD和DSTN-LCD之间的显示原理基本相同,不同之处是液晶分子的扭曲角度有些差别。下面以典型的TN-LCD为例,向大家介绍其结构及工作原理。
在厚度不到1厘米的TN-LCD液晶显示屏面板中,通常是由两片大玻璃基板,内夹着彩色滤光片、配向膜等制成的夹板? 外面再包裹着两片偏光板,它们可决定光通量的最大值与颜色的产生。彩色滤光片是由红、绿、蓝三种颜色构成的滤片,有规律地制作在一块大玻璃基板上。每一个像素是由三种颜色的单元(或称为子像素)所组成。假如有一块面板的分辨率为1280×1024,则它实际拥有3840×1024个晶体管及子像素。 每个子像素的左上角(灰色矩形)为不透光的薄膜晶体管,彩色滤光片能产生RGB三原色。每个夹层都包含电极和配向膜上形成的沟槽,上下夹层中填充了多层液晶分子(液晶空间不到5×10-6m)。在同一层内,液晶分子的位置虽不规则,但长轴取向都是平行于偏光板的。另一方面,在不同层之间,液晶分子的长轴沿偏光板平行平面连续扭转90度。其中,邻接偏光板的两层液晶分子长轴的取向,与所邻接的偏光板的偏振光方向一致。在接近上部夹层的液晶分子按照上部沟槽的方向来排列,而下部夹层的液晶分子按照下部沟槽的方向排列。最后再封装成一个液晶盒,并与驱动IC、控制IC与印刷电路板相连接。
在正常情况下光线从上向下照射时,通常只有一个角度的光线能够穿透下来,通过上偏光板导入上部夹层的沟槽中,再通过液晶分子扭转排列的通路从下偏光板穿出,形成一个完整的光线穿透途径。而液晶显示器的夹层贴附了两块偏光板,这两块偏光板的排列和透光角度与上下夹层的沟槽排列相同。当液晶层施加某一电压时,由于受到外界电压的影响,液晶会改变它的初始状态,不再按照正常的方式排列,而变成竖立的状态。因此经过液晶的光会被第二层偏光板吸收而整个结构呈现不透光的状态,结果在显示屏上出现黑色。当液晶层不施任何电压时,液晶是在它的初始状态,会把入射光的方向扭转90度,因此让背光源的入射光能够通过整个结构,结果在显示屏上出现白色。为了达到在面板上的每一个独立像素都能产生你想要的色彩,多个冷阴极灯管必须被使用来当作显示器的背光源。
2. 主动矩阵式LCD工作原理
TFT-LCD液晶显示器的结构与TN-LCD液晶显示器基本相同,只不过将TN-LCD上夹层的电极改为FET晶体管,而下夹层改为共通电极。
TFT-LCD液晶显示器的工作原理与TN-LCD却有许多不同之处。TFT-LCD液晶显示器的显像原理是采用“背透式”照射方式。当光源照射时,先通过下偏光板向上透出,借助液晶分子来传导光线。由于上下夹层的电极改成FET电极和共通电极,在FET电极导通时,液晶分子的排列状态同样会发生改变,也通过遮光和透光来达到显示的目的。但不同的是,由于FET晶体管具有电容效应,能够保持电位状态,先前透光的液晶分子会一直保持这种状态,直到FET电极下一次再加电改变其排列方式为止。
LCD是在背面开一个灯源,然后需要多少信信号就开多少个窗户(液晶)让光透过,一个像素就是三个窗户(RGB)组成。
LCD 是靠电压驱动的,几乎不消耗功率
参考技术A

用LCD驱动IC驱动的。

LCD驱动详解

参考文档:《液晶屏.pdf》《S3C2440用户手册》《JZ2440-V3原理图》

?

技术图片

frame buffer: 显存,用于存放LCD显示数据;frame buffer通过LCD控制器和LCD Panel建立一一映射关系;

LCD控制器: 参考LCD用户手册,配置LCD控制器,用于发出LCD控制信号,驱动LCD显示;

扫描方向: 如图①所示,由start到end的扫描方向是:从左到右,从上到下(扫描方向的一种);

HSYNC: 行同步信号,用于行切换,一行扫描结束,需要扫描新行时,需要先发送行同步信号;

VSYNC: 列同步信号,用于列切换,一帧扫描结束,需要扫描新的一帧时,需要先发送列同步信号;

时钟信号: 每来一个时钟,扫描的点移位一;

? ?

原理图——管脚说明

技术图片

?

技术图片

? ?

技术图片

?

?

硬件操作配置

①配置LCD控制引脚;

②根据LCD手册,配置LCD控制器;

③分配Frame buffer,并映射到LCD Panel;

? ?

《液晶屏.pdf》

Block Diagram

技术图片

? ?

? ?

Interface Timing

技术图片

? ?

Driver Timing

技术图片

? ?

? ?

Timing Chart

a、

技术图片

? ?

b、

技术图片

?

《S3C2440用户手册》

LCD CONTROLLER SPECIAL REGISTERS

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

? ?

技术图片

?

技术图片

技术图片

?

MEMORY DATA FORMAT (TFT)

技术图片

技术图片

?

技术图片

?

驱动程序

1 /*
2 * 参考内核自带的lcd驱动程序:
3 * C:UsersliangDesktoplinux-2.6.22.6driversvideos3c2410fb.c
4 * 《液晶屏.pdf》、《s3c2440 用户手册》
5 */
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8 #include <linux/errno.h>
9 #include <linux/string.h>
10 #include <linux/mm.h>
11 #include <linux/slab.h>
12 #include <linux/delay.h>
13 #include <linux/fb.h>
14 #include <linux/init.h>
15 #include <linux/dma-mapping.h>
16 #include <linux/interrupt.h>
17 #include <linux/workqueue.h>
18 #include <linux/wait.h>
19 #include <linux/platform_device.h>
20 #include <linux/clk.h>
21 ????????
22 #include <asm/io.h>
23 #include <asm/uaccess.h>
24 #include <asm/div64.h>
25 ????????
26 #include <asm/mach/map.h>
27 #include <asm/arch/regs-lcd.h>
28 #include <asm/arch/regs-gpio.h>
29 #include <asm/arch/fb.h>
30
31 struct lcd_regs {
32 ????????unsigned long????????lcdcon1;
33 ????????unsigned long????????lcdcon2;
34 ????????unsigned long????????lcdcon3;
35 ????????unsigned long????????lcdcon4;
36 ????????unsigned long????????lcdcon5;
37 unsigned long????????lcdsaddr1;
38 unsigned long????????lcdsaddr2;
39 unsigned long????????lcdsaddr3;
40 unsigned long????????redlut;
41 unsigned long????????greenlut;
42 unsigned long????????bluelut;
43 unsigned long????????reserved[9];
44 unsigned long????????dithmode;
45 unsigned long????????tpal;
46 unsigned long????????lcdintpnd;
47 unsigned long????????lcdsrcpnd;
48 unsigned long????????lcdintmsk;
49 unsigned long????????lpcsel;
50 };
51
52
53 static volatile unsigned long *gpb_con;
54 static volatile unsigned long *gpb_dat;
55
56 static volatile unsigned long *gpc_con;
57 static volatile unsigned long *gpd_con;
58 static volatile unsigned long *gpg_con;
59
60 static volatile struct lcd_regs* lcd_regs;
61
62 static u32 pseudo_palette[16];//假的调色板
63
64 static struct fb_info *lcd_info;
65
66 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
67 {
68 ????????chan &= 0xffff;
69 ????????chan >>= 16 - bf->length;
70 ????????return chan << bf->offset;
71 }
72
73 static int lcdfb_setcolreg(unsigned int regno, unsigned int red,
74 ???????????????????????? unsigned int green, unsigned int blue,
75 ???????????????????????? unsigned int transp, struct fb_info *info)
76 {
77 ????????unsigned int val;
78
79 ????????if (regno > 16)
80 ????????{
81 ????????????????return -1;
82 ????????}
83
84 ????????//用三原色构造出val
85 ????????val = chan_to_field(red, &info->var.red);
86 ????????val |= chan_to_field(green, &info->var.green);
87 ????????val |= chan_to_field(blue, &info->var.blue);
88
89 ????????pseudo_palette[regno] = val;????????//调好颜色,放回调色板
90
91 ????????return 0;
92 }
93
94
95 static struct fb_ops lcd_fbops = {
96 ????????.owner????????????????= THIS_MODULE,
97 ????????.fb_setcolreg????????= lcdfb_setcolreg,//假的调色板的调色函数
98 ????????.fb_fillrect????????= cfb_fillrect,????????????????//
99 ????????.fb_copyarea????????= cfb_copyarea,
100 ????????.fb_imageblit????????= cfb_imageblit,
101 };
102
103 /* 1、出入口函数 */
104 static int lcd_init(void)
105 {
106 ????????/* 2、分配一个fb_info结构体 */
107 ????????lcd_info = framebuffer_alloc(0, NULL);
108 ????????/******** 2 end ********/
109
110 ????????/* 3、设置 */
111 ????????/* 设置固定的参数:lcd_info->fix */
112 ????????strcpy(lcd_info->fix.id, "mylcd");????????????????????????????????????????//名字
113 ????????lcd_info->fix.smem_len ????????????????= 240*320*16/8;????????????????????????//framebuffer长度(240*320 dots,lrgb565: 16bit/dots)
114 ????????lcd_info->fix.type ????????????????????????= FB_TYPE_PACKED_PIXELS;
115 ????????lcd_info->fix.visual????????????????= FB_VISUAL_TRUECOLOR;????????//颜色深度(tft-lcd设置为真彩)
116 ????????lcd_info->fix.line_length????????= 240*16/8;????????????????????????????????//framebuffer中每一行(line)占据的字节数;240*2(2:16bit/8)????????????????
117
118 ????????/* 设置可变的参数 */
119 ????????lcd_info->var.xres ????????????????????????= 240;????????//x方向的分辨率
120 ????????lcd_info->var.yres ????????????????????????= 320;????????//y方向的分辨率
121 ????????lcd_info->var.xres_virtual ????????= 240;????????//x方向的虚拟分辨率
122 ????????lcd_info->var.yres_virtual ????????= 320;????????//y方向的虚拟分辨率
123 ????????lcd_info->var.bits_per_pixel= 16;????????//每个像素点16位(rgb565)
124 ????????lcd_info->var.activate????????????????= FB_ACTIVATE_NOW;
125
126 ????????// 颜色数据的位分配 rgb:565
127 ????????lcd_info->var.red.offset????????= 11;????????//(5)bit11 - bit15
128 ????????lcd_info->var.red.length????????= 5;????????
129 ????????lcd_info->var.green.offset????????= 5;????????//(6)bit5 - bit10
130 ????????lcd_info->var.green.length????????= 6;
131 ????????lcd_info->var.blue.offset????????= 0;????????//(5)bit0 - bit4
132 ????????lcd_info->var.blue.length????????= 5;
133 ????????
134 ????????/* 设置操作函数 */
135 ????????lcd_info->fbops = &lcd_fbops;
136
137 ????????/* 其他设置 */
138 ????????lcd_info->pseudo_palette = pseudo_palette;????????//假的调色板
139 ????????lcd_info->screen_size = 240*320*16/8;????????????????//
140 ????????/******** 3 end ********/
141
142 ????????/* 4、硬件相关设置 */
143 ????????/* 配置gpio用于lcd */
144 ????????gpc_con = ioremap(0x56000020, 4);
145 ????????gpd_con = ioremap(0x56000030, 4);
146 ????????gpg_con = ioremap(0x56000060, 4);
147 ????????gpb_con = ioremap(0x56000010, 8);
148 ????????gpb_dat = gpb_con + 1;
149
150 ????????//GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND
151 ????????*gpc_con = 0xaaaaaaaa;
152
153 ????????//GPIO管脚用于VD[23:8]
154 ????????*gpd_con = 0xaaaaaaaa;
155
156 ????????//GPB0设置为输出引脚
157 ????????*gpb_con &= ~(3);
158 ????????*gpb_con |= 1;
159 ????????*gpb_dat &= ~1;????????????????//输出低电平
160
161 ????????//GPG4用作LCD_PWREN
162 ????????*gpg_con |= (3<<8);
163 ????????
164 ????????/* 根据lcd手册设置lcd控制器 */
165 ????????lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
166 ????????lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);
167 ????????lcd_regs->lcdcon2 = (3<<24) | (319<<14) | (1<<6) | (0<<0);
168 ????????lcd_regs->lcdcon3 = (16<<19) | (239<<8) | (10<<0);
169 ????????lcd_regs->lcdcon4 = 4;
170 ????????lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0);
171 ????????
172 ????????/* 分配显存(framebuffer),并把地址告诉lcd控制器 */
173 ????????// 虚拟地址 大小 物理地址
174 ????????lcd_info->screen_base = dma_alloc_writecombine(NULL, lcd_info->fix.smem_len, &lcd_info->fix.smem_start, GFP_KERNEL);
175 ????????
176 ????????lcd_regs->lcdsaddr1 = (lcd_info->fix.smem_start >> 1) & ~(3<<30);
177 ????????lcd_regs->lcdsaddr2 = ((lcd_info->fix.smem_start + lcd_info->fix.smem_len) >> 1) & 0x1fffff;
178 ????????lcd_regs->lcdsaddr3 = (240*16/16); /* 一行的长度(单位: 2字节) */????????
179 ????????
180 ????????/* 启动LCD */
181 ????????lcd_regs->lcdcon1 |= (1<<0); ????????//使能LCD本身
182 ????????lcd_regs->lcdcon5 |= (1<<3);????????
183 ????????*gpb_dat |= 1; ????????????????????????//输出高电平, 使能背光
184 ????????/******** 4 end ********/
185 ????????
186 ????????/* 5、注册 */
187 ????????register_framebuffer(lcd_info);
188 ????????/******** 5 end ********/
189
190 ????????return 0;
191 }
192
193 static void lcd_exit(void)
194 {
195 ????????dma_free_writecombine(NULL, lcd_info->fix.smem_len, lcd_info->screen_base, lcd_info->fix.smem_start);
196 ????????unregister_framebuffer(lcd_info);
197 ????????/* 关闭LCD */
198 ????????lcd_regs->lcdcon1 &= ~(1<<0);
199 ????????lcd_regs->lcdcon5 &= ~(1<<3);
200 ????????*gpb_dat &= ~(1<<0);
201
202 ????????iounmap(lcd_regs);
203 ????????iounmap(gpc_con);
204 ????????iounmap(gpd_con);
205 ????????iounmap(gpg_con);
206 ????????iounmap(gpb_con);
207
208 ????????framebuffer_release(lcd_info);
209 ????????return;
210 }
211
212 module_init(lcd_init);
213 module_exit(lcd_exit);
214 MODULE_LICENSE("GPL");
215 /******** 1 end ********/

? ?

附:

1 /**
2 * framebuffer_alloc - creates a new frame buffer info structure
3 *
4 * @size: size of driver private data, can be zero
5 * @dev: pointer to the device for this fb, this can be NULL
6 *
7 * Creates a new frame buffer info structure. Also reserves @size bytes
8 * for driver private data (info->par). info->par (if any) will be
9 * aligned to sizeof(long).
10 *
11 * Returns the new structure, or NULL if an error occured.
12 *
13 */
14 struct fb_info *framebuffer_alloc(size_t size, struct device *dev);

?

调试

pc-linux:

cd /work/system/linux-2.6.22.6/

make menuconfig

(lcd驱动以模块方式编译)

make uImage

make modules

cp /work/system/linux-2.6.22.6/drivers/video/cfbcopyarea.ko /work/nfs_root

cp /work/system/linux-2.6.22.6/drivers/video/cfbfillrect.ko /work/nfs_root

cp /work/system/linux-2.6.22.6/drivers/video/cfbimgblt.ko /work/nfs_root

cp /work/system/linux-2.6.22.6/arch/arm/boot/uImage /work/nfs_root/uImage_nolcd

? ?

board-u-boot:

nfs 30000000 192.168.0.103:/work/nfs_root/uImage_nolcd

bootm 30000000

? ?

board-linux:

mount -t nfs -o nolock,vers=2 192.168.0.103:/work/nfs_root /mnt

cd /mnt

insmod cfbcopyarea.ko

insmod cfbfillrect.ko

insmod cfbimgblt.ko

insmod lcd.ko

echo hello world! 2019/10/18 > /dev/tty1

技术图片

? ?

cat test.bmp > /dev/fb0

技术图片

? ?

vi /etc/inittab

#+++

tty1::askfirst:-/bin/sh

? ?

reboot

insmod buttons.ko

insmod cfbcopyarea.ko

insmod cfbfillrect.ko

insmod cfbimgblt.ko

insmod lcd.ko

? ?

<input way:key>

KEY_L KEY_S KEY_ENTER(ls‘ ‘)

技术图片

??

以上是关于LCD是怎么驱动的的主要内容,如果未能解决你的问题,请参考以下文章

LCD段码屏可以不用驱动芯片,直接单片机驱动吗

lcd1602 Arduino 为啥显示不了字

LCD驱动应该怎么写?–基于stm32F407 [复制链接]

一个单片机驱动LCD编程思路

一个单片机驱动LCD编程思路

LCD驱动端与设备端名称匹配过程分析(Tiny4412)