嵌入式Linux&Android开发-LCD屏幕调试

本文详细介绍了在嵌入式Linux和Android系统中开发LCD屏幕的流程,包括理解Framebuffer原理、硬件说明、屏参适配、启动时序计算等内容,并提供了多个屏参配置案例和调试方法。
摘要由CSDN通过智能技术生成

目录

一、简介

二、开发流程

三、硬件说明

四、电子特性

五、关注启动时序

六、关注引脚

七、屏参适配

7.1 DTS&驱动配置

7.2 屏参配置(案例一)

7.3屏参配置(案例二)

7.4 屏参配置(案例三)

7.5 屏参配置(案例四)

7.6 通过excel计算启动时序

7.7 填充DTS,编译运行

7.8 编译&运行

7.9 常见问题

八、Excel附件


一、简介

如果我们需要去写一个LCD驱动时候,我们必须了解Framebuffer的具体工作原理以及如何应用。

Framebuffer是内核中用于管理显示相关的框架,翻译过来就是帧缓冲,简称fb,fb是一种机制,将系统中所有跟显示有关的硬件以及软件集合起来,虚拟出一个fb设备。

Linux抽象出的FrameBuffer这个设备来供用户态进程实现直接写屏。FrameBuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过FrameBuffer的读写直接对显存进行操作,而写操作可以立即反应在屏幕上。

framebuffer的设备文件在Linux下一般是 /dev/fb0/dev/fb1 等,但在Android下面一般为/dev/graphics/fb0,/dev/graphics/fb1

相关源码位置:
kernel/drivers/video/fbdev/core/
kernel/drivers/video/rockchip/transmitter/tc358768.c DSI转LVDS驱动

如果我们只是基于SOC平台去点亮某块屏幕,我们关心的更多是如何适配屏参。

如何适配一个LCD屏幕?

二、开发流程

  1. 查看外设Datasheet,了解电子特性、启动时序、屏幕参数
  2. 查看原理图,确定相关IO引脚
  3. 修改DTS
  4. 编译&运行&调试

三、硬件说明

rk3399并没有带LVDS接口,只有MIPI DSI,因此使用东芝的DSI->LVDS芯片TC358775来输出LVDS信号。

因此驱动里配置的就是MIPI DSI了。

四、电子特性

 关注LCD、背光电压,供电电压不正常可能会导致器件烧毁。 

五、关注启动时序

屏幕显示异常时,可使用示波器测量背光&使能时序是否正常。

六、关注引脚

一组IIC加4组MIPI lane

七、屏参适配

7.1 DTS&驱动配置

由于rk3399没有原生LVDS接口,需要用到toshiba_tc358775芯片mipi2lvds,因此配置屏参需要在两部分配置,一部分是配置mipi的初始化指令,一部分是配置lvds的参数。

由于要用到mipi接口,所以先要在menuconfig里打开mipi驱动配置

(1)-> Device Drivers
 |    -> Graphics support
  |      -> Rockchip Misc Video driver
  |        -> LCD Panel Select 
     <*> rk mipi dsi lcd 
(2)-> Device Drivers  
  |    -> Graphics support
  |      -> Rockchip Misc Video driver
  |        -> RockChip display transmitter support
             <*> RK32 RGB to DisplayPort transmitter support
              <*> Rockchip MIPI DSI support
(3)    -> Device Drivers  
  |    -> Graphics support
  |      -> Display Panels  
<*> support for simple panel

配置完上面的驱动保存后,打开.config文件,如果文件里面有如下3条数据,说明配置成功。

CONFIG_LCD_MIPI=y

CONFIG_MIPI_DSI=y

CONFIG_RK32_MIPI_DSI=y

绑定vop,vop是Rockchip系列Soc的Display Controller(显示控制器), 用来将video memory中的image data传送到外部lcd接口,如mipi,edp, dp, hdmi等。

#include <dt-bindings/display/drm_mipi_dsi.h>
&dsi_in_vopl {
        status = "okay";
};
&dsi_in_vopb {
        status = "disabled";
};

 rk3399有两路vop,vopb支持到4k,vopl支持到2k,由于lvds的4k屏很少(目前为止我还没接触过),所以这里我把lvds绑定到vopl上,hdmi的4k屏比较常见,可以绑定到vopb上。

