dev layoutview 怎么显示大小_Liunx驱动学习:基于imx6ul 驱动oledssd1306 实现终端显示...
說明:
在學習linux驅動的過程中,繞不開的就是LCD驅動,網上大部分教程都是教大家如果使用分辨率比較高的LCD作為Linux開發板的顯示終端,但并沒有講過如果驅動spi或者iic這種低分辨率低幀率的液晶屏。正好手頭上有一個ssd1306的OLED,分辨率是128×64,于是就像用這個作為Linux終端,順便也學習了如果開發Linux的framebuffer驅動。
硬件:imx6ul + oledssd1306
應用
Linux 驅動是基于FrameBuffer框架的,網上關于FrameBuffer的介紹很多,我這里就簡單的說明一下。
幀緩沖(framebuffer)是Linux為顯示設備提供的一個接口,把顯存抽象后的一種設備fb,他允許上層應用程序在圖形模式下直接對顯示緩沖區進行讀寫操作。通常我們在dev下目錄中能查找/dev/fb*。
通過/dev/fb,應用程序的操作主要有這幾種:
1.讀/寫(read/write)/dev/fb:相當于讀/寫屏幕緩沖區。
2. 映射(map)操作:由于Linux工作在保護模式,每個應用程序都有自己的虛擬地址空間,在應用程序中是不能直接訪問物理緩沖區地址的。而幀緩沖設備可以通過mmap()映射操作將屏幕緩沖區的物理地址映射到用戶空間的一段虛擬地址上,然后用戶就可以通過讀寫這段虛擬地址訪問屏幕緩沖區,在屏幕上繪圖了。
3. I/O控制:對于幀緩沖設備,對設備文件的ioctl操作可讀取/設置顯示設備及屏幕的參數,如分辨率,屏幕大小等相關參數。ioctl的操作是由底層的驅動程序來完成的。
在應用程序中,操作/dev/fb的一般步驟如下:
1. 打開/dev/fb設備文件。
2. 用ioctl操作取得當前顯示屏幕的參數,根據屏幕參數可計算屏幕緩沖區的大小。
3. 將屏幕緩沖區映射到用戶空間。
4. 映射后即可直接讀寫屏幕緩沖區,進行繪圖和圖片顯示。
原理分析
幀緩沖設備為標準的字符型設備,在Linux中主設備號29,定義在/include/linux/major.h中的FB_MAJOR,次設備號定義幀緩沖的個數,最大允許有32個FrameBuffer,定義在/include/linux/fb.h中的FB_MAX。
幀緩沖設備結構圖
幀緩沖設備抽象層
對于驅動開發來說,內核已經在fbmem.c中實現了.
fbmem.c位于/driver/video/fbdev/core/fbmem.c,在這個文件中內核創建了fb設備。實現了fb_ops 操作函數,當我們打開某一個fb設備時,實際上是調用此文件中的fb_open(),fb_read()等函數。
fbmem.c實際上是一個抽象層,當調用fb_open 等函數時實際上會調用更加底層的操作函數去操作驅動LCD控制器。而這些更加底層的函數就是在xxxfb.c中實現的。
在framebuffer驅動開發過程中驅動開發者只需要將LCD驅動的相關信息填入到fb_info 結構體即可.最后在通過register_framebuffer函數將fb_info 注冊到內核,內核通過調用這個函數內核自動創建fbx設備,過程可以參考上圖。
int幀緩沖設備實現
在/driver/video/fbdev下會發現大量xxfb.c文件,這些文件就是上文說的驅動具體實現。主要完成對功能就實現fb_info 結構體。
struct fb_info {atomic_t count;int node;int flags;struct mutex lock; /* Lock for open/release/ioctl funcs */struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */struct fb_var_screeninfo var; /* Current var 可變參數*/struct fb_fix_screeninfo fix; /* Current fix 固定參數*/struct fb_monspecs monspecs; /* Current Monitor specs 顯示器標準*/struct work_struct queue; /* Framebuffer event queue 事件隊列*/struct fb_pixmap pixmap; /* Image hardware mapper */struct fb_pixmap sprite; /* Cursor hardware mapper */struct fb_cmap cmap; /* Current cmap 當前顏色表*/struct list_head modelist; /* mode list 模式列表*/struct fb_videomode *mode; /* current mode 當前顯示模式*/#ifdef CONFIG_FB_BACKLIGHT/* assigned backlight device *//* set before framebuffer registration, remove after unregister */struct backlight_device *bl_dev;//分配的背光設備,使用fb之前注冊,/* Backlight level curve */struct mutex bl_curve_mutex; u8 bl_curve[FB_BACKLIGHT_LEVELS]; #endif #ifdef CONFIG_FB_DEFERRED_IOstruct delayed_work deferred_work;struct fb_deferred_io *fbdefio; #endifstruct fb_ops *fbops; //操作函數struct device *device; /* 父設備節點This is the parent */struct device *dev; /* 當前幀緩沖設備This is this fb device */int class_flag; /* private sysfs flags */ #ifdef CONFIG_FB_TILEBLITTINGstruct fb_tile_ops *tileops; /* Tile Blitting */ #endifchar __iomem *screen_base; /* Virtual address 虛擬地址*/unsigned long screen_size; /* Amount of ioremapped VRAM or 0 虛擬地址的大小 */ void *pseudo_palette; /* Fake palette of 16 colors */ #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1u32 state; /* Hardware state i.e suspend */void *fbcon_par; /* fbcon use-only private area *//* From here on everything is device dependent */void *par;/* we need the PCI or similar aperture base/size notsmem_start/size as smem_start may just be an objectallocated inside the aperture so may not actually overlap */struct apertures_struct {unsigned int count;struct aperture {resource_size_t base;resource_size_t size;} ranges[0];} *apertures;bool skip_vt_switch; /* no VT switch on suspend/resume required */ };在這個結構體中最主要的是兩個
struct fb_var_screeninfo var; /* Current var 可變參數*/struct fb_fix_screeninfo fix; /* Current fix 固定參數*/struct fb_fix_screeninfo fix; 定義了顯示相關的參數,一般這些參數都是固定不變的。
struct fb_fix_screeninfo {char id[16]; /* identification string eg "TT Builtin" */unsigned long smem_start; /* Start of frame buffer mem 緩存的開始地址*//* (physical address) */__u32 smem_len; /* Length of frame buffer mem 緩沖區內存大小*/__u32 type; /* see FB_TYPE_* 查看FB_TYPE_宏定義 */__u32 type_aux; /* Interleave for interleaved Planes */__u32 visual; /* see FB_VISUAL_* 查看FB_VISUAL_宏定義 */ __u16 xpanstep; /* zero if no hardware panning */__u16 ypanstep; /* zero if no hardware panning */__u16 ywrapstep; /* zero if no hardware ywrap */__u32 line_length; /* length of a line in bytes 一行的字節長度 */unsigned long mmio_start; /* Start of Memory Mapped I/O 內存映射 IO的開始位置 *//* (physical address) */__u32 mmio_len; /* Length of Memory Mapped I/O 內存映射 IO的內存的長度 */__u32 accel; /* Indicate to driver which *//* specific chip/card we have */__u16 capabilities; /* see FB_CAP_* */__u16 reserved[2]; /* Reserved for future compatibility */ };struct fb_var_screeninfo var
struct fb_var_screeninfo {__u32 xres; /* visible resolution 可視區域,一行多少個像素 */__u32 yres; //可視區域 一列多少個像素__u32 xres_virtual; /* virtual resolution 虛擬區域 一行多少個像素*/__u32 yres_virtual; //虛擬區域 一列多少個像素__u32 xoffset; /* offset from virtual to visible 虛擬和可視之間的偏移量*/__u32 yoffset; /* resolution */__u32 bits_per_pixel; /* guess what 每個像素的 bit 數 */__u32 grayscale; /* 0 = color, 1 = grayscale, *//* >1 = FOURCC */struct fb_bitfield red; /* bitfield in fb mem if true color, */struct fb_bitfield green; /* else only length is significant */struct fb_bitfield blue;struct fb_bitfield transp; /* transparency */ __u32 nonstd; /* != 0 Non standard pixel format */__u32 activate; /* see FB_ACTIVATE_* */__u32 height; /* height of picture in mm 內存中的圖像高 */__u32 width; /* width of picture in mm 內存中的圖像寬度 */__u32 accel_flags; /* (OBSOLETE) see fb_info.flags *//* Timing: All values in pixclocks, except pixclock (of course) */__u32 pixclock; /* pixel clock in ps (pico seconds) 像素時鐘*/__u32 left_margin; /* time from sync to picture */__u32 right_margin; /* time from picture to sync */__u32 upper_margin; /* time from sync to picture */__u32 lower_margin;__u32 hsync_len; /* length of horizontal sync */__u32 vsync_len; /* length of vertical sync */__u32 sync; /* see FB_SYNC_* */__u32 vmode; /* see FB_VMODE_* */__u32 rotate; /* angle we rotate counter clockwise */__u32 colorspace; /* colorspace for FOURCC-based modes */__u32 reserved[4]; /* Reserved for future compatibility */ };最后是fb_ops 操作函數
struct fb_ops {/* open/release and usage marking */struct module *owner;int (*fb_open)(struct fb_info *info, int user);//打開int (*fb_release)(struct fb_info *info, int user);//釋放/* For framebuffers with strange non linear layouts or that do not* work with normal memory mapped access*///這兩個函數對于非線性布局的/常規內存映射無法工作的幀緩沖設備需要ssize_t (*fb_read)(struct fb_info *info, char __user *buf,size_t count, loff_t *ppos);ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,size_t count, loff_t *ppos);/* checks var and eventually tweaks it to something supported,* DO NOT MODIFY PAR *///檢測可變參數,并調整到支持的值int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);//設置視頻模式/* set the video mode according to info->var */int (*fb_set_par)(struct fb_info *info);/* set color register *///設置color寄存器的值int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,unsigned blue, unsigned transp, struct fb_info *info);/* set color registers in batch *///批量設置color寄存器,設置顏色表int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);/* blank display *///顯示空白int (*fb_blank)(int blank, struct fb_info *info);/* pan display *///pan 顯示int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);/* Draws a rectangle *///填充矩形void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);/* Copy data from area to another *///數據復制void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);/* Draws a image to the display *///圖形填充void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);/* Draws cursor *///繪制光標int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);/* Rotates the display *///旋轉顯示void (*fb_rotate)(struct fb_info *info, int angle);/* wait for blit idle, optional *///等待blit空閑int (*fb_sync)(struct fb_info *info);/* perform fb specific ioctl (optional) *///fb特定的ioctl操作int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,unsigned long arg);/* Handle 32bit compat ioctl (optional) *///處理32兼容的ioctl操作int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,unsigned long arg);/* perform fb specific mmap *///fb特定的mmap操作int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);/* get capability given var *///通過fb_info獲得framebuffer的能力void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,struct fb_var_screeninfo *var);/* teardown any resources to do with this framebuffer */void (*fb_destroy)(struct fb_info *info);/* called at KDB enter and leave time to prepare the console */int (*fb_debug_enter)(struct fb_info *info);int (*fb_debug_leave)(struct fb_info *info); };把以上結構體實現了,最后在通過“register_framebuffer(info);”注冊到內核即可。
代碼實現
搜索內核代碼發現,Linux 內核已經實現了對ssd1306的驅動,代碼位置:
/driver/staging/fbtft/fb_ssd1306.c
/driver/video/fbdev/ssd1307fb.c
其中fb_ssd1306是基于spi驅動,內核定義了一種新的設備結構fbtft,主要用于spi接口的tftlcd,例如ili9341,ili9320等,
ssd1307fb.c 實現了基于iic 接口驅動,同時支持ssd1306和ssd1307兩種芯片。驅動代碼通過設備樹來判斷到底是ssd1306還是ssd1307.
1,將ssd1307fb編譯到內核。
在內核源碼目錄中執行make menuconfig
Device Drivers
----------->Graphics support
------>Frame buffer Devices
--->Solomon SSD1306 framebuffer support
保存退出
2.修改設備樹
vim arch/arm/boot/dts/imx6ul-14x14-evk.dts
需要注意到是imx6的官方默認已經寫好了lcd的驅動,只不過這個驅動不是我想要的,所以在修改設備樹的時候需要把原來的驅動注釋掉。
同時在設備樹i2c接口中添加ssd1603的硬件定義。
值得注意的是,我使用的液晶屏并沒有reset ,但是源碼調用了這個接口,因此必須定義。修改完成保存退出。
3.編譯
執行:make zImage
將新的內核和設備樹文件燒寫到板子中。
4.問題
液晶屏成功被點量,但是發現顯示有問題,只能顯示半屏,經過分析發現,ssd1307fb.c 在初始化ssd1603時配置寄存器和我用的不一樣,于是修改ssd1307fb.c中的static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)函數。
static重新編譯,燒錄到板子,
成功!
ssd1603作為Linux終端顯示https://www.zhihu.com/video/1226895075344863232后記
之前自己也寫了一版驅動程序,但是和內核自帶的驅動相比差的太遠了,也就不獻丑了。
不過個人認為在學習驅動時應該多動手練習,只有不斷出錯然后查找問題,才能從這個過程當中不斷提高,最后學會驅動開發。
總結
以上是生活随笔為你收集整理的dev layoutview 怎么显示大小_Liunx驱动学习:基于imx6ul 驱动oledssd1306 实现终端显示...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python判断正确错误_第16天:Py
- 下一篇: pythonista3使用说明_pyth