linux 修改分辨率lcd_16.Linux-LCD驱动(详解)
在上一節(jié)
1) 分配一個(gè)fb_info結(jié)構(gòu)體: framebuffer_alloc();
2) 設(shè)置fb_info
3) 設(shè)置硬件相關(guān)的操作
4) 使能LCD,并注冊(cè)fb_info: register_framebuffer()
本節(jié)需要用到的函數(shù):
void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); //分配DMA緩存區(qū)給顯存//返回值為:申請(qǐng)到的DMA緩沖區(qū)的虛擬地址,若為NULL,表示分配失敗,則需要使用dma_free_writecombine()釋放內(nèi)存,避免內(nèi)存泄漏//參數(shù)如下://*dev:指針,這里填0,表示這個(gè)申請(qǐng)的緩沖區(qū)里沒(méi)有內(nèi)容//size:分配的地址大小(字節(jié)單位)//*handle:申請(qǐng)到的物理起始地址//gfp:分配出來(lái)的內(nèi)存參數(shù),標(biāo)志定義在,常用標(biāo)志如下://GFP_ATOMIC 用來(lái)從中斷處理和進(jìn)程上下文之外的其他代碼中分配內(nèi)存. 從不睡眠.//GFP_KERNEL 內(nèi)核內(nèi)存的正常分配. 可能睡眠.//GFP_USER 用來(lái)為用戶(hù)空間頁(yè)來(lái)分配內(nèi)存; 它可能睡眠.
分配一段DMA緩存區(qū),分配出來(lái)的內(nèi)存會(huì)禁止cache緩存(因?yàn)镈MA傳輸不需要CPU)
它和?dma_alloc_coherent?()函數(shù)相似,不過(guò)?dma_alloc_coherent?()函數(shù)是分配出來(lái)的內(nèi)存會(huì)禁止cache緩存以及禁止寫(xiě)入緩沖區(qū)
dma_free_writecombine(dev,size,cpu_addr,handle); //釋放緩存//cpu_addr:虛擬地址,//handle:物理地址
釋放DMA緩沖區(qū), dev和size參數(shù)和上面的一樣
struct fb_info *framebuffer_alloc(size_t size, struct device *dev);//申請(qǐng)一個(gè)fb_info結(jié)構(gòu)體,//size:額外的內(nèi)存,//*dev:指針, 這里填0,表示這個(gè)申請(qǐng)的結(jié)構(gòu)體里沒(méi)有內(nèi)容
int register_framebuffer(struct fb_info *fb_info);//向內(nèi)核中注冊(cè)fb_info結(jié)構(gòu)體,若內(nèi)存不夠,注冊(cè)失敗會(huì)返回負(fù)數(shù)
int unregister_framebuffer(struct fb_info *fb_info) ;//注銷(xiāo)內(nèi)核中fb_info結(jié)構(gòu)體
本節(jié)需要用到的結(jié)構(gòu)體:
fb_info結(jié)構(gòu)體如下:
structfb_info {
... ...struct fb_var_screeninfo var; //可變的參數(shù)
struct fb_fix_screeninfo fix; //固定的參數(shù)... ...struct fb_ops *fbops; //操作函數(shù)... ...char __iomem *screen_base; //顯存虛擬起始地址unsignedlong screen_size; //顯存虛擬地址長(zhǎng)度
void *pseudo_palette;//假的16色調(diào)色板,里面存放了16色的數(shù)據(jù),可以通過(guò)8bpp數(shù)據(jù)來(lái)找到調(diào)色板里面的16色顏色索引值,模擬出16色顏色來(lái),節(jié)省內(nèi)存,不需要的話(huà)就指向一個(gè)不用的數(shù)組即可... ...
};
其中操作函數(shù)fb_info-> fbops 結(jié)構(gòu)體寫(xiě)法如下:
static struct fb_ops s3c_lcdfb_ops ={
.owner=THIS_MODULE,
.fb_setcolreg= my_lcdfb_setcolreg,//設(shè)置調(diào)色板fb_info-> pseudo_palette,自己構(gòu)造該函數(shù)
.fb_fillrect= cfb_fillrect, //填充矩形,用/drivers/video/ cfbfillrect.c里的函數(shù)即可
.fb_copyarea= cfb_copyarea, //復(fù)制數(shù)據(jù), 用/drivers/video/cfbcopyarea.c里的函數(shù)即可
.fb_imageblit= cfb_imageblit, //繪畫(huà)圖形, 用/drivers/video/imageblit.c里的函數(shù)即可};
固定的參數(shù)fb_info-> fix 結(jié)構(gòu)體如下:
structfb_fix_screeninfo {char id[16]; //id名字unsignedlong smem_start; //framebuffer物理起始地址__u32 smem_len;//framebuffer長(zhǎng)度,字節(jié)為單位__u32 type;//lcd類(lèi)型,默認(rèn)值0即可__u32 type_aux;//附加類(lèi)型,為0__u32 visual;//畫(huà)面設(shè)置,常用參數(shù)如下//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;/*如果沒(méi)有硬件panning就賦值為0*/__u16 ypanstep;/*如果沒(méi)有硬件panning就賦值為0*/__u16 ywrapstep;/*如果沒(méi)有硬件ywrap就賦值為0*/__u32 line_length;/*一行的字節(jié)數(shù) ,例:(RGB565)240*320,那么這里就等于240*16/8*//*以下成員都可以不需要*/
unsignedlong mmio_start; /*內(nèi)存映射IO的起始地址,用于應(yīng)用層直接訪(fǎng)問(wèn)寄存器,可以不需要*/__u32 mmio_len;/*內(nèi)存映射IO的長(zhǎng)度,可以不需要*/__u32 accel;
__u16 reserved[3];
};
可變的參數(shù)fb_info-> var 結(jié)構(gòu)體如下:
structfb_var_screeninfo{
__u32xres;/*可見(jiàn)屏幕一行有多少個(gè)像素點(diǎn)*/__u32 yres;/*可見(jiàn)屏幕一列有多少個(gè)像素點(diǎn)*/__u32 xres_virtual;/*虛擬屏幕一行有多少個(gè)像素點(diǎn)*/__u32 yres_virtual;/*虛擬屏幕一列有多少個(gè)像素點(diǎn)*/__u32 xoffset;/*虛擬到可見(jiàn)屏幕之間的行偏移,若可見(jiàn)和虛擬的分辨率一樣,就直接設(shè)為0*/__u32 yoffset;/*虛擬到可見(jiàn)屏幕之間的列偏移*/__u32 bits_per_pixel;/*每個(gè)像素的位數(shù)即BPP,比如:RGB565則填入16*/__u32 grayscale;/*非0時(shí),指的是灰度,真彩直接填0即可*/
struct fb_bitfield red; //fb緩存的R位域, fb_bitfield結(jié)構(gòu)體成員如下://__u32 offset; 區(qū)域偏移值,比如RGB565中的R,就在第11位//__u32 length; 區(qū)域長(zhǎng)度,比如RGB565的R,共有5位//__u32 msb_right; msb_right ==0,表示數(shù)據(jù)左邊最大, msb_right!=0,表示數(shù)據(jù)右邊最大
struct fb_bitfield green; /*fb緩存的G位域*/
struct fb_bitfield blue; /*fb緩存的B位域*/ /*以下參數(shù)都可以不填,默認(rèn)為0*/
struct fb_bitfield transp; /*透明度,不需要填0即可*/__u32nonstd;/*!= 0表示非標(biāo)準(zhǔn)像素格式*/__u32 activate;/*設(shè)為0即可*/__u32height;/*外設(shè)高度(單位mm),一般不需要填*/__u32width;/*外設(shè)寬度(單位mm),一般不需要填*/__u32 accel_flags;/*過(guò)時(shí)的參數(shù),不需要填*/
/*除了pixclock本身外,其他的都以像素時(shí)鐘為 單位*/__u32pixclock;/*像素時(shí)鐘(皮秒)*/__u32 left_margin;/*行切換,從同步到繪圖之間的延遲*/__u32right_margin;/*行切換,從繪圖到同步之間的延遲*/__u32upper_margin;/*幀切換,從同步到繪圖之間的延遲*/__u32lower_margin;/*幀切換,從繪圖到同步之間的延遲*/__u32hsync_len;/*水平同步的長(zhǎng)度*/__u32 vsync_len;/*垂直同步的長(zhǎng)度*/__u32 sync;
__u32 vmode;
__u32 rotate;
__u32reserved[5]; /*保留*/}
1.寫(xiě)驅(qū)動(dòng)程序:
(驅(qū)動(dòng)設(shè)置:參考自帶的LCD平臺(tái)驅(qū)動(dòng)drivers/video/s3c2410fb.c )
1.1 步驟如下:
在驅(qū)動(dòng)init入口函數(shù)中:
1)分配一個(gè)fb_info結(jié)構(gòu)體
2)設(shè)置fb_info
2.1)設(shè)置固定的參數(shù)fb_info-> fix
2.2) 設(shè)置可變的參數(shù)fb_info-> var
2.3) 設(shè)置操作函數(shù)fb_info-> fbops
2.4) 設(shè)置fb_info 其它的成員
3)設(shè)置硬件相關(guān)的操作
3.1)配置LCD引腳
3.2)根據(jù)LCD手冊(cè)設(shè)置LCD控制器
3.3)分配顯存(framebuffer),把地址告訴LCD控制器和fb_info
4)開(kāi)啟LCD,并注冊(cè)fb_info: register_framebuffer()
4.1) 直接在init函數(shù)中開(kāi)啟LCD(后面講到電源管理,再來(lái)優(yōu)化)
控制LCDCON5允許PWREN信號(hào),
然后控制LCDCON1輸出PWREN信號(hào),
輸出GPB0高電平來(lái)開(kāi)背光,
4.2) 注冊(cè)fb_info
在驅(qū)動(dòng)exit出口函數(shù)中:
1)卸載內(nèi)核中的fb_info
2) 控制LCDCON1關(guān)閉PWREN信號(hào),關(guān)背光,iounmap注銷(xiāo)地址
3)釋放DMA緩存地址dma_free_writecombine()
4)釋放注冊(cè)的fb_info
1.2 具體代碼如下:
#include #include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include
/*LCD : 480*272*/
#define LCD_xres 480 //LCD 行分辨率
#define LCD_yres 272 //LCD列分辨率
/*GPIO prot*/
static unsigned long *GPBcon;static unsigned long *GPCcon;static unsigned long *GPDcon;static unsigned long *GPGcon; //GPG4:控制LCD信號(hào)
static unsigned long *GPBdat; //GPB0: 控制背光
/*LCD control*/
structlcd_reg{
unsignedlonglcdcon1;
unsignedlonglcdcon2;
unsignedlonglcdcon3;
unsignedlonglcdcon4;
unsignedlonglcdcon5;
unsignedlonglcdsaddr1;
unsignedlonglcdsaddr2;
unsignedlonglcdsaddr3 ;
unsignedlongredlut;
unsignedlonggreenlut;
unsignedlongbluelut;
unsignedlong reserved[9];
unsignedlongdithmode;
unsignedlongtpal ;
unsignedlonglcdintpnd;
unsignedlonglcdsrcpnd;
unsignedlonglcdintmsk;
unsignedlongtconsel;
};static struct lcd_reg *lcd_reg;static struct fb_info *my_lcd; //定義一個(gè)全局變量
static u32 pseudo_palette[16]; //調(diào)色板數(shù)組,被fb_info->pseudo_palette調(diào)用
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{/*內(nèi)核中的單色都是16位,默認(rèn)從左到右排列,比如G顏色[0x1f],那么chan就等于0XF800*/chan&= 0xffff;
chan>>= 16 - bf->length; //右移,將數(shù)據(jù)靠到位0上
return chan << bf->offset; //左移一定偏移值,放入16色數(shù)據(jù)中對(duì)應(yīng)的位置}static int my_lcdfb_setcolreg(unsigned int regno, unsigned int red,unsigned int green, unsigned int blue,unsigned int transp, struct fb_info *info) //設(shè)置調(diào)色板函數(shù),供內(nèi)核調(diào)用{
unsignedintval;if (regno >=16) //調(diào)色板數(shù)組不能大于15
return 1;/*用red,green,blue三個(gè)顏色值構(gòu)造出16色數(shù)據(jù)val*/val= chan_to_field(red, &info->var.red);
val|= chan_to_field(green, &info->var.green);
val|= chan_to_field(blue, &info->var.blue);
((u32*)(info->pseudo_palette))[regno] = val; //放到調(diào)色板數(shù)組中
return 0;
}static struct fb_ops my_lcdfb_ops ={
.owner=THIS_MODULE,
.fb_setcolreg= my_lcdfb_setcolreg,//調(diào)用my_lcdfb_setcolreg()函數(shù),來(lái)設(shè)置調(diào)色板fb_info-> pseudo_palette.fb_fillrect= cfb_fillrect, //填充矩形.fb_copyarea= cfb_copyarea, //復(fù)制數(shù)據(jù).fb_imageblit= cfb_imageblit, //繪畫(huà)圖形,};static int lcd_init(void)
{/*1.申請(qǐng)一個(gè)fb_info結(jié)構(gòu)體*/my_lcd= framebuffer_alloc(0,0);/*2.設(shè)置fb_info*/
/*2.1設(shè)置固定的參數(shù)fb_info-> fix*/
/*my_lcd->fix.smem_start 物理地址后面注冊(cè)MDA緩存區(qū)設(shè)置*/strcpy(my_lcd->fix.id, "mylcd"); //名字my_lcd->fix.smem_len =LCD_xres*LCD_yres*2; //地址長(zhǎng)my_lcd->fix.type =FB_TYPE_PACKED_PIXELS;
my_lcd->fix.visual =FB_VISUAL_TRUECOLOR; //真彩色my_lcd->fix.line_length =LCD_xres*2; //LCD 一行的字節(jié)
/*2.2 設(shè)置可變的參數(shù)fb_info-> var*/my_lcd->var.xres =LCD_xres; //可見(jiàn)屏X 分辨率my_lcd->var.yres =LCD_yres; //可見(jiàn)屏y 分辨率my_lcd->var.xres_virtual =LCD_xres; //虛擬屏x分辨率my_lcd->var.yres_virtual =LCD_yres; //虛擬屏y分辨率my_lcd->var.xoffset = 0; //虛擬到可見(jiàn)屏幕之間的行偏移my_lcd->var.yoffset =0; //虛擬到可見(jiàn)屏幕之間的行偏移
my_lcd->var.bits_per_pixel=16; //像素為16BPPmy_lcd->var.grayscale = 0; //灰色比例my_lcd->var.red.offset = 11;
my_lcd->var.red.length = 5;
my_lcd->var.green.offset = 5;
my_lcd->var.green.length = 6;
my_lcd->var.blue.offset = 0;
my_lcd->var.blue.length = 5;/*2.3 設(shè)置操作函數(shù)fb_info-> fbops*/my_lcd->fbops = &my_lcdfb_ops;/*2.4 設(shè)置fb_info 其它的成員*/
/*my_lcd->screen_base 虛擬地址在后面注冊(cè)MDA緩存區(qū)設(shè)置*/my_lcd->pseudo_palette =pseudo_palette; //保存調(diào)色板數(shù)組my_lcd->screen_size =LCD_xres * LCD_yres *2; //虛擬地址長(zhǎng)
/*3 設(shè)置硬件相關(guān)的操作*/
/*3.1 配置LCD引腳*/GPBcon= ioremap(0x56000010, 8);
GPBdat= GPBcon+1;
GPCcon= ioremap(0x56000020, 4);
GPDcon= ioremap(0x56000030, 4);
GPGcon= ioremap(0x56000060, 4);*GPBcon &=~(0x03<
*GPBdat &=~(0X1<<0); //關(guān)背光
*GPCcon =0xaaaaaaaa;*GPDcon =0xaaaaaaaa;*GPGcon |=(0x03<
/*3.2 根據(jù)LCD手冊(cè)設(shè)置LCD控制器,參考之前的裸機(jī)驅(qū)動(dòng)*/lcd_reg=ioremap(0X4D000000, sizeof( lcd_reg) );/*HCLK:100Mhz*/lcd_reg->lcdcon1 = (4<<8) | (0X3<<5) | (0x0C<<1) ;
lcd_reg->lcdcon2 = ((3)<<24) | (271<<14) | ((1)<<6) |((0)<<0);
lcd_reg->lcdcon3 = ((16)<<19) | (479<<8) | ((10));
lcd_reg->lcdcon4 = (4);
lcd_reg->lcdcon5 = (1<<11) | (1<<9) | (1<<8) |(1<<0);
lcd_reg->lcdcon1 &=~(1<<0); //關(guān)閉PWREN信號(hào)輸出lcd_reg->lcdcon5 &=~(1<<3); //禁止PWREN信號(hào)
/*3.3 分配顯存(framebuffer),把地址告訴LCD控制器和fb_info*/my_lcd->screen_base=dma_alloc_writecombine(0,my_lcd->fix.smem_len, &my_lcd->fix.smem_start, GFP_KERNEL);/*lcd控制器的地址必須是物理地址*/lcd_reg->lcdsaddr1 =(my_lcd->fix.smem_start>>1)&0X3FFFFFFF;//保存緩沖起始地址A[30:1]lcd_reg->lcdsaddr2 =((my_lcd->fix.smem_start+my_lcd->screen_size)>>1)&0X1FFFFF; //保存存緩沖結(jié)束地址A[21:1]lcd_reg->lcdsaddr3 =LCD_xres& 0x3ff;//OFFSIZE[21:11]:保存LCD上一行結(jié)尾和下一行開(kāi)頭的地址之間的差//PAGEWIDTH [10:0]:保存LCD一行占的寬度(半字?jǐn)?shù)為單位)
/*4開(kāi)啟LCD,并注冊(cè)fb_info: register_framebuffer()*/
/*4.1 直接在init函數(shù)中開(kāi)啟LCD(后面講到電源管理,再來(lái)優(yōu)化)*/lcd_reg->lcdcon1 |=1<<0; //輸出PWREN信號(hào)lcd_reg->lcdcon5 |=1<<3; //允許PWREN信號(hào)
*GPBdat |=(0X1<<0); //開(kāi)背光
/*4.2 注冊(cè)fb_info*/register_framebuffer(my_lcd);return 0;
}static int lcd_exit(void)
{/*1卸載內(nèi)核中的fb_info*/unregister_framebuffer(my_lcd);/*2 控制LCDCON1關(guān)閉PWREN信號(hào),關(guān)背光,iounmap注銷(xiāo)地址*/lcd_reg->lcdcon1 &=~(1<<0); //關(guān)閉PWREN信號(hào)輸出lcd_reg->lcdcon5 &=~(1<<3); //禁止PWREN信號(hào)
*GPBdat &=~(0X1<<4); //關(guān)背光iounmap(GPBcon);
iounmap(GPCcon);
iounmap(GPDcon);
iounmap(GPGcon);/*3.釋放DMA緩存地址dma_free_writecombine()*/dma_free_writecombine(0,my_lcd->screen_size,my_lcd->screen_base,my_lcd->fix.smem_start);/*4.釋放注冊(cè)的fb_info*/framebuffer_release(my_lcd);return 0;
}
module_init(lcd_init);
module_exit(lcd_exit);
MODULE_LICENSE("GPL");
2.重新編譯內(nèi)核,去掉默認(rèn)的LCD
make menuconfig ,進(jìn)入menu菜單重新設(shè)置內(nèi)核參數(shù):
進(jìn)入Device Drivers->Graphics support: S3C2410 LCD framebuffer support //將自帶的LCD驅(qū)動(dòng)設(shè)為模塊, 不編進(jìn)內(nèi)核中
然后make uImage 編譯內(nèi)核
make modules 編譯模塊
為什么要編譯模塊?
因?yàn)長(zhǎng)CD驅(qū)動(dòng)相關(guān)的文件也沒(méi)有編進(jìn)內(nèi)核,而fb_ops里的成員fb_fillrect(), fb_copyarea(), fb_imageblit()用的都是drivers/video下面的3個(gè)文件,所以需要這3個(gè)的.ko模塊,如下圖所示:
3.掛載驅(qū)動(dòng)
將編譯好的LCD驅(qū)動(dòng)模塊 和drivers/video里的3個(gè).ko模塊 放入nfs文件系統(tǒng)目錄中
然后燒寫(xiě)內(nèi)核, 先裝載3個(gè)/drivers/video下編譯好的模塊,再來(lái)裝載LCD驅(qū)動(dòng)模塊
掛載LCD驅(qū)動(dòng)后, 如下圖,可以通過(guò)?ls -l /dev/fb*???命令查看已掛載的LCD設(shè)備節(jié)點(diǎn):
4.測(cè)試運(yùn)行
測(cè)試有兩種:
echo hello> /dev/tty1 ? ??// LCD上便顯示hello字段
cat Makefile>/dev/tty1 ? ?// LCD上便顯示Makeflie文件的內(nèi)容
4.1使用上節(jié)的鍵盤(pán)驅(qū)動(dòng)在LCD終端打印命令行
vi /etc/inittab //修改inittab, inittab:配置文件,用于啟動(dòng)init進(jìn)程時(shí),讀取inittab
添加->tty1::askfirst:-/bin/sh //將sh進(jìn)程(命令行)輸出到tty1里,也就是使LCD輸出信息
然后重啟,insmod裝載3個(gè)/drivers/video下編譯好的模塊,再來(lái)insmod裝載LCD驅(qū)動(dòng)模塊,tty1設(shè)備便有了,就能看到提示信息:
如下圖,我們insmod上一節(jié)的鍵盤(pán)驅(qū)動(dòng)后,按下enter鍵,便能在LCD終端上操作linux了
從上圖可以看到按下enter鍵,它就啟動(dòng)了一個(gè)進(jìn)程號(hào)772的-sh進(jìn)程,如下圖發(fā)現(xiàn)這個(gè)-sh的描述符都指向了tty1:
下章學(xué)習(xí):
總結(jié)
以上是生活随笔為你收集整理的linux 修改分辨率lcd_16.Linux-LCD驱动(详解)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 央行贷款基准利率
- 下一篇: linux安装mysql5.7.18_L