拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

全志T527 MIPI DSI调试复盘:时钟计算、Deskew校准与FPC排线三大坑

全志T527 MIPI DSI调试复盘:时钟计算、Deskew校准与FPC排线三大坑

MIPI DSI,调过屏的人都知道,这接口最烦人的地方不是协议难懂,而是链路太长:从framebuffer里的像素到屏幕真正点亮,中间隔着显示引擎、时序控制器、DSI控制器、D-PHY、排线、面板驱动IC,任何一个环节掉链子,表现出来往往都是同一个结果——黑屏。这周我在全志T527上适配一块720x1280的触摸模组,主控是ST7701S,就被这条链路折磨了整整一天。这篇是BSP调试系列的第11篇,我把整个过程做个复盘,重点写三个我踩得最深的坑:时钟计算想当然、deskew calibration没重视、FPC排线插接太随意。同样在全志平台上调MIPI DSI屏幕的朋友,这篇文章可以当一份排错手册来用。

1. 先聊这次平台:T527的显示链路与调试目标

1.1 T527的显示子系统结构

全志T527这颗SoC,单论外设丰富程度,在工业物联网领域算是比较能打的,显示方向同时保留了RGB并口、LVDS、eDP和MIPI DSI好几类接口。MIPI DSI主要用于中尺寸液晶模组,比如7寸、10.1寸这类平板或工控屏,分辨率从720x1280到1080x1920不等。

在BSP层面,全志的显示链路是一个很经典的流水线:DE(Display Engine)负责图层合成和像素格式转换,TCON(Timing Controller)负责输出像素时序,DSI Controller负责把并行像素数据打包成DSI协议报文,最后由D-PHY在物理层把报文转成一对对差分信号送出去。这块的调试节点在内核里一般以sunxi开头,打开调试文件系统可以看到不少显示相关的状态。

这里我特别想强调一个观点:调MIPI DSI,最重要的一点是先建立"链路意识"。一个像素从framebuffer走到屏幕上,要经过合成、时序、打包、串行化、传输、解包六七个环节。出问题的时候,你的第一件事不是盯着屏参数表看,而是先判断这个问题出在链路的哪一段。链路意识建立起来之后,排查才有方向。

1.2 这次要调的ST7701S模组参数

我这次拿到的模组屏厂给的规格是这样:

  • 分辨率:720 x 1280
  • 接口:MIPI DSI,4条数据lane
  • 色彩格式:RGB888,即24bpp
  • 面板驱动IC:ST7701S
  • 工作模式:Video Mode,Burst模式
  • 背光:独立供电,PWM调节

ST7701S这颗IC在720x1280这个分辨率段非常常见,兴唐微(Sitronix)的方案,很多屏厂都拿它出模组。后续章节里面板驱动的部分,我都以这颗IC为主线来讲。

我建议任何人都别在拿到屏厂资料之前就动手写设备树。所谓资料,至少有四样:接口时序页(含htotal/vtotal、像素时钟)、命令初始化表、上下电时序图、模组规格书。少一样,后面都可能埋雷。

1.3 和瑞芯微那边的适配方式有什么不同

网络热词里有人搜"rk3588 linux 适配mipi屏幕",说明瑞芯微平台调MIPI的讨论非常多。RK3588那边基本是标准DRM框架,dts里挂一个panel节点,panel驱动实现drm_panel的回调接口就行,生态比较统一,社区资料也相对好找。

全志这边的情况不太一样。如果你拿到的BSP是老一些的版本,显示链路可能还是传统的FBDEV框架加上私有的lcd驱动,部分配置不是放在dts里,而是放在sys_config.fex甚至uboot环境变量里。所以我在T527上做的第一件事不是改代码,而是确认手里内核版本到底走的是哪一套框架,再去决定到哪里改参数。这个确认动作能省掉大量无用功。

2. 动手之前先算清楚:像素时钟、lane速率与DPHY频率

2.1 MIPI DSI带宽的推导关系

MIPI DSI链路调参,本质上只有三个数:像素时钟、总带宽、单lane速率。这三个数之间有明确的公式关系:

  • 像素时钟:pixel_clk = htotal × vtotal × refresh
  • 总带宽:total_bitrate = pixel_clk × bpp
  • 单lane速率:lane_rate = total_bitrate / lane数

