lcd 显示驱动显示原理及实现

          近来有人需要使用arm完成工控lcd的显示,所以花了几天时间看了一下相关资料。在此做个总结,以备后用!

          因为手上只有一块2440和sony的3.5寸屏幕,所以就是被人笑也要做了再说,哈哈!

         首先声明我使用的是2.6.32.2的kernel。

         首先应该关注的是/include/linux/fb.h 这里定义了frambuffer所有的结构和操作,使用sourceinsight可以很方便的查找到引用。比如fb_write函数,可以追踪到 

         drivers/video/fbmem.c 喜欢研究底层操作的,一定要看这里面的。

          剩下需要关注的是arch/arm/plat-s3c/include/plat/regs-fb.h和arch/arm/plat-s3c/include/plat/fb.h这里定义了s3c平台通用的fb寄存器和地址信息,

          还有arch/arm/mach-s3c2410/include/mach/fb.h,这里定义了2410自己架构的结构体比如s3c2410fb_mach_info s3c2410fb_display s3c2410fb_hw

          好了,看完这些骨架大概对framebuffer有了一个了解了,下面就是看看这些骨头上的肉是什么样的吧!

         上面已经提到的fbmem.c一类是linux系统通用的代码,我们这里就不深入了,还是单独看看针对2410 2440有哪些需要关注的吧。

        1)先看arch/arm/plat-s3c24xx/devs.c 里面有啥宝贝。/* LCD Controller */ 下面标示的有static struct resource s3c_lcd_resource[],

              static u64 s3c_device_lcd_dmamask,void __init s3c24xx_fb_set_platdata,

              struct platform_device s3c_device_lcd = {
                             .name    = "s3c2410-lcd",
                             .id    = -1,
                             .num_resources   = ARRAY_SIZE(s3c_lcd_resource),
                             .resource   = s3c_lcd_resource,
                             .dev              = {
                             .dma_mask  = &s3c_device_lcd_dmamask,
                             .coherent_dma_mask = 0xffffffffUL
                             }

              s3c_device_lcd 是这里的关键咯,定义了我们需要的基本信息。

          2)顺藤摸瓜,我们找到了arch/arm/mach-s3c2410/mach-bast.c ,这里定义了平台对应系统的一些数据实现,如果我们要自己做驱动那就要关注一下了,因为通过这里 

                进行相应的修改,会大大加快你的进度。对于修改驱动的朋友可以跳过去。

          3)因为我用的是2440的板子所以移植kernel的时候使用的2410+smdk2440的架构,如果使用其他架构的朋友要注意了,这里开始就要分化咯。

                在arch/arm/mach-s3c2440/mach-smdk2440.c里面有我们最终需要的/* LCD driver info */,static struct s3c2410fb_display smdk2440_lcd_cfg __initdata包含了针

               对LCD屏幕的各种参数设置,static struct s3c2410fb_mach_info smdk2440_fb_info __initdata包含了framebuffer驱动的基本信息,这些都是针对2440平台特有的数

               据(所以到这里我们大概了解了linux驱动的大概路径,首先是linux基本结构,再到平台结构,最后才到架构的具体实现)。

          4)剩下最后我们要看的就是drivers/video/s3c2410fb.c了,它是这里的主角,这里包含了s3c2410fb_ops, s3c2410fb_irq, s3c24xxfb_probe等等,做过驱动的朋友一

               定很熟悉这些下划线后面的名字吧,对了,这里就是上面所有准备信息的最后驱动实现,这里包括了注册,中断,操作等等的实体。

到此为止我们已经将2440framebuffer驱动的街道走了一遍,但是没有进入每个房间和花园去欣赏,鉴于很多牛人已经做了这个向导,下面是我找到的一些资源,大家可以去参考一下。

1、想要快速让自己的sony 3.5寸 lcd出现小企鹅的可以参考《LCD驱动移植--x35》http://2378949.blog.51cto.com/2368949/674685 虽然这位兄弟也不是原创,但是内容却是正确的,这里提醒心急的朋友,在2.6.32源码里面s3c2410fb_mach_info下面有一段注释 /* currently setup by downloader */ 一定要打开哦!

2、想要了解lcd驱动更加详细的信息,可以参考《linux-2.6.32.2framebuffer源代码详细分析http://wenku.baidu.com/view/f793780f7cd184254b353580.html,因为时间问题我没有找到pdf版本的下载,不过内容不多,在线看一下应该也可以的。

