LCD驱动分析_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。
基于STM32单片机FSMC接口驱动LCD的配置与分析

基于STM32单片机FSMC接口驱动LCD的配置与分析概述:STM32单片机是一款高性能、低功耗的32位ARM Cortex-M系列微控制器。
它具有丰富的外设接口,其中包括FSMC(Flexible Static Memory Controller)接口,用于连接外部存储器,例如LCD显示器。
本文将详细介绍如何配置和驱动LCD显示器,以及分析FSMC接口的工作原理。
一、LCD驱动接口配置1. 在STM32的标准外设库中,FSMC的配置函数位于STM32F10x_stdperiph_driver库的stm32f10x_fsmc.c和stm32f10x_fsmc.h文件中。
通过这些函数,可以配置FSMC接口的参数,以使它能够连接和驱动LCD。
2.首先,需要配置FSMC的时钟预分频值。
根据LCD的要求以及系统时钟频率,选择适当的预分频值。
这可以通过设置FSMC_BCRx寄存器中的MBKEN和PS字段来实现。
3.然后,需要配置FSMC的存储芯片选择使能信号(CSEN)和片选信号(ALE)。
这可以通过设置FSMC_BCRx寄存器中的CSEN和ALEN字段来实现。
4.接下来,需要配置FSMC的读写延迟、数据宽度、存储器类型等参数。
这可以通过设置FSMC_BTRx和FSMC_BWTRx寄存器来实现。
5.最后,需要配置FSMC的地址线、数据线和控制线的映射关系。
这可以通过设置FSMC_BCRx寄存器中的MWID、MTYP、MUXEN、MWID和NWID 字段来实现。
二、FSMC接口工作原理1.FSMC接口是一种高速并行接口,它通过多路复用来连接不同的外部存储器。
它具有独立的读/写数据线和地址线,以及控制线,用于选择读/写操作和片选信号。
2. FSMC接口支持不同类型的存储器,例如SRAM、NOR Flash、NAND Flash和LCD。
每种存储器都有不同的时序和接口要求。
3.FSMC接口的时序参数主要包括时钟预分频值、读/写延迟、数据宽度和地址线宽度等。
LCD驱动代码 2

