參考文檔:《液晶屏.pdf》《S3C2440用戶手冊》《JZ2440-V3原理圖》 linux
frame buffer: 顯存,用於存放LCD顯示數據;frame buffer經過LCD控制器和LCD Panel創建一一映射關係; app
LCD控制器: 參考LCD用戶手冊,配置LCD控制器,用於發出LCD控制信號,驅動LCD顯示; ide
掃描方向: 如圖①所示,由start到end的掃描方向是:從左到右,從上到下(掃描方向的一種); 函數
HSYNC: 行同步信號,用於行切換,一行掃描結束,須要掃描新行時,須要先發送行同步信號; this
VSYNC: 列同步信號,用於列切換,一幀掃描結束,須要掃描新的一幀時,須要先發送列同步信號; spa
時鐘信號: 每來一個時鐘,掃描的點移位一; 3d
原理圖——管腳說明 調試
硬件操做配置 orm
①配置LCD控制引腳; blog
②根據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:\Users\liang\Desktop\linux-2.6.22.6\drivers\video\s3c2410fb.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 /* 一、出入口函數 */
104 static int lcd_init(void)
105 {
106 /* 二、分配一個fb_info結構體 */
107 lcd_info = framebuffer_alloc(0, NULL);
108 /******** 2 end ********/
109
110 /* 三、設置 */
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 /* 四、硬件相關設置 */
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 /* 五、註冊 */
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'\n')