linux驱动之LCD(无framebuffer)

<简介>

a:什么是液晶

物质一般有三态,固态,气态,和液态。这只是一种比较大致的划分,但是有些物质介于液体和固体之间——液晶。一般固体的分子或原子都由固定的排列方式,但是液晶介于固体和液体之间,具有流动性和排列性,可以用磁场来改变液晶的排列方式。

b:LCD背光

场致发光(Electro-Luminescent),寿命5000-10000小时,常用于小型灰度LCD(俗称黑白)

冷阴极荧光灯(cold cathode fluorecsent lamp),寿命超过250000小时(原理:对填充惰性气体的密闭正空管通高压电,惰性气体电离产生紫光,紫光照射到荧光粉上产生可见关)。常作为彩色LCD的背光。

发光二极管(lightemitting diode),寿命超过100000小时。

c:LCD显示器分类

扭曲向列型(TN):只能显示黑白颜色

超扭曲向列型(STN):用于显示彩色

双层超扭曲向列型(DSTN):用于显示彩色,显示的颜色比STN更加细腻

c-1:以上显示器都有一个共同的缺点就是,在小屏幕下表象良好,但是在屏幕较大时,液晶显示时间较慢

薄膜晶体型(TFT)

注意:

其中TN-LCD,STN-LCD,DSTN-LCD其显示原理基本相同,区别仅仅是扭曲的角度不同而已。

TFT-LCD使用的是一种和TN-LCD,STN-LCD,DSTN-LCD完全不同的显示原理

<LCD驱动主要完成的工作>

a:结构图

b:分析

b-1:大体寄存器功能

从上面结构图可以看出:整个lcd控制器大致可以由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器几个部分组成。

b-1-1:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的

b-1-2:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,视频数据在不需要 CPU的干预的情况下显示在LCD屏上

b-1-2:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器

b-1-3:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。

c:LCD提供的外部接口信号:

c-1:VSYNC/VFRAME/STV:垂直同步信号(TFT)/帧同步信号(STN)/SEC TFT信号

c-2:HSYNC/VLINE/CPV:水平同步信号(TFT)/行同步脉冲信号(STN)/SEC TFT信号

c-3:VD[23:0]:LCD像素数据输出端口(TFT/STN/SEC TFT);

c-4:VDEN/VM/TP:数据使能信号(TFT)/LCD驱动交流偏置信号(STN)/SEC TFT 信号

c-5:说明:

c-5-1:显示指针从矩形左上角的第一行第一个点开始,一个点一个点的在LCD上显示,在上面的时序图上用时间线表示就为VCLK,我们称之为像素时钟信号;

c-5-2:当显示指针一直显示到矩形的右边就结束这一行,那么这一行的动作在上面的时序图中就称之为1 Line;

c-5-3:接下来显示指针又回到矩形的左边从第二行开始显示,注意,显示指针在从第一行的右边回到第二行的左边是需要一定的时间的,我们称之为行切换;

c-5-4:如此类推,显示指针就这样一行一行的显示至矩形的右下角才把一副图显示完成。因此,这一行一行的显示在时间线上看,就是时序图上的HSYNC

c-5-5:然而,LCD的显示并不是对一副图像快速的显示一下,为了持续和稳定的在LCD上显示,就需要切换到另一幅图上(另一幅图可以和上一副图一样或者不一样,目的只是为了将图像持续的显示在LCD上)。那么这一副一副的图像就称之为帧,在时序图上就表示为1 Frame,因此从时序图上可以看出1 Line只是1 Frame中的一行;

c-5-6:同样的,在帧与帧切换之间也是需要一定的时间的,我们称之为帧切换,那么LCD整个显示的过程在时间线上看,就可表示为时序图上的VSYNC

下面是时序图:

