尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

STM32MP1 + MIPI CSI-2 摄像头调试:从设备树到V4L2链路打通

STM32MP1 + MIPI CSI-2 摄像头调试:从设备树到V4L2链路打通 去年我手里有个项目要用 STM32MP157 做一个轻量级的视觉检测设备摄像头选了 MIPI CSI-2 接口的 OV5640 模组。我原先玩 STM32F4 的 DCMI 并口摄像头还算顺手以为这次顶多是多接几根差分线、改几个寄存器的事。真跑起来才知道STM32MP1 这种带 Cortex-A7 的 MPU摄像头链路完全不是单片机时代的玩法内核驱动、设备树、media controller 拓扑、V4L2 参数任一个环节不对画面就是出不来。折腾了小一个月把整套链路摸了个遍。这篇就把 STM32MP1 连接 MIPI CSI-2 摄像头的关键点、踩过的坑和排查思路写出来给准备在这个平台上做视觉方案的朋友做个参照。这里说的“序列产品”指的是 STM32MP151、STM32MP153、STM32MP157 这一族。命名上大家用得最多的是 MP157带 GPU 和更丰富的外设官方评估板也是它。CSI-2 host 这套外设MP157 上是明确具备的具体到某个子型号要查对应数据手册。内容里涉及的内容基本围绕 MP157 Linux 主线内核 OV5640 模组展开这套组合也是目前资料最全、最不容易卡死的方案。1. STM32MP1 的 CSI-2 接口与 DVP 的本质区别1.1 STM32MP1 的摄像头外设全家桶STM32MP1 作为一颗异构 MPU硬件上集成了 Cortex-A7 和 Cortex-M4。跑 Linux 时A7 负责主控制M4 可以用来做实时任务。摄像头这条链路牵涉到的外设主要有三个角色CSI-2 host controller接收来自图像传感器的 MIPI D-PHY 串行数据进行协议解析、字节拆包、数据格式转换最终输出并行数据流。DCMIDigital Camera Memory Interface这是 ST 传统的数字摄像头接口可以接收并行数据也可以接收从 CSI-2 host 转发过来的数据然后把数据写成 YUV/RGB/Bayer 格式存入内存。DMA把 DCMI 输出的数据搬运到 DDR供 CPU 或 GPU 后续处理。在 Linux 侧的体现就是驱动目录drivers/media/platform/st/stm32/下同时存在 DCMI 驱动和 CSI-2 host 相关驱动。硬件上 CSI-2 host 和 DCMI 是级联关系传感器 - MIPI 差分线 - CSI-2 host - 并行总线 - DCMI - DMA - DDR。这个结构和单片机时代直接拿 GPIO 并口读传感器完全不同。以前是传感器自己输出 PCLK、VSYNC、HSYNC、D0-D7MCU 靠外部中断和 DMA 去采样时序全在传感器一侧。现在 MIPI 信号是高速差分串行SoC 端必须有一个专门的 IP 去做解串和协议解析软件上更是一套全新的框架。1.2 DVP 并口接口的瓶颈到底在哪不是说要彻底否定 DVP我在很多低分辨率、低帧率的项目里还用它简单粗暴。但 DVP 的瓶颈是物理性的线多至少 8 根数据线加 PCLK、VSYNC、HSYNC奔着 12 根往上走。PCB 走线要等长超过一定频率串扰和 EMI 都很难压。速率上不去并行总线要保证每个 bit 的建立保持时间PCLK 到了几十 MHz 以后线间 skew 就成了大问题。实际做到 1080p30fps 已经很费劲再做高分辨率高帧率更是不现实。抗干扰差并行线之间的串扰以及对外辐射在中高速场景下会非常头疼。这也是为什么现在手机、平板、工业相机几乎清一色 MIPI CSI-2。STM32MP157 这种定位的芯片既然要跑 Linux、要做视觉类应用就不可能只靠 DVP必须把 CSI-2 host 做进去。1.3 CSI-2 到底好在哪里MIPI CSI-2 的优势可以总结成四句话差分串行时钟和数据都是差分对P/N 两根线互为参考共模噪声被大幅抑制。抗干扰能力和信号完整性都比单端并行好太多。线少1 路时钟 lane 加 12 路数据 laneSTM32MP1 就是 1 clock lane 2 data lane 的配置总共 6 根线PCB 上走线压力小得多。速率高官方标称单 lane 最高 1Gbps 级别双 lane 下 1080p 的 YUV422 在 30fps 内是宽裕的。协议能力CSI-2 协议里带了帧开始/帧结束、行开始/行结束、ECC 校验、数据类型等机制接收端能比较好地判断数据完整性调试的时候也容易定位问题。需要强调的是STM32MP1 的 CSI-2 host 并不是把所有 MIPI 协议功能全做全了比如它支持的数据类型和 lane 数有限制。我建议拿到板子第一步先把参考手册里 CSI-2 host 章节的能力表格过一遍确认你的传感器输出格式在支持列表里否则后面调崩了都不知道原因。1.4 接入方式改变带来的认知转变从工程角度这个改变带来的认知冲击不在于硬件而在于软件。单片机时代调摄像头是读寄存器、查时序图、写中断服务函数。Linux 下完全不是这个路子你要面对的是设备树什么地方接了摄像头、用的是哪个 I2C 控制器、MCLK 从哪来、复位脚和电源脚在哪全要在 device tree 里描述清楚。V4L2 框架采集视频走 Video for Linux 2 这套标准框架涉及 media device、video device、subdev 等对象。驱动分层传感器驱动是 subdevCSI-2 host 和 DCMI 各自有驱动用户态看到的可能是一个/dev/video0节点但背后是一条长长的 pipeline。当时我从“单片机思维”切换到“Linux 媒体框架思维”花了不少时间。后来总结了一句话在 MPU 上接摄像头先别急着写代码先把媒体拓扑图画出来把数据流路径搞明白再动手配置。2. 硬件连接设计中最容易翻车的几个细节2.1 引脚复用查表比想当然重要STM32MP1 的引脚复用是 ALTERNATE FUNCTION 机制同一个引脚可以映射多种外设功能。MIPI CSI-2 不是普通 GPIO它的引脚物理上是固定的差分对这一点和 DVP 可任意分配引脚不一样。但 CSI-2 host 在芯片内部的信号走向以及配套的复位、时钟、I2C 引脚依然要做引脚复用确认。我当时踩的坑是摄像头 sensor 的 I2C 我图省事接到了 I2C4后来发现 I2C4 的引脚和板上另一颗 I2C 设备的地址冲突只能改接。改完 I2C 引脚又发现对应的i2c4节点和某个外设的 pinctrl 冲突。这种问题在 MCU 时代也有但在 MPU 上因为外设更多、pinctrl 更复杂更烦。建议的做法是拿到原理图先做一张引脚占用表把 CSI-2 signal、I2C、MCLK、GPIO 控制脚列全。对照stm32mp157-pinctrl.dtsi里的pinctrl节点逐个确认 alternate function。所有功能引脚尽量从 C ortex-A 侧的 Linux 设备树来管避免 M4 固件和 Linux 争抢同一组引脚。2.2 电源和上电时序I2C 读不到 ID 的第一嫌疑摄像头传感器通常需要多路电源以 OV5640 为例常见的是模拟电压 AVDD2.8V数字核心电压 DVDD1.5V有些模组内部集成 LDO可以统一供电I/O 电压 DOVDD1.8V 或 2.8V不同模组要求不一样但共同点是上电时序不能乱。很多传感器数据手册里明确规定 DOVDD 要先于 AVDD 上电或者要求 MCLK 必须在电源稳定之后才能给。违反了时序最典型的现象就是 I2C 读不到 ID或者读到 ID 但输出数据不对。我在一片自研板上遇到过这样的情况摄像头能读到 ID但输出全是花屏。查了半天最后发现是一路电源的纹波偏大MCLK 上也叠加了噪声。把电源换成低噪声 LDO、MCLK 串了 22Ω 电阻之后问题消失。电源这一块不要图省事直接拿一个 DCDC 输出怼到 AVDDAVDD 和 PLL 相关的供电要求通常比较敏感。2.3 差分走线的三个硬指标MIPI 差分对的设计有三个硬指标是经验值也基本是通用要求差分阻抗 100Ω走线宽度和间距通过阻抗计算工具算好两层板几乎没戏四层板也要看参考平面是否完整。组内等长同一条差分对的 P/N 等长误差控制在 5mil 以内。数据 lane 之间尽量等长误差控制在 50mil 以内具体要求看数据手册。参考平面完整差分线下方不要被其他层的走线切断尤其是不要跨分割。STM32MP1 的 MIPI 引脚在 BGA 封装里引出不少人为了省事把线拉得很远或者绕了好几层过孔。我的建议是HS 信号尽量走表层过孔不超过两个。如果示波器有差分探头可以看 D-PHY 的 HS-TX 信号正常应该是一个干净的差分电压摆幅如果地方出现明显的回沟或者上升沿爬得慢先查走线和阻抗。2.4 MCLK、I2C、复位、PWDN 怎么接除了差分信号控制线才是软件调试的关键路径MCLK传感器需要一个主时钟常用频率是 24MHz。STM32MP1 一般通过时钟树分配一个 PLL 输出给摄像头设备树里用clocks属性描述。I2C作为控制通道给传感器写寄存器用。注意 I2C 上拉电阻通常 2.2k~4.7k速率选 400kHz 以内比较稳。OV5640 在这种应用里我用 7-bit 地址 0x3C 的写法也遇到过要看驱动里的地址定义。复位引脚RESETB和 PWDN这两个 GPIO 必须由 SoC 明确控制不能悬空。上电时先拉低复位等电源和 MCLK 稳定后再释放复位。我建议在硬件设计阶段就把这几个 GPIO 做成可独立控制的方便调试时手动拉高拉低。早期调试阶段甚至可以在用户态直接导出一个 GPIO 来测别一上来就依赖驱动里的上电序列。2.5 关于 ESD 和接插件选型量产产品必须在 MIPI 差分对上做 ESD 保护常见方案是加低电容 TVS 阵列注意结电容要小于 0.5pF否则会破坏信号完整性。0.5pF 以上的 TVS 在高速信号上容易导致边沿劣化。另外接插件选型也有讲究。如果是板对板连接器或 FPC 排线尽量选厂商明确标称支持 MIPI D-PHY 速率的产品。我曾经在一根软排线上栽过跟头摄像头模组通过 30cm FPC 连接主控FPC 上没有很好的参考平面1Gbps 速率下完全起不来后来把速率降到 800Mbps 左右才稳定。方案验证阶段我建议先直接用官方 DK2 那样的标准连接器数据量链路稳定后再改 FPC 长度。不要一上来就挑战极限.3. 内核与设备树配置让摄像头数据走进内存3.1 内核 Kconfig 项STM32MP1 跑 Linux摄像头链路需要的内核配置主要在Device Drivers - Multimedia support菜单下。和 STM32MP1 相关的核心选项包括CONFIG_VIDEO_STM32_DCMIDCMI 并口采集驱动CONFIG_VIDEO_STM32_CSI2HOSTCSI-2 host 驱动部分内核版本命名略有差异CONFIG_MEDIA_CONTROLLER、CONFIG_VIDEO_V4L2_SUBDEV_APImedia controller 和 subdev 支持CONFIG_VIDEO_OV5640OV5640 传感器驱动STM32MP1 的官方 SDK 和主线内核通常默认已经把这些模块编成了模块或直接编进内核。我习惯直接编进内核省得文件系统里还要管理模块加载顺序。内核编译时建议把CONFIG_VIDEOBUF2_DMA_CONTIG、CONFIG_DMA_CMA也确认打开。摄像头这种大分辨率流媒体需要连续物理内存DMA-CMA 不开buffers 经常分配不出来。3.2 设备树链路设备树配置是整个过程中最绕的一环我第一次配置时对着参考手册翻了一个下午。理解链路不难三个节点两对 endpoint。三个节点分别是摄像头传感器节点挂在某个 I2C 总线上CSI-2 host 节点DCMI 节点两对 endpoint 分别是传感器节点内的 port 指向 CSI-2 host 的 portCSI-2 host 内部的 port 指向 DCMI 的 port实际数据流是传感器把 MIPI 数据发到 CSI-2 hostCSI-2 host 解串后送到 DCMIDCMI 把数据写入内存。设备树就是把这个“谁连到谁”的拓扑告诉内核。我当时最大的困惑是为什么 sensor 不直接连到 DCMI这是因为传感器物理上是 MIPI 差分信号DCMI 本身并不认 MIPI 协议必须先经过 CSI-2 host 解串成并行数据DCMI 才能采。这个在理解上特容易绕晕想通了设备树就好配了。3.3 一个简化但可用的设备树片段下面是我项目里一个精简过的设备树片段不是完整的板级 dts但结构可以直接参考csi2host { status okay; ports { #address-cells 1; #size-cells 0; port0 { reg 0; csi2host_from_ov5640: endpoint { remote-endpoint ov5640_to_csi2host; clock-lanes 0; >i2cdetect -y -r 4如果能看到3c或者21这个地址说明 sensor 在线。如果地址都没看到别着急去翻寄存器手册先查电源、MCLK、复位脚这三样是 I2C 枚举的基础。4.2 输出格式、lane 数与带宽的取舍OV5640 在 MIPI 模式下可选的输出格式包括 RAW RGB、YUV422、RGB565 等。对大多数视觉应用来说YUV422 和 RAW10 是最常见的。带宽估算思路很简单假设 1080p1920×108030fpsYUV422每像素 16bit原始数据率 1920 × 1080 × 16 × 30 ≈ 995.3 Mbps加上 MIPI 协议开销帧头、行头、ECC、CRC、填充位实际链路速率要留出余量如果跑 2 lane每 lane 大约需要 500Mbps 以上这样的速率在 STM32MP1 的 CSI-2 host 能力范围内如果输出 RGB88824bit/像素同样分辨率下带宽需求会飙到 1.5Gbps 左右2 lane 就比较紧张了更推荐用 RAW10 或 YUV422。另外lane 数的选择不只是速率问题还和驱动配置、PCB 布线复杂度有关。某些成熟的模组默认固件只出 1 lane你要改配 lane 数就得通过 I2C 写 sensor 寄存器同时把设备树的># 先看当前媒体拓扑 media-ctl -d /dev/media0 -p # 把 sensor 的输出设为 1920x1080 YUV422 media-ctl -d /dev/media0 --set-v4l2 ov5640 4-003c:0[fmt:UYVY8_2X8/1920x1080] # 再设置 DCMI 接收格式 media-ctl -d /dev/media0 --set-v4l2 stm32-dcmi:0[fmt:UYVY8_2X8/1920x1080] # 最后用 v4l2-ctl 拉一帧看看 v4l2-ctl -d /dev/video0 --set-fmt-videowidth1920,height1080,pixelformatYUYV v4l2-ctl -d /dev/video0 --stream-mmap --stream-count1 --stream-to/tmp/frame.yuv如果/tmp/frame.yuv文件拿到 PC 上还是能看到画面说明链路已经通了。如果只有黑屏或者满屏噪声再去怀疑信号完整性或寄存器配置。4.4 确认数据流的几个命令调试链路时我经常交错使用这几个命令dmesg | grep -i ov5640\|dcmi\|csi看驱动 probe 是否成功有没有错误。media-ctl -d /dev/media0 -p看媒体拓扑确认每个 pad 的 format。v4l2-ctl -d /dev/video0 --all看当前 video node 的格式、输入、控制项。yavta --list或v4l2-ctl --list-formats-ext看设备的格式列表确认驱动暴露的格式和传感器支持的格式是否一致。如果media-ctl -p打印出来的 format 和 sensor 实际输出不一致一般就是 format 没有设置到位或者 subdev 驱动没有正确配置寄存器。这个环节需要反复查别怕啰嗦。5. 现场排障记录摄像头不出图的排查链路5.1 检查顺序与 dmesg摄像头不出图我见过不少人一上来就改设备树、调寄存器折腾半天发现是排线松了。我的排查顺序固定为四步物理连接和供电I2C 枚举驱动 probe 日志媒体拓扑和格式设置在驱动层面dmesg永远是最先要看的dmesg | grep -E csi|dcmi|ov5640|v4l2正常情况下会看到 sensor 驱动被 probe、DCMI 注册 video device、CSI-2 host 初始化完成。如果哪一段缺失或报错问题范围就缩小了。下面几种实际碰到的症状和排查思路基本覆盖了大部分情况。5.2 症状I2C 读不到 ID这个症状通常和驱动无关硬件问题居多。按概率排序分别是供电没起来或电压不对。用万用表量 AVDD、DVDD、DOVDD。MCLK 没起振或频率不对。用示波器看传感器时钟脚有没有 24MHz 左右方波。复位脚没释放。默认电平不对sensor 一直处于复位状态。I2C 总线地址不对或接线错了。SDA/SCL 接反或模组实际地址和驱动配置不一致。我遇到过一次非常隐蔽的问题设备树里reset-gpios配错了 GPIO 编号驱动 probe 时把复位脚一直拉低导致 sensor 始终处于复位态I2C 枚举失败。这类问题通过读dmesg里 GPIO 分配日志就能发现。5.3 症状ID 能读到但 v4l2 无数据ID 能读到说明 I2C、供电、时钟都正常。问题通常出在MIPI lane 配置不一致sensor 侧输出 2 lane但设备树里配成了 1 lane反之亦然。数据类型data-type不匹配sensor 输出 YUV422但 CSI-2 host 或 DCMI 配置成 RAW8。MCLK 频率不对OV5640 要求 6MHz~54MHz但不合适的频率会导致 PLL 配置不准输出时序异常。media pipeline 没有正确设置直接v4l2-ctl --stream-mmap之前没有先跑media-ctl --set-v4l2把格式链路配好。这种情况建议先拉一帧并抓一下dmesgv4l2-ctl -d /dev/video0 --stream-mmap --stream-count5如果提示 buffer timeout说明 sensor 可能有 MIPI 信号输出但 DCMI 没有收到有效帧如果提示 no buffer说明链路根本没打通回头查 media pipeline。5.4 症状有流但画面花屏/黑屏花屏通常不是“没信号”而是“信号没对”格式不对用v4l2-ctl --all看当前格式如果用 YUYV 采集但 sensor 实际输出的是 UYVY画面会偏色或花。把两边格式调成一致就能解决。lane 极性接反MIPI 差分线 P/N 接反。这种情况示波器看信号也有波形但数据解析完全不对。时钟或数据 lane 的时序余量不足可以试着降低 lane 速率或者检查走线等长。CMA 内存不足导致 buffer 分配异常分辨率越大需要的连续内存越多可以查/proc/buddyinfo或故意调小分辨率看是否恢复。花屏问题里格式不匹配是最容易验证也最容易犯的。我在项目初期用v4l2-ctl --set-fmt-videopixelformatYUYV采集但 sensor 的 media-ctl 格式配成了 UYVY8_2X8结果画面颜色完全错乱。把两边的 fourcc 对齐后画面瞬间正常。5.5 一个检验清单排障到最后我习惯拿一张纸把链路画出来从 sensor → CSI-2 host → DCMI → memory每个环节标出“验证手段”和“可能出错点”。这里整理一个我常用的检查清单检查项验证方式常见问题供电万用表量电压AVDD/DVDD 电压不对、纹波大MCLK示波器 24MHz无时钟、频率偏差大I2Ci2cdetect地址不对、SDA/SCL 接反复位/PWDNGPIO 控制默认电平错误、时序不满足Lane 配置media-ctl / dtssensor 与设备树 lane 数不一致数据格式v4l2-ctl --allmedia-ctl 与 video 格式不匹配信号完整性示波器差分探头走线等长、阻抗、ESD 电容过大内存分配dmesg / CMA 状态连续内存不足buffer 分配失败在 STM32MP1 上接 MIPI CSI-2 摄像头硬件选型只是第一关真正的复杂度集中在设备树、内核驱动和媒体框架的配合上。我个人在实际操作中的体会是先花半天时间把官方板子的链路跑通再自研板上做移植是性价比最高的路径。不要一上来就在裸板上死磕 MIPI 波形那只会让你陷进“信号问题”和“配置问题”互相干扰的泥潭。最后再分享一个心得摄像头模组别只看价格。OV5640 这类模组水很深同样标着 OV5640有的模组默认输出格式、lane 数、I2C 地址都不同。和供应商确认清楚参数买两片回来量一量比事后再写一堆兼容代码省心得多。
返回列表