米尔电子
直播中

高增华

9年用户 542经验值
擅长:嵌入式技术
私信 关注

【Rico Board试用体验】5.Ricoboard开发板上HDMI模块简单分析和使用framebuffer显示bmp文件

HDMI在目前的嵌入式中应用越来越广,关于其定义,相关的cec,edid,hdcp等不做过多介绍。
相对于其他几家芯片厂家的hdmi模块,ti的hdmi子系统又有很多的不同。
dss可以理解为Display Subsystem的简写,翻译过来就是显示子系统,这个硬件模块负责读从存储器取像素数据,发送到lcd或者hdmi显示器。
它分为两大部分:1)DISPC,获取像素数据,颜色转换,组成和其他像素操作;2)编码器,将原始像素数据转化成标准的显示信息,hdmi,或者mipi DPI。
对于一个芯片来说dss还应该包括其他一些有用的解码器,比如dpi dvi等等,还有显示面板。
DISPC又包括overlays和overlay managers,简单的理解,前者负责接收数据,后者负责数据处理。
overlays又分为GFX和VIDEO ,各自支持一些格式,值得注意的是后者支持yuv,而前者不支持。
dss也有一些不支持的属性,不支持HDCP。dss2是dss的升级版本支持hdcp。
下图是dss整体框架。
dss-architecture.png
上面只是dss模块的整体框架,在实际编码中有很多微小的细节需要注意。
sii9022是开发板使用的hdmi芯片,是Silicon Image公司的产品,支持HDMI 1.2a(1.4应该是目前最新的版本)和DVI 1.0,以及下面一些特性。
  1. Integrated TMDS core
  2. • DTV resolution support - 480i/576i/
  3. 480p/576p/720p/1080i/1080p
  4. • PC resolution support - VGA/XGA/
  5. SXGA/WSXGA/UXGA
  6. • Flexible interface to HD MPEG decoders:
  7. - 12/24-bit RGB YCbCr 4:4:4
  8. - 16/20/24-bit YCbCr 4:2:2
  9. - 8/10/12-bit YCbCr 4:2:2
  10. (ITU-R BT.601 & BT.656)
  11. • Integrated YCbCr —> RGB conversion
  12. • 4:2:2 —> 4:4:4 up-converter
  13. • Programmable Data Enable (DE) generator
sii9022威廉希尔官方网站 图如下:
sii9022.png
下面就简单分析一下hdmi的启动流程。
  1.        
  2.         DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
  3.                 .reserve        = am33xx_reserve,
  4.                 .map_io                = am33xx_map_io,
  5.                 .init_early        = am33xx_init_early,
  6.                 .init_late        = am33xx_init_late,
  7.                 .init_irq        = omap_intc_of_init,
  8.                 .handle_irq        = omap3_intc_handle_irq,
  9.                 .init_machine        = omap_generic_init,
  10.                 .init_late        = am33xx_init_late,
  11.                 .init_time        = omap3_gptimer_timer_init,
  12.                 .dt_compat        = am33xx_boards_compat,
  13.                 .restart        = am33xx_restart,
  14.         MACHINE_END
根据启动log我们可以找到一个入口函数,他的实现是在arch/ARM/mach-omap2中的board-genreic.c文件中。当然kernel的最开始入口函数不是这个函数,但是对于我们关注的某个soc来说,把DT_MACHINE_START函数作为入口函数足够了。
omap_generic_init -->omapdss_init_of(display.c) -->omap_init_fb(fb.c另外两个函数为return 0;)初始化fb等等。
下面omap_dss_init函数通过module_init(omap_dss_init);加载到kernel中,其实现如下,调用探针函数 omap_dss_probe,初始化dss_init_platform_driver和dispc_init_platform_driver,前者初始化dss2,后者启动dispc,跟前面的介绍很吻合。
  1. static int __init omap_dss_init(void)
  2.         {
  3.                 int r;
  4.                 int i;
  5.                 r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
  6.                 if (r)
  7.                         return r;
  8.        
  9.                 r = dss_init_platform_driver();
  10.                 if (r) {
  11.                         DSSERR("Failed to initialize DSS platform drivern");
  12.                         goto err_dss;
  13.                 }
  14.        
  15.                 r = dispc_init_platform_driver();
  16.                 if (r) {
  17.                         DSSERR("Failed to initialize dispc platform drivern");
  18.                         goto err_dispc;
  19.                 }
  20.        
  21.                 /*
  22.                  * It's ok if the output-driver register fails. It happens, for example,
  23.                  * when there is no output-device (e.g. SDI for OMAP4).
  24.                  */
  25.                 for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
  26.                         r = dss_output_drv_reg_funcs[i]();
  27.                         if (r == 0)
  28.                                 dss_output_drv_loaded[i] = true;
  29.                 }
  30.        
  31.                 dss_initialized = true;
  32.                 printk(" KERN_INFO =5=omap_dss_initn");
  33.        
  34.                 return 0;
  35.        
  36.         err_dispc:
  37.                 dss_uninit_platform_driver();
  38.         err_dss:
  39.                 platform_driver_unregister(&omap_dss_driver);
  40.        
  41.                 return r;
  42.         }
