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控制器大致可以由REGBANKLCDCDMATIMEGENVIDPRCS寄存器几个部分组成。

b-1-1:REGBANK17可编程的寄存器组和一块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驱动器需要的控制信号,比如VSYNCHSYNCVCLKLEND等等,而这些控制信号又与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 /[HSPW1)(HSPD1)(HFPD1)(HOZVAL1)]

   场频 =行频 /[(VSPW1)(VBPD1)(VFPD1)(LINEVAL1)]

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

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

LCDCON1LINECNT18--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位色位模式(1BPP8BPP16BPP)

LCDCON2:用于设置VBPD,LINEVAL,VFBD,VSPW,对于STNVBPDVFBD,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-VD23VFRAMEVLINEVCLK等,分别在GPCCON,GPDCON中选择相应功能。

4、设置LCD的频率(VCLK)

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

对于TFT LCDS3C2440提供的VCLK的计算公式为:

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

可以得出:

CLKVAL = HCLK / (VCLK * 2) - 1

我的HCLK100Mhz(CPU运行在400Mhz, CLKDIV_VAL设置为5Fclk: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、确定信号的极性

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

(相关寄存器LCDCON5)

8、禁止LPC3600/LCC3600模式!

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

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 ");
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 ");
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 ");
 
Set_Color(arg); 
               printk("LCD_COLOR =%x ",LCD_COLOR);
return 1;
 
case 1:
printk("draw h_line ");
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 ");
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 ");
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 ");
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 ");
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 ");
 LCD_Clear(0,0,319,239);     // clear screen
               return 1;
 
         case 7:
printk("draw rect ");
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 --- > ");
    result = register_chrdev(LCD_MAJOR, "S3C2410LCD", &LCD_fops);//注册设备
 
    if (result<0)
{
printk(KERN_INFO"[FALLED: Cannot register S3C2410LCD_driver!] ");
return -EBUSY;
}
else
printk("[OK] ");
 
    printk("Initializing S3C2410LCD Device --- > ");
    printk("[OK] ");
 
    printk("S3C2410LCD Driver Installed. ");
    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(" LCDCON1 is already enable. ");
    }
    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, if you want to install again,please use the insmod command ");
}
 
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 ");
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 ");
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