lane_rate是后续D-PHY配置、时钟源选择、deskew校准窗口的核心依据,不能随手抄别的平台的数值,必须自己算一遍。很多第一次调MIPI的朋友,习惯直接从别的项目里复制一份时钟配置,结果屏亮了但闪烁,或者高低温下莫名花屏,都是因为速率的余量和相位关系不对。

2.2 720x1280@60Hz的完整算例

我这块屏,屏厂给的参数是htotal 880、vtotal 1300,包含了水平垂直blank区域。代入公式:

pixel_clk = 880 × 1300 × 60,约等于68.64MHz。 total_bitrate = 68.64MHz × 24bpp,约等于1.65Gbps。 4条lane时,lane_rate = 1.65Gbps / 4,约等于411.84Mbps。

这里有个特别容易绕晕的细节:MIPI D-PHY的时钟lane是DDR双沿采样,所以时钟lane的物理频率约等于lane_rate的一半,也就是206MHz附近。我去配置时钟树的时候,要找的是206MHz附近合适的PLL频率点,而不是直接对着411.84这个数字填。同一个项目里,很多人在这一步会差出一倍,结果DPHY怎么都收敛不了。

另外还想提醒一件事:视频模式下面的DSI链路不是100%时间都在传像素。水平blank区域里,链路要么休息、要么只发同步包,所以实际配置的lane_rate通常会比理论值多留一些余量,常见做法是留10%到30%。余量留太满,信号质量容易崩;余量不够,带宽可能在极端画面下顶不上去,表现为高帧率下滚屏或闪屏。

2.3 video mode的burst和non-burst怎么选

MIPI DSI视频模式下面还细分了non-burst with sync pulses、non-burst with sync events、以及burst mode。Burst模式的好处是,水平blank期间可以把DSI链路切回低功耗状态休息,到了有效显示区再提高速率把整行像素一次性发完,带宽利用率高、屏体功耗也低。

屏厂给的初始化序列和时序参数,通常都是基于burst模式设计的。我见过有人图省事把BSP默认的burst改成了non-burst,结果像素时钟明明够,屏幕却开始闪烁。因为non-burst模式下在blank区还要持续发同步包,DPHY的切换频率变高,时序余量和burst完全不同。所以我建议,除非你明确知道屏厂支持哪种模式并给出了对应参数,否则不要动这个配置。

3. 把面板驱动跑起来:ST7701S初始化序列的调试细节

3.1 panel驱动的注册路径

在全志BSP里,panel驱动通常实现为platform_driver,probe时获取reset引脚、电源和背光资源,等到显示开启流程里再真正调用初始化命令发送。panel驱动要想正常probe,前提是DSI控制器已经注册成功,也就是说dts里节点的status要按依赖关系从底到上逐个打开。

调试早期,我习惯先确认三件事:第一,dmesg里有没有panel设备probe成功的log;第二,DSI控制器节点有没有在系统里初始化成功;第三,通过调试文件系统看panel的state是不是ready。这三件事都过了,才开始往下查命令序列。

3.2 ST7701S初始化序列的来龙去脉

ST7701S的初始化序列看起来很像天书,比如开头经常是:

FF 77 01 04 04 00

这一串什么意思呢。在MIPI DSI协议里它是一条generic long write命令。ST7701S把它的寄存器分成多个bank,你需要先发一个特定的页面切换序列,把后续命令导向正确的寄存器页面,然后才能配置分辨率、porch、gamma、电压这些参数。

我把拿到手的几十条初始化序列分成四段来理解:

  • 页面切换段:用于锁定ST7701S的厂商寄存器页面
  • 显示参数段:分辨率、porch、色彩格式、lane数
  • 面板特性段:扫描方向、反色控制
  • 电压与gamma段:VCOM、gamma曲线微调

这样的分段方式,在后续验证和改错时非常有用。我这次就遇到过屏能亮但整个画面偏绿的情况,最后定位到是gamma段里某个电压寄存器写偏了一位。

3.3 怎么验证初始化序列有没有真发出去

一个非常有效的验证方法:把整段初始化序列去掉,只发0x11(sleep out)和0x29(display on)。如果屏幕能从睡眠状态醒来,哪怕显示的是内部自检画面或白屏,都说明命令通路是通的,问题一定在具体寄存器配置上。如果这样都不亮,那问题大概率发生在物理链路或者电源时序,而不是寄存器内容。