LCD驱动主要程序如下:#ifdef CONFIG_PM#include <linux/pm.h>#endif#include "mys3c2410fbdata.h"#define CONFIG_FB_S3C2410_DEBUG/* Debugging stuff */#ifdef CONFIG_FB_S3C2410_DEBUGstatic int debug = 1;#elsestatic int debug = 0;#endif#define dprintk(msg...) { printk(KERN_ALERT "s3c2410fb: " msg); }/*FrameBuffer设备名称*/static char driver_name[] = "s3c2410_lcd";/*定义一个结构体用来维护驱动程序中各函数中用到的变量*/struct s3c2410fb_var{int lcd_irq_no; /*保存LCD中断号*/struct clk *lcd_clock; /*保存从平台时钟队列中获取的LCD时钟*/struct resource *lcd_mem; /*LCD的IO空间*/void __iomem *lcd_base; /*LCD的IO空间映射到虚拟地址*/struct device *dev;struct s3c2410fb_hw regs; /*表示5个LCD配置寄存器,s3c2410fb_hw 定义在mach-s3c2410/include/mach/fb.h中*//*定义一个数组来充当调色板。
据数据手册描述,TFT屏色位模式为8BPP 时,调色板(颜色表)的长度为256,调色板起始地址为0x4D000400*/ u32 palette_buffer[256];u32 pseudo_pal[16];unsigned int palette_ready; /*标识调色板是否准备好了*/};/*用做清空调色板(颜色表)*/#define PALETTE_BUFF_CLEAR (0x80000000)/*填充调色板*/static void s3c2410fb_write_palette(struct s3c2410fb_var *fbvar){unsigned int i;void __iomem *regs = fbvar->lcd_base;fbvar->palette_ready = 0;for (i = 0; i < 256; i++){unsigned long ent = fbvar->palette_buffer[i];if (ent == PALETTE_BUFF_CLEAR){continue;}/*#define S3C2440_ADDR(x) ((void __iomem __force *)0xF0000000 + (x)) #define S3C24XX_V A_LCD S3C2440_ADDR(0x00300000)#define S3C2440_LCDREG(x) ((x) + S3C24XX_V A_LCD)#define S3C2440_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4))*/writel(ent, regs + S3C2440_TFTPAL(i));if (readw(regs + S3C2440_TFTPAL(i)) == ent){fbvar->palette_buffer[i] = PALETTE_BUFF_CLEAR;}else{fbvar->palette_ready = 1;}}}/*LCD中断服务程序*/static irqreturn_t lcd_fb_irq(int irq, void *dev_id){struct s3c2410fb_var *fbvar = dev_id;void __iomem *lcd_irq_base;/*LCD中断挂起寄存器基地址*/lcd_irq_base = fbvar->lcd_base + S3C2440_LCDINTBASE;/*读取LCD中断挂起寄存器的值*/lcdirq = readl(lcd_irq_base + S3C2440_LCDINTPND);/*判断是否为中断挂起状态*/if(lcdirq & S3C2440_LCDINT_FRSYNC){/*填充调色板*/if (fbvar->palette_ready){s3c2410fb_write_palette(fbvar);}/*设置帧已插入中断请求*/writel(S3C2440_LCDINT_FRSYNC, lcd_irq_base +S3C24XX_LCDINTPND);writel(S3C2440_LCDINT_FRSYNC, lcd_irq_base +S3C24XX_LCDSRCPND);}return IRQ_HANDLED;}/*该函数实现修改GPIO端口的值,注意第三个参数mask的作用是将要设置的寄存器值先清零*/static inline void modify_gpio(void __iomem *reg, unsigned long set, unsigned long mask){unsigned long tmp;tmp = readl(reg) & ~mask;writel(tmp | set, reg);}/*LCD各寄存器进行初始化*/static int s3c2410fb_init_registers(struct fb_info *fbinfo){void __iomem *tpal;void __iomem *lpcsel;/*从lcd_fb_probe探测函数设置的私有变量结构体中再获得LCD相关信息的数据*/struct s3c2410fb_var *fbvar = fbinfo->par;struct s3c2410fb_mach_info *mach_info = fbvar->dev->platform_data;/*获得临时调色板寄存器基地址,S3C2440_TPAL宏定义在mach-s3c2440/include/mach/regs-lcd.h中。
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;}。
LCD液晶显示驱动程序设计指引

美的集团制冷事业本部企业标准QJ/MK03.056-2004 LCD液晶显示驱动程序设计指引1适用范围《LCD液晶显示驱动程序设计指引》主要对采用液晶驱动芯片HD1621(或此系列芯片)进行LCD 液晶的驱动方法进行了分析,说明了驱动芯片的功能、软件编制方法和注意事项,并提供了程序范例,为以后的程序设计者提供类似的开发参考。
2引用资料范例程序采用日本NEC公司的RA78K0S系列汇编语言编写,具体技术资料参照78K0S系列八位单片机UPD78F9177芯片的相关资料。
液晶驱动芯片参考资料:具体见HT1621DATASHEET。
3定义汇编语言:是用于编写微处理器软件的最基本编程语言。
汇编程序包:是一组程序的总称,用于把汇编语言的源程序文件转换成机器代码的程序,通常包括汇编程序﹑连接程序﹑目标码转换程序和其它库管理程序﹑表转换程序等。
LCD:液晶显示器简称。
4HT162X驱动芯片资料介绍4.1概述HT162X系列芯片是由HOTEK公司开发生产的多功能LCD 驱动器芯片,HT162X 的软件配置特性使其适合于各种LCD 的应用包括LCD 模块和显示子系统,主控器与HT162X通信只需要3 到4 条线。
由于采用了电容型偏置电压充电泵使得HT1620 的操作电流非常的小。
HT162X 系列包括多款产品适合不同的应用,目前广泛应用于各种液晶驱动控制上。
4.2芯片特性➢操作电压2.4V~3.3V➢LCD 电压3.6V~4.9V可调➢可选择1/2 或1/3 偏置1/2, 1/3 或1/4 占空比➢内部时基频率源➢片内电容型偏置充电泵➢读/写地址自动增加➢3线(或4线)串行接口➢软件配置特性➢两个可选的蜂鸣器频率2KHz 或4KHz4.3HT162X系列芯片选型表片内振荡器-√√-√√√晶体振荡器√√-√√√√5HT1621芯片说明HT1621为32*4位LCD驱动器,共有四种子型号,分别是HT1621-48SSO、HT1621B-48SSOP/DIP、HT1621D-28SKDIP,我们现在使用的为HT1621B-48SSOP,以下就以此芯片为例进行说明。
RK3399MipiLCDDriver代码分析·Rockchip

