LCD驱动详解

Posted lilto

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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驱动详解的主要内容,如果未能解决你的问题,请参考以下文章

Linux 帧缓冲子系统详解:LCD介绍framebuffer驱动框架LCD驱动源码分析

16.Linux-LCD驱动(详解)

LCD驱动

LCD驱动源码分析(s3cfb.c)

《Linux驱动》iTop4412开发板LCD驱动 详细分析

Arduino TFT_eSPI库来驱动SPI接口的LCD显示文字详解