有条件的话,用带MIPI协议解码功能的逻辑分析仪抓一下启动阶段的命令,确认每条命令的payload和发送间隔是否和配置一致。没有协议分析仪时,也可以通过BSP的调试开关把命令打印出来逐条比对,虽然麻烦一点,但也足够定位大都数问题。

3.4 电源与同步时序里容易踩的坑

屏的上电时序要求往往写在规格书里:先是主电源,再是IO电源,然后reset引脚拉低一段最小时间,再拉高,最后才是发初始化命令。这个顺序错一点,屏有时也能亮,但工作极不稳定。

我这次就遇到过一种情况:reset引脚被BSP里的某个pinctrl配置影响,电平始终拉不干净,面板驱动读到的reset状态永远不对。查了快两个小时才发现是引脚复用冲突,另外一个驱动模块把这个引脚申请走了。这类问题靠看代码很难发现,因为你看到的dts配置是对的,实际运行时的占用者却是别人。

4. 设备树与时钟树:逐级打开DSI通路

4.1 dsi和panel节点的写法

全志平台调MIPI,通常至少要打开三处节点:TCON、DSI控制器、panel。我这次用的dts节点简化长这样:

&dsi { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&dsi_pinctrl>; panel@0 { compatible = "st7701s,720x1280"; reg = <0>; reset-gpios = <&pio 4 20 GPIO_ACTIVE_LOW>; power-supply = <&reg_3v3>; backlight = <&backlight>; }; };

看起来简单,但有几个容易漏的点。reset引脚有没有被别的驱动复用,这个我在前面提过;power-supply对应的regulator在跑起来之后实际输出电压对不对,用万用表量一下比什么都靠谱;backlight的PWM频率和极性如果不一致,屏幕亮度会异常,甚至有些屏会出现LC振荡噪声。

4.2 时钟树配置的原则

时钟树必须和第2节算出的lane_rate严格对齐。全志BSP里一般会把TCON和DSI相关的时钟速率写在assigned-clock-rates里。我的建议是,先把pixel_clk和lane_rate确定,再倒推PLL的配置,并且尽量让PLL到最终输出之间是整除关系,减少时钟抖动。

我这次就把assigned-clock-rates从默认的值改成了跟模组规格匹配的206MHz附近的值。改完再验证的时候,花屏现象明显少了。有人可能觉得这没啥,但分辨率变了、刷新率变了,这些assigned-clock-rates全部要跟着变,这不是一个可以"不管它"的参数。

4.3 冷启动和热复位的差异

这次调试有个现象值得单独记录:每次在系统运行中执行热复位,屏幕都能正常出图;但关机断电后再冷启动,第一次进入Linux时黑屏的概率非常高。一开始我怀疑是屏体电源时序,查了一大圈才发现是DSI控制器在冷启动时没有等D-PHY完全稳定就开始发初始化命令,属于BSP里一个时序窗口问题。

这种问题在标准DRM框架的RK平台上比较少见,全志的老BSP里却不算罕见。排查思路是:分别录制冷启动和热复位的完整串口log,对比DSI控制器和DPHY的初始化时刻,基本就能看出是谁先谁后。

5. 黑屏复盘:这次我走的完整排查链路

5.1 先从日志缩小搜索范围

我的排查顺序,永远是先从内核日志下手:

  1. panel驱动probe成功没有
  2. DSI控制器在发命令时有没有报TX timeout或者LANE错误
  3. TCON有没有抛data path异常

日志都正常但屏幕不亮的时候,我会去确认一个信息:uboot阶段能不能把屏点亮。Linux下不亮、uboot下能亮,基本说明屏体和面板参数没有大问题,问题出在Linux侧的时钟或者电源配置;反过来Linux能亮、uboot不亮,那大概率要去查uboot的lcd参数和配置来源。

这次在日志阶段有个关键词很显眼:DSI控制器在发送初始化命令时连续报了几条host timeout。按我经验,这多半是D-PHY根本没有进入高速模式,命令发出去没人收。

5.2 逻辑分析仪看LP到HS的切换

接着我用了带协议分析能力的逻辑分析仪。MIPI DSI在进入高速模式之前,D-PHY要经历固定的LP序列:从LP-11切到LP-00,再进入HS-Zero,之后才真正开始传高速数据。如果这个切换时序不对,接收端压根不会进入HS状态。

我抓到的波形显示,data lane上的bit流确实有,但非常不稳定,协议解码只能解出不到一半的数据包。当时的第一判断不是寄存器问题,而是物理层信号质量问题。这就引出了后面那个核心问题:deskew calibration。