3、这里还有一篇文章一定要看《Framebuffer原理、使用、测试系列文章http://bbs.chinaunix.net/thread-1932291-1-1.html 能被chinaunix定为精华,相比大家应该知道其分量了吧。
              为了方便大家,我将测试代码复制了过来(这里不得不提一下,chinaunix有个代码复制功能,真的很喜欢,希望csdn也能做一个)


#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <string.h>
#include <errno.h>

struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
char *frameBuffer = 0;

//打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。
void
printFixedInfo ()
{
    printf ("Fixed screen info:\n"
            "\tid: %s\n"
            "\tsmem_start: 0x%lx\n"
            "\tsmem_len: %d\n"
            "\ttype: %d\n"
            "\ttype_aux: %d\n"
            "\tvisual: %d\n"
            "\txpanstep: %d\n"
            "\typanstep: %d\n"
            "\tywrapstep: %d\n"
            "\tline_length: %d\n"
            "\tmmio_start: 0x%lx\n"
            "\tmmio_len: %d\n"
            "\taccel: %d\n"
            "\n",
            finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
            finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
            finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
            finfo.mmio_len, finfo.accel);
}

//打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置
void
printVariableInfo ()
{
    printf ("Variable screen info:\n"
            "\txres: %d\n"
            "\tyres: %d\n"
            "\txres_virtual: %d\n"
            "\tyres_virtual: %d\n"
            "\tyoffset: %d\n"
            "\txoffset: %d\n"
            "\tbits_per_pixel: %d\n"
            "\tgrayscale: %d\n"
            "\tred: offset: %2d, length: %2d, msb_right: %2d\n"
            "\tgreen: offset: %2d, length: %2d, msb_right: %2d\n"
            "\tblue: offset: %2d, length: %2d, msb_right: %2d\n"
            "\ttransp: offset: %2d, length: %2d, msb_right: %2d\n"
            "\tnonstd: %d\n"
            "\tactivate: %d\n"
            "\theight: %d\n"
            "\twidth: %d\n"
            "\taccel_flags: 0x%x\n"
            "\tpixclock: %d\n"
            "\tleft_margin: %d\n"
            "\tright_margin: %d\n"
            "\tupper_margin: %d\n"
            "\tlower_margin: %d\n"
            "\thsync_len: %d\n"
            "\tvsync_len: %d\n"
            "\tsync: %d\n"
            "\tvmode: %d\n"
            "\n",
            vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,
            vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel,
            vinfo.grayscale, vinfo.red.offset, vinfo.red.length,
            vinfo.red.msb_right, vinfo.green.offset, vinfo.green.length,
            vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length,
            vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length,
            vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate,
            vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock,
            vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin,
            vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len,
            vinfo.sync, vinfo.vmode);
}

//画大小为width*height的同色矩阵,8alpha+8reds+8greens+8blues
void
drawRect_rgb32 (int x0, int y0, int width, int height, int color)
{
    const int bytesPerPixel = 4;
    const int stride = finfo.line_length / bytesPerPixel;

    int *dest = (int *) (frameBuffer)
        + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);

    int x, y;
    for (y = 0; y < height; ++y)
    {
        for (x = 0; x < width; ++x)
        {
            dest[x] = color;
        }
        dest += stride;
    }
}

//画大小为width*height的同色矩阵,5reds+6greens+5blues
void
drawRect_rgb16 (int x0, int y0, int width, int height, int color)
{
    const int bytesPerPixel = 2;
    const int stride = finfo.line_length / bytesPerPixel;
    const int red = (color & 0xff0000) >> (16 + 3);
    const int green = (color & 0xff00) >> (8 + 2);
    const int blue = (color & 0xff) >> 3;
    const short color16 = blue | (green << 5) | (red << (5 + 6));

    short *dest = (short *) (frameBuffer)
        + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);

    int x, y;
    for (y = 0; y < height; ++y)
    {
        for (x = 0; x < width; ++x)
        {
            dest[x] = color16;
        }
        dest += stride;
    }
}

//画大小为width*height的同色矩阵,5reds+5greens+5blues
void
drawRect_rgb15 (int x0, int y0, int width, int height, int color)
{
    const int bytesPerPixel = 2;
    const int stride = finfo.line_length / bytesPerPixel;
    const int red = (color & 0xff0000) >> (16 + 3);
    const int green = (color & 0xff00) >> (8 + 3);
    const int blue = (color & 0xff) >> 3;
    const short color15 = blue | (green << 5) | (red << (5 + 5)) | 0x8000;

    short *dest = (short *) (frameBuffer)
        + (y0 + vinfo.yoffset) * stride + (x0 + vinfo.xoffset);

    int x, y;
    for (y = 0; y < height; ++y)
    {
        for (x = 0; x < width; ++x)
        {
            dest[x] = color15;
        }
        dest += stride;
    }
}

