驅動_LCD驅動框架

 

 


 

 

 

 


 

LCD驅動具體編寫:php

        1) 分配一個fb_info結構體       html

        2) 設置fb_info (fix , var , fbops )linux

        3) 設置硬件相關的操做android

        4) 使能LCD,並註冊fb_info: register_framebuffer()數組


 

 


 
 
重要函數:

①:fbmem.c
 
 
struct fb_info *framebuffer_alloc(size_t size, struct device *dev);  
//功能: 向內核申請一段大小爲sizeof(struct fb_info) + size的空間,其中size的大小表明設備的私有數據空間,並用fb_info的par域指向該私有空間。
//參數: 參數一:空間大小       參數二: dev->dev(父類)
//申請一個fb_info結構體

 

   void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); //分配DMA緩存區給顯存緩存

//返回值爲:申請到的DMA緩衝區的虛擬地址,若爲NULL,表示分配失敗,則須要使用dma_free_writecombine()釋放內存,避免內存泄漏
//參數以下: //*dev:指針,這裏填0,表示這個申請的緩衝區裏沒有內容 //size:分配的地址大小(字節單位) //*handle:申請到的物理起始地址 //gfp:分配出來的內存參數,標誌定義在<linux/gfp.h>,經常使用標誌以下: //GFP_ATOMIC 用來從中斷處理和進程上下文以外的其餘代碼中分配內存. 從不睡眠. //GFP_KERNEL 內核內存的正常分配. 可能睡眠. //GFP_USER 用來爲用戶空間頁來分配內存; 它可能睡眠.








int register_framebuffer(struct fb_info *fb_info);  
//向內核中註冊fb_info結構體,若內存不夠,註冊失敗會返回負數

int unregister_framebuffer(struct fb_info *fb_info) ;
//註銷內核中fb_info結構體

 






  error:
      

 

 

 

 
 

 

 

 

 

    ②: xxfb.c app

   struct fb_info *framebuffer_alloc(size_t size, struct device *dev); //申請一個fb_info結構體,ide

   int register_framebuffer(struct fb_info *fb_info);//向內核中註冊fb_info結構體,若內存不夠,註冊失敗會返回負數函數

 

 

// 分配顯存,並告訴fb_info
fb_info->screen_base = dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)  

 

 

 

   error:ui

         int  unregister_framebuffer(struct fb_info *fb_info);   

       struct fb_info * framebuffer_release(size_t size, struct device *dev);

 

 

 

 


 重要結構體

struct fb_info {                            //  記錄緩衝區設備的所有信息
  ... ...
  struct fb_var_screeninfo var; //可變的參數
  struct fb_fix_screeninfo fix; //固定的參數
  ... ...
  struct fb_ops *fbops; //操做函數
  ... ...
  char __iomem *screen_base;  //顯存虛擬起始地址
  unsigned long   screen_size;   //顯存虛擬地址長度

  void *pseudo_palette;
  //假的16色調色板,裏面存放了16色的數據,能夠經過8bpp數據來找到調色板裏面的16色顏色索引值,模擬出16色顏色來,節省內存,不須要的話就指向一個不用的數組便可

 

  struct device *device;/* This is the parent */  父設備(父類)

 

  ... ...
};

 

struct fb_fix_screeninfo {    //記錄控制器不可修改的參數(緩衝區的物理地址和長度)

 char id[16]; //id名字,字符串形式的標識符 unsigned long smem_start; //控制器物理起始地址  __u32 smem_len; //控制器長度,字節爲單位 __u32 type; //lcd類型,默認值0便可 __u32 type_aux; //附加類型,爲0,分界 __u32 visual; //畫面設置,經常使用參數以下     // FB_VISUAL_MONO01 0   單色,0:白色,1:黑色     // FB_VISUAL_MONO10 1   單色,1:白色,0:黑色     // FB_VISUAL_TRUECOLOR 2 真彩(TFT:真彩)     // FB_VISUAL_PSEUDOCOLOR     3 僞彩     // FB_VISUAL_DIRECTCOLOR 4 直彩     __u16 xpanstep; /*若是沒有硬件panning就賦值爲0 */     __u16 ypanstep; /*若是沒有硬件panning就賦值爲0 */     __u16 ywrapstep; /*若是沒有硬件ywrap就賦值爲0 */