5.3 MIPI D-PHY deskew calibration这个坑

关键词里被反复提到的"MIPI DPHY deskew calibration",这次还真是主角。它的作用是:D-PHY为了保证多条数据lane和时钟lane在接收端对齐,会在初始化阶段用一个训练窗口测量每一条lane之间的延迟差,然后调整接收端的采样点。

我遇到的现象是:冷启动后前十行花屏,半秒后自动恢复,有时候干脆一直花屏。这种一会好一会坏的状态,最迷惑人。我先把lane_rate从411.84Mbps降到350Mbps左右,花屏立刻消失。这一步基本锁定了根因——信号裕量不足,deskew校准没有一次成功。

之后我把FPC排线重新拔插压平,又回到410Mbps附近测试,校准寄存器的状态恢复正常,花屏消失。这里想说的经验是:看到花屏、随机噪点,不要一上来就怀疑屏的初始化参数,先确认deskew校准有没有通过。有的BSP日志会打印一行,有的压根不打印,你需要主动把DPHY校准状态寄存器读出来看。

5.4 低level的物理链路排查要排在前

这次最花时间的其实是第一步:我一开始在软件参数上反复试,后来才发现排线接触问题。软件上改来改去毫无变化,改成物理链路反而立竿见影。现在我的习惯是,只要屏不亮又伴随花屏,先花十五分钟把排线、连接器、金手指检查一遍,确认物理链路干净之后,再回头改软件。这个顺序倒过来,往往就是几个小时的无用功。

6. FPC排线:调试现场最容易翻车的物理细节

6.1 FPC插拔的标准步骤

热词里有"mipi口插入fpc的视频"——别看这是一件小事,现场插坏的真的不少。MIPI DSI接口用的FPC连接器,常见两种:掀盖式(flip-lock)和抽屉式(pull-lock),操作细节有区别,但共同原则是一样的。

正确步骤是:断电操作;确认FPC补强面和金手指朝向,不要摸金手指;插入时对齐连接器开口,保证排线两端等高,不要一边深一边浅;压合锁扣时要均匀用力,听到"咔哒"声后,轻轻拉一下FPC确认已经锁紧。

常见的错误:带电插拔,轻则接触不良,重则烧掉屏端驱动IC甚至主机端的DPHY;插线时没用镊子辅助,排线歪斜进入导致金手指翻边;锁扣没有完全压合,机器振动几次之后屏就开始闪。

6.2 排线本身的信号完整性问题

MIPI差分对要求100Ω差分阻抗,FPC越长、弯折越急,损耗和lane之间的skew就越大。这次花屏问题里,有一部分就是FPC一端金手指有一根微微翘起导致的。重新压平之后再没复发。

对于超过15厘米的FPC,最好在接收端用示波器看眼图,确认幅度、上升沿和lane间的偏斜都在合理范围内。FPC走线附近要有足够的地参考,差分对两侧有条件的话加地线包裹。这些板级细节,在调软件调到头昏脑胀的时候往往想不到,但恰恰是它决定了deskew calibration能不能通过。

7. 几条花时间换来的调试习惯

7.1 资料先行,变更留痕

这次调试之后,我把自己的流程固化成了几条。第一,屏厂资料四件套缺一不可;第二,每次改动只改一个变量,调MIPI的时候变量太多,同时改两处之后出了新问题,根本分不清是谁的锅;第三,每一版修改都保留dts和驱动的diff记录,配合串口log一并留档。很多难以复现的偶发问题,最后都是靠这些历史diff才定位到的。

7.2 有条件就搭FPGA验证台架

另一个有价值的做法是,用FPGA实现MIPI DSI发送端,做一个裸屏测试台架。在改Linux驱动之前,先用FPGA把屏点亮,可以把"屏体和排线"的硬件问题与"SoC配置"的软件问题彻底解耦。FPGA里的MIPI控制器和全志BSP的实现方式肯定不一样,但它能验证屏幕本身是不是好的,也能帮助你观察信号质量。

我个人体会是,这次T527的MIPI DSI调试,真正费时间的不是协议本身,也不是驱动框架,而是时钟计算的一环、deskew calibration的一环、FPC插接的一环。这三样看起来都很不起眼,但任何一样出问题,都足以让屏幕从"可以点亮"变成"永远点不亮"。希望这篇记录能让后面调屏的人少走一次弯路。

返回列表