VBPD(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数,对应驱动中的upper_margin;

VFBD(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,对应驱动中的lower_margin;

VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,对应驱动中的vsync_len;

HBPD(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数,对应驱动中的left_margin;

HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,对应驱动中right_margin;

HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,对应驱动中的hsync_len;

行频和场频的计算:

行频 = VCLK /[(HSPW+1)+(HSPD+1)+(HFPD+1)+(HOZVAL+1)]

场频 =行频 /[(VSPW+1)+(VBPD+1)+(VFPD+1)+(LINEVAL+1)]

接下来了解下相关寄存器的字段结构:

对于以上这些参数的值将分别保存到REGBANK寄存器组中的LCDCON1/2/3/4/5寄存器中

LCDCON1:LINECNT18--27设置屏的行数,最大1024行,从LINECNT计数到0,真正要显示区域的大小是在LCDCON2中的LINEVAL设置;CLKVAL 8--17用于设置分频因子,STN: VCLK = HCLK / (CLKVAL x 2)  ( CLKVAL ≥2 )   TFT: VCLK = HCLK / [(CLKVAL+1) x 2]    ( CLKVAL ≥ 0 );   6 - 5位扫描模式(对于STN屏:4位单/双扫、8位单扫); 4 - 1位色位模式(1BPP、8BPP、16BPP等);

LCDCON2:用于设置VBPD,LINEVAL,VFBD,VSPW,对于STN屏VBPD,VFBD,VSPW值都为0。

LCDCON3:功能类似LCDCON2,只是用于垂直方向的一些参数。

LCDCON5:用于查询和设置一些状态信息。

编程步骤:

1、打开LCD背光

将LCD背光对应的GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)。

2、打开LCD电源

可以将GPG4选择为LCD_PWREN(GPGCON:9-8写入11),这时候LCD电源的打开/关闭可以通过LCDCON5:3来控制。

也可以自定义其他GPIO用作LCD电源开关,只需将此GPIO设置为禁止上拉(GPxUP相应位写入1),选择output类型(GPxCON相应位写入01),输出为高电平(GPxDAT相应位写入1)打开LCD电源。

3、设置其他信号线

其他信号线包括VD0-VD23和VFRAME、VLINE、VCLK等,分别在GPCCON,GPDCON中选择相应功能。

4、设置LCD的频率(VCLK)

LCD的Datasheet上一般会写有一个推荐的频率,比如我使用的屏幕推荐频率为6.4M,我需要通过一些计算选择一个合适的CLKVAL以产生这个频率:

对于TFT LCD,S3C2440提供的VCLK的计算公式为:

VCLK = HCLK / ((CLKVAL+1)*2)

可以得出:

CLKVAL = HCLK / (VCLK * 2) - 1

我的HCLK是100Mhz(CPU运行在400Mhz, CLKDIV_VAL设置为5,Fclk:Hclk:Pclk = 1:4:8),VCLK使用屏幕推荐的6.4M,得到:

CLKVAL = 100000000 / (6400000 * 2) - 1 = 6.8

选择最接近的整数值7,写入LCDCON1:17-8。

(VCLK其实就是根据 每秒帧数*帧行数*行像素  计算出来的,帧行数和行像素需要包含空白数和同步数)

5、设置其他相关参数

LCD相关的参数主要还有这几个:

LINEVAL: LCD水平像素-1,如320-1 = 319

HOZVAL:  LCD垂直像素-1,如240-1 = 239

HFPD:    行开始前的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)

HBPD:    行结束后的VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)

HSPW:    行之间水平同步的无效VCLK时钟数(LCD屏幕的Datasheet一般有推荐值)

VFPD:    帧数据开始前的空白行数(LCD屏幕的Datasheet一般有推荐值)

VBPD:    帧数据结束后的空白行数(LCD屏幕的Datasheet一般有推荐值)

VSPW:    帧之间垂直同步的无效行数(LCD屏幕的Datasheet一般有推荐值)

(相关寄存器LCDCON2, LCDCON3, LCDCON4)

6、设置视频缓冲区的地址

2440支持虚拟屏幕,可以通过改变LCD寄存器实现屏幕快速移动

PAGEWIDTH:虚拟屏幕一行的字节数,如果不使用虚拟屏幕,设置为实际屏幕的行字节数,如16位宽320像素,设为320 * 2

OFFSIZE:虚拟屏幕左侧偏移的字节数,如果不使用虚拟屏幕,设置为0

LCDBANK: 视频帧缓冲区内存地址30-22位

LCDBASEU: 视频帧缓冲区的开始地址21-1位

LCDBASEL: 视频帧缓冲区的结束地址21-1位

(相关寄存器LCDSADDR1,LCDSADDR2,LCDSADDR3)

7、确定信号的极性

2440的LCD控制器允许设置VCLK、VLINE、VFRAME等信号的极性(上升沿有效还是下降沿有效),需要对照LCD的Datasheet一一确认。

(相关寄存器LCDCON5)

8、禁止LPC3600/LCC3600模式!

如果不是使用三星LPC3600/LCC3600 LCD,必须禁止LPC3600/LCC3600模式(写入0到TCONSEL)!

9、打开视频输出

ENVID设为1 (LCDCON1:0写入1)

<LCD驱动实例——无framebuffer>

a:def.h

#ifndef __DEF_H__

#define __DEF_H__

#define U32 unsigned long

#define U16 unsigned short

#define S32 long

#define S16 short

#define U8  unsigned char

#defineS8  char

#define I8    char

#define I16   short

#define I32   long

#define I16P I16

#define U16P U16

#define TRUE 1

#define FALSE 0

#endif /*__DEF_H__*/

b:lcd_driver.h

#ifndef __LCDLIB_H__

#define __LCDLIB_H__

#include <string.h>

#include <stddef.h>

#include "GLib.h"

#define MVAL(13)

#define MVAL_USED (0)

#define M5D(n) ((n) & 0x1fffff)// To get lower 21bits

//Color STN LCD Panel(320*240)

#define MODE_CSTN_8BIT   (0x2001)

#define MODE_CSTN_12BIT (0x2002)

//Color STN

#define LCD_XSIZE_CSTN (320)

#define LCD_YSIZE_CSTN (240)

//Color STN

#define SCR_XSIZE_CSTN (LCD_XSIZE_CSTN)   //*2for virtual screen

#define SCR_YSIZE_CSTN (LCD_YSIZE_CSTN)//*2

//Color STN

#define HOZVAL_CSTN(LCD_XSIZE_CSTN*3/8-1)// Valid VD data line number is 8.

#define LINEVAL_CSTN(LCD_YSIZE_CSTN-1)

//CSTN timing parameter for LCBHBT161M(NANYA)

#define WLH_CSTN        (0)

#define WDLY_CSTN(0)

