Linux的LCD驱动源码分析及移植
理解LCD屏幕的驱动原理与调试过程,示例的驱动IC为GC9308,展示整个屏幕的驱动过程。
理解LCD屏幕的驱动原理与调试过程,⽰例的驱动IC为GC9308,展⽰整个屏幕的驱动过程。
起因最近拿到了⼀个⽐较新的驱动 IC 的 LCD 了,此前 K210 上⾯使⽤的都是 ST7789V ILI9342C SH1106 这类驱动 IC 的屏幕模块。
这次来了⼀个 GC9308 ,我想我需要认识⼀下屏幕驱动的整体架构,也就是拿起数据⼿册当作学习教材来学了,实际上学完以后,懂了以后都不难,重点在如何总结这些屏幕的驱动逻辑,以此打下往后的屏幕驱动理解基础。
我需要读懂图像的⼆进制定义、还有传输⽅式,我找了⼀本中⽂的屏幕数据⼿册来读,了解⼀下相关的流程和细节本⽂我只会交待软件层⾯的理解,硬件⽅⾯的定义和特性我⽆法给出准确的解释,姑不会提及。
屏幕的发展历程让我们看⼀下这个⼤哥的故事,就很好的说明了这段 LCD MCU 发展的历史。
记得在很早的时候,那时候还都是FSTN的显⽰屏满天飞的时候(也是⼩弟刚刚毕业开始作⼿机的时候)。
LCD的驱动电路有很多是两⽚芯⽚的,⼀⽚LCDC,⼀⽚LCD Driver,⼀般的LCDC⾥⾯有⼀个display的buffer。
LCDDriver是电路驱动液晶显⽰部分的电路,没有什么好讲的。
更早的时候,LCD上就⼀⽚LCDDriver就⾏了,程序员需要控制两个(H,V)场扫描信号,⽽且程序员希望在某个坐标显⽰,都需要编程控制驱动电路来实现,后来发现显⽰屏越来越⼤,⽽MCU以及程序员没有这个能⼒和精⼒来对LCD进⾏这类的同步控制,于是LCDC就诞⽣出来承担起这些个功能。
后来加上了buffer,就是说程序员可以把⼤批的显⽰内容以显⽰矩阵(display matrix)的形式写到buffer⾥,让LCDC来读取buffer⾥的数据再由LCDDriver显⽰到显⽰屏上。
后来这个buffer越来越⼤,除了显⽰矩阵以外还放很多命令,所以也不能⽼把它笼统的叫buffer啊,所以就对放显⽰矩阵的存储空间有了⼀个专⽤的名字叫做GRAM。
LCD12864驱动源代码
Transfer_command(0xa0); /*列扫描顺序:从左到右*/
Transfer_command(0xaf); /*开显示*/
clear_screen();
}
//===============clear all dot martrics=============
Transfer_command(((column>>4)&0x0f)+0x10); //设置列地址的高4 位
Transfer_command(column&0x0f); //设置列地址的低4 位
}
/*=========延时=====================*/
void Delay(int i)
{
char i;
CS_0(); //CS_PIN=0
RS_0(); //CS_PIN=0
for(i=0;i<8;i++)
{
SCLK_0();
if(data1&0x80) DIN_1();
else DIN_0();
SCLK_1();
data1=data1<<=1;
void Initial_Lcd()
{
RST_0(); //reset=0
P2DIR |=RST_PIN | SPI_MOSI_PIN| SPI_CLK_PIN|RS_PIN|CS_PIN ;
Delay(50);
RST_1(); //reset=1
Delay(50);
{
CS_0(); //CS_PIN=0
DM9000驱动移植详解及问题点
OK6410、2.6.36内核移植,dm9000 驱动移植,详细!分类:嵌入式学习Linux学习2012-04-27 00:54 3004人阅读评论(7) 收藏举报interfaceccompressionresourcesstructtable还是先来吐槽:本来我是在上一个星期的周末已经把Linux2.6.34.11 的驱动已经成功的移植到,OK6410 的开发板上的,并且能够启动主机上的NFS 根文件系统,可是我在周一的时候,开始学习LCD 的驱动程序,在修改内核文件的时候,有几处错误修改,将原来自己做的2.6.34.11 的内核源码搞的乱七八糟的,在这里还是自己在修改内核的时候没有提注重注释,并且没有记录下来自己的操作步骤,以至于我没办法,恢复2.6.34 的内核,所以也就只能重新先开始最基础的内核移植了。
这次我选择的是2.6.36.2 的内核,谁知到一开始移植就出现一大堆问题。
在这里我不得不说,飞凌开发人员对内核修改的代码,管理真的是太扯了,自己在注销任何一个设备是没有一点点注释,就把这个设备原有的线性地址分配给其它设备了,让我让我们这些菜鸟干看着一大堆的报错信息顶个什么用,真的是伤不起。
好了不乱扯了,现在开始记录。
我的开发环境是:VMware Ubuntu 10.10 。
OK6410 A版256M+2G 的开发板。
主机系统:XP。
Uboot:飞凌提供的Uboot。
参考内核:飞凌提供的Forlinx 的2.6.36.2 内核操作步骤以下./ 均代表你的内核根目录1、修改./Makefile191 ARCH ?=arm // 指定cpu类型,arm后面不要有空格,要不然编译是会提醒ARCH 不能为一个目录192 CROSS_COMPILE ?=/usr/local/arm/4.2.2-eabi/usr/bin/arm-linux- // 指定交叉编译器的路径,按照你自己的进行指定路径2、先来说说nand flash 的驱动涉及到的文件:MTD 通用nand flash 驱动程序位置:./drivers/mtd/nand/.nand_base.cNAND Flash 的platform 设备信息: ./drivers/mtd/nand/s3c_nand.c有了上面的依赖驱动依赖程序、接下来修改./arch/arm/mach-s3c64xx/mach-smdk6410.c 1) nandflash 驱动,修改方法加载头文件[cpp]view plaincopyprint?1.#include <linux/mtd/mtd.h>2.#include <linux/mtd/partitions.h>3.#include <plat/nand.h> //这些头文件放在./arch/arm/plat-samsung/include/ 下面添加nand 结构体[cpp]view plaincopyprint?1.// add by acanoe first2.extern void s3c64xx_reserve_bootmem(void); //add by acanoe3.4.5.struct mtd_partition ok6410_nand_part[] = {6. {7. .name = "Bootloader",8. .offset = 0,9. .size = (1 * SZ_1M),10. .mask_flags = MTD_CAP_NANDFLASH,11. },12. {13. .name = "Kernel",14. .offset = (1 * SZ_1M),15. .size = (5*SZ_1M) ,16. .mask_flags = MTD_CAP_NANDFLASH,17. },18. {19. .name = "User",20. .offset = (6 * SZ_1M),21. .size = (120*SZ_1M) ,22. },23. {24. .name = "File System",25. .offset = MTDPART_OFS_APPEND,26. .size = MTDPART_SIZ_FULL,27. }28.};29.30.31.static struct s3c2410_nand_set ok6410_nand_sets[] = {32. [0] = {33. .name = "nand",34. .nr_chips = 1,35. .nr_partitions = ARRAY_SIZE(ok6410_nand_part),36. .partitions = ok6410_nand_part,37. },38.};39.40.41.static struct s3c2410_platform_nand ok6410_nand_info = {42. .tacls = 25,43. .twrph0 = 55,44. .twrph1 = 40,45. .nr_sets = ARRAY_SIZE(ok6410_nand_sets),46. .sets = ok6410_nand_sets,47.};48.//add by acanoe first修改 smdk6410_devices[] __initdata = {对照这个结构体将那些进行修改,注意 by acanoe 的语句为修改重点。
MTK详解LCD移植
详解LCD移植1.Make文件设置设置LCDLCD_MODULE = BROADMOBI68_09B_LCM //这个名字可以自己取,但是//这个名字要和\custom\drv\LCD\下的文件夹一致。
//一般可以不用改。
到时直接修改这个文件夹下的代码就行了。
# Based on the LCM solutions (even multiple LCM modules for this project) # SHOULD BE ONE OF THE FOLLOWINGS, based on the LCM# MTKLCM - Mono, 102x64# MTKLCM_COLOR - Color, 120x160, for MT6218_MW001 or MT6205_CEVB# ORDNANCELCM - Mono, 112x64# KLMLCM - Color, 128x128# INFOLCM - Color, 128x128# TOPPOLY_LCM - Color, 128x160, for MT6218B_EVB# SONY_LCMMAIN_LCD_SIZE = 320X480 //查LCD datasheet可以查到分辨率。
# To distinguish the main lcd size.# We can use it to copy the matching resources, such themecomponents.h, Fontres.c, L_xxx.h, etc, to PLUTO_MMI folderSUB_LCD_SIZE = NONE# NONE, 48X64BW, 64X96, 96X64BW, 96X64, 128X128COM_DEFS_FOR_BROADMOBI68_09B_LCM = BROADMOBI68_09B_LCM TFT_MAINLCD //如果//上面的LCD_MOULE设置改了,这个就要跟着该。
LCD驱动代码
1. 驱动代码#include<linux/module.h>#include<linux/kernel.h>#include<linux/fs.h>#include<linux/init.h>#include<linux/delay.h>#include<asm/uaccess.h>#include<asm/irq.h>#include<asm/io.h>#include<linux/device.h>#define DEV_NAME "cdev_leds"#define rGPBCON (*(volatile unsigned *)(base_addr+0))#define rGPBDAT (*(volatile unsigned *)(base_addr+1))#define rGPBUP (*(volatile unsigned *)(base_addr+2))struct class *char_dev_class;static struct class_device *p_class_devs;int major=0;struct file *filp;unsigned int *base_addr=0;#define DEV_SIZE (4)int first_chardev_open(struct inode *inode,struct file *file){printk(KERN_EMERG"open() call\r\n");return 0;}ssize_t first_chardev_read(struct file *file,char __user *buf,ssize_t count,loff_t *f_pos){int retval=0;char led_buffer[DEV_SIZE]={2,2,2,2};printk(KERN_EMERG"read() call\n");led_buffer[0]=!(rGPBDAT&(1<<5));led_buffer[1]=!(rGPBDAT&(1<<6));led_buffer[2]=!(rGPBDAT&(1<<7));led_buffer[3]=!(rGPBDAT&(1<<8));if(*f_pos>=DEV_SIZE)goto out;if(*f_pos+count>DEV_SIZE)count=DEV_SIZE-*f_pos;if(copy_to_user(buf,&led_buffer[0+*f_pos],count)){retval=-EFAULT;goto out;}*f_pos+=count;retval=count;return retval;out:return 0;}ssize_t first_chardev_write(struct file *file,const char __user *buf,size_t count,loff_t *f_pos){char led_buffer[DEV_SIZE]={3,3,3,3};int retval=0;int i=0;printk(KERN_EMERG"write() call\n");if(*f_pos>=DEV_SIZE)goto out;if(*f_pos+count>DEV_SIZE)count=DEV_SIZE-*f_pos;if(copy_from_user((void *)led_buffer[*f_pos],(const void __user *)buf,count)){retval=-EFAULT;goto out;}for(i=0;i<count;i++){if(led_buffer[*f_pos+i]==1)rGPBDAT&=~(1<<(5+*f_pos+i));else if(led_buffer[*f_pos]==0)rGPBDAT|=(1<<(5+*f_pos+i));else{printk("value err!\r\n");goto out;}}*f_pos+=count;retval=count;out:return retval;}int first_chardev_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg){printk(KERN_EMERG"ioctrl() call\n");return 0;}int first_chardev_release(struct inode *inode,struct file *file) {printk(KERN_EMERG"release call\n");return 0;}loff_t first_chardev_llseek(struct file *file,loff_t off,int whence) {loff_t newpos=0;int offset=off;printk(KERN_EMERG"llseek call\n");printk(KERN_EMERG"offset:%d;whence:%d\r\n",offset,whence);switch(whence){case SEEK_SET:newpos=offset;printk(KERN_EMERG"SEEK_SET:newpos:%d\n",newpos);break;case SEEK_CUR:newpos=filp->f_pos+offset;printk(KERN_EMERG"SEEK_CUR:newpos:%d\n",newpos);break;case SEEK_END:newpos=4+offset;printk(KERN_EMERG"SEEK_END:newpos:%d\n",newpos);break;default:return -EINVAL;}if(newpos<0)return -EINVAL;filp->f_pos=newpos;return newpos;}static struct file_operations first_chardev_fops={.owner=THIS_MODULE,.open=first_chardev_open,.release=first_chardev_release,.read=first_chardev_read,.write=first_chardev_write,.llseek=first_chardev_llseek,.ioctl=first_chardev_ioctl,};static int __init s3c24xx_leds_init(void){printk(KERN_EMERG"module init mow!\n");base_addr=(unsigned int *)ioremap(0x56000010,16);rGPBCON&=~(3<<10|3<<12|3<<14|3<<16);rGPBCON|=(3<<10|3<<12|3<14|3<<16);rGPBUP&=~(1<<5|1<<6|1<<7|1<<8);rGPBDAT&=~(1<<5|1<<6|1<<7|1<<8);rGPBDAT|=(1<<5|1<<6|1<<7|1<<8);major=register_chrdev(major,DEV_NAME,&first_chardev_fops);printk(KERN_EMERG"major:%d\n",major);char_dev_class=class_create(THIS_MODULE,"myleds");if(IS_ERR(char_dev_class)){printk("Err,failed in creating class.\n");return 0;}p_class_devs=device_create(char_dev_class,NULL,MKDEV(major,0), NULL,DEV_NAME);printk(DEV_NAME"initialized\n");return 0;}static void __exit s3c24xx_leds_exit(void){unregister_chrdev(major,DEV_NAME);//device_unregister(p_class_devs);device_destroy(char_dev_class,MKDEV(major,0));class_destroy(char_dev_class);iounmap(base_addr);}module_init(s3c24xx_leds_init);module_exit(s3c24xx_leds_exit);MODULE_AUTHOR("XYD");MODULE_VERSION("1.0");MODULE_DESCRIPTION("S3C2440 LED Driver");MODULE_LICENSE("GPL");2.Makefile代码obj-m:=005th_led_cdev.oKDIR:=/lib/modules/$(shell uname -r)/buildall:make -C $(KDIR) M=$(PWD) modules#cp 005th_led_cdev.ko 005th_led_cdev_test/opt/s3c2440/root_nfs/home/#rm -rf *.o *.mod.o *.symvers .*.o *.cmd modules.order *.bak.tmp_versionsclean:make -C $(KDIR) M=$(PWD) cleanrm -rf *.ko *.o *.mod.o *.mod.c *.symvers .*.o *.cmd modules.order *.bak,tmp_versions *~ *.markers3.测试代码#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<sys/ioctl.h>#define DEV_NAME "/dev/cdev_leds"int main(int argc,char *argv[]){int fd=0;int ret=0;int i=0;int pos=0;unsigned char recv_buf[10]={2,2,2,2};unsigned char send_buf[10]={0,1,0,1};fd=open(DEV_NAME,O_RDWR);if(fd<0){printf(DEV_NAME"can not open devce!\n");prrror("open:");exit(0);}for(i=0;i<4;i++){ret=write(fd,&send_buf[i],1);printf("ret: %d\n",ret);sleep(1);}pos=lseek(fd,1,SEEK_SET);printf("ret:%d\n",ret);sleep(1);ret=read(fd,&recv_buf[pos],4-pos);printf("%d;%d;%d;%d\n",recv_buf[0],recv_buf[1],recv_buf[2],recv_buf[3]);if(recv_buf[0]==0)printf("led0 off\n");else if(recv_buf[0]==1)printf("led0 on\n");elseprintf("led0 status unnowke\n");if(recv_buf[1]==0)printf("led1 off\n");else if(recv_buf[1]==1)printf("led1 on\n");elseprintf("led1 status unnowke\n");if(recv_buf[2]==0)printf("led2 off\n");else if(recv_buf[2]==1)printf("led2 on\n");elseprintf("led2 status unnowke\n");if(recv_buf[3]==0)printf("led3 off\n");else if(recv_buf[3]==1)printf("led3 on\n");elseprintf("led3 status unnowke\n");sleep(1);ret=lseek(fd,SEEK_CUR);printf("ret:%d\n",ret);sleep(1);ret=lseek(fd,SEEK_END);printf("ret:%d\n",ret);sleep(1);return 0;}。
Linux2.6内核移植系列教程
Linux2.6内核移植系列教程第一:Linux 2.6内核在S3C2440平台上移植此教程适合2.6.38之前的版本,其中2.6.35之前使用同一yaffs补丁包,2.6.36--2.6.28 yaffs文件系统有所改变,2.6.39之后的暂时不支持,源码下载请到:/1.解压linux-2.6.34.tar.bz2源码包#tar jxvf linux-2.6.34.tar.bz22.修改linux-2.6.34/Makefile文件,在makefile中找到以下两条信息并做修改ARCH ? =armCROSS_COMPILE?=/usr/local/arm/4.3.2/bin/arm-linux-注意:交叉编译器的环境变量也需要改为4.3.2#export PATH=/usr/local/arm/4.3.2/bin/:$PATH其中ARCH变量用来决定:配置、编译时读取Linux源码arch目录下哪个体系结构的文件PATH 用来决定交叉编译器版本3.修改机器类型ID号Linux源码中支持多种平台的配置信息,内核会根据bootloader传进来的mach-types决定那份平台的代码起作用,本人手里的板子是仿照三星公司官方给出的demo板改版而来,所以采用arch/arm/mach-s3c2440/mach-smdk2440.c此配置文件,打开此文件,翻到最后,有以下信息:MACHINE_START(S3C2440, "SMDK2440")/* Maintainer: Ben Dooks <ben@> */.phys_io= S3C2410_PA_UART,.io_pg_offst= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,.boot_params= S3C2410_SDRAM_PA + 0x100,.init_irq= s3c24xx_init_irq,.map_io= smdk2440_map_io,.init_machine= smdk2440_machine_init,.timer= &s3c24xx_timer,MACHINE_ENDMACHINE_START(S3C2440, "SMDK2440")决定了此板子的mach-types,可以在以下文件中找到S3C2440对应的具体数字,"arch/arm/tools/mach-types"文件查找S3C2440,362,这里刚好与我们的bootloader相同,所以不用做修改,直接保存退出即可,如果不同则根据bootloader的内容修改此文件,或根据此文件修改boorloader的内容(在vivi中可通过param show查看,u-boot在Y:\test\u-boot_src\u-boot_edu-2010.06\board\samsung\unsp2440\unsp2440.c文件:gd->bd->bi_arch_number = MACH_TYPE_S3C2440;中决定)。
文档:、linux-308内核I2C触摸屏移植
Linux3.0.8平台搭建移植文档——I2C触摸屏移植1.I2C子系统goodix电容屏采用I2C接口与处理器连接,我们要首先确保linux内核拥有对I2C子系统的支持,下面我们从子系统的配置和电容屏驱动两个方面进行移植修改1)配置I2C子系统支持#make menuconfigDevice Drivers ---><*> I2C support --->[*] Enable compatibility bits for old user-space (NEW)<*> I2C device interface< > I2C bus multiplexing support (NEW)[*] Autoselect pertinent helper modules (NEW)I2C Hardware Bus support --->进入I2C Hardware Bus support选项,选中以下内容:*** I2C system bus drivers (mostly embedded / system-on-chip) ***< > Synopsys DesignWare (NEW)<*> GPIO-based bitbanging I2C< > OpenCores I2C Controller (NEW)< > PCA9564/PCA9665 as platform device (NEW)<*> S3C2410 I2C Driver< > Simtec Generic I2C interface (NEW)...2.GOODIX电容屏移植1)添加goodix电容屏驱动将“goodix_touch.c”文件copy到drivers/input/touchscreen/目录下,并将"goodix_touch.h"、"goodix_queue.h"文件copy到include/linux/目录下,并修改Kconfig文件及Makefile文件支持触摸屏驱动的配置和编译#vi driver/input/touchscreen/Kconfig在config TOUCHSCREEN_TPS6507X选项的后面添加以下内容:config TOUCHSCREEN_GOODIXtristate "GOODIX based touchscreen"depends on I2ChelpIt is a android driver to support Gooidx's touchscreen whose nameis guitar on s5pv210 platform. The touchscreen can support multi-touch not more than two fingers.Say Y here to enable the driver for the touchscreen on theS5V SMDK board.If unsure, say N.To compile this driver as a module, choose M here:the module will be called goodix_touch.ko.#vi driver/input/touchscreen/Makefile在文件最后添加如下内容:obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_touch.o2)添加i2c_board_info资源(电容屏)#vi arch/arm/mach-s5pv210/mach-smdkv210.c在smdkv210_i2c_devs0结构体数组定义中添加以下内容:...{ I2C_BOARD_INFO("24c08", 0x50), }, /* Samsung S524AD0XD1 */ { I2C_BOARD_INFO("wm8580", 0x1b), },{I2C_BOARD_INFO("Goodix-TS", 0x55),.irq = IRQ_EINT(4),},...3)配置电容屏选项#make menuconfigDevice Drivers --->Input device support --->...[*] Touchscreens ---><*> GOODIX based touchscreen4)make将在arch/arm/boot/下生成编译好的可执行程序zImage下载到开发板即可,执行命令“cat /dev/input/event0”,然后用手触摸屏幕会在终端看到输出打印的乱码信息,表示移植成功,如果没有打印信息或没有“/dev/input/event0”这个设备说明移植失败。
lcd驱动分析文档
嵌入式linux中的lcd驅動分析作者:傑洲村的木棉學校:廣東工業大學QQ:568109894在嵌入式linux中,lcd和觸控式螢幕驅動都是字元驅動,採用“檔層-驅動層”的介面方式,本文檔中分析的lcd驅動是針對linux2.6.13內核的,本人用的開發板是qq2440,lcd是三星的LTV3500V(帶觸控式螢幕的),具體分析的文件:是"include/linux/fb.h","drivers/video/s3c2410fb.h","drivers/video/s3c2410fb.c","drivers/video/fbmem.c","/include/asm/arch- s3c2410.fb.h(些標頭檔是針對s3c2440或s3c2410晶片的)",“/home/linux/5/kernel-2.6.13/arch/arm/mach-s3c2410/mach-smdk2410.c"(驅動移植主要就是要修改這個檔,配置一些參數)。
詳細看一下LCD的驅動,實際上,幾乎lcd設備驅動所要做的所有事情就是填充fb_info結構然後向系統註冊或登出它(1)fb.h包含了framebuffer所用到的結構(2)fbmem.c處於Framebuffer設備驅動技術的中心位置.它為上層應用程式提供系統調用也為下一層的特定硬體驅動提供介面;那些底層硬體驅動需要用到這兒的介面來向系統內核註冊它們自己. fbmem.c 為所有支援FrameBuffer的設備驅動提供了通用的介面,避免重復工作.(3)s3c2410fb.c就是特定硬體驅動(針對s3c2410晶片的),fbmem.c就是溝通應用層跟s3c2410fb.c的橋樑FrameBuffer設備驅動基於如下幾個檔:1)include/linux/fb.h2)drivers/video/fbmem.c3)drivers/video/s3c2410fb.c4)drivers/video/s3c2410fb.h5)include/asm/arch-s3c2410/fb.h現在先來分析這兩個檔:1.fb.h 包含了framebuffer 所用到的結構1)fb_fix_screeninfo 描述顯示卡的屬性,並且系統運行時不能被修改 structfb_fix_screeninfo {char id[16];unsigned long smem_start;/* identification string eg "TT Builtin" */ /* Start of frame buffer mem *//* (physical address) */__u32 smem_len;/* Length of frame buffer mem */__u32 type;__u32 type_aux;/* see FB_TYPE_* *//* Interleave for interleaved Planes */__u32 visual;/* see FB_VISUAL_* */ __u16 xpanstep;/* zero if no hardware panning */__u16 ypanstep;__u16 ywrapstep; __u32 line_length;/* zero if no hardware panning */ /* zero if no hardware ywrap */ /* length of a line in bytes */unsigned long mmio_start;/* Start of Memory Mapped I/O *//* (physical address) */__u32 mmio_len; __u32 accel;/* Length of Memory Mapped I/O *//* Indicate to driver which */ /* specific chip/card we have */};__u16 reserved[3];/* Reserved for future compatibility */2)fb_var_screeninfo 這個結構描述了顯示卡的特性struct fb_var_screeninfo {__u32 xres;__u32 yres;__u32 xres_virtual;/* visible resolution/* virtual resolution*/*/__u32 yres_virtual;__u32 xoffset; /* offset from virtual to visible */ __u32 yoffset;/* resolution*/__u32 bits_per_pixel; __u32 grayscale;/* guess what/* != 0 Graylevels instead of colors */*/struct fb_bitfield red; /* bitfield in fb mem if true color, */struct fb_bitfield green; /* else only length is significant */struct fb_bitfield blue;struct fb_bitfield transp; /* transparency */__u32 nonstd; /* != 0 Non standard pixel format */ __u32 activate;/* see FB_ACTIVATE_**/__u32 height; __u32 width;/* height of picture in mm/* width of picture in mm*/*/__u32 accel_flags; /* (OBSOLETE) see fb_info.flags *//* Timing: All values in pixclocks, except pixclock (of course) */__u32 pixclock; /* pixel clock in ps (pico seconds) */__u32 left_margin; /* time from sync to picture */__u32 right_margin; /* time from picture to sync */__u32 upper_margin; /* time from sync to picture */__u32 lower_margin;__u32 hsync_len; /* length of horizontal sync */__u32 vsync_len; /* length of vertical sync*/__u32 sync; /* see FB_SYNC_* */__u32 vmode; /* see FB_VMODE_* */__u32 rotate; /* angle we rotate counter clockwise */__u32 reserved[5]; /* Reserved for future compatibility */};3)fb_cmap描述設備無關的顏色映射資訊。
韦东山老师LCD驱动程序源码
* bit[18:8]: 多少列, 240, 所以HOZVAL=240-1=239
* bit[7:0] : HFPD, 发出最后一行里最后一个象素数据之后,再过多长时间才发出HSYNC
* LCD手册T8-T11=251-240=11, 所以HFPD=11-1=10
unsigned long lcdintpnd;
unsigned long lcdsrcpnd;
unsigned long lcdintmsk;
unsigned long lpcsel;
};
static struct fb_ops s3c_lcdfb_ops = {
*gpccon = 0xaaaaaaaa; /* GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */
*gpdcon = 0xaaaaaaaa; /* GPIO管脚用于VD[23:8] */
*gpbcon &= ~(3); /* GPB0设置为输出引脚 */
*gpbcon |= 1;
*gpbdat &= ~1; /* 输出低电平 */
*gpgcon |= (3<<8); /* GPG4用作LCD_PWREN */
/* 3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等 */
lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
展讯LCD_tp_camera驱动移植
一、编译:1、cd /home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5ls2、source build/envsetup.shlunch3、KONKA_D7-userdebug或者P5_Russia-userdebug(通用版本)4、kheader5、全部编译make -j8 2>&1 | tee build.log部分编译(改代码时)make bootloader -j8 2>&1 | tee build.logmake bootimage -j8 2>&1 | tee build.log二、克隆:三、下载:1、out/target,考出pac文件,boot.img和u-boot.bin,加载pac文件,然后下载2、每次改完代码,需要重新编译,并且加载pac文件四、改时序:lcd_ili9881c_mipi_1491sl_p5_qc.c里面改五、重新编译:重新编译完,删除/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/out/target/product/1491sl_p5_ hd/obj/u-boot64/drivers/video/sprdfb/lcd目录下的文档六、屏的调试1、LCD驱动初始化,各寄存器的含义。
2、通道数要对应,lan.number和0X80的值,01代表2通道,02代表3通道,03代表4通道七、摄像头增加新型号1、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/vendor/sprd/modules/libcamer a/sensor中的Sprdroid.mk中增加local_src_files目录(先要把驱动文件拷过来,打开驱动文件里边的.c查看变量名称,与文件名无关,与路径有关)2、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/vendor/sprd/modules/libcamer a/oem2v0/src中的sensor_cfg.c中增添型号(对照已有的型号格式)3、改完之后编译systemimage,编译过程或错误查看build.log4、调试摄像头时,如果通信不成功,先检查是否接触不良八、adb devices读不到1、网上做法加设备ID2、检查adb环境是否配置好3、重新下载一次系统九、adb shelladb logcat > '/home/android/test.log' 抓取操作流程日志十、打包1、代码:运行imgpac:cd /home/android/gmk/test/983x_NATIVE_6_s801然后./imgpac(打包程序)2、手动打包:用ReseachDownload点击packet十一、无法对焦1、将#define CONFIG_CAMERA_AUTOFOCUS_NOT_SUPPORT注释掉,目录为/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/vendor/sprd/modules/libcamer a/sensor/gc5025_1713_KONKA_D7十二、新增LCD1、在kernel和uboot中加入驱动代码.c文件2、在驱动所在目录的Makefile中加入语句obj-$(CONFIG_FB_LCD_JD9365_MIPI) += $(filter lcd_jd9365_mipi_%,$(CTL_LCD)).o3、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/u-boot64/drivers/video的sprdfb_panel.c中加:#ifdef CONFIG_FB_LCD_JD9365_MIPI{.lcd_id = 0x9365,.panel = &lcd_jd9365_mipi_spec,},#endif4、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/kernel/arch/arm/configs的deconfig中加CONFIG_FB_LCD_JD9365_MIPI=y5、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/device/sprd/scx35l/1491sl_p5 _hd/project中的P5_Russia.mk中改CTL_LCD6、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/u-boot64/include/configs 的1491SL.h中加#define CONFIG_FB_LCD_JD9365_MIPI7、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/kernel/drivers/video/sprdfb 的Kconfig中添加:config FB_LCD_JD9365_MIPIboolean "support JD9365 mipi panel"depends on FB_SC8825 || FB_SCX35 || FB_SCX15 || FB_SCX30G || FB_SCX35Ldefault n8、新加之前注意将之前的lcd屏蔽掉(deconfig和configs都要注释掉),或加在前面,以免遍历编译时出错“未找到创建规则创建所需的.o文件”9、注意u-boot和kernel驱动代码不完全相同,分开改,以免出错“函数未定义”10、屏不亮时,先检查是否电池没电11、图像偏大或者点的位置与触屏不符,考虑频率密度,修改/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/device/sprd/scx35l/1491sl_p5 _hd中的system.prop中的ro.sf.lcd_density,854*480为24012、开机白屏,检查初始化,很有可能13、编译出错时,先检查error错误,有可能是头文件的事(直接复制过来的头文件可能有错,可参考其他lcd的代码)14、检查out/obj,看kernel和u-boot有没有编译进去15、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/device/sprd/scx35l/1491sl_p5 _hd/modem_bins里放的是开机画面logo,图片的分辨率是固定的16、很多行出现错误时,检查大括号是不是漏掉一个十三、修改LCD读ID 部分代码1、看规格书,ID存在哪个寄存器内2、按照已有的格式改修代码十四、查看LCD_id1、adb shell进入环境2、adb root3、cat /proc/cmdline十五、1、任务:兼容10802和7701两个屏2、新增lcd见上述步骤3、这两个屏分辨率为854*480,为FWVGA,需在/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/u-boot64/include/configs里修改FWVGA和720p的顺序4、出现的错误:1)u-boot没有编译进去:按build.log先修改error,本项目出错为configs与Makefile大小写不一致2)头文件出错3)修改开机logo,分辨率不符十六、修改开机动画1、/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/device/sprd/scx35l/1491sl_p5 _hd/power中拷取两个压缩包,压缩包里是开机连续动画图片,可以替换根据分辨率2、/home/android/gmk/test/983x_NATIVE_6_s801/device/sprd/scx35l/S801/project 对应修改密度值ro.sf.lcd_density=320 \3、/home/android/gmk/test/983x_NATIVE_6_s801/out/target/product/S801/system删除build.prop4、替换/home/android/gmk/test/983x_NATIVE_6_s801/device/sprd/scx35l/S801/thirdparty/S 801G_M506/power中的压缩包用于调用十七、出现libsepol.context_from_record: type bl229x_device is not defined错误,查找/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/device/sprd/scx35l/common/s epolicy中的file_contexts文件,改相应bl229x_device十八、设备树1、dts讲解:/hbk320/article/details/468445852、代码目录:/home/android/gmk/test/sprd9832_6.0_Rls2_W16.35.5/kernel/arch/arm/boot/dts十九、编译分支的deconfig1、=m和=y的含义:首先需要知道:obj-m = *.oobj-y = *.o上面两者的区别在于,前者才会生成ko文件,后者只是代码编译进内核,并不生成ko文件。
linux-2.6.11.1内核移植全纪录
{ name:"kernel", size:0x1d0000, offset:0x30000, }, { name:"rootfs", size:0x1600000, offset:0x200000, }, { name:"yaffsfs", size:0x2800000, offset:0x1800000, }, }; struct s3c2410_nand_set nandset={ nr_partitions:4, partitions:partition_info, }; struct s3c2410_platform_nand gyhPlatform={ tacls:0, twrph0:30, twrph1:0, sets:&nandset, nr_sets:1, }; 在s3c_device_nand结构中添加dev属性: .dev = { .platform_data = & gyhPlatform } 在arch/arm/mach-s3c2410/mach-smdk2410.c中的smdk2410_devices[]结构 体中添加&s3c_device_nand使内核在启动的时候初始化nand flash信息。
(3)修改Kconfig以允许配置 修改drivers/net/arm/目录下的Kconfig文件,在最后添加如下内容: Config ARM_CS8900 tristate "CS8900 support" depends on NET_ETHERNET && ARM && ARCH_SMDK2410 help Support for CS8900A chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the Ethernet-HOWTO, available from as well as . To compile this driver as a module, choose M here and read . The module will be called cs8900.o. (4)修改Makefile加入编译 修改drivers/net/arm/目录下的Makefile文件,在最后添加如下内容: obj-$(CONFIG_ARM_CS8900) += cs8900.o (5)在/arch/arm/mach-s3c2410/mach-smdk2410.c文件中,找到 smdk2410_iodesc[]结构数组,添加如下如下内容: {vSMDK2410_ETH_IO, pSMDK2410_ETH_IO, SZ_1M, MT_DEVICE} 应先添加头文件#include <asm/arch-s3c2410/smdk2410.h> 在include/asm-arm/arch-s3c2410/目录下创建smdk2410.h文件,其内容 为: #ifndef _INCLUDE_SMDK2410_H_ #define _INCLUDE_SMDK2410_H_ #include <linux/config.h> #define pSMDK2410_ETH_IO 0x19000000 #define vSMDK2410_ETH_IO 0xE0000000 #define SMDK2410_ETH_IRQ IRQ_EINT9 #endif // _INCLUDE_SMDK2410_H_ (6)make menuconfig选择CS8900A项,编译下载,CS8900可以工作 了。 6、LCD移植 (1)拷贝驱动源代码 cp s3c2410fb.h drivers/video/ cp s3c2410fb.c drivers/video/ (2)修改drivers/video目录下的Kconfig文件,在最后添加如下内容:
LCD_TFT,RGB接口在LINUX系统中的设置
;----------------------------------------------------------------------------------;disp init configuration;;disp_mode (0:screen0<screen0,fb0>; 1:screen1<screen1,fb0>);screenx_output_type (0:none; 1:lcd; 3:hdmi;);screenx_output_mode (used for hdmi output, 0:480i 1:576i 2:480p 3:576p 4:720p50) ; (5:720p60 6:1080i50 7:1080i60 8:1080p24 9:1080p50 10:1080p60);fbx format (0:ARGB 1:ABGR 2:RGBA 3:BGRA 5:RGB565 8:RGB888 12:ARGB4444 16:ARGB1555 18:RGBA5551);fbx_width,fbx_height (framebuffer horizontal/vertical pixels, fix to output resolution while equal 0);lcdx_backlight (lcd init backlight,the range:[0,256],default:197;----------------------------------------------------------------------------------[disp_init]disp_init_enable = 1disp_mode = 0screen0_output_type = 1screen0_output_mode = 5screen1_output_type = 3screen1_output_mode = 5fb0_format = 0fb0_width = 0fb0_height = 0fb1_format = 0fb1_width = 0fb1_height = 0lcd0_backlight = 50lcd1_backlight = 50;----------------------------------------------------------------------------------;lcd0 configuration;lcd_if: 0:hv(sync+de); 1:8080; 2:ttl; 3:lvds; 4:dsi; 5:edp;lcd_x: lcd horizontal resolution;lcd_y: lcd vertical resolution;lcd_width: width of lcd in mm;lcd_height: height of lcd in mm;lcd_dclk_freq: in MHZ unit;lcd_pwm_freq: in HZ unit;lcd_pwm_pol: lcd backlight PWM polarity;lcd_pwm_max_limit lcd backlight PWM max limit(<=255);lcd_hbp: hsync back porch;lcd_ht: hsync total cycle;lcd_vbp: vsync back porch;lcd_vt: vysnc total cycle;lcd_hspw: hsync plus width;lcd_vspw: vysnc plus width;lcd_lvds_if: 0:single link; 1:dual link;lcd_lvds_colordepth: 0:8bit; 1:6bit;lcd_lvds_mode: 0:NS mode; 1:JEIDA mode;lcd_frm: 0:disable; 1:enable rgb666 dither; 2:enable rgb656 dither ;lcd_gamma_en lcd gamma correction enable;lcd_bright_curve_en lcd bright curve correction enable;lcd_cmap_en lcd color map function enable;lcdgamma4iep: Smart Backlight parameter, lcd gamma vale * 10;; decrease it while lcd is not bright enough; increase while lcd is too bright;----------------------------------------------------------------------------------[lcd0_para]lcd_used = 1lcd_driver_name = "default_lcd"lcd_bl_0_percent = 0lcd_bl_40_percent = 23lcd_bl_100_percent = 100lcd_if = 0lcd_x = 800lcd_y = 480lcd_width = 150lcd_height = 94lcd_dclk_freq = 30lcd_pwm_used = 1lcd_pwm_ch = 0lcd_pwm_freq = 50000lcd_pwm_pol = 1lcd_pwm_max_limit = 255lcd_hbp = 46lcd_ht = 928lcd_hspw = 0lcd_vbp = 23lcd_vt = 1050lcd_vspw = 0lcd_frm = 0lcd_cmap_en = 0lcd_dsi_if = 2lcd_dsi_lane = 4lcd_dsi_format = 0lcd_dsi_te = 0lcd_lvds_if = 0lcd_lvds_colordepth = 1lcd_lvds_mode = 0lcd_hv_clk_phase = 0lcd_hv_sync_polarity = 0lcd_gamma_en = 0lcd_bright_curve_en = 0lcd_cmap_en = 0lcdgamma4iep = 22lcd_bl_en = port:PD29<1><0><default><1>lcd_bl_regulator = "none"lcd_power = "vcc-lcd"lcd_power1 =lcd_power2 =;lcdd0 = port:PD18<3><0><default><default> ;lcdd1 = port:PD19<3><0><default><default> ;lcdd2 = port:PD20<3><0><default><default> ;lcdd3 = port:PD21<3><0><default><default> ;lcdd4 = port:PD22<3><0><default><default> ;lcdd5 = port:PD23<3><0><default><default> ;lcdd6 = port:PD24<3><0><default><default> ;lcdd7 = port:PD25<3><0><default><default> ;lcdd8 = port:PD26<3><0><default><default> ;lcdd9 = port:PD27<3><0><default><default>lcdd2 = port:PD2<2><0><default><default> lcdd3 = port:PD3<2><0><default><default> lcdd4 = port:PD4<2><0><default><default> lcdd5 = port:PD5<2><0><default><default> lcdd6 = port:PD6<2><0><default><default> lcdd7 = port:PD7<2><0><default><default>lcdd10 = port:PD10<2><0><default><default>lcdd11 = port:PD11<2><0><default><default>lcdd12 = port:PD12<2><0><default><default>lcdd13 = port:PD13<2><0><default><default>lcdd14 = port:PD14<2><0><default><default>lcdd15 = port:PD15<2><0><default><default>lcdd18 = port:PD18<2><0><default><default>lcdd19 = port:PD19<2><0><default><default>lcdd20 = port:PD20<2><0><default><default>lcdd21 = port:PD21<2><0><default><default>lcdd22 = port:PD22<2><0><default><default>lcdd23 = port:PD23<2><0><default><default>lcdclk = port:PD24<2><0><default><default>lcdde = port:PD25<2><0><default><default>lcdhsync = port:PD26<2><0><default><default>lcdvsync = port:PD27<2><0><default><default>lcd_io_regulator = "vcc-lvds-18"lcd_io_regulator1 = "vcc-pd";lcd_gpio_0 = port:PD25<1><0><default><0>;lcd_gpio_1 = port:PD26<1><0><default><0>;lcd_io_regulator1 = "vcc-pd";----------------------------------------------------------------------------------。
LCD驱动程序开发指南
LCD驱动程序开发指南LCD驱动开发指引1、LCD驱动概述LCD驱动程序调试,是整个⼿机研发过程中⾮常重要的⼀个环节,在每个新的机型开发的初期,最先都要调试LCD驱动程序,我们俗称“点屏”。
“点屏”的调试包括两个部分,⼀是点亮LCD的背光,⼆是调试LCD显⽰。
背光驱动调试的⽅法与技巧,会在背光⽂档中叙述,暂不在这篇⽂档⾥讨论,本⽂将重点讨论LCD的电路原理、驱动程序分析、LCD驱动调试经验总结和具体驱动调试案例的分析。
2、LCD原理及电路分析相关概念:LCD:全称是Liquid Crystal Display 液晶显⽰屏LCM:全称是Liquid Crystal Module指的是液晶显术模块,包括液晶屏及液晶的外围FPC电路和结构件。
LCD的FPC电路:指LCM模块中的液晶外围电路,这部分电路由LCD模组⼚家按照我们对LCD的接⼝要求进⾏设计的。
在LCD驱动调试中,看FPC电路图也是很重要的⼀个环节。
LCD外围电路:我们通常也简称为LCD电路,指的是baseband端的LCD接⼝电路部分,这部分电路由我们⾃⾏设计。
LCD模组⼚家:指信利,天马,京东⽅这些⼚家。
他们将LCD制作成可以供我们⽣产使⽤的LCM模组。
2.1LCD芯⽚介绍⽬前⼿机使⽤的⼤部分显⽰器件都是LCD(Liguid Crystal Display)器件,⽬前康佳使⽤的LCM模块由信利、京东⽅、天马、凌达这⼏家⼚商供货。
但是LCM⽣产⼚家对我们调试驱动并没有任何关系,我们需要了解的是LCM所使⽤的IC型号。
因为,我们实际上是对LCD的IC进⾏编程,间接控制LCD⾯板,常⽤的IC有HD66773、S6B33B2/ S6B33B6、HD66777等。
LCD驱动的编程,除了要关注IC的型号,还要关注LCD FPC的电路设计,LCD外围电路设计,基带芯⽚的LCD接⼝单元,背光IC的控制等⼏个⽅⾯,当然也包括软件的上层程序。
下⾯我们就先了解⼀下LCD IC的内部结构,这是编程要关注的最主要⽅⾯。
实验5 触摸屏驱动的移植
一、实验目的
掌握 Linux 下触摸屏驱动程序的原理; 掌握 Linux 下触摸屏应用程序的编写方法。
二、实验环境
硬件:TQ2440 核心子板、PC 机; 软件:Windows 2000/NT/XP、Fedora10、其他嵌入式软件包。
三、完成实验所需时间:约90分钟 四、实验内容
#include <asm/arch/idle.h> #include <asm/arch/fb.h> #include <asm/arch/ts.h>
#include <asm/plat-s3c24xx/s3c2410.h> #include <asm/plat-s3c24xx/s3c2440.h> #include <asm/plat-s3c24xx/clock.h>
}; static void __init smdk2440_map_io(void) {
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); s3c24xx_init_clocks(12000000); s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); }
+= elo.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU)
+= fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH)
+= mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712)
linux视频驱动移植
V4L2 视频驱动的移植与应用V4L2(video for linux) 可以支持多种设备,它可以有以下5 种接口:1、视频采集接口(video capture interface) :这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的•下面也是着重讲解这种应用;2、视频输出接口(video output interface) :可以驱动计算机的外围视频图像设备——像可以输出电视信号格式的设备;3、直接传输视频接口(video overlay interface) :它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU;4、视频间隔消隐信号接口(VBI interface) :它可以使应用可以访问传输消隐期的视频信号;5、收音机接口(radio in terface):可用来处理从AM或FM高频头设备接收来的音频流;V4L2 驱动的主要功能是使程序有发现设备的能力和操作设备.它主要是用过一系列的回调函数来实现这些功能.像设置高频头的频率,帧频,视频压缩格式和图像像参数等等.一、V4L2 的移植V4L2 提供了三种不同的API 来传输外围设备和用户空间的数据。
下面就vivi(drivers/media/video/vivi.c) 来讲解一个V4L2 驱动的编写。
注意它是一个虚拟的设备驱动,没有与实际的硬件打交道。
1 、分析几个重要数据结构:vivi.c 包含头文件v4l2-device.h 和v4l2-ioctl.h ,其中v4l2-device.h 中包含了v4l2-subdev.h,v4l2-subdev.h 中又包含了v4l2-common.h ,v4l2-common.h 中包含了v4l2-dev.h。
在v4l2-dev.h 中定义了结构体video_device 和v4l2_file_operations ;在v4l2-ioctl.h 中定义了结构体v4l2_ioctl_ops ;在v4l2-device.h 中定义了结构体v4l2_device;1) vivi_fopsstatic const struct v4l2_file_operations vivi_fops = {.owner = THIS_MODULE,.open = vivi_open,.release = vivi_close,.read = vivi_read,.poll = vivi_poll,.ioctl = video_ioctl2, /* V4L2 ioctl handler */.mmap = vivi_mmap,};2) vivi_ioctl_opsstatic const struct v4l2_ioctl_ops vivi_ioctl_ops = {.vidioc_querycap = vidioc_querycap,.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,.vidiocgmbuf = vidiocgmbuf, #endif };3) vivi_templatestatic struct video_device vivi_template = {.name = "vivi", .fops = &vivi_fops, .ioctl_ops= &vivi_ioctl_ops, .minor= -1,.release = video_device_release,.tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M, };其中函数 vivi_xxx 和 vidioc_xxx 都是在 vivi.c 中实现的。
Linux驱动之LCD驱动编写
Linux驱动之LCD驱动编写在这篇博客中已经分析了编写LCD驱动的步骤,接下来就按照这个步骤来字尝试字节编写LCD驱动。
⽤的LCD屏幕为tft 屏,每个像素点为16bit。
对应与红绿蓝分别为565。
1、分配⼀个fb_info结构2、设置fb_info结构3、硬件相关的操作,配置LCD时钟、配置IO端⼝、配置LCD寄存器。
4、最终注册fbinfo结构到registered_fb数组要理解LCD的⼯作原理,需要了解LCD的时钟,在TFT的LCD中有如下的时钟。
这个⼏个时钟数据在配置LCD寄存器时都说需要设置的。
1、VCLK:两个像素之间的时钟,即两个像素隔多长时间才能显⽰下⼀个像素2、HSYNC:⽔平同步时钟,即第⼀⾏像素点显⽰完成之后隔多长时间才能开始下⼀⾏的显⽰3、VSYNC:垂直⽅向的同步时钟,也叫帧同步信号,即⼀帧数据显⽰完成之后(⼀帧数据表⽰⼀个屏幕显⽰完成,即⼀个显存的数据全部取完),过多长下⼀帧数据才开始显⽰本节需要⽤到的函数:void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); //分配DMA缓存区给显存//返回值为:申请到的DMA缓冲区的虚拟地址,若为NULL,表⽰分配失败,则需要使⽤dma_free_writecombine()释放内存,避免内存泄漏//参数如下://*dev:指针,这⾥填0,表⽰这个申请的缓冲区⾥没有内容//size:分配的地址⼤⼩(字节单位)//*handle:申请到的物理起始地址//gfp:分配出来的内存参数,标志定义在<linux/gfp.h>,常⽤标志如下://GFP_ATOMIC ⽤来从中断处理和进程上下⽂之外的其他代码中分配内存. 从不睡眠.//GFP_KERNEL 内核内存的正常分配. 可能睡眠.//GFP_USER ⽤来为⽤户空间页来分配内存; 它可能睡眠.分配⼀段DMA缓存区,分配出来的内存会禁⽌cache缓存(因为DMA传输不需要CPU)它和 dma_alloc_coherent ()函数相似,不过 dma_alloc_coherent ()函数是分配出来的内存会禁⽌cache缓存以及禁⽌写⼊缓冲区dma_free_writecombine(dev,size,cpu_addr,handle); //释放缓存//cpu_addr:虚拟地址,//handle:物理地址释放DMA缓冲区, dev和size参数和上⾯的⼀样struct fb_info *framebuffer_alloc(size_t size, struct device *dev); //申请⼀个fb_info结构体,//size:额外的内存,//*dev:指针, 这⾥填0,表⽰这个申请的结构体⾥没有内容int register_framebuffer(struct fb_info *fb_info);//向内核中注册fb_info结构体,若内存不够,注册失败会返回负数int unregister_framebuffer(struct fb_info *fb_info) ;//注销内核中fb_info结构体本节需要⽤到的结构体:fb_info结构体如下:struct fb_info {... ...struct fb_var_screeninfo var; //可变的参数struct fb_fix_screeninfo fix; //固定的参数... ...struct fb_ops *fbops; //操作函数... ...char __iomem *screen_base; //显存虚拟起始地址unsigned long screen_size; //显存虚拟地址长度void *pseudo_palette;//假的16⾊调⾊板,⾥⾯存放了16⾊的数据,可以通过8bpp数据来找到调⾊板⾥⾯的16⾊颜⾊索引值,模拟出16⾊颜⾊来,节省内存,不需要的话就指向⼀个不⽤的数组即可 ... ...};其中操作函数fb_info-> fbops 结构体写法如下:static struct fb_ops s3c_lcdfb_ops = {.owner = THIS_MODULE,.fb_setcolreg = my_lcdfb_setcolreg,//设置调⾊板fb_info-> pseudo_palette,⾃⼰构造该函数.fb_fillrect = cfb_fillrect, //填充矩形,⽤/drivers/video/ cfbfillrect.c⾥的函数即可.fb_copyarea = cfb_copyarea, //复制数据, ⽤/drivers/video/cfbcopyarea.c⾥的函数即可.fb_imageblit = cfb_imageblit, //绘画图形, ⽤/drivers/video/imageblit.c⾥的函数即可};固定的参数fb_info-> fix 结构体如下:struct fb_fix_screeninfo {char id[16]; //id名字unsigned long smem_start; //framebuffer物理起始地址__u32 smem_len; //framebuffer长度,字节为单位__u32 type; //lcd类型,默认值0即可__u32 type_aux; //附加类型,为0__u32 visual; //画⾯设置,常⽤参数如下// FB_VISUAL_MONO01 0 单⾊,0:⽩⾊,1:⿊⾊// FB_VISUAL_MONO10 1 单⾊,1:⽩⾊,0:⿊⾊// FB_VISUAL_TRUECOLOR 2 真彩(TFT:真彩)// FB_VISUAL_PSEUDOCOLOR 3 伪彩// FB_VISUAL_DIRECTCOLOR 4 直彩 __u16 xpanstep; /*如果没有硬件panning就赋值为0 */ __u16 ypanstep; /*如果没有硬件panning就赋值为0 */ __u16 ywrapstep; /*如果没有硬件ywrap就赋值为0 */ __u32 line_length; /*⼀⾏的字节数 ,例:(RGB565)240*320,那么这⾥就等于240*16/8 */ /*以下成员都可以不需要*/ unsigned long mmio_start; /*内存映射IO的起始地址,⽤于应⽤层直接访问寄存器,可以不需要*/__u32 mmio_len; /* 内存映射IO的长度,可以不需要*/__u32 accel;__u16 reserved[3];};可变的参数fb_info-> var 结构体如下:structfb_var_screeninfo{ __u32xres; /*可见屏幕⼀⾏有多少个像素点*/__u32 yres; /*可见屏幕⼀列有多少个像素点*/__u32 xres_virtual; /*虚拟屏幕⼀⾏有多少个像素点 */__u32 yres_virtual; /*虚拟屏幕⼀列有多少个像素点*/__u32 xoffset; /*虚拟到可见屏幕之间的⾏偏移,若可见和虚拟的分辨率⼀样,就直接设为0*/ __u32 yoffset; /*虚拟到可见屏幕之间的列偏移*/__u32 bits_per_pixel; /*每个像素的位数即BPP,⽐如:RGB565则填⼊16*/__u32 grayscale; /*⾮0时,指的是灰度,真彩直接填0即可*/struct fb_bitfield red; //fb缓存的R位域, fb_bitfield结构体成员如下://__u32 offset; 区域偏移值,⽐如RGB565中的R,就在第11位//__u32 length; 区域长度,⽐如RGB565的R,共有5位//__u32 msb_right; msb_right ==0,表⽰数据左边最⼤, msb_right!=0,表⽰数据右边最⼤struct fb_bitfield green; /*fb缓存的G位域*/struct fb_bitfield blue; /*fb缓存的B位域*/ /*以下参数都可以不填,默认为0*/struct fb_bitfield transp; /*透明度,不需要填0即可*/__u32nonstd; /* != 0表⽰⾮标准像素格式*/__u32 activate; /*设为0即可*/__u32height; /*外设⾼度(单位mm),⼀般不需要填*/__u32width; /*外设宽度(单位mm),⼀般不需要填*/__u32 accel_flags; /*过时的参数,不需要填*//* 除了pixclock本⾝外,其他的都以像素时钟为单位*/__u32pixclock; /*像素时钟(⽪秒)*/__u32 left_margin; /*⾏切换,从同步到绘图之间的延迟*/__u32right_margin; /*⾏切换,从绘图到同步之间的延迟*/__u32upper_margin; /*帧切换,从同步到绘图之间的延迟*/__u32lower_margin; /*帧切换,从绘图到同步之间的延迟*/__u32hsync_len; /*⽔平同步的长度*/__u32 vsync_len; /*垂直同步的长度*/__u32 sync;__u32 vmode;__u32 rotate;__u32reserved[5]; /*保留*/}1.写驱动程序:(驱动设置:参考⾃带的LCD平台驱动drivers/video/s3c2410fb.c )1.1 步骤如下:在驱动init⼊⼝函数中:1)分配⼀个fb_info结构体2)设置fb_info 2.1)设置固定的参数fb_info-> fix 2.2) 设置可变的参数fb_info-> var 2.3) 设置操作函数fb_info-> fbops 2.4) 设置fb_info 其它的成员3)设置硬件相关的操作 3.1)配置LCD引脚 3.2)根据LCD⼿册设置LCD控制器 3.3)分配显存(framebuffer),把地址告诉LCD控制器和fb_info4)开启LCD,并注册fb_info: register_framebuffer() 4.1) 直接在init函数中开启LCD(后⾯讲到电源管理,再来优化) 控制LCDCON5允许PWREN信号, 然后控制LCDCON1输出PWREN信号, 输出GPB0⾼电平来开背光, 4.2) 注册fb_info在驱动exit出⼝函数中:1)卸载内核中的fb_info2) 控制LCDCON1关闭PWREN信号,关背光,iounmap注销地址3)释放DMA缓存地址dma_free_writecombine()4)释放注册的fb_info1.2 具体代码如下:#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <asm/io.h> //含有iomap函数iounmap函数#include <asm/uaccess.h>//含有copy_from_user函数#include <linux/device.h>//含有类相关的处理函数#include <linux/fb.h> //含有fb_info结构体定义//#include <asm/dma-mapping.h> //含有dma_free_writecombine宏定义#include <linux/dma-mapping.h> //含有dma_free_writecombine宏定义#include <linux/platform_device.h>//含有平台设备总线模型相关变量#include <linux/mm.h>#include <linux/slab.h>//#include <linux/module.h>//#include <linux/kernel.h>//#include <linux/errno.h>//#include <linux/string.h>//#include <linux/mm.h>//#include <linux/slab.h>//#include <linux/delay.h>//#include <linux/fb.h>//#include <linux/init.h>//#include <linux/dma-mapping.h>//#include <linux/interrupt.h>//#include <linux/workqueue.h>//#include <linux/wait.h>//#include <linux/platform_device.h>//#include <linux/clk.h>//#include <asm/io.h>//#include <asm/uaccess.h>//#include <asm/div64.h>//#include <asm/mach/map.h>//#include <asm/arch/regs-lcd.h>//#include <asm/arch/regs-gpio.h>//#include <asm/arch/fb.h>/*lcd控制寄存器放在⼀个结构体⾥⾯*/struct lcd_regs {unsigned long lcdcon1;unsigned long lcdcon2;unsigned long lcdcon3;unsigned long lcdcon4;unsigned long lcdcon5;unsigned long lcdsaddr1;unsigned long lcdsaddr2;unsigned long lcdsaddr3;unsigned long redlut;unsigned long greenlut;unsigned long bluelut;unsigned long reserved[9];unsigned long dithmode;unsigned long tpal;unsigned long lcdintpnd;unsigned long lcdsrcpnd;unsigned long lcdintmsk;unsigned long lpcsel;};static struct fb_info *s3c_mylcdfb_info;//fb_info结构体static volatile unsigned long *gpbcon;//GPB0⽤于lcd背光的控制static volatile unsigned long *gpbdat;//GPB0⽤于lcd背光的控制static volatile unsigned long *gpccon;static volatile unsigned long *gpdcon;static volatile unsigned long *gpgcon;//GPG4⽤于lcd电源static volatile struct lcd_regs* lcd_regs;//lcd寄存器static u32 pseudo_palette[16]; //调⾊板内存/* from pxafb.c */static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf){chan &= 0xffff; //取出16bit的数据chan >>= 16 - bf->length; //return chan << bf->offset;}static int s3c_mylcdfb_setcolreg(unsigned int regno, unsigned int red,unsigned int green, unsigned int blue,unsigned int transp, struct fb_info *info){unsigned int val;if (regno > 16)return1;/* ⽤red,green,blue三原⾊构造出val */val = chan_to_field(red, &info->var.red);val |= chan_to_field(green, &info->var.green);val |= chan_to_field(blue, &info->var.blue);//((u32 *)(info->pseudo_palette))[regno] = val;pseudo_palette[regno] = val;return0;}static struct fb_ops s3c_mylcdfb_ops = { //操作函数结构体.owner = THIS_MODULE,.fb_setcolreg = s3c_mylcdfb_setcolreg,//待会设置,这个是调⾊板,如果使⽤⼩于16bit的像素需要⽤到 .fb_fillrect = cfb_fillrect,.fb_copyarea = cfb_copyarea,.fb_imageblit = cfb_imageblit,};static int lcd_drv_init(void){/*1、分配⼀个fb_info*/s3c_mylcdfb_info = framebuffer_alloc(0,NULL);//size为额外分配的⼤⼩,这⾥不需要,所以设为0if(s3c_mylcdfb_info==NULL){printk("unframebuffer_alloc\n");return1;}/*2、设置*//*2.1 设置固定的参数*/strcpy(s3c_mylcdfb_info->fix.id, "mylcd");//名字//s3c_mylcdfb_info->fix.smem_start = ;//显存的物理起始地址,后⾯设置s3c_mylcdfb_info->fix.smem_len = 480*272*16/8;//单位为字节,每个像素点占⽤16bit :565,显存的⼤⼩ s3c_mylcdfb_info->fix.type = FB_TYPE_PACKED_PIXELS;//LCD类型,填充像素的类型 tft//s3c_mylcdfb_info->fix.type_aux= //附加的LCD类型,不需要设置s3c_mylcdfb_info->fix.visual = FB_VISUAL_TRUECOLOR;//视觉类型,选择真彩⾊s3c_mylcdfb_info->fix.line_length = 480*16/8; //⼀⾏的长度,单位为字节// s3c_mylcdfb_info->fix.mmio_start = //控制lcd的寄存器的物理地址// s3c_mylcdfb_info->fix.mmio_len = //控制lcd的寄存器的⼤⼩/*2.2 设置可变的参数*/s3c_mylcdfb_info->var.xres = 480;//x⽅向的分辨率s3c_mylcdfb_info->var.yres = 272;//y⽅向的分辨率s3c_mylcdfb_info->var.xres_virtual = 480;//x⽅向的虚拟分辨率s3c_mylcdfb_info->var.yres_virtual = 272;//y⽅向的虚拟分辨率s3c_mylcdfb_info->var.bits_per_pixel = 16;//每个像素的⼤⼩,单位为bits3c_mylcdfb_info->var.grayscale = 0;//灰度值s3c_mylcdfb_info->var.red.length = 5;//红⾊像素占⽤的长度,单位bits3c_mylcdfb_info->var.green.length = 6;//绿⾊像素占⽤的长度,单位bits3c_mylcdfb_info->var.blue.length = 5;//蓝⾊像素占⽤的长度,单位bits3c_mylcdfb_info->var.red.offset= 11;//红⾊像素在16bit中的偏移值s3c_mylcdfb_info->var.green.offset= 6;//绿⾊像素在16bit中的偏移值s3c_mylcdfb_info->var.blue.offset=0;//蓝⾊像素在16bit中的偏移值s3c_mylcdfb_info->var.red.msb_right= 0;//低位在前还是⾼位在前,⼀般⾼位在前,也就是⼩端模式s3c_mylcdfb_info->var.green.msb_right= 0;s3c_mylcdfb_info->var.blue.msb_right=0;s3c_mylcdfb_info->var.activate = FB_ACTIVATE_NOW;//使⽤默认参数,显存⽴刻⽣效/*2.3 设置操作函数*/s3c_mylcdfb_info->fbops = &s3c_mylcdfb_ops;/*2.4 其它的⼀些设置 */s3c_mylcdfb_info->pseudo_palette = pseudo_palette;//调⾊板的地址//s3c_mylcdfb_info->screen_base = ;//显存的虚拟基地址s3c_mylcdfb_info->screen_size = 480*272*16/8;//单位为字节,每个像素点占⽤16bit :565,显存的⼤⼩/*3、硬件相关的操作 *//*3.1、配置GPIO⽤于LCD*/gpbcon = ioremap(0x56000010, 8);//将实际的寄存器地址转换为虚拟地址gpccon = ioremap(0x56000020 , 4);gpdcon = ioremap(0x56000030 , 4);gpgcon = ioremap(0x56000060 , 4);gpbdat = gpbcon + 1;*gpccon = 0xaaaaaaaa; /* GPIO管脚⽤于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND */*gpdcon = 0xaaaaaaaa; /* GPIO管脚⽤于VD[23:8] */*gpbcon &= ~(3); /* GPB0设置为输出引脚 */*gpbcon |= 1;*gpbdat &= ~1; /* 输出低电平关闭LCD背光 */*gpgcon |= (3<<8); /* GPG4⽤作LCD_PWREN 电源*//*3.2、根据LCD⼿册设置LCD控制器,⽐如VCLK的频率等 */lcd_regs = ioremap(0X4D000000 , sizeof(struct lcd_regs));/** bit[17:8] : VCLK = HCLK / [(CLKVAL+1) x 2]* 10M = 100M/[(CLKVAL+1) x 2]* CLKVAL = 4** bit[6:5] :PNRMODE = 11显⽰模式,选择TFT模式** bit[4:1] :BPPMODE = 1100;像素=16bit 565** bit[0] :ENVID = 0;先关闭LCD控制器*/lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);///** [31:24] : VBPD = 帧同步信号发出后,过多长时间开始显⽰数据,单位为⾏,理解为1⾏的时间* 看LCD⼿册tvb = VBPD + 1 = 2;所以VBPD = 1** [23:14]:LINEVAL + 1= 272;,所以LINEVAL = 271;垂直⽅向尺⼨,多少⾏** [13:6]:VFPD = ⼀帧的数据传输完成之后,过多长时间开始下⼀帧数据的帧同步信号,单位为⾏,理解为1⾏的时间 * 看LCD⼿册tvf = VFPD + 1 = 2;所以VFPD = 1** [5:0]:VSPW = 帧同步信号的脉冲宽度,单位为⾏* 看LCD⼿册tvp = VSPW + 1 =10;所以VSPW = 9*/lcd_regs->lcdcon2 = (1<<24) | (271<<14) | (1<<6) | (9<<0);/** [25:19]:HBPD = ⾏同步信号发出后,经过多少个VCLK,才发送像素的数据,单位为VCLK* 看LCD⼿册thb = HBPD + 1 = 2;所以HBPD=1** [18:8]:HOZVAL + 1 = 480,所以 HOZVAL = 479;⽔平⽅向尺⼨,多少列**[7:0]:HFPD = ⼀⾏的像素数据传输完成之后,经过多长时间,才能发送下⼀个⾏同步信号,单位为VCLK*看LCD⼿册thf = HFPD + 1 = 2;所以HFPD = 1;*/lcd_regs->lcdcon3 = (1<<19) | (479<<8) | (1<<0);/** [7:0]:HSPW = ⾏同步信号的脉冲宽度,单位为VCLK* 看LCD⼿册thp = HSPW + 1 = 41;所以HSPW = 40**/lcd_regs->lcdcon4 = (40<<0);/** [11] :FRM565 = 1;16位模式的格式 R:G:B = 5:6:5* [10] :INVVCLK = 0;VCLK在哪个边沿取数据 = 0表⽰下降沿取数据* [9] :INVVLINE = 1;⾏同步信号是否需要反转= 1需要反转* [8] :INVVFRAME = 1;帧同步信号是否需要反转= 1需要反转* [7] :INVVD = 0; 数据是否需要反转* [6] :INVVDEN = 0; 数据使能信号是否需要反转* [5] :INVPWREN = 0;电源使能信号是否需要反转* [4] :INVLEND = 0;⾏结束信号是否需要反转* [3] :PWREN = 0;电源使能信号,先不使能* [2] :ENLEND = 1;//⾏结束信号先使能* [1:0] :BSWP 、HWSWP = 0 1;字节内部不需要交换,字节间需要交换*/lcd_regs->lcdcon5= (1<<11) | (3<<8) | (1<<2) | (1<<0);/*3.3、显存和调⾊板设置 *//**利⽤dma_alloc_writecombine分配⼀块连续的显存*/s3c_mylcdfb_info->screen_base = dma_alloc_writecombine(NULL,s3c_mylcdfb_info->screen_size,(&(s3c_mylcdfb_info->fix.smem_start)),GFP_KERNEL);//返回虚拟地址if(s3c_mylcdfb_info->screen_base==NULL) //如果显存分配失败,直接返回{printk("undma_alloc_writecombine\n");return1;}/**将显存的地址告诉LCD控制器(物理地址)*/lcd_regs->lcdsaddr1 = (s3c_mylcdfb_info->fix.smem_start >> 1) & (~(3<<30));//起始地址lcd_regs->lcdsaddr2 = ((s3c_mylcdfb_info->fix.smem_start + s3c_mylcdfb_info->screen_size) >> 1) & 0x1fffff;//结束地址lcd_regs->lcdsaddr3 = (480*16/16); /* ⼀⾏的长度(单位: 2字节) *///s3c_lcd->fix.smem_start = xxx; /* 显存的物理地址 *//* 启动LCD */lcd_regs->lcdcon1 |= (1<<0); /* 使能LCD控制器 */lcd_regs->lcdcon5 |= (1<<3); /* 使能LCD本⾝电源 */*gpbdat |= 1; /* 输出⾼电平, 使能背光 *//*4、注册LCD*/register_framebuffer(s3c_mylcdfb_info);printk("register_framebuffer\n");return0;}static void lcd_drv_exit(void){unregister_framebuffer(s3c_mylcdfb_info);lcd_regs->lcdcon1 &= ~(1<<0); /* 关闭LCD本⾝ */*gpbdat &= ~1; /* 关闭背光 */dma_free_writecombine(NULL, s3c_mylcdfb_info->fix.smem_len, s3c_mylcdfb_info->screen_base, s3c_mylcdfb_info->fix.smem_start);iounmap(lcd_regs);iounmap(gpbcon);iounmap(gpccon);iounmap(gpdcon);iounmap(gpgcon);framebuffer_release(s3c_mylcdfb_info);}module_init(lcd_drv_init);module_exit(lcd_drv_exit);MODULE_LICENSE("GPL");2.重新编译内核,去掉默认的LCDmake menuconfig ,进⼊menu菜单重新设置内核参数:进⼊Device Drivers-> Graphics support:<M> S3C2410 LCD framebuffer support //将⾃带的LCD驱动设为模块, 不编进内核中然后make uImage 编译内核make modules 编译模块为什么要编译模块?因为LCD驱动相关的⽂件也没有编进内核,⽽fb_ops⾥的成员fb_fillrect(), fb_copyarea(), fb_imageblit()⽤的都是drivers/video下⾯的3个⽂件,所以需要这3个的.ko模块,如下图所⽰:3.挂载驱动将编译好的LCD驱动模块和drivers/video⾥的3个.ko模块放⼊nfs⽂件系统⽬录中然后烧写内核, 先装载3个/drivers/video下编译好的模块,再来装载LCD驱动模块挂载LCD驱动后, 如下图,可以通过 ls -l /dev/fb* 命令查看已挂载的LCD设备节点:4.测试运⾏测试有两种:echo hello> /dev/tty1 // LCD上便显⽰hello字段cat Makefile>/dev/tty1 // LCD上便显⽰Makeflie⽂件的内容4.1使⽤上节的键盘驱动在LCD终端打印命令⾏vi /etc/inittab //修改inittab, inittab:配置⽂件,⽤于启动init进程时,读取inittab添加->tty1::askfirst:-/bin/sh //将sh进程(命令⾏)输出到tty1⾥,也就是使LCD输出信息然后重启,insmod装载3个/drivers/video下编译好的模块,再来insmod装载LCD驱动模块,tty1设备便有了,就能看到提⽰信息:如下图,我们insmod上⼀节的键盘驱动后,按下enter键,便能在LCD终端上操作linux了从上图可以看到按下enter键,它就启动了⼀个进程号772的-sh进程,如下图发现这个-sh的描述符都指向了tty1:以上内容转载⾃。
S3C2440上LCD驱动详解
S3C2440上LCD驱动(FrameBuffer)实例开发讲解一、开发环境·主机:VMWare--Fedora 9·开发板:Mini2440--64MB Nand, Kernel:2.6.30.4·编译器:arm-linux-gcc-4.3.2二、背景知识1. LCD工作的硬件需求:要使一块LCD正常的显示文字或图像,不仅需要LCD驱动器,而且还需要相应的LCD控制器。
在通常情况下,生产厂商把LCD驱动器会以COF/COG 的形式与LCD玻璃基板制作在一起,而LCD控制器则是由外部的电路来实现,现在很多的MCU内部都集成了LCD控制器,如S3C2410/2440等。
通过LCD 控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT屏了。
2. S3C2440内部LCD控制器结构图:我们根据数据手册来描述一下这个集成在S3C2440内部的LCD控制器:a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组成;b:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的;c:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,视频数据在不需要CPU的干预的情况下显示在LCD屏上;d:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器;e:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN 就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。
uboot内核移植和裁剪详细步骤
uboot内核移植和裁剪详细步骤-U-boot内核移植步骤:Linux 3.3.5系统移植1. 将arch/arm/mach-s3c6410/下的,mach-smdk6410.c cp为mach-my6410.c;2. 打开arch/arm/mach-s3c6410/下的Kconfig,仿照MACH_SMDK6410做一个菜单项:config MACH_MY6410bool "MY6410"select CPU_S3C6410select SAMSUNG_DEV_ADCselect S3C_DEV_HSMMCselect S3C_DEV_HSMMC1select S3C_DEV_I2C1select SAMSUNG_DEV_IDEselect S3C_DEV_FBselect S3C_DEV_RTCselect SAMSUNG_DEV_TSselect S3C_DEV_USB_HOSTselect S3C_DEV_USB_HSOTGselect S3C_DEV_WDTselect SAMSUNG_DEV_BACKLIGHTselect SAMSUNG_DEV_KEYPADselect SAMSUNG_DEV_PWMselect HAVE_S3C2410_WATCHDOG if WATCHDOGselect S3C64XX_SETUP_SDHCIselect S3C64XX_SETUP_I2C1select S3C64XX_SETUP_IDEselect S3C64XX_SETUP_FB_24BPPselect S3C64XX_SETUP_KEYPADhelpMachine support for the Pillar MY64103. 打开arch/arm/tools/mach-types文件,这里面存的是机器ID必须要和uboot里面的ID保持一致,将其283行复制添加在后面并修改为: smdk6410MACH_SMDK6410 SMDK6410 1626 xx6410 MACH_XX6410 XX6410 1626 这个机器ID和UBOOT里的机器ID相同时才能启动内核;1. 修改BSP文件mach-my6410.c,内容如下:将mach-mach-my6410.c文件中的所有smdk6410改成my6410(不要改大写SMDK6410的)MACHINE_START(MY6410, "MY6410")//这个要和Kconfig里的MACH-MY6410匹配 2. 在当前目录的Makefile最后一行加上 obj-$(CONFIG_MACH_MY6410) += mach-my6410.o3. 修改顶层的Makefile:ARCH ?= armCROSS_COMPILE ?= /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux- 4. 复制arch/arm/configs/下的s3c6400-defconfig文件,然后将其保存为.config,配置内核支持EABI,再选中XX6410 board这一项,保存退出;5. 执行make menuconfig对内核进行配置:执行make编译执行make zImage生成zImage将uboot根目录下的mkimage拷贝到/user/bin目录下执行make uImage生成uImage通过以上几步linux内核移植完了,剩下就移植驱动了。
用Verilog编写代码来驱动LCD
课程设计实验目的●如何运用Libero IDE来完成一个具体的设计实例●如何使用Fusion器件内部的静态PLL●如何使用Verilog编写代码来驱动LCD●掌握基本的Verilog语言编程知识一、实验设备●硬件:PC机,Fusion开发板一套,FlashPro3下载器一个●软件:Libero 8.5二、实验内容本实验的主要功能是在Fusion StartKit开发板上的LCD屏显示字符串”Zhang Jingwei”及”200706010127”。
整个系统由时钟模块Clock_Gen,液晶驱动模块LCD_Driver组成。
其中Clock_Gen的任务就是将系统时钟分频到较低的时钟,以适合LCD的读写要求。
LCD_Driver主要完成LCD的读写时序,将相应的命令和数据写入LCD的控制器。
三、实验原理四、程序设计ClockGen时钟产生模块// Clock_Gen.v/****************为LCD_Drvier模块产生500Hz的时钟信号**************/module Clock_Gen(clk_48M,rst,clk_LCD);input clk_48M,rst; //rst为全局复位信号(高电平有效)output clk_LCD;wire clk_counter;reg [9:0] count;reg clk_BUF;PLL_1M U1(.POWERDOWN(1'b1), //调用PLL模块对48M晶振进行分频 .CLKA(clk_48M),.GLA(clk_counter)); //clk_counter为1M时钟输出always @(posedge clk_counter or posedge rst)begin //利用计数器分频产生500Hz时钟if(rst)beginclk_BUF <= 1'b0;count <= 10'b0;endelsebeginif(count == 10'd1000)beginclk_BUF <= ~clk_BUF;count <= 10'b0;endelsebeginclk_BUF <= clk_BUF; //clk_BUF为500Hz的时钟信号count <= count + 1'b1;endendendassign clk_LCD = clk_BUF;//clk_LCD为LCD_Drvier模块所需要的500Hz的时钟信号endmoduleLCD驱动模块// LCD_Driver.v//功能简述:在1602液晶模块上显示字符串,其中第一行显示“Welcome To ZLG”,// 在第二行显示“”。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux的LCD驱动源码分析及移植(三部曲)第一部分:基于ARM9处理器的linux-2.6.32.2操作系统内核移植手记part5.1(LCD驱动源码分析及移植之platform device)1.与LCD控制器硬件相关的寄存器内容请参照三星S3C2440A技术手册中的第15章。
2. LCD Controller的平台设备定义如下(文件位于linux/arch/arm/plat-s3c24xx/devs.c):1./* LCD Controller */2.3.static struct resource s3c_lcd_resource[] = {4. [0] = {5. .start = S3C24XX_PA_LCD,6. .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,7. .flags = IORESOURCE_MEM,8. },9. [1] = {10. .start = IRQ_LCD,11. .end = IRQ_LCD,12. .flags = IORESOURCE_IRQ,13. }14.15.};16.17.static u64 s3c_device_lcd_dmamask = 0xffffffffUL;18.19.struct platform_device s3c_device_lcd = {20. .name = "s3c2410-lcd",21. .id = -1,22. .num_resources = ARRAY_SIZE(s3c_lcd_resource),23. .resource = s3c_lcd_resource,24. .dev = {25. .dma_mask = &s3c_device_lcd_dmamask,26. .coherent_dma_mask = 0xffffffffUL27. }28.};29.30.EXPORT_SYMBOL(s3c_device_lcd);平台设备的结构体定义为s3c_device_lcd,该设备在平台总线中的名字取为s3c2410-lcd,该平台设备申请的两个板级资源为以S3C24XX_PA_LCD为起始的IORESOURCE_MEM资源和一个定义为IRQ_LCD的IORESOURCE_IRQ资源。
其中,1.#define S3C24XX_PA_LCD S3C2410_PA_LCD1./* LCD controller */2.#define S3C2410_PA_LCD (0x4D000000)3.#define S3C24XX_SZ_LCD SZ_1M0x4D000000为LCDCON1寄存器的地址。
3. LCD Controller的平台设备的注册如下(文件位于linux/arch/arm/mach-s3c2440/mach-smdk24 40.c):1.static struct platform_device *smdk2440_devices[] __initdata = {2. &s3c_device_usb,3.4. &s3c_device_lcd,5.6. &s3c_device_wdt,7. &s3c_device_i2c0,8. &s3c_device_iis,9. &s3c_device_rtc,10.};以上第4行代码将lcd平台设备注册进内核。
4.在系统初始化时将smdk2440_fb_info结构体添加进平台设备的私有结构中。
具体流程如下:4.11.MACHINE_START(S3C2440, "SMDK2440")2. /* Maintainer: Ben Dooks <ben@> */3. .phys_io = S3C2410_PA_UART,4. .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,5. .boot_params = S3C2410_SDRAM_PA + 0x100,6.7. .init_irq = s3c24xx_init_irq,8. .map_io = smdk2440_map_io,9. .init_machine = smdk2440_machine_init,10. .timer = &s3c24xx_timer,11.MACHINE_END启动S3C2440机器,系统将通过“.init_machine = smdk2440_machine_init,”调用smdk2440_machine_init()函数。
4.21.static void __init smdk2440_machine_init(void)2.{3. s3c24xx_fb_set_platdata(&smdk2440_fb_info);4. s3c_i2c0_set_platdata(NULL);5.6. platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));7. smdk_machine_init();8.}在 smdk2440_machine_init函数中,通过“s3c24xx_fb_set_platdata(&smdk2440_fb_info);”将smdk2440_fb_info添加进平台设备的私有结构中。
4.31.void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)2.{3. struct s3c2410fb_mach_info *npd;4.5. npd = kmalloc(sizeof(*npd), GFP_KERNEL);6.if(npd){7. memcpy(npd, pd, sizeof(*npd));8. s3c_device_lcd.dev.platform_data = npd;9.}else{10. printk(KERN_ERR "no memory for LCD platform data\n");11.}12.}以上代码为smdk2440_fb_info结构的添加过程,其中“s3c_device_lcd.dev.platform_data = npd;”为核心实现部分。
4.41.static struct s3c2410fb_mach_info smdk2440_fb_info __initdata ={2..displays =&smdk2440_lcd_cfg,3..num_displays = 1,4..default_display = 0,5.6.#if 07./* currently setup by downloader */8..gpccon = 0xaa940659,9..gpccon_mask = 0xffffffff,10..gpcup = 0x0000ffff,11..gpcup_mask = 0xffffffff,12..gpdcon = 0xaa84aaa0,13..gpdcon_mask = 0xffffffff,14..gpdup = 0x0000faff,15..gpdup_mask = 0xffffffff,16.#endif17.18.//.lpcsel =((0xCE6)&~7)| 1<<4,19.};以上为smdk2440_fb_info结构体定义。
在此需要注释掉源码中的“.lpcsel = ((0xCE6) & ~7) | 1<<4”!本结构中的关键为“ .displays = &smdk2440_lcd_cfg,”,即LCD的硬件参数,需要根据具体的LCD屏幕来确定,小生使用的是天嵌3.5寸屏幕,所以该结构体的赋值如下:4.51.static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {2.3. .lcdcon5 = S3C2410_LCDCON5_FRM565 |4. S3C2410_LCDCON5_INVVLINE |5. S3C2410_LCDCON5_INVVFRAME |6. S3C2410_LCDCON5_PWREN |7. S3C2410_LCDCON5_HWSWP,8.9. .type = S3C2410_LCDCON1_TFT,10.11. .width = 320,12. .height = 240,13.14. .pixclock = 80000, /* HCLK 100 MHz, divisor 3 */15. .xres = 320,16. .yres = 240,17. .bpp = 16,18.19. .setclkval = 0x3,20. .left_margin = 28, /* for HFPD*/21. .right_margin = 24, /* for HBPD*/22. .hsync_len = 42, /* for HSPW*/23. .upper_margin = 6, /* for VFPD*/24. .lower_margin = 2, /* for VBPD*/25. .vsync_len = 12, /* for VSPW*/26.27.};以上位LCD屏幕硬件参数。
注:a.本文旨在将与友善之臂开发板配套的的linux-2.6.32.2内核移植到天嵌科技的TQ2440开发板上。
b. 硬件平台:天嵌科技TQ2440开发板(标配)c. 软件平台:linux-2.6.32.2内核源码第二部分:基于ARM9处理器的linux-2.6.32.2操作系统内核移植手记part5.2(LCD驱动源码分析及移植之platform driver)5.LCD驱动模块的注册与注销:注册与注销模块由module_init宏与module_exit宏指定。
6.LCD平台设备驱动s3c2410fb_driver。
该结构定义了LCD驱动程序的名字:"s3c2410-lcd",以及探测函数probe,移除函数remove,电源挂起函数suspend和电源恢复函数resume。
由此可见,真正的探测函数为s3c24xxfb_probe。
第一行用于获取platform device中定义的平台数据(已经在本博客的上一篇文章中提及)。