zoukankan      html  css  js  c++  java
  • LCD驱动详解

    参考文档:《液晶屏.pdf》《S3C2440用户手册》《JZ2440-V3原理图》

     

    frame buffer: 显存,用于存放LCD显示数据;frame buffer通过LCD控制器和LCD Panel建立一一映射关系;

    LCD控制器: 参考LCD用户手册,配置LCD控制器,用于发出LCD控制信号,驱动LCD显示;

    扫描方向: 如图①所示,由start到end的扫描方向是:从左到右,从上到下(扫描方向的一种);

    HSYNC: 行同步信号,用于行切换,一行扫描结束,需要扫描新行时,需要先发送行同步信号;

    VSYNC: 列同步信号,用于列切换,一帧扫描结束,需要扫描新的一帧时,需要先发送列同步信号;

    时钟信号: 每来一个时钟,扫描的点移位一;

       

    原理图——管脚说明

     

       

     

     

    硬件操作配置

    ①配置LCD控制引脚;

    ②根据LCD手册,配置LCD控制器;

    ③分配Frame buffer,并映射到LCD Panel;

       

    《液晶屏.pdf》

    Block Diagram

       

       

    Interface Timing

       

    Driver Timing

       

       

    Timing Chart

    a、

       

    b、

     

    《S3C2440用户手册》

    LCD CONTROLLER SPECIAL REGISTERS

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

       

     

     

    MEMORY DATA FORMAT (TFT)

     

     

    驱动程序

    1 /*
    2 * 参考内核自带的lcd驱动程序:
    3 * C:UsersliangDesktoplinux-2.6.22.6driversvideos3c2410fb.c
    4 * 《液晶屏.pdf》、《s3c2440 用户手册》
    5 */
    6 #include <linux/module.h>
    7 #include <linux/kernel.h>
    8 #include <linux/errno.h>
    9 #include <linux/string.h>
    10 #include <linux/mm.h>
    11 #include <linux/slab.h>
    12 #include <linux/delay.h>
    13 #include <linux/fb.h>
    14 #include <linux/init.h>
    15 #include <linux/dma-mapping.h>
    16 #include <linux/interrupt.h>
    17 #include <linux/workqueue.h>
    18 #include <linux/wait.h>
    19 #include <linux/platform_device.h>
    20 #include <linux/clk.h>
    21         
    22 #include <asm/io.h>
    23 #include <asm/uaccess.h>
    24 #include <asm/div64.h>
    25         
    26 #include <asm/mach/map.h>
    27 #include <asm/arch/regs-lcd.h>
    28 #include <asm/arch/regs-gpio.h>
    29 #include <asm/arch/fb.h>
    30
    31 struct lcd_regs {
    32         unsigned long        lcdcon1;
    33         unsigned long        lcdcon2;
    34         unsigned long        lcdcon3;
    35         unsigned long        lcdcon4;
    36         unsigned long        lcdcon5;
    37 unsigned long        lcdsaddr1;
    38 unsigned long        lcdsaddr2;
    39 unsigned long        lcdsaddr3;
    40 unsigned long        redlut;
    41 unsigned long        greenlut;
    42 unsigned long        bluelut;
    43 unsigned long        reserved[9];
    44 unsigned long        dithmode;
    45 unsigned long        tpal;
    46 unsigned long        lcdintpnd;
    47 unsigned long        lcdsrcpnd;
    48 unsigned long        lcdintmsk;
    49 unsigned long        lpcsel;
    50 };
    51
    52
    53 static volatile unsigned long *gpb_con;
    54 static volatile unsigned long *gpb_dat;
    55
    56 static volatile unsigned long *gpc_con;
    57 static volatile unsigned long *gpd_con;
    58 static volatile unsigned long *gpg_con;
    59
    60 static volatile struct lcd_regs* lcd_regs;
    61
    62 static u32 pseudo_palette[16];//假的调色板
    63
    64 static struct fb_info *lcd_info;
    65
    66 static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
    67 {
    68         chan &= 0xffff;
    69         chan >>= 16 - bf->length;
    70         return chan << bf->offset;
    71 }
    72
    73 static int lcdfb_setcolreg(unsigned int regno, unsigned int red,
    74                          unsigned int green, unsigned int blue,
    75                          unsigned int transp, struct fb_info *info)
    76 {
    77         unsigned int val;
    78
    79         if (regno > 16)
    80         {
    81                 return -1;
    82         }
    83
    84         //用三原色构造出val
    85         val = chan_to_field(red, &info->var.red);
    86         val |= chan_to_field(green, &info->var.green);
    87         val |= chan_to_field(blue, &info->var.blue);
    88
    89         pseudo_palette[regno] = val;        //调好颜色,放回调色板
    90
    91         return 0;
    92 }
    93
    94
    95 static struct fb_ops lcd_fbops = {
    96         .owner                = THIS_MODULE,
    97         .fb_setcolreg        = lcdfb_setcolreg,//假的调色板的调色函数
    98         .fb_fillrect        = cfb_fillrect,                //
    99         .fb_copyarea        = cfb_copyarea,
    100         .fb_imageblit        = cfb_imageblit,
    101 };
    102
    103 /* 1、出入口函数 */
    104 static int lcd_init(void)
    105 {
    106         /* 2、分配一个fb_info结构体 */
    107         lcd_info = framebuffer_alloc(0, NULL);
    108         /******** 2 end ********/
    109
    110         /* 3、设置 */
    111         /* 设置固定的参数:lcd_info->fix */
    112         strcpy(lcd_info->fix.id, "mylcd");                                        //名字
    113         lcd_info->fix.smem_len                 = 240*320*16/8;                        //framebuffer长度(240*320 dots,lrgb565: 16bit/dots)
    114         lcd_info->fix.type                         = FB_TYPE_PACKED_PIXELS;
    115         lcd_info->fix.visual                = FB_VISUAL_TRUECOLOR;        //颜色深度(tft-lcd设置为真彩)
    116         lcd_info->fix.line_length        = 240*16/8;                                //framebuffer中每一行(line)占据的字节数;240*2(2:16bit/8)                
    117
    118         /* 设置可变的参数 */
    119         lcd_info->var.xres                         = 240;        //x方向的分辨率
    120         lcd_info->var.yres                         = 320;        //y方向的分辨率
    121         lcd_info->var.xres_virtual         = 240;        //x方向的虚拟分辨率
    122         lcd_info->var.yres_virtual         = 320;        //y方向的虚拟分辨率
    123         lcd_info->var.bits_per_pixel= 16;        //每个像素点16位(rgb565)
    124         lcd_info->var.activate                = FB_ACTIVATE_NOW;
    125
    126         // 颜色数据的位分配 rgb:565
    127         lcd_info->var.red.offset        = 11;        //(5)bit11 - bit15
    128         lcd_info->var.red.length        = 5;        
    129         lcd_info->var.green.offset        = 5;        //(6)bit5 - bit10
    130         lcd_info->var.green.length        = 6;
    131         lcd_info->var.blue.offset        = 0;        //(5)bit0 - bit4
    132         lcd_info->var.blue.length        = 5;
    133         
    134         /* 设置操作函数 */
    135         lcd_info->fbops = &lcd_fbops;
    136
    137         /* 其他设置 */
    138         lcd_info->pseudo_palette = pseudo_palette;        //假的调色板
    139         lcd_info->screen_size = 240*320*16/8;                //
    140         /******** 3 end ********/
    141
    142         /* 4、硬件相关设置 */
    143         /* 配置gpio用于lcd */
    144         gpc_con = ioremap(0x56000020, 4);
    145         gpd_con = ioremap(0x56000030, 4);
    146         gpg_con = ioremap(0x56000060, 4);
    147         gpb_con = ioremap(0x56000010, 8);
    148         gpb_dat = gpb_con + 1;
    149
    150         //GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND
    151         *gpc_con = 0xaaaaaaaa;
    152
    153         //GPIO管脚用于VD[23:8]
    154         *gpd_con = 0xaaaaaaaa;
    155
    156         //GPB0设置为输出引脚
    157         *gpb_con &= ~(3);
    158         *gpb_con |= 1;
    159         *gpb_dat &= ~1;                //输出低电平
    160
    161         //GPG4用作LCD_PWREN
    162         *gpg_con |= (3<<8);
    163         
    164         /* 根据lcd手册设置lcd控制器 */
    165         lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
    166         lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);
    167         lcd_regs->lcdcon2 = (3<<24) | (319<<14) | (1<<6) | (0<<0);
    168         lcd_regs->lcdcon3 = (16<<19) | (239<<8) | (10<<0);
    169         lcd_regs->lcdcon4 = 4;
    170         lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0);
    171         
    172         /* 分配显存(framebuffer),并把地址告诉lcd控制器 */
    173         // 虚拟地址 大小 物理地址
    174         lcd_info->screen_base = dma_alloc_writecombine(NULL, lcd_info->fix.smem_len, &lcd_info->fix.smem_start, GFP_KERNEL);
    175         
    176         lcd_regs->lcdsaddr1 = (lcd_info->fix.smem_start >> 1) & ~(3<<30);
    177         lcd_regs->lcdsaddr2 = ((lcd_info->fix.smem_start + lcd_info->fix.smem_len) >> 1) & 0x1fffff;
    178         lcd_regs->lcdsaddr3 = (240*16/16); /* 一行的长度(单位: 2字节) */        
    179         
    180         /* 启动LCD */
    181         lcd_regs->lcdcon1 |= (1<<0);         //使能LCD本身
    182         lcd_regs->lcdcon5 |= (1<<3);        
    183         *gpb_dat |= 1;                         //输出高电平, 使能背光
    184         /******** 4 end ********/
    185         
    186         /* 5、注册 */
    187         register_framebuffer(lcd_info);
    188         /******** 5 end ********/
    189
    190         return 0;
    191 }
    192
    193 static void lcd_exit(void)
    194 {
    195         dma_free_writecombine(NULL, lcd_info->fix.smem_len, lcd_info->screen_base, lcd_info->fix.smem_start);
    196         unregister_framebuffer(lcd_info);
    197         /* 关闭LCD */
    198         lcd_regs->lcdcon1 &= ~(1<<0);
    199         lcd_regs->lcdcon5 &= ~(1<<3);
    200         *gpb_dat &= ~(1<<0);
    201
    202         iounmap(lcd_regs);
    203         iounmap(gpc_con);
    204         iounmap(gpd_con);
    205         iounmap(gpg_con);
    206         iounmap(gpb_con);
    207
    208         framebuffer_release(lcd_info);
    209         return;
    210 }
    211
    212 module_init(lcd_init);
    213 module_exit(lcd_exit);
    214 MODULE_LICENSE("GPL");
    215 /******** 1 end ********/

       

    附:

    1 /**
    2 * framebuffer_alloc - creates a new frame buffer info structure
    3 *
    4 * @size: size of driver private data, can be zero
    5 * @dev: pointer to the device for this fb, this can be NULL
    6 *
    7 * Creates a new frame buffer info structure. Also reserves @size bytes
    8 * for driver private data (info->par). info->par (if any) will be
    9 * aligned to sizeof(long).
    10 *
    11 * Returns the new structure, or NULL if an error occured.
    12 *
    13 */
    14 struct fb_info *framebuffer_alloc(size_t size, struct device *dev);

     

    调试

    pc-linux:

    cd /work/system/linux-2.6.22.6/

    make menuconfig

    (lcd驱动以模块方式编译)

    make uImage

    make modules

    cp /work/system/linux-2.6.22.6/drivers/video/cfbcopyarea.ko /work/nfs_root

    cp /work/system/linux-2.6.22.6/drivers/video/cfbfillrect.ko /work/nfs_root

    cp /work/system/linux-2.6.22.6/drivers/video/cfbimgblt.ko /work/nfs_root

    cp /work/system/linux-2.6.22.6/arch/arm/boot/uImage /work/nfs_root/uImage_nolcd

       

    board-u-boot:

    nfs 30000000 192.168.0.103:/work/nfs_root/uImage_nolcd

    bootm 30000000

       

    board-linux:

    mount -t nfs -o nolock,vers=2 192.168.0.103:/work/nfs_root /mnt

    cd /mnt

    insmod cfbcopyarea.ko

    insmod cfbfillrect.ko

    insmod cfbimgblt.ko

    insmod lcd.ko

    echo hello world! 2019/10/18 > /dev/tty1

       

    cat test.bmp > /dev/fb0

       

    vi /etc/inittab

    #+++

    tty1::askfirst:-/bin/sh

       

    reboot

    insmod buttons.ko

    insmod cfbcopyarea.ko

    insmod cfbfillrect.ko

    insmod cfbimgblt.ko

    insmod lcd.ko

       

    <input way:key>

    KEY_L KEY_S KEY_ENTER(ls' ')

      

  • 相关阅读:
    如何更改SQL Server2008默认数据库的存储路径
    虚拟内存页面文件pagefile.sys(棉文件)改变存放位置
    Redis热点数据高频访问问题以及解决方案
    gc日志收集和分析
    oauth2中client_id_to_access数据膨胀问题
    Redis慢查询日志
    24个Jvm面试题总结及答案
    springboot-使用assembly进行项目打包
    volatile关键字解读
    redis的zset结构跳表
  • 原文地址:https://www.cnblogs.com/lilto/p/11877847.html
Copyright © 2011-2022 走看看