STM32MP257 DCMIPP并行接口实战:BT.656老相机直连,省掉桥接芯片
2026/8/31 22:02:07 网站建设 项目流程

做嵌入式视觉方案的人,应该都有过这种经历:客户手里压了一批老相机,接口是BT.656,8位并行、内嵌同步,看起来和现在主流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交替排列。一行的有效像素数据前有SAV(Start of Active Video),行结束有EAV(End of Active Video),中间是有效视频区域,行消隐期插了一段固定数据格式,垂直消隐期还有若干行完全的空数据。

2.2 SAV/EAV定时基准码与XY字节的位级拆解

BT.656里面最重要的就是定时基准码,四个字节依次是FF、00、00、XY。FF 00 00是固定的同步前缀,最后的XY才是真正携带状态信息的字节。XY里真正有用的其实是三个标志位加上四个错误保护位,位分布如下:

bit7bit6bit5bit4bit3bit2bit1bit0
含义固定1FVHP3P2P1P0

其中F是场标志,隔行扫描时用来区分奇数场和偶数场,逐行模式下一般固定为0;V是垂直消隐标志,垂直消隐期间为1,有效图像区域为0;H是水平同步标志,SAV里面H=0,EAV里面H=1。

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字节发生一位翻转,接收端能知道这个值是非法的;发生两位翻转,也能检测到特定模式。对老式串行或者抗干扰差的链路来说,这种设计能在接收端快速识别同步损坏,代价只是几个异或门,很划算。

举个例子,有效视频开始行的第一行,F=0、V=0、H=0,那么P3=0、P2=0、P1=0、P0=0,整个XY字节就是0x80。如果是有效视频结束的EAV,F=0、V=0、H=1,则P3=1、P2=1、P1=0、P0=1,XY就是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填576,NTSC填486,别把两种制式的有效行数搞混。我自己就在早期调试时按720x576配置了NTSC相机,结果图像下半部分一直是绿的,原因就是有效高度不对,导致DCMIPP在解析垂直消隐时把有效数据行算多了。

分辨率这块有一个容易踩的坑:BT.656的时钟频率和有效区域是绑定的,720x576@25fps对应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,子节点里有一个port,port下面就是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-activevsync-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-video=width=720,height=576,pixelformat=UYVY

这套流程的前后顺序有讲究。如果先设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-video=width=720,height=576,pixelformat=UYVY --stream-mmap --stream-count=1 --stream-to=frame.raw

抓出来的raw文件可以用RAW查看器打开,或者自己写个小脚本把它转成PNG。Linux下最省事的办法是用ImageMagick:

convert -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-activevsync-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的调试手段,老相机在新板卡上跑起来,也就是一个下午的事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询