RK3399MipiLCDDriver代码分析·Rockchip RK3399 Mipi LCD Driver 代码分析KernelVersion: 4.4.70+Documentation/devicetree/bindings/video/rockchip_fb.txt+概览总的来说,RK LCD 的 driver 有如下四个部分:+1. FB 框架相关的部分2. LCDC 控制器相关的部分3. LCD 屏幕配置相关的部分4. Mipi 驱动代码➜ rockchip git:(master) ✗ tree ./driver/video/.├── backlight 背光相关├── fbdev FB 框架│└── core FB 核⼼代码│├── fbmem.c│└── fbsysfs.c└── rockchip├── rk_fb.c 平台 FB 驱动├── rkfb_sysfs.c├── lcdc│├── rk322x_lcdc.c│└── rk322x_lcdc.h├── screen│├── lcd_general.c│├── lcd_mipi.c│└── rk_screen.c 屏幕配置⽂件共⽤代码└── transmitter Mipi 驱动代码├── rk32_mipi_dsi.c├── rk32_mipi_dsi.h├── mipi_dsi.c└── mipi_dsi.hRK FBDEV 框架相关代码drivers/video/fbdev/core/fbmem.cdrivers/video/rockchip/rk_fb.cdrivers/video/rockchip/rkfb_sysfs.cinclude/linux/rk_fb.hfbmem.c是 upstream 的代码。
它的作⽤在于:向上提供了和⽤户空间交接的接⼝(open/read/write/ioctl); 向下联系平台相关的 fb 驱动 rk_fb.c。
lcd设备驱动之全解析

linux中LCD设备驱动(1)——framebuffer(帧缓冲)1、framebuffer 帧缓冲帧缓冲(framebuffer)是Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差别,允许上层应用步伐在图形模式下直接对显示缓冲区进行读写操纵。
用户不必体贴物理显示缓冲区的具体位置及存放方法,这些都由帧缓冲设备驱动自己来完成。
framebuffer机制模仿显卡的功效,将显卡硬件结构抽象为一系列的数据结构,可以通过framebuffer的读写直接对显存进行操纵。
用户可以将framebuffer看成是显存的一个映像,将其映射到进程空间后,就可以直接进行读写操纵,写操纵会直接反应在屏幕上。
framebuffer是个字符设备,主设备号为29,对应于/dev/fb%d 设备文件。
通常,使用如下方法(前面的数字表现次设备号)0 = /dev/fb0 第一个fb 设备1 = /dev/fb1 第二个fb 设备fb 也是一种普通的内存设备,可以读写其内容。
例如,屏幕抓屏:cp /dev/fb0 myfilefb 虽然可以像内存设备(/dev/mem)一样,对其read,write,seek 以及mmap。
但区别在于fb 使用的不是整个内存区,而是显存部门。
2、fb与应用步伐的交互对付用户步伐而言,它和其他的设备并没有什么区别,用户可以把fb看成是一块内存,既可以向内存中写数据,也可以读数据。
fb的显示缓冲区位于内核空间,应用步伐可以把此空间映射到自己的用户空间,在进行操纵。
在应用步伐中,操纵/dev/fbn的一般步调如下:(1)打开/dev/fbn设备文件。
(2)用ioctl()操纵取恰当前显示屏幕的参数,如屏幕辨别率、每个像素点的比特数。
凭据屏幕参数可盘算屏幕缓冲区的巨细。
(3)用mmap()函数,将屏幕缓冲区映射到用户空间。
(4)映射后就可以直接读/写屏幕缓冲区,进行画图和图片显示了。
LCD驱动程序开发指南