    char __iomem *screen_base;  /* "顯存「的基地址 */
    unsigned long screen_size;  /* 」顯存「的大小 */ 
    void *pseudo_palette;      /* 16位假的調色板 */      __u32 line_length; /*一行的字節數 ,例:(RGB565)240*320,那麼這裏就等於240*16/8 */     /*如下成員均可以不須要*/     unsigned long mmio_start; /*內存映射IO的起始地址,用於應用層直接訪問寄存器,能夠不須要*/ __u32 mmio_len; /* 內存映射IO的長度,能夠不須要*/ __u32 accel; __u16 reserved[3];       /* 保留 */
};

 

 

struct  fb_var_screeninfo  {              //記錄控制器能夠修改的參數 (分辨率,像素位數)

   __u32 xres; /*可見屏幕一行有多少個像素點(就是分辨率X)*/
   __u32 yres; /*可見屏幕一列有多少個像素點(就是分辨率Y)*/
    __u32 xres_virtual; /*虛擬屏幕一行有多少個像素點*/       
    __u32 yres_virtual; /*虛擬屏幕一列有多少個像素點*/
    __u32 xoffset; /*虛擬到可見屏幕之間的行偏移,若可見和虛擬的分辨率同樣,就直接設爲0*/
    __u32 yoffset; /*虛擬到可見屏幕之間的列偏移*/
    __u32 bits_per_pixel;   /*每一個像素的位數即BPP,好比:RGB565則填入16*/
    __u32 grayscale;        /*非0時,指的是灰度,真彩直接填0便可*/

    struct fb_bitfield red;//fb緩存的R位域, fb_bitfield結構體成員以下:
   __u32 offset;          //區域偏移值,好比RGB565中的R,就在第11位
   __u32 length;          //區域長度,好比RGB565的R,共有5位
   __u32 msb_right;       //msb_right ==0,表示數據左邊最大, msb_right!=0,表示數據右邊最大


    struct fb_bitfield green;        /*fb緩存的G位域*/
    struct fb_bitfield blue;         /*fb緩存的B位域*/

   /*如下參數均可以不填,默認爲0*/
    struct fb_bitfield transp; /*透明度,不須要填0便可*/    
 
    __u32 nonstd;              /* != 0表示非標準像素格式*/
    __u32 activate;            /*設爲0便可*/
    __u32 height;              /*外設高度(單位mm),通常不須要填*/
    __u32 width;               /*外設寬度(單位mm),通常不須要填*/
    __u32 accel_flags;         /*過期的參數,不須要填*/

    /* 除了pixclock自己外,其餘的都以像素時鐘爲 單位*/ 
 __u32 pixclock; /*像素時鐘(皮秒)*/ __u32 left_margin; /*行切換,從同步到繪圖之間的延遲*/ __u32 right_margin; /*行切換,從繪圖到同步之間的延遲*/
 __u32 upper_margin; /*幀切換,從同步到繪圖之間的延遲*/ __u32l ower_margin; /*幀切換,從繪圖到同步之間的延遲*/ __u32 hsync_len; /*水平同步的長度*/ __u32 vsync_len; /*垂直同步的長度*/ __u32 sync; __u32 vmode; __u32 rotate; __u32 reserved[5]; /*保留*/

}


static struct fb_ops  = {      // 底層硬件操做函數的集合

.owner = THIS_MODULE //被使用時阻止模塊被卸載

      int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);    //檢查可變參數並進行設置  

     int (*fb_set_par)(struct fb_info *info);              //根據設置的值進行更新,使之有效  

     int (*fb_blank)(int blank, struct fb_info *info);   //顯示空白  
 .fb_setcolreg  //設置調色板fb_info-> pseudo_palette,本身構造該函數, //設置顏色寄存器   .fb_fillrect //填充矩形,用/drivers/video/ cfbfillrect.c裏的函數便可, //矩形填充   .fb_copyarea //複製數據, 用/drivers/video/cfbcopyarea.c裏的函數便可 //複製數據   .fb_imageblit //繪畫圖形, 用/drivers/video/imageblit.c裏的函數便可 //圖形填充   };


 


 時序參數:

                     ① 控制器輸出時序

 

    

幀參數:

     VSYNC:垂直同步時鐘

     VSPW  :垂直同步脈寬  VBPD:垂直後肩  LINEVAL:垂直有效  VFPD:垂直前肩

     INT_FRSyn :幀同步中斷

     VDEN :   視頻數據使能  

 