7.2 屏参配置(案例一)

时序参数解析:

由屏参表格可以得出

clock-frequency = 71.1MHz = 71100000 //像素时钟

Hactive = Horizontal Address = 1280 //水平像素点

Vactive = Vertical Address = 800 //垂直像素点

在填充vbp vfp vs hbp hfp hs 6个参数时只需要满足关系:

vbp+vfp+vs = Tv - Tvd = 823 - 800 = 23

hbp+hfp+hs = Th - Thd = 1440 - 1280 = 160

各值自行分配(通常hbp和vbp取较大值)

DTS配置如下:

                timing0: timing0 {
                        clock-frequency = <71100000>; //像素时钟
                        hactive = <1280>; //水平像素点
                        vactive = <800>;  //垂直像素点
                        
                        hsync-len = <10>;   //行同步脉宽
                        hback-porch = <40>; //水平后沿
                        hfront-porch = <110>;//水平前沿

                        vsync-len = <2>;    //垂直同步脉宽
                        vback-porch = <13>; //垂直后沿
                        vfront-porch = <8>; //垂直前沿

                        hsync-active = <0>;
                        vsync-active = <0>;
                        de-active = <0>;
                        pixelclk-active = <0>;
                };

 7.3 屏参配置(案例二)

由屏参表格可以得出hactive、vactive、hsl、hbp、hfp、vsl、vbp、bfp值

7.4 屏参配置(案例三)

hback-porch = <150>;
hfront-porch = <50>;
vback-porch = <30>;
vfront-porch = <11>;
hsync-len = <4>;
vsync-len = <1>;

hback-porch = <200>;
hfront-porch = <100>;
hsync-len = <20>;

vback-porch = <15>;
vfront-porch = <6>;
vsync-len = <3>;

7.5 屏参配置(案例四)

                disp_timings: display-timings {
                        native-mode = <&timing0>;
                        timing0: timing0 {
                                clock-frequency = <123750000>; 
                                 hactive = <1920>;
                                vactive = <1080>;

                                hback-porch = <100>;
                                hsync-len = <20>;
                                hfront-porch = <160>;
                                vback-porch = <25>;
                                vfront-porch = <10>;
                                vsync-len = <10>;
                                hsync-active = <0>;
                                vsync-active = <0>;
                                de-active = <0>;
                                pixelclk-active = <0>;
                        };
                };

 往下确定背光、DSI配置、对应IO配置。

7.6 通过excel计算启动时序

部分屏幕需要添加启动时序,可以直接向原厂或代理商咨询,或者自行用下面方法调试。

根据DTS修改excel(表格位于文章结尾),可以自行选择SYNC_PULSE或SYNC_EVENT模式,这里选择SYNC_EVENT表格,根据DTS的hsl hbp hfp vsl vbp bfp修改。

dsi时钟计算

公式:dsi_hs_clk = ((h_active + hfp + hbp + h_sync) * (v_active + vfp + vbp + v_sync) * fps * bpp) / lane_number

例如屏参案例一:dsi_hs_clk = 1440x823x71.1x24/4 = 390M

在Source选择Sync Event Mode表格作为生成源

 下一步可以生成DTS启动时序,到Code中选择对应参数。 

最后,完整DTS时序如下(案例四)。

                panel-init-sequence = [                 
                        29 00 06 3C 01 05 00 03 00
                        29 00 06 14 01 03 00 00 00
                        29 00 06 64 01 0C 00 00 00
                        29 00 06 68 01 0C 00 00 00
                        29 00 06 6C 01 0C 00 00 00
                        29 00 06 70 01 0C 00 00 00
                        29 00 06 34 01 1F 00 00 00
                        29 00 06 10 02 1F 00 00 00
                        29 00 06 04 01 01 00 00 00
                        29 00 06 04 02 01 00 00 00
                        29 00 06 50 04 20 01 F0 03
                        29 00 06 54 04 14 00 64 00
                        29 00 06 58 04 80 07 A0 00
                        29 00 06 5C 04 0A 00 19 00
                        29 00 06 60 04 38 04 0A 00
                        29 00 06 64 04 01 00 00 00
                        29 00 06 A0 04 2D 80 44 00
                         
                        29 00 06 A0 04 2D 80 04 00
                        29 00 06 04 05 04 00 00 00
                        29 00 06 80 04 00 01 02 03
                        29 00 06 84 04 04 07 05 08
                        29 00 06 88 04 09 0A 0E 0F
                        29 00 06 8C 04 0B 0C 0D 10
                        29 00 06 90 04 16 17 11 12
                        29 00 06 94 04 13 14 15 1B
                        29 14 06 98 04 18 19 1A 06
                        29 78 06 9C 04 63 02 00 00
                ];

 7.7 填充DTS,编译运行