LCD驱动程序开发指南LCD(液晶显示器)是一种常见的显示设备,广泛应用于电子产品中。
开发LCD驱动程序是实现LCD显示的重要环节。
本文将对LCD驱动程序的开发进行指南。
首先,开发LCD驱动程序前需要了解LCD的基本原理和特性。
LCD主要由像素阵列、控制芯片和背光源组成。
像素阵列是由许多小点组成的,每个小点称为像素。
控制芯片负责控制像素点的显示和刷新。
背光源提供背光亮度和显示效果。
在开发LCD驱动程序时,需要先选择适合的开发板和LCD控制芯片。
开发板上的LCD接口和控制芯片的接口需要匹配。
然后需要了解LCD控制芯片的规格和技术手册,包括寄存器的功能和操作方式等。
接下来,需初始化LCD控制芯片。
初始化的目的是设置LCD控制芯片的工作模式和参数。
通常包括设置像素点的个数和位深度、设置显示模式和刷新率等。
初始化还需要设置LCD的工作电压和背光源的亮度。
初始化的具体步骤可以参考LCD控制芯片的技术手册。
然后,需编写LCD控制代码。
这部分工作需要根据LCD控制芯片的通讯协议和接口规范进行。
常见的通讯协议有RGB接口、I2C总线和SPI总线等。
根据协议进行通讯后,可以发送命令和数据到LCD控制芯片,以实现显示和刷新。
具体的代码编写要根据具体的开发板和控制芯片进行,可以参考控制芯片的技术手册和示例代码。
另外,需编写LCD驱动程序的测试代码。
测试代码可以验证LCD驱动程序的功能和正确性。
可以通过显示图像、文本和图形等方式进行测试。
测试代码应涵盖各种显示模式和刷新率,以保证LCD驱动程序的稳定性和可靠性。
最后,需进行调试和优化。
调试主要是针对LCD显示不正常或显示效果不理想的问题。
可以通过查看LCD控制芯片的寄存器状态和输出信号等,确定问题的原因和解决方案。
优化可以提高LCD驱动程序的性能和效率,例如采用硬件加速或优化算法等。
综上所述,开发LCD驱动程序需要了解LCD的基本原理和特性,选择适合的开发板和LCD控制芯片,进行初始化和编写控制代码,编写测试代码,进行调试和优化。
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:以上内容转载⾃。
LCD控制器 (1)

A[31]A[30]…A[1]A[0]B[31]B[30]…B[1]B[0]C[31]C[30]…C[1]C[0]…
4位或8位单扫描数据显示
0000 0004
0008
┇ …
1000
1004
┇ …
A[31: 0] B[31: 0] C[31: 0]
┇┇ L[3…1: 0] M[31: 0]
┇ …
A[31]A[30]…A[1]A[0]B[31]B[30]…B[1]B[0]C[31]C[30]…C[1]C[0]… L[31]L[30]…L[1]L[0]M[31]M[30]…M[1]M[0]
数据传送速率=水平尺寸×垂直尺寸×帧速率×模式值
• 帧速率的计算公式为
VCLK=MCLK/(VCLKVAL×2) 帧速率 ={[(1/VCLK)×(HOZVAL+1)+(1/MCLK)×(WLH+WDLY+LINEBLANK)]× (LINEVAL+1)}
• VCLK还可以使用下式计算:
VCLK=(HOZVAL+1)/{[1/(帧速率×(LlNEVAL+1))]- [(WLH+WDLY+LINEBLANK) /MCLK]}
液晶类型和扫描模式 单色液晶 4级灰度屏 16级灰度屏 彩色液晶
4位单扫描 1/4 1/4 1/4 3/4
液晶扫描模式值
8位单扫描或4位双扫描 1/8 1/8 1/8 3/8
(3)设置数据帧显示控制 • LCDBASEU:设置显示扫描方式中的开始地址(单扫描方
式)或高位缓存地址(双扫描方式)。 • LCDBASEL:设置双扫描方式的低位缓存开始地址。可以使
1 个像素
4位单扫描
LCD的驱动控制实验