module_platform_driver(omapfb_driver);函数将omapfb_driver模块加载到系统中,且与上面的omap_init_fb函数内容呼应。注意def_mode的数值是如何获取的。
  1. static struct platform_driver omapfb_driver = {
  2.         .probe                = omapfb_probe,
  3.         .remove         = __exit_p(omapfb_remove),
  4.         .driver         = {
  5.                 .name   = "omapfb",
  6.                 .owner  = THIS_MODULE,
  7.         },
  8. };
  9. /*Kernel command line: console=ttyO0,115200n8
  10. omapdss.def_disp=display1
  11. omapfb.mode=display1:1024x768MR-24@60
  12. root=/dev/nfs nfsroot=192.168.9.217:/opt/nfs_dir,nolock rw ip=dhcp
  13. */
  14. module_param_named(mode, def_mode, charp, 0);
  15. module_param_named(vram, def_vram, charp, 0);
  16. module_param_named(rotate, def_rotate, int, 0);
  17. module_param_named(vrfb, def_vrfb, bool, 0);
  18. module_param_named(mirror, def_mirror, bool, 0);
  19. module_platform_driver(omapfb_driver);


module_platform_driver(hdmi_connector_driver);函数将hdmi_connector_driver模块加载到系统中,与下面的内容呼应

  1.   hdmi0: connector@1 {
  2.                 compatible = "ti,hdmi_connector";
  3.                 video-source = <&sii9022>;
  4.         };


module_i2c_driver(sil9022_driver); 函数将sil9022_driver模块加载到系统中,且与下面的内容呼应。注意其是module_i2c_driver函数,从这里才能找到一点其他soc中hdmi模块的影子。
  1. module_i2c_driver(sil9022_driver);
  2.                 sii9022: sii9022@3b {
  3.                 compatible = "sii,sii9022";
  4.                 reg = <0x3b>;
  5.                 reset-gpio = <&gpio5 8 GPIO_ACTIVE_LOW>;
  6.                 video-source = <&dpi>;
  7.                 data-lines = <24>;
  8.         };


dts中的定义也与下面iic的设备节点对应起来。0x3b
i2c-devices.png
module_platform_driver(panel_dpi_driver);函数将panel_dpi_driver加载到系统中,
  1. static struct platform_driver panel_dpi_driver = {
  2.         .probe = panel_dpi_probe,
  3.         .remove = __exit_p(panel_dpi_remove),
  4.         .driver = {
  5.                 .name = "panel-dpi",
  6.                 .owner = THIS_MODULE,
  7.                 .of_match_table = panel_dpi_of_match,
  8.         },
  9. };

panel_dpi_driver与下面的内容呼应。

  1. lcd0: display@0 {
  2.                 compatible = "osddisplays,osd057T0559-34ts", "panel-dpi";
  3.                 video-source = <&dpi>;
  4.                 data-lines = <24>;
  5.                 panel-timing {
  6.                         clock-frequency = <36000000>;
  7.                         hactive = <800>;
  8.                         vactive = <480>;
  9.                         hfront-porch = <210>;
  10.                         hback-porch = <1>;
  11.                         hsync-len = <43>;
  12.                         vback-porch = <1>;
  13.                         vfront-porch = <22>;
  14.                         vsync-len = <22>;
  15.                         hsync-active = <0>;
  16.                         vsync-active = <0>;
  17.                         de-active = <1>;
  18.                         pixelclk-active = <1>;
  19.                 };
  20.         };


