1.Linux幀緩沖子系統
幀緩沖(FrameBuffer)是Linux為顯示設備提供的一個接口,用戶可以將幀緩沖看成是顯示內存的一種映像,將其映射到進程地址空間之后,就可以直接進行讀寫操作,而寫操作可以立即反映到屏幕上,這種操作是抽象和統一的,用戶不必關心顯存的位置、換頁機制等具體細節,這些都是由FrameBuffer設備驅動來實現,幀緩沖把顯示設備描述成一個緩沖區,允許應用程序通過幀緩沖定義好的接口訪問這些圖形設備,從而不用關心具體的硬件細節。個人感覺,更抽象一點,幀緩沖從本質上是圖形設備的硬件抽象,對于我們開發者而言,幀緩沖是一種顯示緩存,向顯示緩存寫入特定格式的數據就意味著向屏幕輸出內容,通過不斷向幀緩存中寫入數據,顯示控制器會自動從幀緩沖中取數據并顯示出來。FrameBuffer的設備文件一般是dev/fb0、dev/fb1等,最多支持32個設備,FrameBuffer是個字符設備,主設備號是29,對應于/dev/fb%d設備文件,對于我們驅動工程師而言,FrameBuffer設備和其他的文件沒有區別,可以通過配置對FrameBuffer設備文件完成對硬件的參數設置,Framebuffer對應的源文件在linux/drivers/video/目錄下。總的抽象設備文件為fbcon.c,在這個目錄下還有與各種顯卡驅動相關的源文件。
在應用程序中,一般通過將 FrameBuffer 設備映射到進程地址空間的方式使用,比如下面的程序就打開 /dev/fb0 設備,并通過 mmap 系統調用進行地址映射,隨后用 memset 將屏幕清空(這里假設顯示模式是 1024x768-8 位色模式,線性內存模式):
int fb;
unsigned char* fb_mem;
fb = open ('/dev/fb0', O_RDWR);
fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
memset (fb_mem, 0, 1024*768); //這個命令應該只有在root可以執行
Framebuffer驅動實現:
一般來說,應用程序通過內核對Framebuffer的控制,主要有以下3種方式:
1,讀/寫 /dev/fb相當于讀/寫屏幕緩沖區;
2,通過映射操作,可將屏幕緩沖區的物理地址映射到用戶空間的一段虛擬地址中,之后用戶就可以通過讀寫這段虛擬地址訪問屏幕緩沖區,在屏幕上繪圖;
3,I/O控制對于幀緩沖設備,設備文件的ioctl()函數可讀取/設置顯示設備及屏幕的參數,如分辨率、顯示顏色數、屏幕大小等,ioctl()函數由底層的驅動程序完成;
Linux幀緩沖子系統的層次結構圖如下所示,由幀緩沖設備層和控制器驅動組成,幀緩沖設備層在drivers/video/fbmem.c中實現,向上給應用程序提供設備文件結構操作接口,向下提供硬件操作接口,硬件操作接口需要根據具體的LCD控制器硬件來實現,這也是控制器驅動要完成的工作,對比IIC和SPI的軟件層次結構,相對較為簡單,幀緩沖驅動程序主要依靠四個數據結構,分別是fb_info、fb_var_screeninfo、fb_fix_screeninfo和fb_monospecs,后3個數據結構可以在用戶空間訪問,數據結構fb_info只能在內核空間訪問。
2.LCD工作時序分析:
(1)顯示指針從矩形左上角的第一行第一個點開始,一個點一個點的在LCD上顯示,在上面的時序圖上用時間線表示就為VCLK,我們稱之為像素時鐘信號;
(2) 當顯示指針一直顯示到矩形的右邊就結束這一行,那么這一行的動作在上面的時序圖中就稱之為1 Line;
(3)接下來顯示指針又回到矩形的左邊從第二行開始顯示,注意,顯示指針在從第一行的右邊回到第二行的左邊是需要一定的時間的,我們稱之為行切換;
(4)如此類推,顯示指針就這樣一行一行的顯示至矩形的右下角才把一副圖顯示完成。因此,這一行一行的顯示在時間線上看,就是時序圖上的HSYNC;
(5)然而,LCD的顯示并不是對一副圖像快速的顯示一下,為了持續和穩定的在LCD上顯示,就需要切換到另一幅圖上(另一幅圖可以和上一副圖一樣或者不一樣,目的只是為了將圖像持續的顯示在LCD上)。那么這一副一副的圖像就稱之為幀,在時序圖上就表示為1 Frame,因此從時序圖上可以看出1 Line只是1 Frame中的一行;
(6)同樣的,在幀與幀切換之間也是需要一定的時間的,我們稱之為幀切換,那么LCD整個顯示的過程在時間線上看,就可表示為時序圖上的VSYNC。
參照下圖:VSYNC/VFRAME/STV:垂直同步信號(TFT)/幀同步信號(STN)/SEC TFT信號; HSYNC/VLINE/CPV:水平同步信號(TFT)/行同步脈沖信號(STN)/SEC TFT信號; VCLK/LCD_HCLK:象素時鐘信號(TFT/STN)/SEC 參照TFT信號; VD[23:0]:LCD像素數據輸出端口(TFT/STN/SEC TFT); VDEN/VM/TP:數據使能信號(TFT)/LCD驅動交流偏置信號(STN)/SEC TFT 信號; LEND/STH:行結束信號(TFT)/SEC TFT信號; LCD_LPCOE:SEC TFT OE信號; LCD_LPCREV:SEC TFT REV信號; LCD_LPCREVB:SEC TFT REVB信號;
上面時序圖中上各時鐘延時參數的含義如下:(這些參數的值,LCD產生廠商會提供相應的數據手冊):
VBPD(vertical back porch):表示在一幀圖像開始時,垂直同步信號以后的無效的行數,對應驅動中的upper_margin;
VFBD(vertical front porch):表示在一幀圖像結束后,垂直同步信號以前的無效的行數,對應驅動中的lower_margin;
VSPW(vertical sync pulse width):表示垂直同步脈沖的寬度,用行數計算,對應驅動中的vsync_len;
HBPD(horizontal back porch):表示從水平同步信號開始到一行的有效數據開始之間的VCLK的個數,對應驅動中的left_margin;
HFPD(horizontal front porth):表示一行的有效數據結束到下一個水平同步信號開始之間的VCLK的個數,對應驅動中的right_margin;
HSPW(horizontal sync pulse width):表示水平同步信號的寬度,用VCLK計算,對應驅動中的hsync_len;
注意以下細節:(1)VSYNC信號有效時,表示一幀數據的開始
(2)VSPW表示VSYNC信號的脈沖寬度為(VSPW+1)個HSYNC信號周期,即(VSPW+1)行,這(VSPW+1)行的數據無效。
(3)VSYNC信號脈沖之后,還要經過(VBPD+1)個HSYNC信號周期,有效的行數據才出現。所以,在VSYNC信號有效后要經過(VSPW+1+VBPD+1)個無效的行,第一個有效行才出現,對應上邊框。
(4)隨后即連續發出(LINEVAL+1)行的有效數據。
(5)最后是(VFPD+1)個無效的行,它對應下邊框,完整的一幀結束,緊接著就是下一幀數據了。
下面我們深入到一行中像素數據的傳輸過程,它與上面行數據的傳輸相似:
(1)HSYNC信號有效時,表示一行數據的開始
(2)HSPW表示HSYNC信號的脈沖寬度為(HSPW+1)個VCLK信號周期,即(HSPW+1)個像素,這(HSPW+1)個像素的數據無效。
(3)HSYNC信號脈沖之后,還要經過(HBPD+1)個VCLK信號周期,有效的像素數據才出現。所以,在HSYNC有效之后,總共要經過(HSPW+1+HBPD+1)個無效的像素,它對應左邊框,第一個有效的像素才出現。
(4)隨后即連續發出(HOZVAL+1)個像素的有效數據。
(5)最后是(HFPD+1)個無效的像素,它對應右邊框,完整的一行結束
3.s3c2440和Exynos4412硬件資源分析
s3c2440 LCD驅動采用Platform設備驅動模型實現,內核自帶的LCD驅動模型代碼路徑是drivers/vide0/s3c2410fb.c,Exynos 4412的驅動代碼里,framebuffer主要代碼在driver/video/,文件名是s3c-fb.c Exynos 4412顯示控制器可以控制0~5個windows,代碼中分給它們分別編號win0, win1,win2......,這里一個window就對應一個獨立的驅動控制個體, 每個framebuffer有自己的一個FBI(fb_info)結構,顯示控制器對應的抽象結構是s3c_fb結構體,window對應的抽象結構是s3c_fb_win結構體。s3c2440內部LCD控制器結構圖如下,根據數據手冊:
1、LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器組成;
2、REGBANK由17個可編程的寄存器組和一塊256*16的調色板內存組成,它們用來配置LCD控制器的;
3、LCDCDMA是一個專用的DMA,它能自動地把在偵內存中的視頻數據傳送到LCD驅動器,通過使用這個DMA通道,視頻數據在不需要CPU的干預的情況下顯示在LCD屏上;
4、VIDPRCS接收來自LCDCDMA的數據,將數據轉換為合適的數據格式,比如說4/8位單掃,4位雙掃顯示模式,然后通過數據端口VD[23:0]傳送視頻數據到LCD驅動器;
5、TIMEGEN由可編程的邏輯組成,他生成LCD驅動器需要的控制信號,比如VSYNC、HSYNC、VCLK和LEND等等,而這些控制信號又與REGBANK寄存器組中的LCDCON1/2/3/4/5的配置密切相關,通過不同的配置,TIMEGEN就能產生這些信 號的不同形態,從而支持不同的LCD驅動器(即不同的STN/TFT屏)。
Exynos4412內部集成了一個FIMD(Fully Interactive Mobile Display),在FS4412開發板上使用的是rgb接口連接外部的LCD屏,相關的電路原理圖如下,
3.幀緩沖子系統中數據結構分析
Fb_info:該結構體重要是用來描述幀緩沖設備的屬性和操作的完整描述,包括了設備的設置參數,狀態以及操作函數指針,每個緩沖設備都必須對應一個fb_info
/* struct fb_info 結構體 */
struct fb_info {
int node;
int flags;
struct mutex lock; /* 用于 open/release/ioctl的鎖 */
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; /* 顯示器標準 */
struct work_struct queue; /* Framebuffer event queue 幀緩沖事件隊列 */
struct fb_pixmap pixmap; /* Image hardware mapper 圖像硬件mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper 光標硬件mapper */
struct fb_cmap cmap; /* Current cmap 目前顏色表 */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode 目前video模式 */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device 對應的背光設備 */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve 背光調整 */
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;
struct fb_deferred_io *fbdefio;
#endif
struct fb_ops *fbops; /* 幀緩沖操作 */
struct device *device; /* This is the parent 父設備 */
struct device *dev; /* This is this fb device fb設備 */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __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 1
u32 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 similiar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap */
resource_size_t aperture_base;
resource_size_t aperture_size;
};
Fb_ops:該結構體是fb_info中的成員變量,主要是用來為指向底層操作的函數的指針,fb_ops結構體中的成員函數fb_check_var是用來檢查可以修改的屏幕參數并調整到最合適的值;成員函數fb_set_par是用來使得用戶設置的屏幕參數可以在硬件上生效。
/* 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);
/* 對于非線性布局的/常規內存映射無法工作的幀緩沖設備*/
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);
/* 調整可變參數,并調整到支持的值 */
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
/* 根據info->var設置video模式 */
int (*fb_set_par)(struct fb_info *info);
/* set color register */
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,unsigned blue, unsigned transp, struct fb_info *info);
/* 批量設置color寄存器,設置顏色表 */
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
/* 顯示空白 */
int (*fb_blank)(int blank, struct fb_info *info);
/* pan display */
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
/* 矩形填充 */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
/* 數據復制 */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
/* 圖形填充 */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
/* 繪制光標 */
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
/* 旋轉顯示 */
void (*fb_rotate)(struct fb_info *info, int angle);
/* 等待blit空閑(可選) */
int (*fb_sync)(struct fb_info *info);
/* fb特定的ioctl(可選) */
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,unsigned long arg);
/* 處理32位的compat ioctl(可選) */
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,unsigned long arg);
/* fb特定的mmap */
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
/* get capability given var */
上一篇:SPI在linux3.14.78 FS_S5PC100(Cortex A8)和S3C2440上驅動移植(deep dive)
下一篇:基于S3C2440的linux-3.6.6移植——LED驅動
- 熱門資源推薦
- 熱門放大器推薦
設計資源 培訓 開發板 精華推薦
- 使用 Analog Devices 的 LTC1728HS5-5 的參考設計
- 用于手機的 5-LED 通用 LED 驅動器
- 測功率芯片HLW8032設計
- 使用 Infineon Technologies AG 的 IRU3038 的參考設計
- 使用 Microchip Technology 的 TC18C47MJE 的參考設計
- LTC3204BEDC-5 演示板、低噪聲穩壓、電荷泵
- DC905A、LT3491ESC8 演示板固定頻率升壓電流模式 DC-DC 轉換器
- 有源鉗位正激DC-DC電源基礎仿真電路
- LTC1655CS8 寬擺幅、雙極性輸出 16 位軌至軌微功率 DAC 的典型應用
- MIC2097-1YMT限流配電開關典型應用