LCD能够支持彩色图像的显示和视频的播放,是一种很重要的输出设备,在一些嵌入式人机交互系统中,也往往需要lcd进行显示。Linux内核已经支持了s3c2416的lcd控制器。

1. lcd设备

lcd设备包含了名字、独有的资源等等一些驱动程序的硬件或自定义信息。 通过platform_add_devices(platform_device_register)函数将定义的平台设备注册到内核中,用于匹配设备驱动。

内核在drivers\video\fbdev\s3c-fb.c中实现了s3c2416 lcd驱动,lcd设备平台代码如下:

Eastar: /arch/arm/mach-s3c24xx/mach-home2416.c

  1. static struct s3c_fb_pd_win home2416_fb_win[] = {
  2. [0]= {
  3. .default_bpp = 16,
  4. .max_bpp = 32,
  5. .xres = 800,
  6. .yres = 480,
  7. },
  8. };
  9. static struct fb_videomode home2416_lcd_timing = {
  10. .pixclock = 41094,
  11. .left_margin = 19,
  12. .right_margin = 37,
  13. .upper_margin = 10,
  14. .lower_margin = 26,
  15. .hsync_len = 27,
  16. .vsync_len = 13,
  17. .xres = 800,
  18. .yres = 480,
  19. };
  20. static void s3c2416_fb_gpio_setup_24bpp(void)
  21. {
  22. unsignedint gpio;
  23. for(gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) {
  24. s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(2));
  25. s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);
  26. }
  27. for(gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) {
  28. s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(2));
  29. s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);
  30. }
  31. for(gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) {
  32. s3c_gpio_cfgpin(gpio,S3C_GPIO_SFN(2));
  33. s3c_gpio_setpull(gpio,S3C_GPIO_PULL_NONE);
  34. }
  35. }
  36. static struct s3c_fb_platdata home2416_fb_platdata = {
  37. .win[0] = &home2416_fb_win[0],
  38. .vtiming = &home2416_lcd_timing,
  39. .setup_gpio = s3c2416_fb_gpio_setup_24bpp,
  40. .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
  41. .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
  42. };
  43. static struct resource s3c_fb_resource[]= {
  44. [0]= DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
  45. [1]= DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
  46. [2]= DEFINE_RES_IRQ(IRQ_LCD_FIFO),
  47. [3]= DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
  48. };
  49. struct platform_device s3c_device_fb = {
  50. .name = "s3c-fb",
  51. .id = -1,
  52. .num_resources = ARRAY_SIZE(s3c_fb_resource),
  53. .resource = s3c_fb_resource,
  54. .dev = {
  55. .dma_mask = &samsung_device_dma_mask,
  56. .coherent_dma_mask = DMA_BIT_MASK(32),
  57. },
  58. };
  59. void __init s3c_fb_set_platdata(structs3c_fb_platdata *pd)
  60. {
  61. s3c_set_platdata(pd,sizeof(struct s3c_fb_platdata),
  62. &s3c_device_fb);
  63. }

在板级初始化函数 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背光驱动,背光设备平台代码如下:

Eastar: arch/arm/mach-s3c24**/mach-home2416.c

  1. static int s3c2416_backlight_init(structdevice *dev)
  2. {
  3. gpio_request(S3C2410_GPB(0),"Backlight"); //使用的IO口为: GPB.0
  4. gpio_direction_output(S3C2410_GPB(0),0);
  5. s3c_gpio_setpull(S3C2410_GPB(0),S3C_GPIO_PULL_NONE);
  6. s3c_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPB0_TOUT0);
  7. return 0;
  8. }
  9. static int s3c2416_backlight_notify(struct device *dev, int brightness)
  10. {
  11. if(!brightness)
  12. {
  13. gpio_direction_output(S3C2410_GPB(0),0);
  14. }
  15. else
  16. {
  17. gpio_direction_output(S3C2410_GPB(0),0);
  18. s3c_gpio_setpull(S3C2410_GPB(0),S3C_GPIO_PULL_NONE);
  19. s3c_gpio_cfgpin(S3C2410_GPB(0),S3C2410_GPB0_TOUT0);
  20. }
  21. return brightness;
  22. }
  23. static void s3c2416_backlight_exit(struct device *dev)
  24. {
  25. gpio_direction_output(S3C2410_GPB(0),0);
  26. }
  27. static struct platform_pwm_backlight_data backlight_data =
  28. {
  29. .max_brightness= 100,
  30. .dft_brightness= 50,
  31. .enable_gpio = -1,
  32. .init = s3c2416_backlight_init,
  33. .notify = s3c2416_backlight_notify,
  34. .exit = s3c2416_backlight_exit,
  35. };
  36. static struct platform_device s3c2416_backlight =
  37. {
  38. .name= "pwm-backlight",
  39. .dev = {
  40. .parent= &samsung_device_pwm.dev,
  41. .platform_data= &backlight_data,
  42. },
  43. .id = -1,
  44. };
  45. static struct pwm_lookup s3c2416_pwm_lookup[] = {
  46. PWM_LOOKUP("samsung-pwm",0, "pwm-backlight", NULL, 36296, PWM_POLARITY_NORMAL),
  47. };