本实验参数设置
single
scan LCD 分辨率:640×480 TFT 16 BPP (Bits Per Pixel) mode
RGB 5:6:5 一级缓冲大小 16bit×(640×480) 二级缓冲大小 24bit×(640×480)
建立两个一级缓冲,一个二级缓冲:
与ARM自带LCD驱动器有关的寄存 器
LCDSADDR1
Frame buffer start address 1 register LCDSADDR2 Frame buffer start address 2 register LCDSADDR3 Virtual screen address set
LCDSADDR2
LCDBASEL
These bits indicate A[21:1] of the end address of the LCD frame buffer.
程序流程
初始化实验开发板 初始化LCD 修改二级显存
刷新LCD屏幕
待机
LCD初始化程序流程
设置GPIO(GPC,GPD) 关闭LCD输出 设置LCD控制寄存器(LCDCON1-5)
Le bits indicate A[30:22] of the bank location for the video buffer in the system memory. LCDBASEU These bits indicate A[21:1] of the start address of the LCD frame buffer.
实验原理
Frame
Buffer通常是在内存空间中由连续 的字节组成.显示器操作:从左到右逐点象素 扫描,从上到下逐行扫描.这使得显示屏上的 象素同Frame Buffer中的内存空间建立了 一对一映射.
LCD12864液晶驱动编程指南

LCD12864液晶驱动编程指南
1.连接硬件:
2.初始化液晶:
在开始使用液晶之前,需要进行初始化。
初始化过程包括设置液晶的
工作模式、显示模式和其他参数。
通过向液晶发送一系列的指令,可以完
成初始化过程。
3.编写驱动程序:
液晶驱动程序的主要目的是将需要显示的内容以及液晶的控制指令发
送给液晶屏。
根据液晶屏的通信方式,可以采用单片机的IO口直接控制
液晶屏,也可以通过SPI或I2C等接口芯片间接控制。
4.显示图形:
5.显示文本:
除了图形外,液晶还可以显示文本。
可以通过设置显示位置和发送需
要显示的文本来实现。
6.更新显示:
当需要更新液晶上的内容时,可以通过重新设置显示的内容和刷新液
晶来实现。
可以定时刷新液晶,或者通过检测外部事件来触发刷新。
7.扩展功能:
除了基本功能外,还可以实现一些扩展功能,如显示动画、滚动显示、倒计时等。
只需要根据需求编写相应的代码即可实现。
总结:
注意事项:
在编写驱动程序时,需要注意及时更新液晶上的内容,避免频繁刷新导致的卡顿现象。
同时,为了保证程序的可移植性,可以将液晶驱动程序与其他功能模块进行分离,便于代码的维护和移植。
s3c2440LCD控制器设置及代码详解

s3c2440LCD控制器设置及代码详解要使一块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屏)。
3. 常见TFT屏工作时序分析:LCD提供的外部接口信号:VSYNC/VFRAME/STV:垂直同步信号(TFT)/帧同步信号(STN)/SEC TFT信号; HSYNC/VLINE/CPV:水平同步信号(TFT)/行同步脉冲信号(STN)/SEC TFT信号;VCLK/LCD_HCLK:象素时钟信号(TFT/STN)/SEC TFT信号;VD[23:0]:LCD像素数据输出端口(TFT/STN/SEC TFT);VDEN/VM/TP:数据使能信号(TFT)/LCD驱动交流偏置信号(STN)/SEC TFT 信号;LEND/STH:行终止信号(TFT)/SEC TFT信号;LCD_LPCOE:SEC TFT OE信号;LCD_LPCREV:SEC TFT REV信号;LCD_LPCREVB:SEC TFT REVB信号。
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 的控制等几个方面, 当然也包括软件的上层程序。
1.44寸tftlcd驱动程序详解

