参考:

http://liu1227787871.blog.163.com/blog/static/205363197201242393031250/

http://blog.csdn.net/cumtgao/article/details/8649006

http://www.360doc.com/content/12/0424/17/9159905_206213245.shtml

http://blog.csdn.net/yj4231/article/details/7878762

硬件平台:TQ2440

LCD型号:WXCAT43,分辨率480*270

U-boot版本:u-boot-2015.04

内核版本:Linux-3.14

作者:彭东林

邮箱:pengdonglin137@163.com

下面主要完成Linux下面的LCD驱动的移植。

首先我们需要知道一些LCD的知识:

我们使用的LCD是TFT类型,下面是S3C2440的LCD控制器的信号引脚:

下面是TQ2440的LCD原理图:

下面介绍一下这些引脚的功能:

VCLK:发出lcd时钟信号,每来一个时钟,就会在屏幕上显示一个像素

VLINE:发出lcd行扫描信号

VFRAME:发出lcd桢扫描信号

VM:VDEN,有效时才会在屏幕上显示象素

LCD_PWREN:发出lcd面板电源使能控制信号

VD[3]——VD[7]   :lcd数据总线

VD[10]——VD[15] :lcd数据总线

VD[19]——VD[23] :lcd数据总线

各信号的含义

VSYNC:帧同步信号

每发出一个脉冲,表示新的一屏图像数据开始传送。

HSYNC:行同步信号

每发出一个脉冲,表示新的一行图像数据开始传送。

VCLK:像素时钟信号

每发出一个脉冲,表示新的一个点图像数据开始传送。

LEND:行结束信号

VBPD:表示在一帧图像开始时,帧同步信号以后的无效的行数,对应驱动中的upper_margin

VFBD:表示在一帧图像结束后,帧同步信号以前的无效的行数,对应驱动中的lower_margin

VSPW:表示垂直同步脉冲的宽度,单位是行数

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

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

HSPW:表示水平同步信号的宽度,单位是vclk的个数

下面我们结合两张图理解一下:

下面我们结合TQ2440上的LCD芯片手册分析:

注意上面这幅图下面的文字中对CLK和H的说明,其中:CLK表示的是像素时钟周期,H表示的是行同步时钟周期。可以发现上面图中的规律:

525=480+2+41+2   他们的单位都是CLK

286=272+2+10+2   他们的单位都是H

所以帧率就是: 1/(525*286*像素时钟周期) Hz

这样我们也容易理解S3C2440上的两个公式:

VCLK(Hz) = HCLK/[(CLKVAL+1)x2]   像素时钟频率(Hz)

Frame Rate = 1/ [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1) } x {(HSPW+1) + (HBPD +1)+ (HFPD+1) + (HOZVAL + 1) } x { 2 x ( CLKVAL+1 ) / ( HCLK ) } ]   帧率(Hz)

对照上面的两幅图,我们采用典型值来填充这个结构体

static struct s3c2410fb_display tq2440_lcd_cfg __initdata = {

 

    .lcdcon5    = S3C2410_LCDCON5_FRM565 |

              S3C2410_LCDCON5_INVVLINE |

              S3C2410_LCDCON5_INVVFRAME |

              S3C2410_LCDCON5_PWREN |

              S3C2410_LCDCON5_HWSWP,

 

    .type        = S3C2410_LCDCON1_TFT,

 

    .width        = 480,

    .height        = 272,

 

    .pixclock    = 100000,

    .xres        = 480,

    .yres        = 272,

    .bpp        = 16,

    .left_margin    = 2,   /* For HBPD+1, 这里我们取的都是典型值  */

    .right_margin    = 2,  /* For HFPD+1  */

    .hsync_len    = 41,    /* For HSPW+1  */

    .upper_margin    = 2,  /* For VBPD+1  */

    .lower_margin    = 2,  /* For VFPD+1  */

    .vsync_len    = 10,    /* For VSPW+1  */

};

 

#define S3C2410_GPCCON_MASK(x)    (3 << ((x) * 2))

#define S3C2410_GPDCON_MASK(x)    (3 << ((x) * 2))

 

static struct s3c2410fb_mach_info tq2440_fb_info __initdata = {

    .displays    = &tq2440_lcd_cfg,

    .num_displays    = 1,

    .default_display = 0,

 

