Linux開發十五
lcd驅動
象棋小子 1048272975
lcd能夠支持彩色圖像的顯示和視頻的播放,是一種很重要的輸出設備,在一些嵌入式人機交互系統中,也往往需要lcd進行顯示。Linux內核已經支持了s3c2416的lcd控制器。
1. lcd設備
lcd設備包含了名字、獨有的資源等等一些驅動程序的硬件或自定義信息。通過platform_add_devices(platform_device_register)函數將定義的平臺設備註冊到內核中,用於匹配設備驅動。
內核在drivers\video\fbdev\s3c-fb.c中實現了s3c2416 lcd驅動,lcd設備平臺代碼如下。
static struct s3c_fb_pd_winhome2416_fb_win[] = {
[0]= {
.default_bpp = 16,
.max_bpp = 32,
.xres = 800,
.yres = 480,
},
};
static struct fb_videomodehome2416_lcd_timing = {
.pixclock = 41094,
.left_margin = 19,
.right_margin = 37,
.upper_margin = 10,
.lower_margin = 26,
.hsync_len = 27,
.vsync_len = 13,
.xres = 800,
.yres = 480,
};
static voids3c2416_fb_gpio_setup_24bpp(void)
{
unsignedint gpio;
for(gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) {
s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);
}
for(gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) {
s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);
}
for(gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) {
s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(2));
s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);
}
}
static struct s3c_fb_platdatahome2416_fb_platdata = {
.win[0] = &home2416_fb_win[0],
.vtiming = &home2416_lcd_timing,
.setup_gpio = s3c2416_fb_gpio_setup_24bpp,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
};
static struct resource s3c_fb_resource[]= {
[0]= DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
[1]= DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
[2]= DEFINE_RES_IRQ(IRQ_LCD_FIFO),
[3]= DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
};
struct platform_device s3c_device_fb = {
.name = "s3c-fb",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_fb_resource),
.resource = s3c_fb_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
void __init s3c_fb_set_platdata(structs3c_fb_platdata *pd)
{
s3c_set_platdata(pd,sizeof(struct s3c_fb_platdata),
&s3c_device_fb);
}
在板級初始化函數home2416_machine_init()中加入lcd平臺數據s3c_fb_set_platdata(&home2416_fb_platdata),在static struct platform_device *home2416_devices[]板級平臺設備列表中加入&s3c_device_fb,使lcd設備能夠註冊到內核中。
內核在drivers\video\backlight\ pwm_bl.c中實現了基於pwm方式的lcd背光驅動,背光設備平臺代碼如下。
static int s3c2416_backlight_init(structdevice *dev)
{
gpio_request(S3C2410_GPB(0),"Backlight");
gpio_direction_output(S3C2410_GPB(0),0);
s3c_gpio_setpull(S3C2410_GPB(0),S3C_GPIO_PULL_NONE);
s3c_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPB0_TOUT0);
return0;
}
static ints3c2416_backlight_notify(struct device *dev, int brightness)
{
if(!brightness) {
gpio_direction_output(S3C2410_GPB(0),0);
}else {
gpio_direction_output(S3C2410_GPB(0),0);
s3c_gpio_setpull(S3C2410_GPB(0),S3C_GPIO_PULL_NONE);
s3c_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPB0_TOUT0);
}
returnbrightness;
}
static voids3c2416_backlight_exit(struct device *dev)
{
gpio_direction_output(S3C2410_GPB(0),0);
}
static structplatform_pwm_backlight_data backlight_data = {
.max_brightness= 100,
.dft_brightness= 50,
.enable_gpio = -1,
.init = s3c2416_backlight_init,
.notify = s3c2416_backlight_notify,
.exit = s3c2416_backlight_exit,
};
static struct platform_devices3c2416_backlight = {
.name= "pwm-backlight",
.dev = {
.parent= &samsung_device_pwm.dev,
.platform_data= &backlight_data,
},
.id = -1,
};
static struct pwm_lookups3c2416_pwm_lookup[] = {
PWM_LOOKUP("samsung-pwm",0, "pwm-backlight", NULL, 36296,
PWM_POLARITY_NORMAL),
};
在板級初始化函數home2416_machine_init ()中把pwm背光映射到pwm設備表中pwm_add_table(s3c2416_pwm_lookup, ARRAY_SIZE(s3c2416_pwm_lookup)),在static struct platform_device *home2416_devices[]板級平臺設備列表中加入&s3c2416_backlight,使背光設備能夠註冊到內核中。
修改drivers\tty\vt\vt.c,禁止lcd開機一段時間後自動關屏。
static int blankinterval = 0;
修改drivers/video/console/fbcon.c,禁止光標閃爍。
static int fbcon_cursor_noblink = 1;
2. 內核配置
Linux配置支持lcd設備驅動,選中Device Drivers->Graphics support->Framebuffer Devices->Samsumg S3C framebuffer support 。
Linux配置支持lcd背光驅動,選中DeviceDrivers->Graphics support->Backlight & LCD device support->GenericPWM based Backlight Driver。
Linux配置開機logo,DeviceDrivers->Graphics support->Bootup logo->Standard 224-color Linux logo。
3. lcd測試
cat /proc/devices可以知道lcd主設備號爲29,次設備號爲0,在/dev目錄中創建fb0設備文件。
mknod /dev/fb0 c 29 0
lcd顯示黑屏。
mknod /dev/zero c 1 5
dd if=/dev/zero of=/dev/fb0
4. 應用編程
應用程序可以通過設備文件訪問lcd,lcd純色顯示應用測試代碼lcd_test.c如下。
#include "fcntl.h"
#include "unistd.h"
#include "stdio.h"
#include "stdlib.h"
#include "sys/mman.h"
void screen_clear(unsigned short*ppixel, unsigned short color)
{
inti;
for(i=0; i<800*480; i++)
ppixel[i]= color;
}
int main(void)
{
unsignedshort colors[] = {0xffff, 0x0000, 0xf800,
0x07e0,0x001f, 0xffe0, 0xf81f, 0x7ff};
intscreen_size;
intfd;
intindex;
unsignedshort *ppixel;
fd= open("/dev/fb0", O_RDWR);
if(fd == -1) {
printf("Openframebuffer failed\n");
exit(1);
}
screen_size= 800*480*2;
ppixel=(unsigned short *)mmap(0, screen_size,
PROT_READ|PROT_WRITE,MAP_SHARED, fd,0);
if(ppixel == (unsigned short *)-1) {
printf("Mapframebuffer failed\n");
exit(1);
}
while(1) {
screen_clear(ppixel,colors[index]);
index++;
if(index >= sizeof(colors)/sizeof(colors[0]))
index= 0;
sleep(2);
}
umap(ppixel,screen_size);
close(fd);
return0;
}
用arm-linux-gcc靜態編譯,使之生成arm cpu可執行的指令,並且可脫離任何庫獨立運行,arm-linux-gcc -static -o lcd_test lcd_test.c,生成lcd_test可執行文件。複製可執行文件到根文件系統,目標板啓動後在目錄輸入./lcd_test即可執行。
5. 附錄
https://pan.baidu.com/s/1slczwhJ
bootloader源碼以及使用說明
https://pan.baidu.com/s/1eRDJtNs
Qt5.8官網源碼
https://pan.baidu.com/s/1nuGmSqt
本系列例程的根文件系統
https://pan.baidu.com/s/1i5btLGT
opev3.2.0官網源碼
https://pan.baidu.com/s/1pLpuHw3
yaffs官網源碼
https://pan.baidu.com/s/1bpkZynt
busybox-1.26.2官網源碼
https://pan.baidu.com/s/1i4EtjfR
tslib官網源碼
https://pan.baidu.com/s/1i5MGRhb
mplayer-1.3.0官網源碼
https://pan.baidu.com/s/1sl0fXlr
基於S3C2416修改的linux-4.10.10源碼