/dts-v1/;
#include "rk3399-embeded-aiojd4.dtsi"
/ {
 model = "AIO-3399JD4 Board lvds HSX101H40C (Android)";
 compatible = "rockchip,android", "rockchip,rk3399-embeded-lvds", "rockchip,rk3399";
};
&backlight {
 status = "okay";
 //pwm0 0对应pwm0的的第一组pwm,25000为25000ns,也就是频率40kHz,最后一个1为极性
 pwms = <&pwm0 0 25000 1>; 
 //enable的gpio脚
 enable-gpios = <&gpio1 1 GPIO_ACTIVE_HIGH>; 
 //默认开机到Android系统启动前的背光为第200个元素的值
 default-brightness-level = <200>;
 polarity = <1>;
 //背光级别,pwm为正极性时,0-255表示占空比从0-100%,反之则相反
 //有的屏幕最黑和最亮不是0-100%,例如最暗是20%,最亮是80%,那我们数组只需要设置50-200的范围
 brightness-levels = </*
 0 1 2 3 4 5 6 7
 8 9 10 11 12 13 14 15
 16 17 18 19 20 21 22 23
 24 25 26 27 28 29 30 31
 32 33 34 35*/36 37 38 39
 40 41 42 43 44 45 46 47
 48 49 50 51 52 53 54 55
 56 57 58 59 60 61 62 63
 64 65 66 67 68 69 70 71
 72 73 74 75 76 77 78 79
 80 81 82 83 84 85 86 87
 88 89 90 91 92 93 94 95
 96 97 98 99 100 101 102 103
 104 105 106 107 108 109 110 111
 112 113 114 115 116 117 118 119
 120 121 122 123 124 125 126 127
 128 129 130 131 132 133 134 135
 136 137 138 139 140 141 142 143
 144 145 146 147 148 149 150 151
 152 153 154 155 156 157 158 159
 160 161 162 163 164 165 166 167
 168 169 170 171 172 173 174 175
 176 177 178 179 180 181 182 183
 184 185 186 187 188 189 190 191
 192 193 194 195 196 197 198 199
 200 201 202 203 204 205 206 207
 208 209 210 211 212 213 214 215
 216 217 218 219 220 221 222 223
 224 225 226 227 228 229 230 231
 232 233 234 235 236 237 238 239
 240 241 242 243 244 245 246 247
 248 249 250 251 252 253 254 255>; 
};
&dsi {
             status = "okay";
             dsi_panel: panel {
             compatible ="simple-panel-dsi";
             reg = <0>;
             //绑定背光节点
             backlight = <&backlight>;
             //DSI相关配置,瑞芯微已经设置好了会去自动匹配对应的flags
             dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
             //format根据屏幕来选择,如果是24位就用MIPI_DSI_FMT_RGB888,18为就用MIPI_DSI_FMT_RGB666
             dsi,format = <MIPI_DSI_FMT_RGB888>; 
             dsi,lvds-force-clk = <800>; 
             dsi,lanes = <4>;
             dsi,channel = <0>;
             //启动时序相关
             enable-delay-ms = <35>;
             prepare-delay-ms = <6>;

             unprepare-delay-ms = <0>;
             disable-delay-ms = <20>;

             size,width = <120>;
             size,height = <170>;

             status = "okay";
            
             //mipi的初始化指令是通过TC358764_5_774_5XBG_DSI-LVDS_Tv11p_nm.xls的excel工具导出的
             //该工具只要在对应地方输入屏参,配置完后就能导出对应的指令。
             panel-init-sequence = [
                                29 00 06 3C 01 05 00 03 00
                                29 00 06 14 01 03 00 00 00
                                29 00 06 64 01 04 00 00 00
                                29 00 06 68 01 04 00 00 00
                                29 00 06 6C 01 04 00 00 00
                                29 00 06 70 01 04 00 00 00
                                29 00 06 34 01 1F 00 00 00
                                29 00 06 10 02 1F 00 00 00
                                29 00 06 04 01 01 00 00 00
                                29 00 06 04 02 01 00 00 00
                                29 00 06 50 04 20 01 F0 03
                                29 00 06 54 04 0A 00 28 00
                                29 00 06 58 04 00 05 6E 00
                                29 00 06 5C 04 02 00 0D 00
                                29 00 06 60 04 20 03 08 00
                                29 00 06 64 04 01 00 00 00
                                29 00 06 A0 04 06 80 44 00
                                29 00 06 A0 04 06 80 04 00
                                29 00 06 04 05 04 00 00 00

                                29 00 06 80 04 00 01 02 03
                                29 00 06 84 04 04 07 05 08
                                29 00 06 88 04 09 0A 0E 0F
                                29 00 06 8C 04 0B 0C 0D 10
                                29 00 06 90 04 16 17 11 12
                                29 00 06 94 04 13 14 15 1B
                                29 02 06 98 04 18 19 1A 06

                                29 02 06 9C 04 31 04 00 00


            ];
            //这个是标准的退出指令,默认照抄就行,不用改。
            panel-exit-sequence = [
                    05 05 01 28
                    05 78 01 10
            ];
            enable和reset的gpio脚
            power_ctr: power_ctr {
                    rockchip,debug = <0>;
                    power_enable = <1>;
                    bl_en:bl_en {
                            gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
                            pinctrl-names = "default";
                            pinctrl-0 = <&lcd_panel_bl_en>;
                            rockchip,delay = <0>;
                    };
                    lcd_en:lcd_en {
                            gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
                            pinctrl-names = "default";
                            pinctrl-0 = <&lcd_panel_lcd_en>;
                            rockchip,delay = <10>;
                    };
                    lcd_pwr_en: lcd-pwr-en {
                            gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
                            pinctrl-names = "default";
                            pinctrl-0 = <&lcd_panel_pwr_en>;
                            rockchip,delay = <10>;
                    };

                    lcd_rst: lcd-rst {
                            gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
                            pinctrl-names = "default";
                            pinctrl-0 = <&lcd_panel_reset>;
                            rockchip,delay = <6>;
                    };
            };
            //配置具体屏参
            disp_timings: display-timings {
                    native-mode = <&timing0>;
                    timing0: timing0 {
                            clock-frequency = <71100000>; 
                            hactive = <1280>;
                            vactive = <800>;
                            hsync-len = <10>;   
                            hback-porch = <40>; 
                            hfront-porch = <110>;

                            vsync-len = <2>;
                            vback-porch = <13>;
                            vfront-porch = <8>;

                            hsync-active = <0>;
                            vsync-active = <0>;
                            de-active = <0>;
                            pixelclk-active = <0>;
                    };
            };
    };
};
&pcie_clkreqnb_cpm {
 rockchip,pins =
 <4 24 RK_FUNC_GPIO &pcfg_pull_none>;
};
&hdmi_dp_sound {
 status = "okay";
};
&route_dsi {
 status = "okay";
 logo,mode = "center";
};
&route_hdmi {
 status = "disabled";
 logo,mode = "center";
};
&pwm0 {
 status = "okay";
};
&dsi_in_vopl {
 status = "disabled";
};
&dsi_in_vopb {
 status = "okay";
};
&hdmi {
 status = "okay";
};
&hdmi_in_vopb {
 status = "disabled";
};
&hdmi_in_vopl {
 status = "okay";
};
&dp_in_vopb {
 status = "disabled";
};
&i2c4 {
 status = "okay";
 gslx680: gslx680@41 { 
 compatible = "gslX680";
 reg = <0x41>;
 screen_max_x = <800>;
 screen_max_y = <1280>;
 touch-gpio = <&gpio2 2 IRQ_TYPE_LEVEL_LOW>;
 reset-gpio = <&gpio1 23 GPIO_ACTIVE_HIGH>;
 flip-x = <1>;
 flip-y = <0>;
 swap-xy = <0>;
 gsl,fw = <1>;
 };
};
&pinctrl {
lcd-panel {
    lcd_panel_reset: lcd-panel-reset {
        rockchip,pins = <1 13 RK_FUNC_GPIO &pcfg_pull_down>;
    };

    lcd_panel_pwr_en: lcd-panel-pwr-en {
        rockchip,pins = <0 12 RK_FUNC_GPIO &pcfg_pull_down>;
    };

    lcd_panel_lcd_en:lcd_panel_lcd_en {
        rockchip,pins = <1 4 RK_FUNC_GPIO &pcfg_pull_down>;
    };

    lcd_panel_bl_en:lcd_panel_bl_en {
        rockchip,pins = <0 1 RK_FUNC_GPIO &pcfg_pull_down>;
    };
};

};

