VxWorks开发板驱动程序学习之LCD(2.2寸)
来源:互联网 发布:域名怎么注册? 编辑:程序博客网 时间:2024/04/30 10:49
- TFT22
- TFT简介
- 2寸LCD实物图
- 原理图
- TFTLCD 驱动芯片
- ILI9320
- 驱动程序学习
- VxWorks API open read
- open
- read
- VxWorks API open read
今天继续学习VxWorks开发板上的2.2寸LCD屏驱动程序。
先来介绍一下开发板上用的2.2寸的LCD屏。
TFT2.2
这里介绍的TFT2.2相关资料,部分来自网页,部分来自@正点原子 的STM32不完全手册寄存器版本_V3.0 文档,在此一并表示感谢。
TFT简介
TFT-LCD 即薄膜晶体管液晶显示器。其英文全称为: Thin Film Transistor-Liquid Crystal Display。 TFT-LCD 与无源 TN-LCD、 STN-LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管( TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。 TFT-LCD 也被叫做真彩液晶显示器。
2.2寸LCD实物图
先来看看开发板上所带LCD屏外观,上实物图:
然而并没有多美观。此2.2寸TFT液晶屏,分辨率为240*320,高320像素,宽240像素。
原理图
再来看看这个LCD显示屏和开发板接口的原理图:
其中 有
DB0-DB15 共16位数据线
X+,X-,Y+,Y- 四个坐标信号线
RESEST
RD
WR
CS
RS
VDD、GND 电源
再看看这些引脚与S3C2410的连接:(与2410的连接,地址线中,实际用到的,只有A0-A3, A7)
这是这块开发板上的系统总线通过JB2的32针接口扩展。总共包含16条数据线(D0-D15),8条地址线(A0-A7)、还有一些控制信号线(片选、读写、复位等),同时JB2可以向外提供3.3V电压输出。而实际应用中很少有用户通过总线扩展外设。
此开发板通过这个总线外接2.2寸TFT液晶屏。可以看到LCD2.2显示屏总共引出32根口线,其中
- D0-D15 共16位数据线
- A0-A7 共8位地址线
- RD 读信号
- WR 写信号
- EXCS2 外部片选2
- EXCS3 外部片选3
- VDD33 x 2
- GND x 2
除去4位电源线,现在再来看看,剩下的信号线的实际连接,先来看看 数据线:
很清晰,16位数据线直接通过排阻拉到了S3C2410的DATA[15:0]数据总线上。
再看看地址线:
也是很直接地通过排阻接到S3C2410的 ADDR[7:0]地址总线上。
再来看 EXCS2和EXCS3 两个外部片选信号的连接:
可以看到,此处的两个外部片选信号通过两个电阻直接接到了 S3C2410的 GPA13、GPA14两个位上,这两个口线均可复用作片选信号:nGCS2 、nGCS3
由上可知 nGCS2 接了LCD2.2的片选信号,nGCS3接了LCD2.2的复位信号。
最后来看看,读写控制信号:
读写信号直接通过电阻接到 S3C2410的 nOE、nWE 上了。
TFTLCD 驱动芯片
有了TFTLCD硬件模块,还得有相应的驱动芯片才行。常见的型号众多:ILI9341/ILI9325/RM68042/RM68021/ILI9320/ILI9328/LGDP4531/LGDP4535/SPFD5408/SSD1289/1505/B505/C505/NT35310/NT35510 等。
本开发板上用的是 ILI9320DS,接下来先简单了解一下 ILI9320DS。
ILI9320
{关于ILI9320的操作,请直接学习datasheet和相关的网站,@正点原子 讲STM32的教程里面也对ILI系列的操作非常清晰,可查阅相关资料,此处暂时略去,回头再来学习}
驱动程序学习
此处再来回顾一下开发板的2410与TFT驱动ILI9320的连接:
这是一种典型的总线扩展方式,具体不会的,此处暂以红色标记,回头再来学习。
下面开始来学习驱动代码:
#define LCD22_COM_BASE (0X10000000) //CS2#define LCD22_DATA_BASE (0X10000080)
先看看S3C2410复位后的存储器映射:
可以看到, nGCS2 所指向的SROM区首地址为 0x1000_0000,也就是总线扩展出来驱动LCD驱动芯片的基地址了。但 LCD22_DATA_BASE 宏为什么是在此基础上偏移8*16 = 128个字节,此时还不懂,待学习。
接下来几个函数简单,边看边注释,
void delayms(int count) // X1ms{ int i,j; for(i=0;i<count;i++) for(j=0;j<100;j++); }void Lcd_Write_Com(UINT16 com) // 发送命令{ *(volatile UINT16 *)LCD22_COM_BASE = com; // 直接往 0x1000_0000 写数据}void Lcd_Write_Data(UINT16 data) // 发送数据{ *(volatile UINT16 *)LCD22_DATA_BASE = data; // 0x1000_0080 **地址是为何?}void Lcd_Write_Com_Data(UINT16 com,UINT16 val) // 发送数据命令{ Lcd_Write_Com(com); Lcd_Write_Data(val);}
此处的 Lcd_Write_Com_Data 函数先写命令,再写数据,实现S3C2410向ILI9320发送命令字控制显示的作用。
// 函数名称:Address_set// 函数功能:设置起始点位置,可以理解为绘图开窗void Address_set(UINT16 x1,UINT16 y1,UINT16 x2,UINT16 y2){ Lcd_Write_Com(0x0020);Lcd_Write_Data(x1); // 设置X坐标位置 Lcd_Write_Com(0x0021);Lcd_Write_Data(y1); // 设置Y坐标位置 Lcd_Write_Com(0x0050);Lcd_Write_Data(x1); // 设置X开始 Lcd_Write_Com(0x0052);Lcd_Write_Data(y1); // 设置Y开始 Lcd_Write_Com(0x0051);Lcd_Write_Data(x2); // 设置X结束 Lcd_Write_Com(0x0053);Lcd_Write_Data(y2); // 设置Y结束 Lcd_Write_Com(0x0022); }
这个 Address_set 函数设置相关位置,就不得不提一下ILI9320的指令描述了。直接看datasheet 上的表格:
具体到每条指令的值如何设置,作用是何就要自己查阅datasheet了。此节只对用到的几条指令做简单讲解。
从表格来看和上面代码中的中文注释是一致的。
接下来是LCD2.2初始化函数,这个函数非常重要:
void Lcd22_Init(void){ UINT32 dwValReg; // GPA[14]: 0=Output, 1=nGCS3 SNGS3C_REG_READ( rGPACON, dwValReg ); dwValReg = dwValReg & (~(1<<14)); SNGS3C_REG_WRITE( rGPACON, dwValReg ); // 配置GPA[14]为普通输出,控制TFT2.2的复位信号 // 连续复位TFT2.2两次, ILI9320需要上电复位,低电平复位 *(volatile UINT32 *)rGPADAT |=(1<<14); taskDelay(1); *(volatile UINT32 *)rGPADAT &=~(1<<14); // 复位 taskDelay(1); *(volatile UINT32 *)rGPADAT |=(1<<14); taskDelay(1); Lcd_Write_Com_Data(0x0000, 0x0001); // Start internal OSC. Lcd_Write_Com_Data(0x0001, 0x0100); // set SS and SM bit Lcd_Write_Com_Data(0x0002, 0x0700); // set 1 line inversion Lcd_Write_Com_Data(0x0003, 0x0030); // set GRAM write direction and BGR=1. Lcd_Write_Com_Data(0x0004, 0x0000); // Resize register Lcd_Write_Com_Data(0x0008, 0x0207); // set the back porch and front porch Lcd_Write_Com_Data(0x0009, 0x0000); // set non-display area refresh cycle ISC[3:0] Lcd_Write_Com_Data(0x000A, 0x0000); // FMARK function Lcd_Write_Com_Data(0x000C, 0x0000); // RGB interface setting Lcd_Write_Com_Data(0x000D, 0x0000); // Frame marker Position Lcd_Write_Com_Data(0x000F, 0x0000); // RGB interface polarity // power on sequence Lcd_Write_Com_Data(0x0010, 0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB Lcd_Write_Com_Data(0x0011, 0x0000); // DC1[2:0], DC0[2:0], VC[2:0] Lcd_Write_Com_Data(0x0012, 0x0000); // VREG1OUT voltage Lcd_Write_Com_Data(0x0013, 0x0000); // VDV[4:0] for VCOM amplitude delayms(20); // Dis-charge capacitor power voltage Lcd_Write_Com_Data(0x0010, 0x1590); // SAP, BT[3:0], AP, DSTB, SLP, STB Lcd_Write_Com_Data(0x0011, 0x0007); // DC1[2:0], DC0[2:0], VC[2:0] delayms(20); // Delay 50ms Lcd_Write_Com_Data(0x0012, 0x013A); // VREG1OUT voltage delayms(20); // Delay 50ms Lcd_Write_Com_Data(0x0013, 0x1500); // VDV[4:0] for VCOM amplitude Lcd_Write_Com_Data(0x0029, 0x0000); // VCM[4:0] for VCOMH delayms(20); Lcd_Write_Com_Data(0x0020, 0x0000); // GRAM horizontal Address Lcd_Write_Com_Data(0x0021, 0x0000); // GRAM Vertical Address // Adjust the Gamma Curve Lcd_Write_Com_Data(0x0030, 0x0000); Lcd_Write_Com_Data(0x0031, 0x0707); Lcd_Write_Com_Data(0x0032, 0x0700); Lcd_Write_Com_Data(0x0035, 0x0004); Lcd_Write_Com_Data(0x0036, 0x1f00); Lcd_Write_Com_Data(0x0037, 0x0004); Lcd_Write_Com_Data(0x0039, 0x0007); Lcd_Write_Com_Data(0x003C, 0x0400); Lcd_Write_Com_Data(0x003D, 0x1f00); Lcd_Write_Com_Data(0x0050, 0x0000); // Horizontal GRAM Start Address Lcd_Write_Com_Data(0x0051, 0x00EF); // Horizontal GRAM End Address Lcd_Write_Com_Data(0x0052, 0x0000); // Vertical GRAM Start Address Lcd_Write_Com_Data(0x0053, 0x013F); // Vertical GRAM Start Address Lcd_Write_Com_Data(0x0060, 0x2700); // Gate Scan Line Lcd_Write_Com_Data(0x0061, 0x0001); // NDL,VLE, REV Lcd_Write_Com_Data(0x006A, 0x0000); // set scrolling line // Partial Display Control Lcd_Write_Com_Data(0x0080, 0x0000); Lcd_Write_Com_Data(0x0081, 0x0000); Lcd_Write_Com_Data(0x0082, 0x0000); Lcd_Write_Com_Data(0x0083, 0x0000); Lcd_Write_Com_Data(0x0084, 0x0000); Lcd_Write_Com_Data(0x0085, 0x0000); // Panel Control Lcd_Write_Com_Data(0x0090, 0x0013); Lcd_Write_Com_Data(0x0092, 0x0000); Lcd_Write_Com_Data(0x0093, 0x0003); Lcd_Write_Com_Data(0x0095, 0x0110); Lcd_Write_Com_Data(0x0097, 0x0000); Lcd_Write_Com_Data(0x0098, 0x0000); Lcd_Write_Com_Data(0x0007, 0x0173); }
这个函数就不再具体分析,全部是对TFT2.2写指令数据,可以参照@正点原子的TFTLCD模块使用流程图:
接下来看看再个非常实际的驱动函数:
// 函数名称: Pant// 函数功能: 整屏写入数据void Pant(UINT16 data){ int i,j; Address_set(0,0,240,320); // 设置开始和结束点的位置,以像素为单位,宽240p,高320p for(i=0; i<320; i++) { for(j=0; j<240; j++) { Lcd_Write_Data(data); // 挨个像素点,整屏全部写入参数数据,初始化的时候设置好参数,可以自动扫描(地址指针自动加) } }}
// 函数名称:Lcd22DispPicture// 函数功能:在TFT2.2寸显示屏指定开窗区域显示图片void Lcd22DispPicture(UINT16 x1,UINT16 y1,UINT16 x2,UINT16 y2,char* DispBuf){ int j; UINT16 dispdata; Address_set(x1,y1,x2,y2); // 开窗左上角(x1,y1),右下角(x2,y2) for (j=0;j<(x2-x1)*(y2-y1);j++) { dispdata=DispBuf[j*2+1]; dispdata=(dispdata<<8)|DispBuf[j*2]; Lcd_Write_Data(dispdata); // 挨个像素点写入16位的图像数据 }}// 其中,图片数据 DispBuf 组织格式为:两个char元素为一个像素点数据// 其中前一个字节为高8位,后一个字节为低8位
有了上面这个开窗绘图函数 Lcd22DispPicture,还需要为其组织图片数据,也就是下面这个函数了:
// 函数名称:WriteLcd22Buf// 函数功能:由文件名读出图片数据组织为可以直接写入到ILI9320的格式数组buf里面int WriteLcd22Buf(char* FileName,char* DispBuf){ int iFileSize; int fd; iFileSize = 0; fd = open(FileName, O_RDONLY, 0); // VxWorks 系统API函数 if(ERROR == fd) { return ERROR; } iFileSize = read(fd, (DispBuf + iFileSize), 200*1024); if(ERROR == iFileSize) { printf("Failed to read the file! return!\n"); close(fd); return ERROR; } close(fd); return iFileSize;}
这个函数也没有什么好说的,直接打开文件并读取文件数据到 DispBuf中,这可以证明原始的图片文件就已经是满足要求格式(两个字节一个像素点,前一个字节高8位,后一个字节低8位)的文件。
但此处要讲的是VxWorks的两个API函数 open, read.
VxWorks API — open, read
打开VxWorks的API参考手册(file:///D:/Tornado2.2/docs/VxWorks_API_Reference.htm),进入到 OS Library中,找到I字母打头的库,可以看到I/O interface library库—— ioLib,该IO接口库包含了以下函数:
ROUTINES:
creat( ) - create a file
open( ) - open a file
unlink( ) - delete a file (POSIX)
remove( ) - remove a file (ANSI)
close( ) - close a file
rename( ) - change the name of a file
read( ) - read bytes from a file or device
write( ) - write bytes to a file
ioctl( ) - perform an I/O control function
lseek( ) - set a file read/write pointer
ioDefPathSet( ) - set the current default path
ioDefPathGet( ) - get the current default path
chdir( ) - set the current default path
getcwd( ) - get the current default path (POSIX)
getwd( ) - get the current default path
ioGlobalStdSet( ) - set the file descriptor for global standard input/output/error
ioGlobalStdGet( ) - get the file descriptor for global standard input/output/error
ioTaskStdSet( ) - set the file descriptor for task standard input/output/error
ioTaskStdGet( ) - get the file descriptor for task standard input/output/error
isatty( ) - return whether the underlying driver is a tty device
ioLib总共包含20个函数,可以分为以下四类:
- 7个基本驱动:create(), remove(), open(), close(), read(), write(), ioctl()
- 文件系统功能:rename(), lseek()
- 设置或获取当前工作目录:ioDefPathSet(), ioDefPathGet(), chdir(), getcwd(), getwd()
- 指派任务和全局标准文件描述符:ioTaskStdSet(), ioTaskStdGet(), ioGlobalStdSet(), ioGlobalStdGet()
- isatty():判断基础驱动是否是一个tty设备
在VxWorks中,基本的IO层,用一个小的整数(文件描述符)来描述文件,通常是一个由open()或create()返回的值。
三个保留的文件描述符:
- 0 (STD_IN)
- 1 (STD_OUT)
- 2 (STD_ERR)
用到IO库里面的文件(比如此处的 open(), read())时均需要包含头文件 ioLib.h
open
SYNOPSIS
int open ( const char* name, int flags, /* O_RDONLY, O_WRONLY, O_RDWR, or O_CREAT */ int mode /* mode of file to create(UNIT chmod style) */ )
通常,open()只能打开存在的设备或文件,然而NFS网络设备也可以通过open()函数来创建,例子:
fd = open("/usr/myFile", O_CREAT | O_RDWR, 0644);
当然也只有NFS驱动使用这个mode参数。
RETURNS
A file descriptor number, or ERROR if a file name is not specified, the device does not exist, no file descriptors are available, or the driver returns ERROR.
ERRNO
ELOOP
read
NAME
read() - - - read bytes from a file or device
SYNOPSIS
int read ( int fd, /* file descriptor from which to read */ char * buffer, /* pointer to buffer to receive bytes */ size_t maxbytes /* max no. of bytes to read into buffer */ )
read函数从fd读取最多maxbytes的数据到buffer,实际会调用底层设备驱动来工作。
RETURNS
The number of bytes read (between 1 and maxbytes, 0 if end of file), or ERROR if the file descriptor does not exist, the driver does not have a read routines, or the driver returns ERROR. If the driver does not have a read routine, errno is set to ENOTSUP.
函数返回读取到的实际数据字节数(1<= returns <= maxbytes),遇到文件结束就返回0;若底层驱动没有读取函数,则置错误号 errno 为 ENOTSUP.
TFTLCD2.2寸液晶屏的驱动程序到此基本结束,再来看看向外部提供的任务接口函数:
//2*240*320=153600, 定义一个全局的缓存用来存储整屏数据,按前分析,大小应两倍于像素点个数unsigned char Lcd22DispBuf[153600];// 函数名称:Lcd_Main// 函数功能:界面显示处理主函数int Lcd_Main(void){ UINT16 dispdata; int i, j, k; Lcd22_Init(); // TFT LCD 初始化 taskDelay(1); Pant(0xffff); // 清屏 Pant(0xf800); // 红屏 taskDelay(120); Pant(0x07E0); // 绿屏 taskDelay(120); Pant(0x001f); // 蓝屏 taskDelay(120); i = 0; while(1) { if(4 == MenuDisp) // 一个全局变量指示进入图片测试界面 { i++; switch(i) { case 1: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 2: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 3: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 4: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 5: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 6: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 7: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; case 8: WriteLcd22Buf("/C/butterfly240.bin", Lcd22DispBuf); break; } i %= 9; Lcd22DispPicture(0,0,240,240,Lcd22DispBuf); // 开窗绘图 taskDelay(120); // 延时让出CPU } else // 退出图片界面 { i = 0; WriteLcd22Buf("/C/RK2410-240.bin", Lcd22DispBuf); Lcd22DispPicture(0,0,240,240,Lcd22DispBuf); // 显示标准LOGO界面 taskDelay(10); } }}
好了,开发板的LCD2.2寸液晶屏驱动程序就学习到这里,可以看到,除了LCD2.2屏驱动芯片ILI9320的驱动程序还需要仔细学习外,应用上驱动一个LCD屏还是比较容易的。
以上代码几乎全部来自Rock,若有侵权,请联系我删除,谢谢!
- VxWorks开发板驱动程序学习之LCD(2.2寸)
- VxWorks开发板驱动程序学习之IIC
- VxWorks开发板驱动程序学习之LED
- VxWorks开发板驱动程序学习之KEY
- VxWorks开发板驱动程序学习之SPI
- VxWorks开发板驱动程序学习之普通ADC驱动
- VxWorks开发板驱动程序学习之内部UART0
- VxWorks开发板驱动程序学习之SD卡
- VxWorks开发板驱动程序学习之文件系统(一)
- S5PV210 之Sate210-F 开发板配套七寸LCD 调试成功,解决了显示上下左右相反的问题
- 嵌入式系统学习——S3C2451之2.4寸LCD函数封装
- 卖一个二手的idea6410 开发板(带wifi模块以及4.3寸LCD的)
- ok6410之lcd驱动程序设计
- lcd驱动程序之显示图片
- linux之lcd驱动程序总结
- LCD驱动程序之硬件操作
- VxWorks下数据采集卡驱动程序开发
- VxWorks设备驱动程序开发指南(三)---驱动程序的分类
- 深入IO之 IO的工作机制 & IO模型
- BootstrapCDN和本地化
- 第二本第四章课后4加盟申请表
- 《改善Python程序的91个建议》阅读笔记
- BSS段和数据段的区别
- VxWorks开发板驱动程序学习之LCD(2.2寸)
- 剑指offer(10)-打印二叉树的镜像
- iOS 超Easy实现 渐变导航栏
- socket.io 实现在线聊天室
- 毕业的第一份工作,到底什么才重要
- 怎么安装VMwaretools在Linux系统里
- 2 进制的转化
- Git速查
- 51单片机—电亮LED灯