行參數:

    HSYNC:水平同步時鐘  VCLK :像素時鐘

       HSPW  :水平同步脈寬   HBPD:水平後肩  HOZVAL:水平有效  HFPD:水平前肩

    VD :  視頻數據

    VDEN :  視頻數據使能信號

    LDEN :   行結束信號

 

                     ② 液晶屏輸出時序

 

     


 

 

 

 

 

<程序控制>

1.打開設備   

  int fd = open("/dev/fd0",O_RDWR);


2.獲取到lcd屏的信息xres,yres,bpp    

  應用:  ioctl(fd,FBIOGET_VSCREENINFO,&var);
---------------------------------------------------------------------------------
  驅動:  static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

 

3.映射顯存到應用空間

  char *addr  = mmap(NULL, length,  PROT_READ|PROT_WRITE,  MAP_SHARED, int fd, 0);

  framebuffer_ptr =(char *)mmap( NULL,//若是此值爲NULL,則表示用內核來自動給你分配一塊虛擬空間
  screensize, //空間大小
  PROT_READ|PROT_WRITE,//權限
  MAP_SHARED, //是否能夠共享
  framebuffer_fd, //文件描述符
  0); //從哪一個地方開始

 

4. 獲得圖片的數據,將數據寫入到映射的虛擬地址指向的空間

  運行程序的格式:./lcd_test   dev/fbx   pic.bmp 

  /*1.打開一副圖片*/
  pic_fd =open(argv[2],O_RDWR);
  printf("pic_fd=%d\n",pic_fd);

  /*2.獲取圖片大小*/
  len =lseek(pic_fd, 0, SEEK_END);
  printf("len =%ld\n",len);

  /*3.讀取圖片數據*/
  read(pic_fd,buffer,len);

  /*4.初始化lcd*/
  fd=init_lcd(argv[1]);

  //5.buffer存放了bmp圖片數據,framebuffer_ptr映射後返回的顯存的地址
  draw_bmp(buffer,(unsigned short *) framebuffer_ptr);

    代碼示例:https://www.cnblogs.com/panda-w/p/10992943.html

 

 

<筆記>

1. 

 

 


 

 

 幀率:每秒生成圖片個數(60fps就是每秒鐘顯卡生成60張畫面圖片)

 刷新率:顯示信號輸出刷新的速度。60赫茲(hertz)就是每秒鐘顯卡向顯示器輸出60次信號。

假設幀數是刷新率的1/2,那麼意思就是顯卡每兩次向顯示器輸出的畫面是用一幅畫面。相反,若是幀數是刷新率的2倍,那麼畫面每改變兩次,其中只有1次是被顯卡發送並在顯示器上顯示的。 因此高於刷新率的幀數都是無效幀數,對畫面效果沒有任何提高,反而可能致使畫面異常。

 

幀率 =dotclock/((xres+left_margin+right_margin+hsync)*(yres+upper_margin+low_margin+vsync))

而android系統最高幀率爲60fps,因此最好保證lcd的幀率也應大於等於60fps。xres和yres已經由硬件固定,所以根據公式調整其餘參數,能夠調整lcd幀率,使其儘可能接近60fps。

https://blog.csdn.net/zqh2007/article/details/46504835

 

先說明下像素時鐘pixclock的概念pixclock=1/dotclock  其中dotclock是視頻硬件在顯示器上繪製像素的速率dotclock=(x向分辨率+左空邊+右空邊+HSYNC長度)* (y向分辨率+上空邊+下空邊+YSYNC長度)*整屏的刷新率其中x向分辨率、左空邊、右空邊、HSYNC長度、y向分辨率、上空邊、下空邊和YSYNC長度能夠在X35LCD說明文檔中查到。整屏的刷新率計算方法以下:假如咱們經過查X35LCD說明文檔,知道fclk=6.34MHZ,那麼畫一個像素須要的時間就是1/6.34us,若是屏的大小是240*320,那麼現實一行須要的時間就是240/6.34us,每條掃描線是240,可是水平回掃和水平同步也須要時間,若是水平回掃和水平同步須要29個像素時鐘,所以,畫一條掃描線完整的時間就是(240+29) /6.34us。完整的屏有320根線,可是垂直回掃和垂直同步也須要時間,若是垂直回掃和垂直同步須要13個像素時鐘,那麼畫一個完整的屏須要(240+29)*(320+13)/6.34us,因此整屏的刷新率就是6.34/((240+29)*(320+13))MHZ

相關文章
相關標籤/搜索