在板级初始化函数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开机一段时间后自动关屏:

  1. static int blankinterval = 0;

修改drivers/video/console/fbcon.c,禁止光标闪烁:

  1. static int fbcon_cursor_noblink = 1;

2、内核配置

Linux配置支持lcd设备驱动,选中 Device Drivers->Graphics support->Frame buffer Devices->Samsumg S3C framebuffer support : 15_LCD驱动 - 图1

Linux配置支持lcd背光驱动,选中DeviceDrivers->Graphics support->Backlight & LCD device support->Generic PWM based Backlight Driver。 15_LCD驱动 - 图2

Linux配置开机logo,DeviceDrivers->Graphics support->Bootup logo->Standard 224-color Linux logo。 15_LCD驱动 - 图3

3、lcd测试

cat /proc/devices可以知道lcd主设备号为29,次设备号为0,在/dev目录中创建fb0设备文件。

  1. mknod /dev/fb0 c 29 0

lcd显示黑屏。

  1. mknod /dev/zero c 1 5
  2. dd if=/dev/zero of=/dev/fb0

4、应用编程

应用程序可以通过设备文件访问lcd,lcd纯色显示应用测试代码lcd_test.c如下。

  1. #include "fcntl.h"
  2. #include "unistd.h"
  3. #include "stdio.h"
  4. #include "stdlib.h"
  5. #include "sys/mman.h"
  6. void screen_clear(unsigned short*ppixel, unsigned short color)
  7. {
  8. int i;
  9. for(i=0; i<800*480; i++)
  10. ppixel[i]= color;
  11. }
  12. int main(void)
  13. {
  14. unsignedshort colors[] = {0xffff, 0x0000, 0xf800,
  15. 0x07e0,0x001f, 0xffe0, 0xf81f, 0x7ff};
  16. int screen_size;
  17. int fd;
  18. int index;
  19. unsignedshort *ppixel;
  20. fd= open("/dev/fb0", O_RDWR);
  21. if(fd == -1) {
  22. printf("Openframebuffer failed\n");
  23. exit(1);
  24. }
  25. screen_size= 800*480*2;
  26. ppixel=(unsigned short *)mmap(0, screen_size,
  27. PROT_READ|PROT_WRITE,MAP_SHARED, fd,0);
  28. if(ppixel == (unsigned short *)-1) {
  29. printf("Mapframebuffer failed\n");
  30. exit(1);
  31. }
  32. while(1) {
  33. screen_clear(ppixel,colors[index]);
  34. index++;
  35. if(index >= sizeof(colors)/sizeof(colors[0]))
  36. index= 0;
  37. sleep(2);
  38. }
  39. umap(ppixel,screen_size);
  40. close(fd);
  41. return0;
  42. }

用arm-linux-gcc静态编译,使之生成arm cpu可执行的指令,并且可脱离任何库独立运行:

  1. arm-linux-gcc -static -o lcd_test

lcd_test.c,生成lcd_test可执行文件。复制可执行文件到根文件系统,目标板启动后在目录输入./lcd_test即可执行。

5、附录

文件 源码下载
bootloader源码以及使用说明 https://pan.baidu.com/s/1slczwhJ
Qt5.8官网源码 https://pan.baidu.com/s/1eRDJtNs
本系列例程的根文件系统 https://pan.baidu.com/s/1nuGmSqt
opev3.2.0官网源码 https://pan.baidu.com/s/1i5btLGT
yaffs官网源码 https://pan.baidu.com/s/1pLpuHw3
busybox-1.26.2官网源码 https://pan.baidu.com/s/1bpkZynt
tslib官网源码 https://pan.baidu.com/s/1i4EtjfR
mplayer-1.3.0官网源码 https://pan.baidu.com/s/1i5MGRhb
基于S3C2416修改的linux-4.10.10源码 https://pan.baidu.com/s/1sl0fXlr