#define LINEBLANK_CSTN(16 &0xff)

//Timing parameter for LTS350Q1(SAMSUNG)

#define VBPD_240320((2-1)&0xff)

#define VFPD_240320((3-1)&0xff)

#define VSPW_240320((2-1) &0x3f)

#define HBPD_240320((7-1)&0x7f)

#define HFPD_240320((3-1)&0xff)

#define HSPW_240320((4-1)&0xff)

#define CLKVAL_CSTN(6)

// 130hz @50Mhz,WLH=16hclk,WDLY=16hclk,LINEBLANK=16*8hclk,VD=8

#define LCDFRAMEBUFFER 0x33800000 //_NONCACHE_STARTADDRESS

// 1. The LCD frame buffer should be write-through or non-cachable.

// 2. The total frame memory should be inside 4MB.

// 3. To meet above 2 conditions, the frame buffer should be

// inside the following regions.

// 0x31000000~0x313ffffff,

// 0x31400000~0x317ffffff,

// 0x31800000~0x31bffffff,

//        .....

// 0x33800000~0x33bffffff

void Lcd_CstnOnOff(int onoff);

void LCD_Init(int type);

void Lcd_Port_Init(void);

#endif /*__LCDLIB_H__*/

c:lcd_driver.c

#include <linux/config.h>

#include <linux/utsname.h>

#include <linux/kernel.h>

#include <linux/major.h>

#include <linux/string.h>

#include <linux/fcntl.h>

#include <linux/slab.h>

#include <linux/timer.h>

#include <linux/init.h>

#include <linux/poll.h>

#include <linux/errno.h>

#include <linux/sched.h>

#include <linux/tty.h>

#include <linux/module.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/mm.h>

#include <asm/uaccess.h>

#include <asm/hardware.h>

#include <asm/io.h>

#include <asm/irq.h>

#include <asm/system.h>

#include <asm/proc/pgtable.h>

#include <asm/io.h>

#include <linux/poll.h>

#include <asm/arch/memory.h>

#include <asm/arch/io.h>

#include <asm/arch/smdk.h>

#include "def.h"

#define        MVAL         (13)

#define        MVAL_USED (0)

#define        M5D(n)            ((n) & 0x1fffff)// To get lower 21bits

#define        LCD_XSIZE_CSTN (320)

#define        LCD_YSIZE_CSTN (240)

#define        SCR_XSIZE_CSTN (LCD_XSIZE_CSTN)          //*2for virtual screen

#define        SCR_YSIZE_CSTN (LCD_YSIZE_CSTN)          //*2

#define        HOZVAL_CSTN (LCD_XSIZE_CSTN*3/8-1)   // Valid VD data line number is 8.

#define        LINEVAL_CSTN (LCD_YSIZE_CSTN-1)

#define        WLH_CSTN         (0)

#define        WDLY_CSTN (0)

#define        LINEBLANK_CSTN (16 &0xff)

#define        CLKVAL_CSTN (6)

#define        LCDFRAMEBUFFER    LCD_BASE                 //_NONCACHE_STARTADDRESS

set in the smdk.c

#define        BYTESPERLINE (LCD_XSIZE_CSTN)

typedef unsigned long tOff;

#define        XY2OFF(x,y) (tOff)((tOff)y*(tOff)BYTESPERLINE + (x))

#define        READ_MEM(Off, Data)    Data = LCD_READ_MEM(Off)

#define        WRITE_MEM(Off, Data)   LCD_WRITE_MEM(Off, Data)

#define        GETPIXEL(x, y)         GetPixelIndex(x, y)

#define        SETPIXEL(x, y, c)      SetPixel(x, y, c)

unsigned lcd_count;

void Lcd_CstnOnOff(int onoff);

U8 LCD_COLOR = 0x00;

U16 LCD_BKCOLOR;

#define LCD_MAJOR 60

/*

*************************************************************************************************************

- 函数名称 : void CloseLCD(struct inode * inode, struct file * file)

- 函数说明 : LCD关闭

- 输入参数 : struct inode * inode, struct file * file

- 输出参数 : 0

*************************************************************************************************************

*/

static void CloseLCD(struct inode * inode, struct file * file)

{

printk("LCD is closed\n");

return ;

}

/*

*************************************************************************************************************

- 函数名称 : static int OpenLCD(struct inode * inode, struct file * file)

- 函数说明 : LCD打开

- 输入参数 : struct inode * inode, struct file * file

- 输出参数 : 0

*************************************************************************************************************

*/

static int OpenLCD(struct inode * inode, struct file * file)

{

printk("LCD is open\n");

return 0;

}

/*

*************************************************************************************************************

- 函数名称 : static int LCDIoctl(struct inode *inode,struct file * file,unsigned int cmd,unsigned long arg)

- 函数说明 : LCD控制输出

- 输入参数 :

- 输出参数 : 0

*************************************************************************************************************

*/

static int LCDIoctl(struct inode *inode,struct file * file,unsigned long cmd,unsigned long arg)

