本文所有的调试都是基于mm_swiftio, 一款使用rt1052 mcu的zephyr开发板。
RGB接口屏
嵌入式使用的小屏接口一般有MCU接口,RGB接口,8080接口,LVDS。其中MCU接口需要占用硬件连线最少,但速度也最慢,通常采用SPI总线。其它的都是并行接口,占用硬件连线多,速度快。RGB接口的屏一般来说不自带framebuffer,需要MCU有专门的lcd控制器来驱动。
屏的基本参数
像素:屏的最小显示单位是像素,屏上显示图像的内容是由像素组成。
分辨率:“行像素值 x 列像素值”表示屏幕的分辨率。
色彩深度:像素能显示多少种颜色,用bit数表示。一般有1,8,16,24,32bit几种, 其是2的幂次对应的颜色数量
尺寸:屏的对角线长度,有4.3寸,5寸,7寸等。
RGB接口屏控制信号
屏是由像素组成,设置屏上每个像素的色彩就控制了屏的显示,RGB接口屏的控制信号如下:
R[0:7] :红
G[0:7]:绿
B[0:7]:蓝
DE :数据使能
VSYNC:场同步(垂直)
HSYNC:行同步(水平)
CLK:时钟信号
其中RGB是颜色信号。DE数据使能为高时RGB上的数据才有效。clk是时钟信号每一个时钟上的RGB信号就是一个像素的颜色。HSYNC是行同步,当一行数据传送结束时配合一个HSYNC。 VSYNC是场同步,当一屏的数据传送结束时配合一个VSYNC。
为什么需要VSYNC和HSYNC信号,因为光靠clk信号传送数据,可能由于clk的频偏导致积累误差出现画面扭曲,及画面场数不正常,因此需要使用行场同步来进行纠正。对于不同的屏这几组信号之间会有一定的时序要求,驱动屏比较重要的有下面几个,LCD屏的规格书会有列出
HSW:行同步信号的宽度,以CLK为单位表示
HFP:行同步前肩,是前一行数据结束到行同步之间的clk数量
HBP:行同步后肩,是行同步到下一行数据开始之间的clk数量
VSW:场同步信号的宽度,以CLK为单位表示
VFP:场同步前肩,是前一帧数据结束到场同步之间的clk数量
VBP:场同步后肩,是场同步到下一帧数据开始之间的clk数量
示例,为了简化说明我们以一个3X2分辨率的屏进行说明时序:
LCD控制器
rt1052带有一个柔性的LCD控制器,不占用CPU,直接通过DMA读出framebuffer的数据送到IO进行LCD刷新
- 每一个clk传递一个像素, 可选上升沿和下降沿
- DE有效时RGB的数据才有效,可选高有效或低有效
- 一行数据传递完后有一个HSYNC通知行结束,可选高有效或低有效
- 一帧数据传递玩后有一个VSYNC通知帧结束,可选高有效或低有效
- 支持8/16/18/24 bit的lcd
添加屏方法
Zephyr已经支持了rt1052的LCD驱动,但目前只支持RK043FN02H,对于不同的RGB屏的支持需要进行修改。这里说明如何添加其它屏的支持
Zephyr增加LCD屏
1. Kconfig增加新屏
在 drivers/display/Kconfig.mcux_elcdif 中添加屏的配置选项
1 | config MCUX_ELCDIF_PANEL_RGBLCD |
2. 增加新屏的配置参数
在drivers/display/display_mcux_elcdif.c中的mcux_elcdif_config_1结构体中增加屏的参数,这些参数的意义前面已经介绍,需要根据屏的规格来配置,如下
1 | #ifdef CONFIG_MCUX_ELCDIF_PANEL_RGBLCD |
以上DT_开头的宏需要我们自己定义或者直接按照规格写实际的值就可以了,其它的宏都是hal_nxp内定义的。
由于我驱动的几片屏基本都只配置这些参数,因此是使用zephyr的dts来产生的这些宏:
1 | #define DT_LCD_RGB_INTERFACE_PANEL_WIDTH 800 |
由于不确定这种做法是不是符合标准,另外并没有对全部信号(背光,显示控制等)和参数(color format, 信号电平等)进行dts配置,这里就不做详细介绍了。
RT1052 配置
除了对屏参进行专门的设置外,还要对Zephyr 中RT1052其它部分进行配置才能驱动起来屏
1.Pin mux
rt1052的的pin是复用的,因此当pin做为lcd驱动信号输出时需要对pin进行配置,在boards/arm/mm_swiftio/pinmux.c中的mm_swiftio_init函数添加下面代码进行pin功能配置
1 | #ifdef CONFIG_DISPLAY_MCUX_ELCDIF |
2.LCD时钟配置
LCD的时钟决定了屏的刷新频率,因此配置非常重要, 修改soc/arm/nxp_imx/rt/soc.c
1 | #ifdef CONFIG_INIT_VIDEO_PLL |
时钟计算方法:
外部晶振频率为24M,lcd控制器输出的clk = 24M*(loopDivider+denominator/numerator)/postDivider/(kCLOCK_LcdifPreDiv+1)/(kCLOCK_LcdifPreDiv+1)=28.5M
帧率计算:
一帧需要的clk=(width+hsw+hfp+hbp)*(height+vsw+vfp+vbp) = 457094
因此一秒的帧率 = 28.5M/457094 = 62帧
从上面的计算可以看到一帧所需要的clk数量是由屏参决定,如果我们要修改帧率就要调整LCD的输出clock,值得注意的是不同的屏的刷新率是有上限的,我们在设置LCD输出时钟时应该参考LCD屏的最高帧率
Zephyr Display驱动使用
配置
需要先配置启动display, 我们使用的屏是800*480,16bit,因此一帧数据的framebuffer大小为800*480*2 = 750K,因此需要配置elcdif pool大于750k,elcdif的驱动使用的是double buffer,因此pool number需要配置为2
1 | CONFIG_MCUX_ELCDIF_POOL_BLOCK_MIN=0x100000 |
实际的rt1052在lcd上的驱动可以看drivers/display/display_mcux_elcdif.c
使用
Zephyr有标准的display驱动接口,include/display.h,接口定义的说明可以参考ssd1306驱动要点中Zephyr display driver 模型章节,这里不做详细介绍了.
实际帧率的测试方法:rt1052每刷新完一帧会产生一次中断,在display_mcux_elcdif.c的mcux_elcdif_isr中加入时间打印就可以探测到实际的帧率了。
调试方法
本小节只是罗列在调屏时遇到的问题和检查应对方法
问题罗列
屏幕不显示图像,发白或者成细线条无规律散开装
clk/vsync/hsync 不正常,检查参数配置和对应信号连线是否正常
部分屏幕显示形状正常,但颜色异常
帧率过高,降低帧率
画一个区域影响其它区域显示
帧率过高或者是vsync线连接不好,这一般只出现在调试阶段用杜邦线连接屏和开发板
案例及分析
在初步调好屏后,画了R,G,B三种颜色,看起来正常。于是配置lvgl,画了一些控件发现显示异常,如下图下半部分,所有的红色空间看起来都有一些红色的彩条
为了对比问题使用了lvgl定义的蓝色直接在framebuffer上画了一个矩形,看起来也正常,因此开始怀疑是lvgl的渲染的锅,相同的代码在SDL上面模拟跑了一下看起来又正常,因此还是将问题定位在display驱动以下,使用下面方法分别显示各种R,G,B所有颜色空间
1 | u16_t *colorb = buf; |
看到下图:
可以明显的看到红色的颜色空间有问题(发现问题后,我在每个红色之间加了gap以方便观察),这样问题已经有很明显的指向性了,因为蓝色和绿色没有问题,因此不太可能是驱动的问题,查硬件是红色的线序插反了,调整过来后,显示正常了
参考
i.MX RT1050 Processor Reference Manual