根据下面的log,我们可以清晰的看到fb,sii9022,panel-pdi,dss是如何串联起来。
  1. =6=omapfb_probe
  2. =1=omapfb_init_connections
  3. =1=hdmic_connect
  4. =1=hdmic_connect in->ops.hdmi->connect
  5. =1=sil9022_connect
  6. sii9022 1-003b: CONNECT
  7. =2=omapfb_init_connections fbdev->num_displays=2
  8. =2=omapfb_init_connections fbdev->num_displays=2 i=0
  9. =1=panel_dpi_connect
  10. =2=panel_dpi_connect
  11. omapdss APPLY error: manager lcd is already connected to an output
  12. fbcvt: 1024x768@60: CVT Name - .786M3-R
  13. =7=omapfb_probe
  14. create 3 framebuffers
  15. fb_infos allocated
  16. =1=omapdss_default_get_resolution
  17. fbmems allocated
  18. =1=omapdss_default_get_resolution
  19. fb_infos initialized
  20. =1=omapfb_set_par
  21. =2=omapfb_set_par
  22. =3=omapfb_set_par
  23. =1=omapfb_apply_changes
  24. =4=omapfb_set_par
  25. pan_display(0)
  26. Console: switching to colour frame buffer device 128x48
  27. pan_display(0)
  28. framebuffers registered
  29. =1=omapfb_apply_changes
  30. =1=omapfb_apply_changes
  31. =1=omapfb_apply_changes
  32. Enable fb0
  33. create_framebuffers done
  34. =8=omapfb_probe
  35. =1=omapfb_init_display
  36. =1=sil9022_enable
  37. sii9022 1-003b: ENABLE
  38. =2=sil9022_enable
  39. =3=sil9022_enable
  40. =1=sil9022_hw_enable
  41. sii9022 1-003b: HW_ENABLE -> Timings
  42. pixel_clk                       = 56000
  43. horizontal res          = 1024
  44. vertical res                    = 768
  45. sii9022 1-003b: hdmi enabled
  46. =4=sil9022_enable
  47. =2=omapfb_init_display
  48. =3=omapfb_init_display
  49. =6=omapfb_init_display
  50. =9=omapfb_probe


omapdss的节点有哪些?
dss-ls.png
sysfs接口测试
cat /sys/devices/platform/omapdss/overlay0/name
gfx

与介绍中的概念对应起来。
echo "0" > /sys/devices/platform/omapdss/overlay0/enabled
echo "1" > /sys/devices/platform/omapdss/overlay0/enabled

上面两个语句可以控制屏幕的亮灭。
echo 2 > /sys/class/graphics/fb0/rotate可以控制屏幕的旋转180度,只是我们这里运行出错。
4-rotate-error.jpg
另外还有一个问题,不知道大家注意到没有dts和相应的probe函数一一对应,他们会调用几次?
一般情况是一次,但是如果我们想多次调用探针函数可以吗?答案是肯定可以的。
掌握上面的信息,我感觉对于开发板hdmi模块已经有了一个简单的入门,当然更加细节的问题则需要时间继续研究,比如edid如何处理,HDCP如何实现。
帧缓冲(framebuffer)是 Linux 为显示设备提供的一个接口,出现在kernel2.2.x以后,它把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作,写操作可以立即反应到显示屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer 设备驱动来完成的,所以可知其具有良好的移植性。
       帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显示卡,Linux 下还可支持多个帧缓冲设备,最多可达32 个,分别为/dev/fb0 到/dev/fb31,当前缺省的帧缓冲设备通常指向/dev/fb0。当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号则从0到31。分别对应/dev/fb0-/dev/fb31。在MID上,设备信息是/dev/graphics/fb0。   

对于我们来说omapfb_driver驱动实现了对framebuffer的支持。
  1. fh = openFB(NULL);
  2.         getVarScreenInfo(fh, &var);
  3.         getFixScreenInfo(fh, &fix);
  4.        
  5. //        fb_mem_offset = (unsigned long)(fix.smem_start) & (~PAGE_MASK);
  6.         fb_mem = (unsigned long int)mmap(NULL, fix.smem_len ,
  7.                 PROT_READ | PROT_WRITE, MAP_SHARED, fh, 0);
  8.                             memcpy((void*)(fb_mem + offset), color, 4);
  9.         closeFB(fh);

上面是帧缓冲的简单步骤,附件是我显示bmp的源代码。



下面是运行的结果,一图是没有运行的抓图,二图是显示第一个bmp,三图是显示第二个bmp。
4-1.jpg
4-2.jpg
4-21.jpg
知识点总结:
1.dss;
2.sii9022;
3.probe函数多次调用;
4.framebuffer。

回帖(5)

番茄番茄

2016-11-9 18:15:34
知识点总结棒棒哒  赞一个
举报

jinyi7016

2016-11-12 15:33:33
楼主的显示是用的什么方法,HDMI还是HDMI转VGA呢?
举报

高增华

2016-11-13 09:57:02
使用HDMI转dvi线。
举报

゛向日葵的执着

2017-9-28 15:24:39
HDMI的输出分辨率可以改不
举报

高增华

2017-9-28 17:56:12
在另外的开发板上改过,米尔的开发板没有试过,板子已经还给厂家。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分