{

//char color;

struct para

{

unsigned long a;

unsigned long b;

unsigned long c;

unsigned long d;

}*p_arg;

switch(cmd)

{

case 0:

printk("set color\n");

Set_Color(arg);

printk("LCD_COLOR =%x\n",LCD_COLOR);

return 1;

case 1:

printk("draw h_line\n");

p_arg =(struct para *)arg;

LCD_DrawHLine(p_arg->a,p_arg->b,p_arg->c);// draw h_line

LCD_DrawHLine(p_arg->a,p_arg->b+15,p_arg->c);// draw h_line

LCD_DrawHLine(p_arg->a,p_arg->b+30,p_arg->c);// draw h_line

return 1;

case 2:

printk("draw v_line\n");

p_arg =(struct para *)arg;

LCD_DrawVLine(p_arg->a,p_arg->b,p_arg->c); // draw v_line

LCD_DrawVLine(p_arg->a+15,p_arg->b,p_arg->c); // draw v_line

LCD_DrawVLine(p_arg->a+30,p_arg->b,p_arg->c); // draw v_line

return 1;

case 3 :

printk("drwa circle\n");

p_arg =(struct para *)arg;

LCD_DrawCircle(p_arg->a,p_arg->b,p_arg->c);// draw circle

return 1;

case 4:

printk("draw rect\n");

p_arg =(struct para *)arg;

LCD_FillRect(p_arg->a,p_arg->b,p_arg->c,p_arg->d);      // draw rect

return 1;

case 5:

printk("draw fillcircle\n");

p_arg =(struct para *)arg;

LCD_FillCircle(p_arg->a, p_arg->b, p_arg->c);// draw fillcircle

return 1;

case 6 :

printk("LCD is clear\n");

LCD_Clear(0,0,319,239);     // clear screen

return 1;

case 7:

printk("draw rect\n");

p_arg =(struct para *)arg;

LCD_FillRect(p_arg->a,p_arg->b,p_arg->c,p_arg->d);      // draw rect

return 1;

default:

return -EINVAL;

}

return 1;

}

/*

*************************************************************************************************************

- 函数名称 : struct file_operations LCD_fops

- 函数说明 : 文件结构

- 输入参数 : 无

- 输出参数 : 无

*************************************************************************************************************

*/

static struct file_operations LCD_fops =

{

ioctl:   LCDIoctl,           /* ioctl */

open:   OpenLCD,    /* just a selector for the real open */

release:   CloseLCD,            /* release */

};

/*

*************************************************************************************************************

- 函数名称 : U16  LCD_Init(U8 Lcd_Bpp)

- 函数说明 : LCD硬件初始化函数

- 输入参数 :

- 输出参数 : 无

*************************************************************************************************************

*/

U16  Setup_LCDInit(void)

{

long i; unsigned char * base;

GPCUP = 0xffffffff; // Disable Pull-up register

GPCCON= 0xaaaaaaaa; //Initialize VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND

GPDUP = 0xffffffff; // Disable Pull-up register

GPDCON= 0xaaaaaaaa; //Initialize VD[23:8]

// Packed Type : The L.C.M of 12 and 32 is 96.

LCDCON1 = (CLKVAL_CSTN<<8)|(MVAL_USED<<7)|(2<<5)|(3<<1)|0;

// 8-bit single scan,8bpp CSTN,ENVID=off

LCDCON2 = (0<<24)|(LINEVAL_CSTN<<14)|(0<<6)|0;

LCDCON3 = (WDLY_CSTN<<19)|(HOZVAL_CSTN<<8)|(LINEBLANK_CSTN<<0);

LCDCON4 = (MVAL<<8)|(WLH_CSTN<<0);

LCDCON5 = 2;

LCDADDR1 = ((U32)0x33800000>>22)<<21;

//use th physical address

LCDADDR2 = M5D((((SCR_XSIZE_CSTN )*LCD_YSIZE_CSTN))>>1);

LCDADDR3 = (((SCR_XSIZE_CSTN - LCD_XSIZE_CSTN)/2)<<11)|(LCD_XSIZE_CSTN / 2);

DITHMODE = 0;

REDLUT   = 0xfdb96420;

GREENLUT = 0xfdb96420;

BLUELUT  = 0xfb40;

base =(unsigned char*)LCD_BASE;

Lcd_CstnOnOff(1);

for(i=0;i<320*240;i++)

{

*base++ = 0xff;

}

return 0;

}

/*

*************************************************************************************************************

- 函数名称 : U16 LCD_READ_MEM(U32 off)

- 函数说明 : 针对硬件的读点函数

- 输入参数 : x,y,c

- 输出参数 : 无

*************************************************************************************************************

*/

U16 LCD_READ_MEM(U32 off)

