STM32MP257 DCMIPP并行接口实战:BT.656老相机直连,省掉桥接芯片

STM32MP257 DCMIPP并行接口实战:BT.656老相机直连,省掉桥接芯片 做嵌入式视觉方案的人应该都有过这种经历客户手里压了一批老相机接口是BT.6568位并行、内嵌同步看起来和现在主流MIPI CSI-2完全是两个时代的东西。以前换主控平台基本都要加一颗并转MIPI的桥接芯片又贵又难买还得吃一版硬件改动。这次我用STM32MP257F-EV1做评估时发现这颗MPU上的DCMIPP控制器本身就带Parallel interface输入通道BT.656可以直接接进来连转换芯片都省了。这篇文章就把我在这块板子上把DCMIPP并行接口配成BT.656模式的完整过程写出来包括协议拆解、设备树设置、抓帧验证和一些排错经验。如果你正好在做工业相机升级、老旧视频设备改主控或者纯粹想了解DCMIPP除了接MIPI还能怎么玩这篇应该能帮你省不少时间。1. 从MIPI到并行DCMIPP为什么还要留一个Parallel接口1.1 都什么年代了BT.656为什么还存在先说一个容易让人误解的点BT.656不是什么淘汰垃圾格式它在工业视觉、广播设备、医疗影像、车载后装这些领域里还有大量存量设备在用。模组级的老相机比如很多CCD方案的模拟数字一体机输出的就是BT.656或者BT.601格式。这些设备的光学结构、镜座、传感器板是厂商花了很多年磨合好的客户升级主控板但不想动前端那套东西所以主控就必须能直接吃BT.656。另一个现实问题是成本。一颗并转MIPI的桥接芯片比如一些常见的转换方案单颗价格加上外围电路和改板成本在小批量工业项目里非常可观。如果主控本身支持并行接口方案就简单得多FPC排线一接设备树配一下软件层面就完事了。STM32MP257F-EV1这块板子的DCMIPP正好有两路输入能力一路CSI-2一路Parallel这就是我这次不转MIPI、直接走并行口的根本原因。1.2 并行接口和CSI-2接口的思路差异MIPI CSI-2走的是LVDS差分对特点就是高速、线少、抗干扰好但协议本身比较复杂接收端要做deskew、lane管理、包解析。并行接口则简单粗暴数据线一条条摆在那还有独立的像素时钟。DCMIPP把两种接口都做进去了好处很明显做一个摄像头底板既可以接现代MIPI传感器也可以接老并行传感器BOM不用分成两套一套PCB兼容多种前端。但并行接口也不是没有代价。它的像素时钟、数据线都靠MCU的GPIO复用引脚占用比MIPI多不少而且高速并行信号对PCB走线等长、地平面完整性要求比差分线高。好在BT.656本身是27MHz的时钟频率不算高普通的FPC连接器、正常的layout都能跑稳这属于老但皮实的接口。DCMIPP这块的设计思路和STM32MP1时代的DCMI相比最大的变化是它把像素处理流水线直接做进了控制器里。老DCMI接进来的裸数据基本就是原始帧后续crop、scale、格式转换都得靠DMA搬到内存里用软件处理或者依赖ISP去做。DCMIPP则把一组像素处理算子内建在控制器里输入进来的BT.656数据流可以先做格式解析、裁剪、缩放再输出到内存。后面我会单独讲这部分对实际项目的影响。2. 先用30秒搞懂BT.656把同步信息藏进视频流里2.1 BT.656相比BT.601到底少了哪三根线BT.601定义的是数字视频的电平、采样结构和时序范围它需要外部提供像素时钟、行同步、场同步再配合8位或10位数据线给到接收端。BT.656则把行场同步信息压缩成特定字节序列内嵌在数据流中一起传输这样接口只需要像素时钟加数据线不需要HSYNC、VSYNC这两根线连线从一路减掉三根控制信号后端接线的便利性就出来了。这个内嵌同步的设计理念实际上是在模拟视频时代做传输格式数字化时为了省线路、简化连接器而推出来的。今天看这个设计仍然有合理性特别是对线束连接器有严格限制的设备少两根信号线就是少两个失效点。具体到图像数据传输BT.656默认传的是YCbCr 4:2:2格式8位数据位宽下数据流的顺序是Cb、Y、Cr、Y交替排列。一行的有效像素数据前有SAVStart of Active Video行结束有EAVEnd of Active Video中间是有效视频区域行消隐期插了一段固定数据格式垂直消隐期还有若干行完全的空数据。2.2 SAV/EAV定时基准码与XY字节的位级拆解BT.656里面最重要的就是定时基准码四个字节依次是FF、00、00、XY。FF 00 00是固定的同步前缀最后的XY才是真正携带状态信息的字节。XY里真正有用的其实是三个标志位加上四个错误保护位位分布如下位bit7bit6bit5bit4bit3bit2bit1bit0含义固定1FVHP3P2P1P0其中F是场标志隔行扫描时用来区分奇数场和偶数场逐行模式下一般固定为0V是垂直消隐标志垂直消隐期间为1有效图像区域为0H是水平同步标志SAV里面H0EAV里面H1。P3到P0是根据F、V、H算出来的校验位公式如下P3 V XOR H P2 F XOR H P1 F XOR V P0 F XOR V XOR H这四个校验位设计得很巧妙它不只是简单的校验和而是保证每个合法的F、V、H组合对应的XY值和另外三个组合的XY值之间的汉明距离至少是2。也就是说如果传输过程中XY字节发生一位翻转接收端能知道这个值是非法的发生两位翻转也能检测到特定模式。对老式串行或者抗干扰差的链路来说这种设计能在接收端快速识别同步损坏代价只是几个异或门很划算。举个例子有效视频开始行的第一行F0、V0、H0那么P30、P20、P10、P00整个XY字节就是0x80。如果是有效视频结束的EAVF0、V0、H1则P31、P21、P10、P01XY就是0x9D。这个推导过程调试时如果自己用逻辑分析仪抓数据按这个公式就能快速判断相机输出的同步码是不是对的。2.3 一帧图像到底多大时序怎么算BT.656最典型的配置就是PAL制每帧625行其中有效数据行是576行每行总像素数为864其中有效像素是720。像素时钟27MHz按照每行864个像素计算一行耗时864/27MHz约32微秒625行正好是20毫秒对应25fps帧率。NTSC配置则是每帧525行有效行486行每行858像素同样跑27MHz帧率约29.97fps。所以如果你在DCMIPP里配置BT.656的高度时PAL填576NTSC填486别把两种制式的有效行数搞混。我自己就在早期调试时按720x576配置了NTSC相机结果图像下半部分一直是绿的原因就是有效高度不对导致DCMIPP在解析垂直消隐时把有效数据行算多了。分辨率这块有一个容易踩的坑BT.656的时钟频率和有效区域是绑定的720x57625fps对应27MHz。如果你强行把像素时钟提高比如从27MHz提到54MHz那每行总像素数和每帧总行数都不一样了帧率会变而且多数老相机根本不支持非标时钟。所以配置并行接口时像素时钟要和相机的输出时钟严格一致设备树里通常不用设置时钟频率因为并行接口只是被动采样DCMIPP不需要反向給相机供时钟。3. 硬件连接与Linux侧配置把DCMIPP Parallel接口切到BT.656模式3.1 EV1板上的实际接线怎么走STM32MP257F-EV1评估板上DCMIPP的并行接口信号一般会被引到板载的摄像头FPC连接器上。这个连接器的引脚定义可以在评估板原理图里查到通常包括D0到D7、PIXCLK以及电源和地。接线时我建议先看原理图确认一下DCMIPP的并行数据线复用的是哪个GPIO bank因为DCMIPP管脚和GPIO是共用的需要软件配置pinctrl。EV1板出厂一般会把默认的摄像头接口配置成MIPI CSI-2并行接口很可能没有引出或者复用在其它外设上。我这个板子上并行信号引到了FPC座但有几根线和以太网RMII在复用SDK默认配置里没打开需要自己检查。电气连接上除了数据线和时钟线最重要的一点是地线。BT.656虽然只有27MHz但8根数据线同时翻转时地反弹造成的噪声足够让接收端误采样。我的做法是FPC排线尽量短并且在靠近连接器的地方放一个0.1uF的退耦电容给DCMIPP的IO电源做好滤波。3.2 设备树里让驱动识别BT.656的关键属性Linux侧配置DCMIPP主要改设备树里和视频接口有关的节点。STM32MP2系列的内核里DCMIPP驱动一般挂在platform总线上节点路径类似dcmipp子节点里有一个portport下面就是endpoint。下面是BT.656并行接口场景下典型配置的骨架dcmipp { pinctrl-names default, sleep; pinctrl-0 dcmipp_pins; pinctrl-1 dcmipp_sleep_pins; status okay; port { dcmipp_parallel_ep: endpoint { remote-endpoint bt656_camera_ep; bus-width 8; hsync-active 0; vsync-active 0; pclk-sample 0; }; }; };bus-width 8表示8位并行这个没悬念。关键在于hsync-active和vsync-active都配成0。对BT.656来说物理上根本没有HSYNC和VSYNC这两根线那这里为什么还要写极性因为在部分ST驱动实现里驱动会通过检测这两个属性来切换同步模式如果都配成0驱动就认为输入流是内嵌同步也就是BT.656模式忽略外部H/V信号如果其中一个配1则按外部独立同步的BT.601类似模式处理。这种做法在ST早期DCMI驱动里就有DCMIPP延续了这个设计。pclk-sample 0表示在像素时钟的下降沿采样数据1则是上升沿。BT.656本身没有强制规定数据在哪个沿稳定完全取决于传感器输出。这里没有任何理论可以预判只能实测两种配置看哪种出图正常。这是整个调试里最典型的一个坑后面我会细说。另外如果内核版本比较新DCMIPP驱动也可能识别标准video-interfaces里的bus-type属性用来声明接口类型是并行还是CSI-2。这个要看具体SDK的驱动实现最稳妥的办法是打开内核设备树中的参考dts看一下官方给并行传感器是怎么配的。3.3 media pipeline的路由与格式协商DCMIPP控制器在Linux media controller框架里不是一个简单的video设备它内部有多个entity比如输入侧有一个input entity后面接着几个pipe实体每个pipe可以独立配置crop和scale最后每个pipe再对应一个/dev/videoX节点。这意味着光配好设备树还不够上电后media pipeline默认是断开的必须用media-ctl显式配置路由和格式。以典型的单路输出场景为例我需要把这几个entity串起来media-ctl -d /dev/media0 -V dcmipp_input:0[fmt:UYVY8_2X8/720x576] media-ctl -d /dev/media0 -V dcmipp_pipe1:0[fmt:UYVY8_2X8/720x576] media-ctl -d /dev/media0 -V dcmipp_pipe1:1[fmt:UYVY8_2X8/720x576]这里UYVY8_2X8是media bus format的写法表示8位宽UYVY两样本打包。BT.656进来的是YCbCr 4:2:2在media层面对应的就是UYVY。分辨率720x576是PAL制这个要和相机实际输出一致。做完media-ctl设置之后还不能直接抓帧因为video节点的format和media层的format也要同步。用v4l2-ctl再设一次v4l2-ctl -d /dev/video0 --set-fmt-videowidth720,height576,pixelformatUYVY这套流程的前后顺序有讲究。如果先设video节点再设media层或者只设其中一方应用层拿到的格式和实际DMA搬运的数据格式对不上轻则花屏重则驱动报EINVAL。我的经验是每次改完media-ctl之后都重新执行一次v4l2-ctl --set-fmt-video保证两边一致。4. 抓帧实测从黑屏到正常出图的排错链路4.1 用v4l2-ctl确认数据通路是否打通配置完成后先别急着写复杂的应用程序直接用v4l2-ctl抓一帧验证通路。v4l2-ctl -d /dev/video0 --set-fmt-videowidth720,height576,pixelformatUYVY --stream-mmap --stream-count1 --stream-toframe.raw抓出来的raw文件可以用RAW查看器打开或者自己写个小脚本把它转成PNG。Linux下最省事的办法是用ImageMagickconvert -size 720x576 -depth 8 -interlace plane YUV:frame.raw frame.png如果这一步能正常出图说明从相机到DCMIPP到内存的链路完全通了。如果出不来多半要按下面的链路排查。这里特别提醒raw文件里的UYVY数据直接按YUV去解释看到的灰度图是带颜色的条纹才是正常的不要一看到灰不拉几的图就以为数据有问题。想快速判断数据内容可以先看单通道Y的数据如果能看到物体轮廓基本就说明数据进来了。4.2 常见问题的定位顺序先看时钟再看信号最后查配置我在这次调试中遇到过几类问题按排查顺序整理一下。**第一类全黑或全绿图像。**这种情况首先要确认DCMIPP有没有锁到同步信号。如果BT.656的SAV/EAV一直没被识别控制器会把整帧当空白处理输出全绿或全黑。这时候用示波器测PIXCLK引脚的波形确认有27MHz方波再测D0到D7有没有数据跳变。如果时钟和数据都有问题多半在设备树极性或媒体层格式配置上。还有一种情况FPC线没插紧或地线没接好数据也能跑但全是毛刺DCMIPP想锁也锁不上。检查信号时别忘了用示波器看数据线的沿质量不一定要多漂亮但至少不能有大量振铃。**第二类花屏、斜纹。**这种最典型的根因是pclk-sample极性反了。BT.656没有同步头之外的额外对齐机制采样沿不对每bit或者每字节的采样点就会落在数据跳变沿上抓出来的数据就是乱的。我的习惯是两种极性都试一遍每次改完在设备树上改配置后重新编译设备树、重启通常都能解决。如果是花屏但偶尔能出几行正确图像还有一个可能media pipeline里crop配得不一致。比如输入是720x576但pipe里配了1280x720的裁剪窗口DCMIPP按固定长度消隐期解析后面的行数据就会错位。这种错位花屏和极性花屏的视觉特征不一样极性错是全局完全乱码配置错则是部分行正确、部分行错位。**第三类图像左移或右移左右有黑边。**这通常是像素时钟采样沿选对了但行消隐期的解析有偏差。BT.656在SAV之后、有效数据之前的水平消隐区有固定的数据填充如果DCMIPP配置的有效像素起始位置偏了图像就会整体平移。这个调整一般要动驱动里的水平前肩参数或者检查相机侧输出的时序是否存在非标准偏移。遇到这种情况先看相机输出的精确时序别急着改驱动。**第四类颜色整体偏绿或者偏紫。**颜色不对往往是格式协商的问题。BT.656上来是YCbCr 4:2:2如果DCMIPP输出的格式被设置成了RGB888应用层按RGB解释YUV数据颜色必然不正常。这种问题靠调设备树没用要看media-ctl和v4l2-ctl里设置的格式是不是都是UYVY。**第五类帧率不对或者帧率忽高忽低。**如果输入的BT.656是25fps的视频源DCMIPP的输出帧率也应该是25。如果应用层拿到的帧率变成50或者12.5大概率是驱动在隔行转逐行或者场同步处理上出了问题。需要核对相机的隔行还是逐行配置BT.656可以承载隔行数据F标志位标志奇偶场。DCMIPP本身对隔行数据的处理策略不同内核版本有差异遇到帧率问题时要查一下驱动源码里对FIELD标志的处理。4.3 实测中容易忽略的DCMIPP细节有几个细节是这次调试后期才注意到的写在这里给以后做类似项目的朋友提个醒。第一设备树里hsync-active和vsync-active虽然都配成了0但DCMIPP驱动仍然可能在probe阶段对这两个属性做合法性检查。不同内核版本的行为不一致有的版本如果检测到两个属性同时为0会主动打印一条embedded synchronization detected之类的提示有的版本则会拒绝初始化。升级内核后行为可能会变新版dts里最好显式加注释说明这是BT.656模式。第二DCMIPP的并行接口输入像素时钟最高能到多少一定要去查板子对应的数据手册。MP257F的DCMIPP支持多个档位的并行时钟但EV1板上的走线实际能跑多高还得看具体的FPC连接器质量和走线长度。BT.656的27MHz没问题但如果你接的是一个更高分辨率的BT.1120设备像素时钟翻倍信号完整性就要重新评估。第三DCMIPP的多个pipe输出是独立的。假如你配置了DCMIPP_0输出720x576的全分辨率同时让DCMIPP_1输出一个320x240的缩放预览流这两个pipe的crop参数是独立配置的但输入端的格式必须一致。调试时如果一条链路出现格式协商失败可以先只保留一个pipe把单路跑通再扩展多路能少很多干扰变量。第四别忽略初始化时相机侧的上电时序。BT.656相机本身可能没有这个要求但如果你的前端是一个带解码功能的模拟前端芯片它输出的BT.656流需要先稳定运行几十毫秒DCMIPP才能抓到有效的垂直消隐。Linux驱动里如果没做时序延迟可以在用户空间通过初始化脚本延时几秒再开视频流。这个坑在评估阶段很容易被忽略因为demo板上的相机经常是长供电的但实际产品里由GPIO控制相机电源时上电时序问题会直接导致首帧黑屏。5. 我还想多说几句BT.656方案的扩展与替代5.1 从BT.656到BT.1120并行接口还能顶多久BT.656本身只能承载标清信号带宽上限就在那里到了1080i或者720p时代行业推出了BT.1120同样是并行内嵌同步数据是YCbCr 4:2:2但时钟频率提高到了74.25MHz或者148.5MHz数据位宽也支持12位或16位。DCMIPP的并行接口能不能直接支持BT.1120取决于它对像素时钟的承受能力以及内嵌同步解析逻辑能否识别BT.1120的EAV/SAV序列。如果DCMIPP硬件只能解析BT.656的语法那即使电气上能采到软件层也难以正确拆出帧。这个需要看具体芯片手册里的DCMIPP特性表不能想当然。如果确实不支持那就把它当纯并行接口用BT.1120老设备该加转换就加转换不必为情怀买单。从产品选型的角度我觉得并行接口在DCMIPP里的存在价值主要还是兼容存量设备。新设计如果还没定点前端传感器直接上MIPI CSI-2是更省心的选择毕竟新传感器、镜头模组、ISP生态全都在往MIPI走。但如果你要维护的是一个已经在产的老产品用MP257换主控、保留原有BT.656前端这个并行口就是兜底方案省下桥接芯片和改板成本BOM、layout、供应链都能少操很多心。5.2 DCMIPP除了格式转换还能做什么这次调试过程中我顺带验证了DCMIPP的crop和scale能力对应用层来说意义不小。传统方案里相机输入是720x576如果最终显示区域只有640x480你会面临两个选择让相机出低分辨率但很多BT.656相机不支持自定义分辨率或者在CPU/DSP里做缩放。这两种方式一个是灵活性差一个是占CPU。DCMIPP则是在DMA搬运之前由硬件完成裁剪和缩放输出到内存的就是最终要用的分辨率。DCMIPP还支持多pipe同时输出不同分辨率也就是说DCMIPP_0可以输出全分辨率用于算法分析DCMIPP_1可以输出小分辨率用于本地预览两个pipe互不干扰。这个特性在很多需要记录预览双路并发的产品里非常实用省掉了上游把同一帧数据拆分给两个消费者的问题。另外一个值得提的是DCMIPP的像素处理能力不仅限于格式转换。它内部还有一些基本的像素效果处理包括亮度和对比度调整。虽然这些功能不如独立ISP那么强大但对于BT.656这种老接口的标清信号来说在硬件层面先把亮度和对比度调整好再用应用层做后续处理整个pipeline的压力会小很多。5.3 如果让我重新选一次还会走并行口吗认真想过这个问题。如果这是一个从零开始的全新项目前端传感器还没有定点我会直接选MIPI传感器理由很简单DCMIPP的CSI-2通道在驱动成熟度、分辨率扩展性、信号完整性方面都比并行口更有优势MP257这种量级的主控匹配25fps标清输入其实有些浪费。但如果项目是老相机新主控的升级改造或者前端已经锁定了一款只出BT.656的传感器那走DCMIPP并行口就是当前最优解。省掉桥接芯片不只是省几块钱成本的事还意味着少了一颗需要额外写驱动的芯片少一个调试变量换来的稳定性收益是实打实的。从我这次的实际体验来说DCMIPP并行接口搭BT.656整套方案的软件配置复杂度主要集中在前三板斧设备树极性、media pipeline路由、格式一致性。这三步走通了后面就是稳定的数据流。老接口并不可怕可怕的是对老协议的理解停留在表面遇到花屏就盲目瞎试。只要把BT.656的同步码、XY字节、时序结构吃透再配合DCMIPP的调试手段老相机在新板卡上跑起来也就是一个下午的事。