1.44寸tftlcd驱动程序详解1.44寸TFT LCD(TFT液晶显示屏)是一种小型彩色液晶屏,通常应用于嵌入式系统和消费电子产品中。
为了使其正常显示图像,需要编写相应的驱动程序。
下面是对1.44寸TFT LCD驱动程序的详细解析:1. 建立通信:首先,需要确定与TFT LCD之间的通信接口,例如SPI (串行外设接口),I2C(串行总线接口)或并行接口等。
根据选定的接口,配置相应的引脚和通信参数,以确保正确的数据传输。
2. 初始化LCD控制器:接下来,需要初始化LCD控制器。
这包括设置控制器的工作模式、像素格式、扫描方向等。
此外,还需设置LCD的分辨率和颜色模式,以确定显示的像素数和色彩深度。
3. 像素数据传输:在驱动程序中,需要实现像素数据的传输和写入。
根据TFT LCD的工作原理,像素数据一般以行为单位进行传输。
通过逐行扫描,将图像数据按照指定的颜色格式和像素排列方式写入LCD的显示缓冲区。
4. 刷新显示:驱动程序需要定期刷新LCD的显示,以确保图像持续显示并且没有残留。
可以使用定时器中断或其他方式来触发刷新操作。
在刷新过程中,将显示缓冲区的数据传输到实际的LCD面板上,使其显示出正确的图像。
5. 特殊功能:根据不同的TFT LCD型号和应用需求,可能还需要实现一些特殊功能。
例如,调节LCD的亮度、对比度和背光等。
这些功能可以通过操作LCD控制器的寄存器来实现。
6. 错误处理:在驱动程序中,还需要添加适当的错误处理机制。
这可以包括检测和处理通信错误、数据传输错误以及其他异常情况。
通过合理的错误处理,可以提高驱动程序的健壮性和可靠性。
综上所述,编写1.44寸TFT LCD驱动程序需要建立通信接口、初始化LCD控制器、像素数据传输、刷新显示、实现特殊功能以及添加错误处理。
这样的驱动程序可以确保TFT LCD正常工作并显示出准确的图像。
驱动程序的编写需要根据具体的硬件规格和驱动芯片的特性进行调整和优化,以实现最佳的性能和用户体验。
LCD驱动的介绍

HT56R6x LCD驅動應用介紹文件編碼:HA0178T簡介HT56R6x均內建有R、C-Type LCD驅動功能提供1/2 bias或1/3 Bias、4個COM的驅動能力,以及兩種LCD驅動波形輸出方式 --- Type A和Type B。
本文以HT56R64為母體,給出一種1/3 Bias、1/4 Duty的LCD驅動使用方法。
工作原理根據LCD的驅動原理可知,LCD像素點上只能加上AC電壓,如果加上DC電壓,將會引起永久性的破壞。
LCD顯示器的對比度由COM腳上的電壓值減去SEG腳上的電壓值決定,當這個電壓差大於LCD的飽和電壓就能打開像素點,小於LCD閾值電壓就能關閉像素點,LCD型MCU已經由內建的LCD驅動電路自動產生LCD驅動信號,因此只要組合好相應COM埠和SEG埠的驅動信號,就能完成LCD的驅動。
HT56R6x系列微控制器有內部LCD信號產生電路以及多種配置選項,可以自動地產生時間和增益可變的信號直接驅動LCD,與用戶的介面連接也相當容易。
該系列微控制器都為LCD資料提供特殊的資料暫存器,這樣的資料區域就是LCD記憶體。
任何寫入此處的資料,會自動地被內部LCD驅動電路讀取,進而自動地產生所需要的LCD驅動信號。
因此任何寫入LCD驅動器的資料,可以同過連接微控制器的LCD顯示器上顯示出來。
HT56R64中LCD資料記憶體的儲存區域為儲存區1 (即 Bank1) 中的40H~60H區域,記憶體指針Bank Pointer (BP) 是通用記憶體LCD顯示記憶體之間切換的開關。
當BP被設定為"1",任何資料寫入40H~60H (用MP1和R1間接尋址訪問) 將會影響LCD的顯示。
當BP被清除為"0",任何資料寫入40H~60H意味著訪問一般意義上的資料記憶體。
12HT56R64 LCD 顯示幕顯示如下:LCD Memory MapLCD 驅動器的輸出數目由兩個控制LCD 輸出的暫存器 -- LCDOUT1、LCDOUT2來決定。
MTK平台LCD驱动过程详解

