zoukankan      html  css  js  c++  java
  • 11. Linux——LCD驱动程序

    由上一节

    得出写个LCD驱动入口函数,需要以下4步:

    1) 分配一个fb_info结构体: framebuffer_alloc();

    2) 设置fb_info

    3) 设置硬件相关的操作

    4) 使能LCD,并注册fb_info: register_framebuffer()

    本节需要用到的函数:

     1 void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);  //分配DMA缓存区给显存
     2 //返回值为:申请到的DMA缓冲区的虚拟地址,若为NULL,表示分配失败,则需要使用dma_free_writecombine()释放内存,避免内存泄漏
     3 //参数如下: 
     4 
     5 //*dev:指针,这里填0,表示这个申请的缓冲区里没有内容
     6 
     7 //size:分配的地址大小(字节单位)
     8 
     9 //*handle:申请到的物理起始地址
    10 
    11 //gfp:分配出来的内存参数,标志定义在<linux/gfp.h>,常用标志如下:
    12     //GFP_ATOMIC    用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
    13     //GFP_KERNEL    内核内存的正常分配. 可能睡眠.
    14     //GFP_USER      用来为用户空间页来分配内存; 它可能睡眠.

      分配一段DMA缓存区,分配出来的内存会禁止cache缓存(因为DMA传输不需要CPU)

      它和 dma_alloc_coherent ()函数相似,不过 dma_alloc_coherent ()函数是分配出来的内存会禁止cache缓存以及禁止写入缓冲区


    1 dma_free_writecombine(dev,size,cpu_addr,handle);   //释放缓存
    2 //cpu_addr:虚拟地址, 
    3 //handle:物理地址

      释放DMA缓冲区, dev和size参数和上面的一样


    1 struct fb_info *framebuffer_alloc(size_t size, struct device *dev);      //申请一个fb_info结构体,
    2 //size:额外的内存,
    3 //*dev:指针, 这里填0,表示这个申请的结构体里没有内容
    1 int register_framebuffer(struct fb_info *fb_info);  
      //向内核中注册fb_info结构体,若内存不够,注册失败会返回负数
    4 
    5 int unregister_framebuffer(struct fb_info *fb_info) ;
    6 //注销内核中fb_info结构体

    需要用到的结构体:

      fb_info结构体

     1 struct fb_info {
     2         ... ...
     3        struct fb_var_screeninfo var;    //可变的参数
     4        struct fb_fix_screeninfo fix;    //固定的参数
     5        ... ...
     6        struct fb_ops *fbops;            //操作函数
     7        ... ...
     8        char __iomem *screen_base;       //显存虚拟起始地址
     9        unsigned long screen_size;       //显存虚拟地址长度
    10   
    11        void *pseudo_palette;                
    12    //假的16色调色板,里面存放了16色的数据,可以通过8bpp数据来找到调色板里面的16色颜色索引值,模拟出16色颜色来,节省内存,不需要的话就指向一个不用的数组即可
    13        ... ...
    14 };

      其中操作函数fb_info-> fbops 结构体写法如下:

     1 static struct fb_ops s3c_lcdfb_ops = {
     2          .owner                = THIS_MODULE,
     3 
     4          .fb_setcolreg    = s3c_lcdfb_setcolreg,//设置调色板fb_info-> pseudo_palette,自己构造该函数
     5 
     6          .fb_fillrect      = cfb_fillrect,     //填充矩形,用/drivers/video/ cfbfillrect.c里的函数即可
     7 
     8          .fb_copyarea    = cfb_copyarea,  //复制数据, 用/drivers/video/cfbcopyarea.c里的函数即可
     9 
    10          .fb_imageblit    = cfb_imageblit, //绘画图形, 用/drivers/video/imageblit.c里的函数即可
    11 };

      固定的参数fb_info-> fix 结构体如下:

     1 struct fb_fix_screeninfo {
     2        char id[16];                   //id名字
     3        unsigned long smem_start;  //framebuffer物理起始地址                          
     4        __u32 smem_len;           //framebuffer长度,字节为单位
     5        __u32 type;                 //lcd类型,默认值0即可
     6        __u32 type_aux;               //附加类型,为0
     7        __u32 visual;                     //画面设置,常用参数如下
     8 // FB_VISUAL_MONO01             0   单色,0:白色,1:黑色
     9 // FB_VISUAL_MONO10             1    单色,1:白色,0:黑色
    10 // FB_VISUAL_TRUECOLOR          2     真彩(TFT:真彩)
    11 // FB_VISUAL_PSEUDOCOLOR     3     伪彩
    12 // FB_VISUAL_DIRECTCOLOR        4     直彩
    13 
    14     __u16 xpanstep;                /*如果没有硬件panning就赋值为0 */
    15     __u16 ypanstep;                /*如果没有硬件panning就赋值为0 */
    16     __u16 ywrapstep;                 /*如果没有硬件ywrap就赋值为0 */
    17 
    18     __u32 line_length;                 /*一行的字节数 ,例:(RGB565)240*320,那么这里就等于240*16/8 */
    19 
    20     /*以下成员都可以不需要*/
    21     unsigned long mmio_start;        /*内存映射IO的起始地址,用于应用层直接访问寄存器,可以不需要*/                                   
    22        __u32 mmio_len;                   /* 内存映射IO的长度,可以不需要*/
    23        __u32 accel;                 
    24        __u16 reserved[3];        
    25 
    26 };
    fb_info->fix

      可变的参数fb_info-> var 结构体如下:

     1 structfb_var_screeninfo{                                    
     2    __u32xres;                    /*可见屏幕一行有多少个像素点*/
     3     __u32 yres;                      /*可见屏幕一列有多少个像素点*/
     4     __u32 xres_virtual;         /*虚拟屏幕一行有多少个像素点 */       
     5     __u32  yres_virtual;       /*虚拟屏幕一列有多少个像素点*/
     6     __u32 xoffset;                 /*虚拟到可见屏幕之间的行偏移,若可见和虚拟的分辨率一样,就直接设为0*/
     7     __u32 yoffset;                 /*虚拟到可见屏幕之间的列偏移*/
     8     __u32  bits_per_pixel;    /*每个像素的位数即BPP,比如:RGB565则填入16*/
     9     __u32 grayscale;           /*非0时,指的是灰度,真彩直接填0即可*/
    10 
    11     struct fb_bitfield red;          //fb缓存的R位域, fb_bitfield结构体成员如下:
    12 //__u32 offset;          区域偏移值,比如RGB565中的R,就在第11位
    13 //__u32 length;                   区域长度,比如RGB565的R,共有5位
    14 //__u32 msb_right;  msb_right ==0,表示数据左边最大, msb_right!=0,表示数据右边最大
    15 
    16 
    17     struct fb_bitfield green;    /*fb缓存的G位域*/
    18     struct fb_bitfield blue;       /*fb缓存的B位域*/
    19 
    20    /*以下参数都可以不填,默认为0*/
    21     struct fb_bitfield transp;   /*透明度,不需要填0即可*/    
    22  
    23     __u32nonstd;                    /* != 0表示非标准像素格式*/
    24     __u32 activate;                 /*设为0即可*/
    25     __u32height;                     /*外设高度(单位mm),一般不需要填*/
    26     __u32width;                      /*外设宽度(单位mm),一般不需要填*/
    27     __u32 accel_flags;        /*过时的参数,不需要填*/
    28 
    29     /* 除了pixclock本身外,其他的都以像素时钟为 单位*/ 
    30     __u32pixclock;                   /*像素时钟(皮秒)*/
    31     __u32 left_margin;         /*行切换,从同步到绘图之间的延迟*/
    32     __u32right_margin;        /*行切换,从绘图到同步之间的延迟*/
    33     __u32upper_margin;       /*帧切换,从同步到绘图之间的延迟*/
    34     __u32lower_margin;       /*帧切换,从绘图到同步之间的延迟*/
    35     __u32hsync_len;              /*水平同步的长度*/
    36     __u32 vsync_len;           /*垂直同步的长度*/
    37     __u32 sync;
    38     __u32 vmode;
    39     __u32 rotate;
    40     __u32reserved[5];        /*保留*/
    41 
    42 }
    fb_info->var

    1.写驱动程序:

    (驱动设置:参考自带的LCD平台驱动drivers/video/s3c2410fb.c )

    (LCD控制寄存器设置:参考韦老大的LCD裸机驱动:)

    1.1 步骤如下:

    在驱动init入口函数中:

    1)分配一个fb_info结构体

    2)设置fb_info

      2.1)设置固定的参数fb_info-> fix

      2.2) 设置可变的参数fb_info-> var

      2.3) 设置操作函数fb_info-> fbops

      2.4) 设置fb_info 其它的成员

    3)设置硬件相关的操作    

      3.1)配置LCD引脚

      3.2)根据LCD手册设置LCD控制器

      3.3)分配显存(framebuffer),把地址告诉LCD控制器和fb_info

    4)开启LCD,并注册fb_info: register_framebuffer()

      4.1) 直接在init函数中开启LCD(后面讲到电源管理,再来优化)

        控制LCDCON5允许PWREN信号,

        然后控制LCDCON1输出PWREN信号,

        输出GPB0高电平来开背光,

      4.2) 注册fb_info

    在驱动exit出口函数中:

    1)卸载内核中的fb_info

    2) 控制LCDCON1关闭PWREN信号,关背光,iounmap注销地址

    3)释放DMA缓存地址dma_free_writecombine()

    4)释放注册的fb_info

    1.2 具体代码如下:

      1 /*写程序的思路如下:
      2 * 1.查看LCD芯片手册,查看相关的时间参数、分辨率、引脚极性;
      3 
      4 * 2.根据以上信息设置LCD控制器寄存器,让其发出正确信号;
      5 
      6 * 3.在内存里面分配一个FrameBuffer,在里面用若干位表示一个像素,再把首地址告诉LCD控制器;
      7 
      8 之后LCD控制器就能周而复始取出FrameBuffer里面的像素数据,配合其它控制信号,发送给电子枪,
      9 电子枪再让在LCD上显示出来。若想显示图像,只需要编写程序向FrameBuffer填入相应数据即可,
     10 硬件会自动的完成显示操作。*/
     11 
     12 
     13 
     14 #include <linux/module.h>
     15 #include <linux/kernel.h>
     16 #include <linux/errno.h>
     17 #include <linux/string.h>
     18 #include <linux/mm.h>
     19 #include <linux/slab.h>
     20 #include <linux/delay.h>
     21 #include <linux/fb.h>
     22 #include <linux/init.h>
     23 #include <linux/dma-mapping.h>
     24 #include <linux/interrupt.h>
     25 #include <linux/workqueue.h>
     26 #include <linux/wait.h>
     27 #include <linux/platform_device.h>
     28 #include <linux/clk.h>
     29 
     30 #include <asm/io.h>
     31 #include <asm/uaccess.h>
     32 #include <asm/div64.h>
     33 
     34 #include <asm/mach/map.h>
     35 #include <asm/arch/regs-lcd.h>
     36 #include <asm/arch/regs-gpio.h>
     37 #include <asm/arch/fb.h>
     38 
     39 static struct fb_info *s3c_lcd;
     40 static volatile unsigned long *gpbcon;
     41 static volatile unsigned long *gpbdat;
     42 static volatile unsigned long *gpccon;
     43 static volatile unsigned long *gpdcon;
     44 static volatile unsigned long *gpgcon;
     45 static volatile struct lcd_regs *lcd_regs; //定义一个结构体指针,并进行映射 
     46 static u32 pseudo_palette[16]; ///调色板数组,被fb_info->pseudo_palette调用
     47 
     48 /* LCD Control */
     49 struct lcd_regs {
     50     unsigned long    lcdcon1;
     51     unsigned long    lcdcon2;
     52     unsigned long    lcdcon3;
     53     unsigned long    lcdcon4;
     54     unsigned long    lcdcon5;
     55     unsigned long    lcdsaddr1;
     56     unsigned long    lcdsaddr2;
     57     unsigned long    lcdsaddr3;
     58     unsigned long    redlut;
     59     unsigned long    greenlut;
     60     unsigned long    bluelut;
     61     unsigned long    reserved[9]; //28--4C 相差36(16进制),除以4-->9byte
     62     unsigned long    dithmode;
     63     unsigned long    tpal;
     64     unsigned long    lcdintpnd;
     65     unsigned long    lcdsrcpnd;
     66     unsigned long    lcdintmsk;
     67     unsigned long    lpcsel;
     68 };
     69 
     70 static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
     71 {
     72     chan &= 0xffff;
     73     chan >>= 16 - bf->length; //右移,将数据靠到位0上
     74     return chan << bf->offset; //左移一定偏移值,放入16色数据中对应的位置
     75 }
     76 
     77 
     78 /* 类比调色板,混3色于碟子regno,  */
     79 static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,
     80                  unsigned int green, unsigned int blue,
     81                  unsigned int transp, struct fb_info *info)
     82 {
     83     unsigned int val;
     84     if (regno > 16)
     85         return 1;
     86 
     87     /* 用red, green, blue三原色构造出16色数据val */
     88     
     89     val  = chan_to_field(red,    &info->var.red);
     90     val |= chan_to_field(green,  &info->var.green);
     91     val |= chan_to_field(blue,    &info->var.blue);
     92     
     93     //((u32 *)(info->pseudo_palette))[regno] = val;
     94     pseudo_palette[regno] = val;
     95     return 0;
     96 
     97 }
     98 
     99 
    100 static struct fb_ops s3c_lcdfb_ops = {
    101     .owner          = THIS_MODULE,
    102     .fb_setcolreg    = s3c_lcdfb_setcolreg, //设置调色板fb_info-> pseudo_palette,自己构造该函数
    103     .fb_fillrect        = cfb_fillrect,  //填充矩形
    104     .fb_copyarea        = cfb_copyarea,  //复制数据
    105     .fb_imageblit    = cfb_imageblit, //绘画图形,
    106 };
    107 
    108 
    109 
    110 static int lcd_init(void)
    111 {
    112     /* 1.分配一个fbinfo结构体:framebuffer_alloc*/
    113     s3c_lcd = framebuffer_alloc(0, NULL);
    114     
    115     /* 2.设置 fb_info*/
    116     /* 2.1设置固定的参数(4.3寸横屏) */
    117     strcpy(s3c_lcd->fix.id, "mylcd");  //字符串拷贝至参数dest所指的地址
    118     s3c_lcd->fix.smem_len = 480*272*16; //480*272个像素点*16位/像素
    119     s3c_lcd->fix.type     = FB_TYPE_PACKED_PIXELS; //FB_TYPE_:LCD类型,默认0
    120     s3c_lcd->fix.visual   = FB_VISUAL_TRUECOLOR;   //表示真彩色
    121     s3c_lcd->fix.line_length = 480*2;       //一行的字节数,240*16/8
    122     
    123     /* 2.2设置可变的参数 */
    124     s3c_lcd->var.xres           = 480;  //可见屏X 分辨率
    125     s3c_lcd->var.yres           = 272;  //可见屏y 分辨率
    126     s3c_lcd->var.xres_virtual   = 480;  //虚拟屏x分辨率
    127     s3c_lcd->var.yres_virtual   = 272;  //虚拟屏y分辨率
    128     s3c_lcd->var.xoffset        =   0;  //虚拟到可见屏幕之间的行偏移
    129     s3c_lcd->var.yoffset        =   0;  //虚拟到可见屏幕之间的行偏移
    130     s3c_lcd->var.bits_per_pixel =  16;  //像素为16BPP
    131     s3c_lcd->var.grayscale      =   0;  //灰色比例
    132 
    133     /* R-G-B : 5-6-5*/
    134     s3c_lcd->var.red.offset     = 11;
    135     s3c_lcd->var.red.length     = 5;
    136     
    137     s3c_lcd->var.green.offset   = 5;
    138     s3c_lcd->var.green.length   = 6;
    139     
    140     s3c_lcd->var.blue.offset    = 0;
    141     s3c_lcd->var.blue.length    = 5;
    142 
    143     s3c_lcd->var.activate       = 0;
    144     
    145     /* 2.3设置操作函数 */
    146     s3c_lcd->fbops               = &s3c_lcdfb_ops;
    147     
    148     /* 2.4其他的设置 */
    149     s3c_lcd->pseudo_palette     = pseudo_palette; //假的调色板
    150     //s3c_lcd->screen_base        = ; //显存的虚拟地址,,在分配显存时,得到的返回值就是虚拟地址
    151     s3c_lcd->screen_size            = 480*272*2;//显存的物理大小
    152     
    153     /* 3.硬件相关操作 */
    154     /* 3.1配置GPIO用于LCD */
    155     gpbcon = ioremap(0x56000010, 8);
    156     gpbdat = gpbcon + 1;
    157     gpccon = ioremap(0x56000020, 4);
    158     gpdcon = ioremap(0x56000030, 4);
    159     gpgcon = ioremap(0x56000060, 4);
    160 
    161     *gpccon = 0xaaaaaaaa;   // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND
    162     *gpdcon = 0xaaaaaaaa;   // GPIO管脚用于VD[23:8]
    163       *gpbcon &= ~(3);  // GPB0设置为输出引脚,先清零
    164     *gpbcon |= 1;
    165     *gpbdat &= ~1;    // Power off,先输出低电平,再后面使能的时候再输出高电平
    166 
    167     *gpgcon |= (0x03<<8); //GPG4用作LCD_PWREN
    168     
    169 
    170     /* 3.2根据LCD手册设置LCD控制器,比如VCLK的频率 */
    171         /* 将寄存器放入结构体中,同一映射,方便 */
    172     lcd_regs = ioremap(0x4D000000, sizeof(struct lcd_regs));
    173 
    174     /*
    175      *bit[17:8] : VCLK = HCLK / [(CLKVAL+1) x 2] ( CLKVAL >=  0 )
    176      *       10MHZ(10ns)= 100MHZ/ [(CLKVAL+1) x 2]-->LCD手册P14
    177      *       CLKVAL = 4;
    178      *bit[7]: MMODE--决定VM的触发频率,不用管
    179      *bit[6:5]:PNRMODE--选择显示模式--TFT LCD面板--[1:1]
    180      *bit[4:1]:BPPMODE--位每像素--1100=16bpp
    181      *bit[0]  :ENVID  --LCD视频输出和逻辑使能/禁止(使能LCD控制器) 
    182      */
    183     lcd_regs->lcdcon1 = (4<<8) | (3<<5) | (0x0c<<1);
    184 
    185     /*垂直方向的时间参数
    186      *bit[31:24] :VBPD, VSYNC之后再过多长时间才能发出第一行数据
    187      *     LCD手册 :T0-(T1+T2) = 4 --> VBPD = 3
    188      *bit[23:14] :LINEVAL+1 = 272行-->271
    189      *bit[13:6]  :VFPD,发出最后一行数据之后,再过多久才发出VSYNC
    190      *             :LCD手册T2 - T5 = 2-->VFPD = 2-1
    191      *bit[5:0]   :VSPW, VSYNC信号的脉冲宽度,手册,1-1=0
    192      */
    193     lcd_regs->lcdcon2 = (3<<24) | (271<<14) | (1<<6) | (0<<0);
    194 
    195     /*水平方向的时间参数
    196      *bit[25:19] :HBPD, HSYNC之后多久才能发出第一个像素的数据
    197      *             T6 - T7 - T8 = 17, HBPD = 16
    198      *bit[18:8]  :HOZVAL,480-1 = 479 
    199      *bit[7:0]   :最后一行有效数据结束后,过多久发出HSYNC
    200      *             :LCD手册T8-T11=251-240=11, 所以HFPD=11-1=10
    201      */
    202     lcd_regs->lcdcon3 = (16<<19) | (479<<8) | (10<<0);
    203 
    204     /* 水平方向的同步信号
    205      * bit[7:0]    : HSPW, HSYNC信号的脉冲宽度, LCD手册T7=5, 所以HSPW=5-1=4
    206      */    
    207     lcd_regs->lcdcon4 = 4;
    208 
    209     /* 信号的极性 */
    210     /*bit[11]: 选择16bpp输出视频数据的格式---1 = 5:6:5 Format
    211      *bit[10]: 默认0--在下降沿取数据
    212      *bit[ 9]: 在2440芯片手册上Hsync信号为高电平有效,但是在LCD产品手册上,
    213      *           是低电平有效,要与产品手册一致,故反转,低电平有效,1
    214      *bit[ 8]:VSYNC,与HSYNC同样,低电平有效,故反转
    215      *bit[ 7]:INVVD, VD(视频数据)不需要管
    216      *bit[ 6]:INVVDEN,VDEN不需要反转, 0
    217      *bit[ 5]:INVPWREN,电源使能信号,不需要反转
    218      *bit[ 4]:INVLEND, 没用到LEND信号不用管
    219      *bit[ 3]:决定使能信号PWREN是否有效,1
    220      *bit[ 2]:不用管
    221      *bit[ 1]:BSWP = 0
    222      *bit[ 0]:HWSWP = 1
    223      */
    224     lcd_regs->lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (1<<0);
    225     
    226     
    227     /* 3.3分配显存,framebuffer,并把地址告诉LCD控制器 */
    228     //s3c_lcd->fix.smem_start = xxx; 显存的物理地址
    229                                                  //(dev, size,     物理地址,             , 标记)
    230     s3c_lcd->screen_base = dma_alloc_writecombine(NULL, 480*272*2, &s3c_lcd->fix.smem_start, GFP_KERNEL);
    231 
    232     /* 将framebuffer的起始地址的[30:1]保存到此寄存器的[29:0]中*/
    233     lcd_regs->lcdsaddr1 = (s3c_lcd->fix.smem_start >> 1) & ~(3<<30);
    234     
    235     /* 将framebuffer的结束地址的[21:1]保存到此寄存器的[20:0]中 */
    236     lcd_regs->lcdsaddr2 = (s3c_lcd->fix.smem_start + s3c_lcd->fix.smem_len >>1) & 0x1fffff;
    237 
    238     /* 虚拟屏地址设置,虚拟盘与真实屏尺寸相同,offsize,[21:11] = 0,  */
    239     /* PAGEWIDTH, 虚拟盘页宽度,即真实屏一行宽度,单位(半字) */
    240     lcd_regs->lcdsaddr3 = (480*16/16);  
    241 
    242     /* 注册前要使能LCD本身,及开启背光,可以提供接口,便于管理,
    243      *但涉及到电源管理,此处全程为使能的状态,直接启动 
    244      */
    245     /* 启动LCD */
    246     lcd_regs->lcdcon1 |= (1<<0);//使能LCD控制器
    247     lcd_regs->lcdcon5 |= (1<<3);//令使能信号LCD_PWREN有效,使能LCD本身 
    248     *gpbdat |= 1;  //KEYBOARD-->GPB0 ,背光使能,输出高电平
    249     /* 4.注册 */
    250     register_framebuffer(s3c_lcd);
    251 
    252 return 0;
    253 }
    254 
    255 static void lcd_exit(void)
    256 {
    257     unregister_framebuffer(s3c_lcd); //卸载内核中的info
    258     lcd_regs->lcdcon1 &= ~(1<<0);    //关闭LCD    
    259     *gpbdat &= ~1;    //关闭背光
    260     dma_free_writecombine(NULL, s3c_lcd->fix.smem_len, s3c_lcd->screen_base, s3c_lcd->fix.smem_start);
    261     iounmap(lcd_regs);
    262     iounmap(gpbcon);
    263     iounmap(gpccon);
    264     iounmap(gpdcon);
    265     iounmap(gpgcon);
    266     framebuffer_release(s3c_lcd); //释放显存
    267 }
    268 
    269 module_init(lcd_init); //修饰入口函数
    270 module_exit(lcd_exit); //修饰出口函数
    271 
    272 MODULE_LICENSE("GPL");       //声明函数
    lcd.c

    2.测试

    2.1重新编译内核,去掉默认的LCD

      make menuconfig ,进入menu菜单重新设置内核参数:

    进入Device Drivers-> Graphics support:
    <M> S3C2410 LCD framebuffer support          //将自带的LCD驱动设为模块, 不编进内核中

      make uImage 编译内核

       make modules 编译模块

    为什么要编译模块?

    因为LCD驱动相关的文件也没有编进内核,而fb_ops里的成员fb_fillrect(), fb_copyarea(), fb_imageblit()用的都是drivers/video下面的3个文件,所以需要这3个的.ko模块,

    2.2挂载驱动

    将编译好的LCD驱动模块 和drivers/video里的3个.ko模块 放入nfs文件系统目录中

    然后烧写内核, 先装载3个/drivers/video下编译好的模块,再来装载LCD驱动模块

    可以通过  ls -l /dev/fb*   命令查看已挂载的LCD设备节点

    2.3测试运行

    测试有两种: 

    echo hello> /dev/tty1     // LCD上便显示hello字段

    cat Makefile>/dev/tty1    // LCD上便显示Makeflie文件的内容

    2.4使用上节的键盘驱动在LCD终端打印命令行

    vi  /etc/inittab         //修改inittab, inittab:配置文件,用于启动init进程时,读取inittab
    
    添加->tty1::askfirst:-/bin/sh   //将sh进程(命令行)输出到tty1里,也就是使LCD输出信息

      然后重启,insmod装载3个/drivers/video下编译好的模块,再来insmod装载LCD驱动模块,tty1设备便有了,就能看到提示信息:

      insmod上一节的键盘驱动后,按下enter键,便能在LCD终端上操作linux

      但是我测试出的显示有花屏,花屏之后隐约能看见显示信息(有待解决)

           

    (以上大部分摘自:16.Linux-LCD驱动(详解)

  • 相关阅读:
    singleton 创建static类型的对象
    记忆曲线 遗忘曲线
    创建classic 得到函数 调用函数
    abstract factory 创建相互关联的类
    log4j PatternLayout
    C#中override重写与new隐藏的区别,以及C#与Java的override区别 转
    iptables如何做内网的https端口映射 转
    得到一棵树 取自表内自递归(即ID 与ParentID)
    Common.TcpLibTcpClientT
    得到汉字的首拼音字符 ZT
  • 原文地址:https://www.cnblogs.com/y4247464/p/10159965.html
Copyright © 2011-2022 走看看