void
drawRect (int x0, int y0, int width, int height, int color)
{
    switch (vinfo.bits_per_pixel)
    {
    case 32:
        drawRect_rgb32 (x0, y0, width, height, color);
        break;
    case 16:
        drawRect_rgb16 (x0, y0, width, height, color);
        break;
    case 15:
        drawRect_rgb15 (x0, y0, width, height, color);
        break;
    default:
        printf ("Warning: drawRect() not implemented for color depth %i\n",
                vinfo.bits_per_pixel);
        break;
    }
}

#define PERFORMANCE_RUN_COUNT 5
void
performSpeedTest (void *fb, int fbSize)
{
    int i, j, run;
    struct timeval startTime, endTime;
    unsigned long long results[PERFORMANCE_RUN_COUNT];
    unsigned long long average;
    unsigned int *testImage;

    unsigned int randData[17] = {
        0x3A428472, 0x724B84D3, 0x26B898AB, 0x7D980E3C, 0x5345A084,
        0x6779B66B, 0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33,
        0x0E26EB73, 0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B,
        0x5F2C22FB, 0x6A742130
    };

    printf ("Frame Buffer Performance test...\n");
    for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run)
    {
        /* Generate test image with random(ish) data: */
        testImage = (unsigned int *) malloc (fbSize);
        j = run;
        for (i = 0; i < (int) (fbSize / sizeof (int)); ++i)
        {
            testImage[i] = randData[j];
            j++;
            if (j >= 17)
                j = 0;
        }

        gettimeofday (&startTime, NULL);
        memcpy (fb, testImage, fbSize);
        gettimeofday (&endTime, NULL);

        long secsDiff = endTime.tv_sec - startTime.tv_sec;
        results[run] =
            secsDiff * 1000000 + (endTime.tv_usec - startTime.tv_usec);

        free (testImage);
    }

    average = 0;
    for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)
        average += results[i];
    average = average / PERFORMANCE_RUN_COUNT;

    printf (" Average: %llu usecs\n", average);
    printf (" Bandwidth: %.03f MByte/Sec\n",
            (fbSize / 1048576.0) / ((double) average / 1000000.0));
    printf (" Max. FPS: %.03f fps\n\n",
            1000000.0 / (double) average);

    /* Clear the framebuffer back to black again: */
    memset (fb, 0, fbSize);
}

int
main (int argc, char **argv)
{
    const char *devfile = "/dev/fb0";
    long int screensize = 0;
    int fbFd = 0;


    /* Open the file for reading and writing */
    fbFd = open (devfile, O_RDWR);
    if (fbFd == -1)
    {
        perror ("Error: cannot open framebuffer device");
        exit (1);
    }

    //获取finfo信息并显示
    if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)
    {
        perror ("Error reading fixed information");
        exit (2);
    }
    printFixedInfo ();
    //获取vinfo信息并显示
    if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)
    {
        perror ("Error reading variable information");
        exit (3);
    }
    printVariableInfo ();

    /* Figure out the size of the screen in bytes */
    screensize = finfo.smem_len;

    /* Map the device to memory */
    frameBuffer =
        (char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                     fbFd, 0);
    if (frameBuffer == MAP_FAILED)
    {
        perror ("Error: Failed to map framebuffer device to memory");
        exit (4);
    }

    //测试virt fb的性能
    performSpeedTest (frameBuffer, screensize);

    printf ("Will draw 3 rectangles on the screen,\n"
            "they should be colored red, green and blue (in that order).\n");
    drawRect (vinfo.xres / 8, vinfo.yres / 8,
             vinfo.xres / 4, vinfo.yres / 4, 0xffff0000);
    drawRect (vinfo.xres * 3 / 8, vinfo.yres * 3 / 8,
             vinfo.xres / 4, vinfo.yres / 4, 0xff00ff00);
    drawRect (vinfo.xres * 5 / 8, vinfo.yres * 5 / 8,
             vinfo.xres / 4, vinfo.yres / 4, 0xff0000ff);

    sleep (5);
    printf (" Done.\n");

    munmap (frameBuffer, screensize);    //解除内存映射,与mmap对应

    close (fbFd);
    return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值