{

return (*((U8*)LCDFRAMEBUFFER + (off)));

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_WRITE_MEM( U32 off,U8 Data)

- 函数说明 : 针对硬件的画点函数

- 输入参数 : x,y,c

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_WRITE_MEM( U32 off,U8 Data)

{

(* ((U8*)LCDFRAMEBUFFER + (off)) ) = Data;

}

/*

*************************************************************************************************************

- 函数名称 : static void SetPixel(U16 x,U16 y,int c)

- 函数说明 : 针对硬件的画点函数

- 输入参数 : x,y,c

- 输出参数 : 无

*************************************************************************************************************

*/

static void SetPixel(U16 x, U16 y, U32 c)

{

tOff Off = XY2OFF(x,y);

WRITE_MEM(Off, c);

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_DrawPixel  (U16 x, U16 y)

- 函数说明 : 画点函数

- 输入参数 : x,y

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_DrawPixel  (U16 x, U16 y)

{

SETPIXEL(x, y, LCD_COLOR);

}

/*

*************************************************************************************************************

- 函数名称 : U32 GetPixelIndex(U16 x, U16 y)

- 函数说明 : 针对硬件的得到点的颜色的函数

- 输入参数 : x,y

- 输出参数 : color

*************************************************************************************************************

*/

U32 GetPixelIndex(U16 x, U16 y)

{

U32 col;

U8 Data;

tOff Off = XY2OFF(x,y);

READ_MEM(Off,Data);

col = Data;

return col;

}

/*

*************************************************************************************************************

- 函数名称 : U32 LCD_GetPixel(U16 x, U16 y)

- 函数说明 : 得到点值的函数

- 输入参数 : x,y

- 输出参数 : colof

*************************************************************************************************************

*/

U32 LCD_GetPixel(U16 x, U16 y)

{

return GETPIXEL(x,y);

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_DrawHLine  (U16 x0, U16 y,  U16 x1)

- 函数说明 : 画水平线函数

- 输入参数 : x,y,x1

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_DrawHLine  (U16 x0, U16 y0,  U16 x1)

{

while (x0 <= x1)

{

SETPIXEL(x0, y0, LCD_COLOR);

x0++;

}

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_DrawVLine  (U16 x, U16 y0,  U16 y1)

- 函数说明 : 画竖直线函数

- 输入参数 : x,y,x1

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_DrawVLine(U16 x0, U16 y0,  U16 y1)

{

while (y0 <= y1)

{

SETPIXEL(x0, y0, LCD_COLOR);

y0++;

}

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_FillRect(U16 x0, U16 y0, U16 x1, U16 y1)

- 函数说明 : 填充矩形函数

- 输入参数 : x0,y0,x1,y1

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_FillRect(U16 x0, U16 y0, U16 x1, U16 y1)

{

for (; y0 <= y1; y0++)

{

LCD_DrawHLine(x0,y0, x1);

}

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_Clear(U16 x0, U16 y0, U16 x1, U16 y1)

- 函数说明 :  清屏函数

- 输入参数 : x0,y0,x1,y1

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_Clear(U16 x0, U16 y0, U16 x1, U16 y1)

{

LCD_COLOR = 0x00;

for (; y0 <= y1; y0++)

{

LCD_DrawHLine(x0,y0, x1);

}

}

/*

*************************************************************************************************************

- 函数名称 : static  void DrawPoint(U16 x0,U16 y0, U16 xoff, U16 yoff)

- 函数说明 : 画辅助点函数

- 输入参数 : x,y

- 输出参数 : 无

*************************************************************************************************************

*/

static  void _DrawPoint(U32 x0,U32 y0, U32 xoff, U32 yoff)

{

LCD_DrawPixel(x0+xoff,y0+yoff);

LCD_DrawPixel(x0-xoff,y0+yoff);

LCD_DrawPixel(x0+yoff,y0+xoff);

LCD_DrawPixel(x0+yoff,y0-xoff);

if (yoff)

{

LCD_DrawPixel(x0+xoff,y0-yoff);

LCD_DrawPixel(x0-xoff,y0-yoff);

LCD_DrawPixel(x0-yoff,y0+xoff);

LCD_DrawPixel(x0-yoff,y0-xoff);

}

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_DrawCircle(U16 x0, U16 y0, U16 r)

- 函数说明 : 画圆函数

- 输入参数 : x,y

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_DrawCircle(U32 x0, U32 y0, U32 r)

{

U32 i;

U32 imax = ((int)((int)r*707))/1000 + 1;

U32 sqmax = (int)r*(int)r + (int)r/2;

U16 y = r;

_DrawPoint(x0,y0,r,0);

for (i=1; i<= imax; i++)

{

if ((i*i+y*y) > sqmax)

{

_DrawPoint(x0,y0,i,y);

y--;

}

_DrawPoint(x0,y0,i,y);

}

}

/*

*************************************************************************************************************

- 函数名称 : void LCD_FillCircle(U16 x0, U16 y0, U16 r)

- 函数说明 : 填充圆函数

- 输入参数 : x,y

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_FillCircle       (U16 x0, U16 y0, U16 r)

{

U32 i;

U32 imax = ((int)((int)r*707))/1000+1;

U32 sqmax = (int)r*(int)r+(int)r/2;

U16 x = r;

LCD_DrawHLine(x0-r,y0,x0+r);

for (i=1; i<= imax; i++)

{

if ((i*i+x*x) >sqmax)

{

if (x>imax)

{

LCD_DrawHLine (x0-i+1,y0+x, x0+i-1);

LCD_DrawHLine (x0-i+1,y0-x, x0+i-1);

}

x--;

}

LCD_DrawHLine(x0-x,y0+i, x0+x);

LCD_DrawHLine(x0-x,y0-i, x0+x);

}

}

/*

*************************************************************************************************************

- 函数名称 : Log2Phy(int Color)

- 函数说明 : 逻辑颜色转实际颜色函数

- 输入参数 : color

- 输出参数 : 无

*************************************************************************************************************

*/

U16 Log2Phy(U32 Color)

{

U32 r,g,b;

b = Color & 255;

g = (Color >> 8 ) & 255;

r = Color >> 16;

b = (b + 42) / 85;

g = (g * 7 + 127) / 255;

r = (r * 7 + 127) / 255;

return b + (g << 2) + (r << 5);

}

/*

*************************************************************************************************************

- 函数名称 : LCD_Log2Phy(int Color)

- 函数说明 : 逻辑颜色转实际颜色上层函数

- 输入参数 : color

- 输出参数 : 无

*************************************************************************************************************

*/

U16 LCD_Log2Phy(U32 Color)

{

U16 PhyColor;

PhyColor = Log2Phy(Color);

return PhyColor;

}

/*

*************************************************************************************************************

- 函数名称 : void Set_Color(int color)

- 函数说明 : 设定颜色的上层函数

- 输入参数 : color

- 输出参数 : 无

*************************************************************************************************************

*/

void Set_Color(U32 color)

{

LCD_SetColor(LCD_Log2Phy(color));

}

/*

*************************************************************************************************************

- 函数名称 : void Set_Color(int color)

- 函数说明 : 设定颜色函数

- 输入参数 : color

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_SetColor(U16 PhyColor)

{

LCD_COLOR = PhyColor;

}

/*

*************************************************************************************************************

- 函数名称 : void Set_Color(int color)

- 函数说明 : 设定颜色的上层函数

- 输入参数 : color

- 输出参数 : 无

*************************************************************************************************************

*/

void Set_BkColor(U32 color)

{

LCD_SetBkColor(LCD_Log2Phy(color));

}

/*

*************************************************************************************************************

- 函数名称 : void Set_Color(int color)

- 函数说明 : 设定颜色函数

- 输入参数 : color

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_SetBkColor(U16 PhyColor)

{

LCD_BKCOLOR = PhyColor;

}

/*

*************************************************************************************************************

- 函数名称 : int LCDInit(void)

- 函数说明 : 注册LCD设备

- 输入参数 : 无

- 输出参数 : 0,或-EBUSY

*************************************************************************************************************

*/

int __init  LCD_Init(void)

{

int     result;

Setup_LCDInit();

printk("Registering S3C2410LCD Device\t--- >\t");

result = register_chrdev(LCD_MAJOR, "S3C2410LCD", &LCD_fops);//注册设备

if (result<0)

{

printk(KERN_INFO"[FALLED: Cannot register S3C2410LCD_driver!]\n");

return -EBUSY;

}

else

printk("[OK]\n");

printk("Initializing S3C2410LCD Device\t--- >\t");

printk("[OK]\n");

printk("S3C2410LCD Driver Installed.\n");

return 0;

}

/*

*************************************************************************************************************

- 函数名称 : LCD_CstnOnOff

- 函数说明 : 打开和关闭lcd设备

- 输入参数 : 无

- 输出参数 : 无

*************************************************************************************************************

*/

void Lcd_CstnOnOff(int onoff)

{

// 1:CSTN Panel on  0:CSTN Panel off //

if(onoff==1)

{LCDCON1 |= 1; // ENVID=ON

printk("\nLCDCON1 is already enable.\n");

}

else

LCDCON1 = LCDCON1 & 0x3fffe; // ENVID Off

GPBUP  = GPBUP|(1<<5);                // Pull-up disable

GPBDAT =( GPBDAT & (~(1<<5))) |(onoff<<5); // GPB5=On or Off

GPBCON =( GPBCON & (~(3<<10)))|(1<<10);   //GPD9=output

}

/*

*************************************************************************************************************

- 函数名称 : LCD_Exit

- 函数说明 : 卸载lcd设备

- 输入参数 : 无

- 输出参数 : 无

*************************************************************************************************************

*/

void __exit LCDdriver_Exit(void)

{

Lcd_CstnOnOff(0);

unregister_chrdev(LCD_MAJOR, "S3C2410LCD");

printk("You have uninstall The LCD Driver succesfully,\n if you want to install again,please use the insmod command \n");

}

module_init(LCD_Init);

module_exit(LCDdriver_Exit);

/*

*****************************************************************************************************************

**                                                  结束文件                                                   **

*****************************************************************************************************************

*/

d:应用程序测试

d-1:lcd_app

#include <stdio.h>

#include <stdlib.h>

#include <sys/ioctl.h>

#include <unistd.h>

int main(void)

{

int fd;

int rt;

int cmd;

char enter_c;

unsigned long arg_G,arg_B,arg_R,arg_Y,arg_W,arg_K,arg_CY;

struct arg

{

unsigned long a;

unsigned long b;

unsigned long c;

unsigned long d;

};

struct arg arg1 = {0,120,300,0};

struct arg arg2 = {140,0,239,0};

struct arg arg3 = {100,100,50,0};

struct arg arg4 = {0,0,319,239};

struct arg arg5 = {240,100,60,0};

struct arg arg6 = {0,0,319,239};

struct arg arg7 = {40,170,100,200};

arg_G = 0x00FF00;

arg_R = 0xFF0000;

arg_B = 0x0000FF;

arg_Y = 0xAAAA00;

arg_W = 0xFFFFFF;

arg_K = 0x000000;

arg_CY = 0x808080;

if ((fd = open("/dev/S3C2410LCD", 0)) < 0)

{

printf("cannot open /dev/S3C2410LCD\n");

exit(0);

};

do{

cmd = getchar();

switch (cmd)

{

case 49:

enter_c = getchar();

rt = ioctl(fd, 0,arg_R);   // set RED

cmd = 0;

break;

case 50:

enter_c = getchar();

rt = ioctl(fd, 0,arg_G);   //  set GREEN

break;

case 51:

enter_c = getchar();

rt = ioctl(fd, 0,arg_B);   // set BLUE

cmd = 0;

break;

case 52:

enter_c = getchar();

rt = ioctl(fd, 0,arg_Y); // set YELLOW

cmd = 0;

break;

case 53:

enter_c = getchar();

rt = ioctl(fd, 0,arg_W); // set WHITE

cmd = 0;

break;

case 54:

enter_c = getchar();

rt = ioctl(fd, 0,arg_K); // set BLACK

cmd = 0;

break;

case 55:

enter_c = getchar();

rt = ioctl(fd, 0,arg_CY); // set CYNE

cmd = 0;

break;

case ‘a‘:

enter_c = getchar();

rt = ioctl(fd, 1,(unsigned long )&arg1); // draw h_line

cmd = 0;

break;

case ‘b‘:

enter_c = getchar();

rt = ioctl(fd, 2,(unsigned long )&arg2); // draw v_line

cmd = 0;

break;

case ‘c‘:

enter_c = getchar();

rt = ioctl(fd, 3,(unsigned long )&arg3); // draw circle

cmd = 0;

break;

case ‘d‘:

enter_c = getchar();

rt = ioctl(fd, 4,(unsigned long )&arg4); // draw rect

cmd = 0;

break;

case ‘e‘:

enter_c = getchar();

rt = ioctl(fd, 5,(unsigned long )&arg5); // draw fillcircle

cmd = 0;

break;

case ‘f‘:

enter_c = getchar();

rt = ioctl(fd, 6,(unsigned long )&arg6); // clear screen

cmd = 0;

break;

case ‘g‘:

enter_c = getchar();

rt = ioctl(fd, 7,(unsigned long )&arg7); // draw rect

cmd = 0;

break;

default:

break;

}

}while(cmd != ‘q‘);                                  // "q" is quit command

close(fd);

return 0;

}

d-2:write.c

#include <stdio.h>

#include <stdlib.h>

#include <sys/ioctl.h>

#include <unistd.h>

#include <fcntl.h>

#include <linux/fb.h>

#include <sys/mman.h>

#define LCDHEIGHT240

#define LCDWIDTH320

typedef unsigned int  U32;

typedef unsigned char U8;

U32 LCDBuffer[LCDHEIGHT][LCDWIDTH];

/*

*************************************************************************************************************

- 函数名称 : void LCD_Refresh(int *fbp)

- 函数说明 : 更新区域

- 输入参数 : int *fbp

- 输出参数 : 无

*************************************************************************************************************

*/

void LCD_Refresh(int *fbp)

{

int i,j;

U32 lcddata;

U32 pixcolor;

U8* pbuf = (U8*)LCDBuffer[0];

for(i=0;i<LCDWIDTH*LCDHEIGHT/4;i++)

{

lcddata = 0;

for(j=24;j>=0;j-=8)

{

pixcolor = (pbuf[0]&0xe0)|((pbuf[1]>>3)&0x1c)|(pbuf[2]>>6);

lcddata |= pixcolor<<j;

pbuf    += 4;

}

*(fbp+i) = lcddata;

}

}

/*

*************************************************************************************************************

- 函数名称 : Exep_S3cint_Init(void)

- 函数说明 : 异常及中断控制器的初始化

- 输入参数 : 无

- 输出参数 : 无

*************************************************************************************************************

*/

void Test_Cstn256(U32 *fbp)

{

int i,j,k,jcolor=0x00;

for(i=0;i<9;i++)

{

switch(i)

{

case 0:

jcolor = 0x00000000;

break;

case 1:

jcolor = 0x000000e0;

break;

case 2:

jcolor = 0x000070e0;

break;

case 3:

jcolor = 0x0000e0e0;

break;

case 4:

jcolor = 0x0000e000;

break;

case 5:

jcolor = 0x00e0e000;

break;

case 6:

jcolor = 0x00e00000;

break;

case 7:

jcolor = 0x00e000e0;

break;

case 8:

jcolor = 0x00e0e0e0;

break;

}

for(k=0;k<240;k++)

for(j=i*32; j<i*32+32; j++)

LCDBuffer[k][j]=jcolor;

}

jcolor=0x000000ff;

for(i=0;i<240;i++)

{

if(i==80||i==160)

jcolor<<=8;

for(j=288;j<320;j++)

LCDBuffer[i][j]=jcolor;

}

for(i=0;i<240;i++)

for(j=0;j<320;j++)

LCD_Refresh(fbp);

}

/*

*************************************************************************************************************

- 函数名称 : Exep_S3cint_Init(void)

- 函数说明 : 异常及中断控制器的初始化

- 输入参数 : 无

- 输出参数 : 无

*************************************************************************************************************

*/

int main(void)

{

int fb;

int cmd;

unsigned char*  fb_mem;

if ((fb = open("/dev/fb0", O_RDWR)) < 0)

{

printf("cannot open /dev/fb0\n");

exit(0);

};

fb_mem =(unsigned char *) mmap(NULL,320*240,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);

memset(fb_mem,0,320*240);

Test_Cstn256(fb_mem);

cmd = getchar();

munmap(fb, 320*240);

close(fb);

return 0;

}

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

原文地址:https://www.cnblogs.com/big-devil/p/8590045.html

时间: 2024-11-07 03:48:33

linux驱动之LCD(无framebuffer)的相关文章

linux驱动之LCD

LCD程序步骤:1. 分配一个fb_info 2. 设置 3. 硬件相关的操作4. 注册 register_framebuffer 5.入口函数 6.出口函数 #include <linux/string.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#i

linux驱动开发之framebuffer驱动介绍

framebuffer是linux里面的显示设备.在驱动底下如何操作lcd实现图形的显示. 1.什么是framebuffer? (1)首先想一下在裸机中我们是怎么操作LCD的. Soc内部有lcd的控制器,Soc外面有lcd的驱动器,lcd的驱动器连接着lcd的屏幕,Soc的内部还有CPU,外部还有DDR内存.这些设备都参与到了lcd的显示中. 在裸机中我们是怎么搞的呢,lcd的驱动器和lcd的控制器之间通过排线进行链接,连接的接口就是lcd所特有的一个接口.lcd控制器里面是很多和lcd相关的

Linux驱动LCD driver学习总结

这篇文章写于13年11月,这里仅记录一下曾经涉猎了这方面的知识,可能对以后的一些知识了解有所帮助 关于platform总线模型,可以参考之前的一篇文章Linux驱动Platform总线模型,这对frameBuffer的驱动注册可能有所帮助 一.LCD硬件框架 二.LCD软件框架 三.LCD初始化流程 四.LCD on与off的流程 五.LCD数据流 六.驱动程序framebuffer 所在文件 /android/kernel/drivers/video/fbmem.c /android/kern

Linux驱动开发盲点笔记1

1. vim中在找到搜索目标后,使用n与N进行定位查找 2. vim中使用gg到最好第一行,使用xxxG到某一行,否则G直接到最后一行: 3. ln -s 产生的链接文件最终指向的目标文件src 新产生的当前软链接文件dst. ln -s project(磁盘上实际存在的文件或者目录) a.lnk ln -s src dst(新产生的文件dst,dst链接到src) symlink功能类似 4 tar -czvf 最终生产的tar打包好的文件 待打包的文件或者文件夹 tar czvf a.tar

linux驱动面试题整理

资料来自网上,简单整理,答案后续补充...... 1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也叫手动创建设备文件.还有UDEV/MDEV自动创建设备文件的方式,UDEV/MDEV是运行在用户态的程序,可以动态管理设备文件,包括创建和删除设备文件,运行在用户态意味着系统要运行之后.那么在系统启动期间还有devfs创建了设备文件.一共有三种方式可

linux驱动移植(nand,yaffs2)

原文:http://blog.sina.com.cn/s/blog_7090b8670101b0bi.html linux驱动移植(nand,yaffs2) 在linux操作系统的顺利移植之后,linux的内核虽然在板子上跑了起来,但是此时linux还不支持板子的的各个硬件,比如说lcd,摄像头,声卡,usb等模块,我们必须要在板子上装入驱动程序后,才能上这些硬件在linux操作系统下工作. 这些驱动在内核中都有驱动的源码,我们要做的就是将这些驱动源码编译到内核中,当然在编译之前是需要对驱动源码

linux驱动开发流程

嵌入式linux驱动开发流程嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的.设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,可以像操作普通文件一样对硬件设备进行操作.设备驱动程序是内核的一部分,完成以下功能:◇ 驱动程序的注册和注销.◇ 设备的打开和释放.◇ 设备的读写操作.◇ 设备的控制操作.◇ 设备的中断和轮询处理.Linux主要将设备分为三类:字符设备.块设备和网络设备.字符设备是指发送和接收数据以字符的

第1个linux驱动___整个系统是怎样工作的

接着上一篇博文中,我们已经在first_drv.c中写好了空壳驱动程序. 但是编译这个空壳驱动程序之前,我们需要了解整个系统是怎么工作的. 不着急,首先,我们先来了解一点linux驱动的基本概念: linux驱动分为字符设备驱动.块设备驱动.网络设备驱动. 这是按照驱动程序对不同的硬件的操作方式差异而划分的: [ 字符设备驱动 ] 以字节级别的数据量来对硬件设备进行操作,涉及的硬件如:LED.LCD.串口.触摸屏等. [ 块设备驱动 ] 则操作的数据量较大,如读写存储芯片的驱动就是块设备驱动,一

如何写分层驱动(复杂的字符驱动)----以lcd驱动为例

*********如何写分层驱动(复杂的字符驱动)----以lcd驱动为例************** 思路:复杂的驱动都是建立在简单的驱动的基础上,所以首先要知道内核简单字符设备驱动如何写 1.如何简单驱动程序 1.1 构造file_operations .open = drv_open .read = drv_read 1.2 告诉内核有1.1这个结构,register_chrdev(主设备号,fop,name) 上面可以被下面三句话代替 分配cdev 设置cdev cdev_add 1.3