    /* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN

     * and disable the pull down resistors on pins we are using for LCD

     * data. */

 

    .gpcup        = (0xf << 1) | (0x3f << 10),

 

    .gpccon        = (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE |

               S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |

               S3C2410_GPC8_VD0   | S3C2410_GPC9_VD1 |

               S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 |

               S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 |

               S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7),

 

    .gpccon_mask    = (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  |

               S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  |

               S3C2410_GPCCON_MASK(8) | S3C2410_GPCCON_MASK(9) |

               S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |

               S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |

               S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),

 

    .gpdup        = (0x3f << 2) | (0x3f << 10),

 

    .gpdcon        = (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 |

               S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 |

               S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 |

               S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |

               S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |

               S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),

 

    .gpdcon_mask    = (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) |

               S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) |

               S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) |

               S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|

               S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|

               S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),

 

//    .lpcsel        = ((0xCE6) & ~7) | 1<<4,  // 禁用lpsel,因为如果不是使用三星LPC3600/LCC3600 LCD,必须禁止LPC3600/LCC3600模式(写入0到TCONSEL)。

};

 

接下来要说的参数是pixclock,他是用来计算像素频率的。

在driver/video/s3c2410fb.c中:

static void s3c2410fb_activate_var(struct fb_info *info)

{

    struct s3c2410fb_info *fbi = info->par;

    void __iomem *regs = fbi->io;

    int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;

    struct fb_var_screeninfo *var = &info->var;

    int clkdiv;

 

    clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2);

 

    dprintk("%s: var->xres  = %d\n", __func__, var->xres);

    dprintk("%s: var->yres  = %d\n", __func__, var->yres);

    dprintk("%s: var->bpp   = %d\n", __func__, var->bits_per_pixel);

 

    if (type == S3C2410_LCDCON1_TFT) {

        s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);

        --clkdiv;

        if (clkdiv < 0)

            clkdiv = 0;

    } else {

        s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);

        if (clkdiv < 2)

            clkdiv = 2;

    }

 

    fbi->regs.lcdcon1 |=  S3C2410_LCDCON1_CLKVAL(clkdiv);

 

     ......

}

上面计算得到的clkdiv就是VCLK(Hz) = HCLK/[(CLKVAL+1)x2] 中的CLKVAL.

static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,

                      unsigned long pixclk)

{

    unsigned long clk = fbi->clk_rate;

    unsigned long long div;

 

    /* pixclk is in picoseconds, our clock is in Hz

     *

     * Hz -> picoseconds is / 10^-12

     */

 

    div = (unsigned long long)clk * pixclk;

    div >>= 12;            /* div / 2^12 */

    do_div(div, 625 * 625UL * 625); /* div / 5^12 */

 

    dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div);

    return div;

}

首先pixclock作为参数传递给了s3c2410fb_calc_pixclk函数,当该函数执行完以后

clkdiv  = (clk * pixclk  / 10^12 + (2 - 1))/ 2。

随后由于是采用TFT模式,将clkdiv-1。最后得:

clkdiv  = (clk * pixclk  / 10^12 + (2 - 1))/ 2 - 1,

这里的clk即为HCLK,LCD模块使用HCLK作为时钟源,从内核启动代码中可以看到HCLK是100MHz

为方便观察,将前面datasheet中的计算公式复制在此:CLKVAL = HCLK / VCLK / 2 -1。

我们可以看出1/VCLK = pixclk / 10^12,也就是说pixclk = 10^12 / VCLK。 从LCD的芯片手册上可以看到VCLK的典型值是9MHz,我们取10MHz。

因此,pixclk=100000。

其实在内核的参考文档中有这样一段话:

The speed at which the electron beam paints the pixels is determined by the
dotclock in the graphics board. For a dotclock of e.g. 28.37516 MHz (millions
of cycles per second), each pixel is 35242 ps (picoseconds) long:
    1/(28.37516E6 Hz) = 35.242E-9 s

也就是说VCLK的倒数,再乘10^12即为pixclk。picoseconds单位表示微微秒,即10^12。

完。