MTK平台LCD驱动过程详解
首先,MTK平台LCD驱动的基本任务是将图像数据转换为可显示的信号,并通过LCD控制器将信号传输到液晶显示器上。
这个过程主要包括以下几个步骤:
1.初始化:在驱动LCD之前,需要对LCD控制器进行初始化设置。
这些设置包括选择LCD接口类型、设置像素时钟频率、配置数据线数目、设置显示像素点数等。
初始化完成后,LCD控制器就可以根据这些设置来控制LCD的操作。
2.数据处理:接下来,驱动程序需要将图像数据转换为LCD可以接受的格式。
这个过程可以包括调整图像数据的位深度、颜色格式、调整图像的分辨率等。
转换完成后,图像数据就可以传输到LCD控制器。
3.数据传输:在传输数据之前,驱动程序需要根据像素时钟频率和数据线数目等参数,计算出每一行数据需要的传输时间。
然后,通过LCD控制器将图像数据按行传输到LCD上。
传输完成后,LCD控制器会自动将数据驱动到液晶显示器的每一个像素点上。
4.功能控制:在数据传输的同时,驱动程序还需要控制LCD的各种功能,如背光控制、电源管理、色彩校正等。
这些功能控制可以通过编程接口进行设置。
5.刷新显示:一旦将图像数据传输到液晶显示器上,驱动程序可以根据需要定期刷新显示图像。
刷新可以通过设置刷新频率、调整显示内容等方式进行。
总的来说,MTK平台LCD驱动的过程可以分为初始化、数据处理、数据传输、功能控制和刷新显示等几个步骤。
通过这些步骤,驱动程序可以
将图像数据转换并传输到液晶显示器上,实现图像的显示功能。
这些步骤需要通过编程接口和LCD控制器进行交互,以完成LCD驱动的过程。
LCD_驱动原理解析

生 的。它的数据传输率最高可达132Mbytes/s。它的许多引线引自CPU,因
而负 载能力相对较差。随着Pentium级计算机的不断普及,PCI总线产品所占的
LVDS信号传输采用多通道串口方式。串口是每条通道顺序传输8位灰 度数据。但是并口并不比串口传输速度快,由于8位通道之间的互相 干扰,传输时速度就受到了限制。而且当传输出错时,要同时重新传 8个位的数据。串口没有干扰,传输出错后重发一位就可以了。所以 要比并口快。再加上LVDS信号有四条通道传输8位数据,这样比CMOS/ TTL传输通道要快许多。
SXGA@60Hz 1280 pixels 408 pixels 0 pixel 48 pixels 112 pixels 248 pixels 0 pixel 1024 lines 42 lines 0 line 1 line 3 lines 38 lines 0 line 108 MHz (9.3nS)
A bit of progress every dBaOyE!Copyright ⓒ 2009
液晶显示器的图象表示规格
图象表示规格 Color Graphics Adapter Enhanced Graphics Adapter
Video Graphics Array Super VGA
eXtended Graphics Array Engineering Work Station
XGA @ 75Hz 1024 pixels 288 pixels 0 pixels 16 pixels 96 pixels 166 pixels 0 pixels 768 lines 32 lines 0 line 1 lines 3 lines 28 lines 0 line 78.5 MHz(12.7nS)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LCD驱动分析_LCD控制器设置及代码详解
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屏)。
3. 常见TFT屏工作时序分析:
LCD提供的外部接口信号:。