7.8 编译&运行

/kernel/arch/arm64/boot/dts/rockchip/xxxxx.dts

./FFTools/make.sh -k -j8

sudo cp -r kernel/*.img /media/sf_ubuntuShare/img3399

 7.9 常见问题


1. 在点亮屏后刚开始有开机 logo 闪烁,向右偏移了近半个屏幕的长度,等问题。
重新确认 clock-frequence 后发现少打了一个 0 ,修改后解决了闪烁大偏移的问题。
2. 画面偏移
稍微降低 hs_clk ,由 504 降低到 496 解决。
3. 垂直方向会显示多一点内容。
调整 VFP 后解决,将 VFP 增大为 15 。
4. 有黑边
稍微增大 VBP 后解决,将 VBP 增大为 15。
5. 开机 android 最左边会被裁剪一部分
增大 HBP 后解决,将 HBP 由 10 增加到 30。
6. 显示偏移、图像位置偏差
timing 中的参数设置有误。优先确认。
看着图像调节前扫、回扫进行左右上下移动
7. 白屏
随机出现白屏有可能是静电问题,把LCD拿到头发上擦几下,如果很容易出现白屏那肯定就是静电问题了。另外一个在有Backend IC的情况下,也有可能bypass没处理好。
結束開機logo至android動畫出現之間出現閃屏或者閃白光的情況。原因:在這個時間點kernel會會對屏再次初始化,我們可以軟件上屏蔽第一次初始化動作從而解决。
8. 屏在进出睡眠或者显示过程中白屏
喚醒屏幕閃白光問題,說白了是背光早亮了,很有可能是下序列mdelay太久,改小點就沒有這個問題了。根本原因屏幕初始化序列下慢了。
sleep out(0x11)和 display on(0x29)之间需要 mdelay(120ms)左右。
9. 花屏
说明 lcd 初始化成功,但是没有 rgb 刷过来。
timing 中的参数设置有误。优先确认 pclk。
花屏 还可能是总线速度有问题。
开机就花屏最简单的解决方式是,在 Init 结束的地方加一个刷黑屏的功能。也可以在睡眠函数里加延时函数。
10. 屏幕闪烁
pclk 有问题
在最开始的时候,我的 pclk 漏了一个 0 ,为之前的 1/10 此时就有图像闪烁问题。
proch 有问题
在调试完后,我尝试将 proch 增加到极限,发现会出现图像闪烁的问题。
11. 屏幕抖动
测时序,延时不足
12.  屏幕闪动
通过调节电压来稳定,一般调节的电压为VRL、VRH、VDV和VCM
13. 唤醒闪屏问题
这是由於每次重新RST下序列過程delay久了導致,适當減少delay時間
14. 屏幕唤醒显示灰色底面
寄存器没有使能外部升压电路
15.  水波纹
通常都是rgb interface polarity導致,需要調整pclk hsync vsync de極性使之符合平台極性
16. 调节对比度
VRL、VRH、VDV和VCM,这些电压也可以用来调节亮暗(对比度)
也可以通过调节Gamma值来实现,要调节的对象为 PRP、PRN、VRP、VRN 等
17. 确认有没有 framebuffer 输出
要是改动了display这块的clk很有可能没有buffer输出的,可以通过cat /dev/graphyics/fb0 查看有没有输出字符
如果有说明是 mipi 还没有调通,如果没有说明是 fb 有问题

八、Excel附件

https://x509p6c8to.feishu.cn/docs/doccnaMagMhxFpLXApcnBkz3GjJ#sBF4N5

补充说明

如果在移植过程中,出现异常情况,可查询TC358764数据手册,具体细节查看寄存器配置说明。

  • 7
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值