TQ2440平台上LCD驱动的移植的更多相关文章

  1. linux 驱动之LCD驱动(有framebuffer)

    <简介> LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作.用户根本不用关心物理显 ...

  2. 运行在TQ2440开发板上以及X86平台上的linux内核编译

    一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的“linux-2.6.30.4_20100531.tar.bz2”源码包. 解压(天嵌默认解压到/opt/E ...

  3. LCD驱动移植在在mini2440(linux2.6.29)和FS4412(linux3.14.78)上实现对比(deep dive)

    1.Linux帧缓冲子系统 帧缓冲(FrameBuffer)是Linux为显示设备提供的一个接口,用户可以将帧缓冲看成是显示内存的一种映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作 ...

  4. AM335x(TQ335x)学习笔记——LCD驱动移植

    TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由 ...

  5. 移植ok6410 LCD驱动

    1.本次移植过程选择 linux-2.6.28 lcd驱动为参考移植到 linux-2.6.34 ok6410 开发板上. 2.移植过程 主要以给内核增加驱动的思想,在/driver/video/ 下 ...

  6. Linux的LCD驱动分析及移植

    测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 LCD驱动分析 LCD屏的驱动总体上分成两块,一块是GUI ...

  7. 全志A33移植LCD驱动(ILI9806E)

    0x00 环境说明: 所使用的开发板为锐尔威视的插针版A33_Vstar 屏幕是买的第三方的KD050FWFPA011-C009A,其中LCD驱动IC为ILI9806E,所使用的接口为RGB666 0 ...

  8. Linux平台上DPDK入门指南

    1. 简介 本文档包含DPDK软件安装和配置的相关说明.旨在帮助用户快速启动和运行软件.文档主要描述了在Linux环境下编译和 运行DPDK应用程序,但是文档并不深入DPDK的具体实现细节. 1.1. ...

  9. S3C2440 LCD驱动(FrameBuffer)实例开发<一>(转)

    1. 背景知识 在多媒体的推动下,彩色LCD越来越多地应用到嵌入式系统中,PDA和手机等大多都采用LCD作为显示器材,因此学习LCD的应用很有实际意义! LCD工作的硬件需求:要使一块LCD正常的显示 ...

随机推荐

  1. python XlsxWriter创建Excel 表格

    文档(英文) https://xlsxwriter.readthedocs.io/index.html 常用模块说明(中文) https://blog.csdn.net/sinat_35930259/ ...

  2. http和Tcp的长连接和短连接

    . http协议和tcp/ip 协议的关系(1) http是应用层协议,tcp协议是传输层协议,ip协议是网络协议.(2) IP协议主要解决网络路由和寻址问题(3) tcp协议主要解决在IP层协议之上 ...

  3. Python列表及元组操作

    #列表(一组有序数据的组合就是列表) #创建列表 #空列表 var = list()#var = [] print(var,type(var)) #具有多个元素的列表 var = ['风','水',' ...

  4. POJ 1204 Word Puzzles | AC 自动鸡

    题目: 给一个字母矩阵和几个模式串,矩阵中的字符串可以有8个方向 输出每个模式串开头在矩阵中出现的坐标和这个串的方向 题解: 我们可以把模式串搞成AC自动机,然后枚举矩阵最外围一层的每个字母,向八个方 ...

  5. babelrc配置

    { "presets": [ ["env", { // webapck2/3必须配置,放弃使用babel的模块化,使用webpack的模块化,webpack1不 ...

  6. java合并两个有序数组的算法(抛砖引玉)

    前几天看见一道面试题中要将两个有序数组合并成一个新的有序数组,首先使用了嵌套循环,之后想那样效率太低,又想出了以下思路,和大家分享下,如果有更好的方法,请留言指教: 思路: 1.新建一个数组大小为fi ...

  7. [ CodeVS冲杯之路 ] P1116

    不充钱,你怎么AC? 题目:http://codevs.cn/problem/1116/ 数据很小,DFS可A,每层枚举颜色,判断相邻的点是否有重复的颜色,记得回溯时把颜色染回0,即无颜色 这里我使用 ...

  8. bzoj 4765 普通计算姬 dfs序 + 分块

    题目链接 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...

  9. 01深入理解C指针之---指针含义符号

    该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. 1.指针的含义: 指针本身也是变量,与其他一般变量不同的是:指针变量中没有存储具体类型 ...

  10. hdu 2461(AC) & poj 3695(TLE)(离散化+矩形并)

    Rectangles Time Limit: 5000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...