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

资讯详情

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

STM32MP1接入MIPI CSI-2摄像头:从硬件设计到Linux驱动调试实战

STM32MP1接入MIPI CSI-2摄像头:从硬件设计到Linux驱动调试实战 你手里的活儿要是涉及在嵌入式 Linux 上接摄像头STM32MP1 这名字肯定不陌生。这颗芯片和 MIPI CSI-2 接口的组合在我这几年做过的项目里算是点名率相当高的一类需求。今天不聊那些花里胡哨的概念直接说人话把 STM32MP1 序列产品连接 MIPI CSI-2 摄像头这件事从头到尾捋一遍方案怎么定、硬件怎么接、驱动怎么调、遇到那些玄学问题该怎么查。这篇文章适合刚拿到开发板想接摄像头的朋友也适合被 ISP 调性折磨得想摔板子的老哥。1. 项目概述与整体方案选型1.1 为什么是 STM32MP1 配 MIPI CSI-2STM32MP1 这个系列跟传统的 STM32 单片机完全两个路子。它内部是一颗 Cortex-A7 加一颗 Cortex-M4典型的异构多核架构。跑 Linux 系统的时候A7 核负责主要业务M4 核可以拿来干实时控制类的活儿。我最早接触这个系列是 STM32MP157后来 ST 又出了成本更低的 STM32MP135、STM32MP151 这些型号核心板加底板的方案在国内工控、IoT 网关、边缘计算盒子里用得特别多。为什么要在这个平台上面接 MIPI CSI-2 摄像头核心原因其实就两个带宽和生态。带宽上MIPI CSI-2 接口的 D-PHY 物理层可以做到每条 lane 跑 1Gbps 以上四条 lane 就是 4Gbps 的吞吐。这个带宽量级下720p60fps、1080p30fps 甚至 4K 的原始 Bayer 数据都能走得很稳。对比传统的 DVP 并口虽然布线简单但 8 位并口加像素时钟的方案上到高清分辨率就极其痛苦时钟频率高不说同步信号还容易受干扰。我印象特别深有一次用 DVP 接口的 sensor 跑 1080p板子布线稍微差一点图像上就全是横条纹后来换 MIPI CSI-2 方案清净多了。生态上STM32MP1 的 Linux BSPBoard Support Package已经比较成熟ST 官方把 V4L2Video for Linux 2框架下的 sensor 驱动、CSI 控制器驱动都整进了内核。你在设备树里把 sensor 的 I2C 地址、MIPI lane 数、数据格式配好v4l2 子系统就能把图像数据送出来。对于做产品的人来说从官方 Demo 到自研板卡迁移成本被大大压低了。1.2 摄像头传感器选型怎么定接 MIPI CSI-2 之前先把 sensor 定了。这步要是拍脑袋后面全是眼泪。市面上面向嵌入式 Linux 的 MIPI 摄像头传感器大体分两类一类是纯 sensor 芯片比如 OV5640、OV5647、OV8865、IMX219、IMX290 这类。买回来要么自己画板子把 sensor 焊上去要么买现成的模组通过 FPC 排线连到主板上。这类方案灵活成本低适合做产品。另一类就是市售的 USB 摄像头跟这个项目没关系。别拿 UVC 的摄像头往 MIPI 口上插协议都对不上物理接口也不长那样。选 sensor 的时候在我看来有四个硬指标分辨率你要 1080p 还是 720p这直接决定了 sensor 的输出格式和 MIPI lane 数。1080p30fps 用 2-lane 也能跑但余量小我通常直接上 4-lane稳。接口类型必须是 MIPI CSI-2 输出这个不用多说。部分老 sensor 只出 DVP直接排除。驱动支持重点查一下 STM32MP1 的 Linux 内核里有没有现成驱动或者传感器厂家有没有提供 Linux driver。没有驱动就得自己啃 datasheet 写 v4l2 subdev工作量不是一个量级的。供应链这条是血泪教训。选型别选太偏门的到时候断货、涨价、找不到人调全是你自己扛。我习惯优先看 OV 和 Sony 这两个御三家市占率高买模组容易出问题也有社区答案。我实际项目里用得最多的是 OV5640 模组30 万像素到 500 万像素都能出1080p 模式下输出格式支持 YUV422 和 RAW Bayer兼容性好到离谱。树莓派上那颗 OV5647 也能用我就是从树莓派上拆过一颗接 STM32MP157 的板子照样跑得起来不过 OV5647 的驱动得自己折腾一下。1.3 DVP 与 MIPI 的差异以及为什么别走回头路有些朋友搞过单片机习惯用 DVP 接口的摄像头一看 STM32MP1 也有 DVP 控制器就想着省事继续用 DVP。我的建议是新项目无论成本多敏感优先 MIPI CSI-2。DVP 最大的问题是时钟和数据线的并行关系。像素时钟 PCLK 通常几十 MHz 到上百 MHz数据总线 8 位或者 10 位加上 VSYNC、HSYNC、PCLK十几根线并排走。高速下每一根线的走线长度都影响时序眼图PCB layout 做不好就等着被图像噪声折磨吧。而且 DVP 没法做长距离传输FPC 超过 5cm 就开始明显退化。MIPI CSI-2 走的是差分串行每个 lane 两根线抗干扰能力强得多而且理论上可以跑到 1.5Gbps per lane。虽然布线也有要求差分对等长、阻抗控制但比 DVP 那种并口要宽松不少。再加一条MIPI CSI-2 可以动态切换 lane 数调试的时候 4-lane 挂了可以改成 2-lane 来降速排查DVP 就没这灵活性。所以从方案稳健性的角度我劝你们别在 DVP 上恋战直接上 MIPI CSI-2。2. MIPI CSI-2 协议基础与信号链路2.1 从物理层到协议层的三个层次MIPI CSI-2 不是一个单一的东西它是一个协议栈。从底下往上看至少分三层。最底层是物理层叫 D-PHY。这一层定了电平和时序。D-PHY 里每个 lane 用一对差分信号传输时钟 lane 和 data lane 是分开的。时钟 lane 一直跑data lane 是双向的可以做 LP 通信和高速传输切换。D-PHY 有两种状态LPLow Power状态用于控制信号HSHigh Speed状态用于高速数据。这两种状态的切换就是我在示波器上经常看到的 LP→HS 的跳变过程。这个跳变里面有专门的时序参数比如 T-LPX、T-HS-PREPARE、T-HS-ZERO 这些。如果这些参数没有配对sensor 和 host 之间的握手就会失败表现出来就是“没图像”。中间这一层叫协议层Protocol Layer。它把图像数据打包成一个个 packet。lane 上传输的基本单位是包包的类型由 Data Type 字段决定。比如 0x2A 表示 RAW100x1E 表示 YUV422-8bit0x2B 表示 RAW12。host 控制器收到包之后解析出里面装的到底是像素数据还是帧同步信息。对于应用层的开发人员来说这一层的概念不用抠得太死但你要知道sensor 的 datasheet 里说“输出 RAW10 格式”那在设备树和驱动里就要把 Data Type 配成 0x2A配错了图像会花或者直接黑屏。最上面就是应用层也就是你最终拿到图像数据的地方。Linux 里就是 V4L2 框架。V4L2 的应用比如 GStreamer、FFmpeg、OpenCV都是从 /dev/video0 这个设备节点读数据。你通过 V4L2 的 ioctl 设置分辨率和像素格式底层 CSI 控制器会负责把 lane 上的数据拆包重组交给内存里的 DMA buffer。2.2 D-PHY 的通道配置与带宽计算摄像头贴的标签上写的“4-lane MIPI”指的就是数据 lane 数量。D-PHY 配置中1 个时钟 lane 加 N 个数据 laneN 一般是 1、2 或 4。带宽怎么算理论值就是 lane 数乘以每 lane 速率。设每 lane 速率是 800 Mbps4-lane 就是 3.2 Gbps。但这是链路层的原始速率不是有效图像数据速率。图像数据要包头、包尾、校验和还有 LP 状态切换的空隙实际效率大约 80% 到 90%。所以选型的时候不能卡着算要留 20% 的余量。举例我想跑 1080p30fps像素位深 10bitRAW10。一帧原始数据量是 1920×1080×10 bit 20736000 bit ≈ 19.77 Mbit。30fps 就是 593 Mbit/s。加上协议开销和消隐区大约需要 700 Mbit/s 左右的 MIPI 带宽。用 2-lane 的 sensor每 lane 跑到 500 Mbps总共 1Gbps够用。用 4-lane 当然更宽裕但 sensor 的 lane 数不是你想改就改得看硬件设计。所以前期选 sensor 时就把分辨率、帧率、位深一起算清楚。2.3 时钟来源与同步关系MIPI CSI-2 的时钟 CLK lane 由 sensor 侧产生它和像素时钟是什么关系简单说MIPI 的 HS 时钟和图像像素是“捆绑”在一起的sensor 内部 PLL 从 MCLK主时钟产生 pixel clock再从 pixel clock 衍生出 MIPI 的 byte clock。因此要想图稳MCLK 必须干净。STM32MP1 的评估板上通常有个 24MHz 晶振专门给摄像头 MCLK 用。我碰到过因为 MCLK 走线太远、串扰严重导致图像抖动的案例。解决办法是把 MCLK 的走线做短并加一个 33Ω 的串阻靠近 sensor 端放置。要是没晶振用 SoC 的 GPIO 输出 MCLK 也行但时钟精度不如晶振对某些 sensor 来说会敏感。3. 硬件连接与板级设计要点3.1 连接器与引脚定义对照STM32MP1 系列官方评估板比如 STM32MP157F-DK2的摄像头接口是一个 22-pin 的 FPC 连接器排距 0.5mm。引脚顺序大致是电源 VDD 3.3V、VDD 1.8V、地、I2C 的 SCL/SDA、MIPI 的 Clock lane 一对差分、Data lane 0 到 3 四对差分、还有 MCLK 和复位 GPIO。我见过不少朋友自己画板子时把 FPC 座子的差分对顺序搞反了。MIPI 的差分信号本身是有极性的lane 0 的 P/N 接反虽然不至于烧坏但图像会完全出不来而且 CSI-2 协议不支持 lane 重映射的自动协商所以画板前一定要对照核心板原理图把 lane 顺序确认好。我做一个项目时踩过一个大坑因为 FPC 排线的引脚间距太密手焊时连锡了结果是一条 lane 对地短路。sensor 上电后电流异常摸着发烫。排查了半小时最后拿万用表蜂鸣档一量发现 PCB 上 lane 1 的 P 和 N 焊盘之间呈导通状态吹下来重新贴片才恢复。3.2 电源设计与去耦MIPI 摄像头对电源的纹波和瞬态响应比较敏感。sensor 的模拟电源 AVDD通常 2.8V和数字电源 DVDD1.8V 或 1.2V要分别走 LDO不要在板子上直接拿一个 3.3V 去供所有电源轨。电源纹波若超过 30mVpp图像上极易出现水波纹或暗部横条。PCB 上面每个电源引脚旁边至少放一个 100nF 的高频去耦电容再并一个 10μF 的钽电容做低频储能。位置要靠近引脚走线要短。这块没啥捷径就是把电源的“清净度”当成头等大事来对待。另外sensor 的 IOVDD 一般接 1.8V 或 3.3V它要和 SoC 的 I2C 电平匹配。STM32MP1 的 I2C 引脚一般是 1.8V 或 3.3V 可配注意别搞成电平不匹配否则 I2C 通信时好时坏。3.3 差分走线需要注意的细则MIPI D-PHY 的走线要求核心是阻抗和等长。差分阻抗100Ω 差分阻抗±10%这要靠叠层设计和线宽线距来控制。四层板中表层走差分线参考层为第二层完整地平面线宽线距差别不大时阻抗通常可以满足。对内等长同一对差分线 P/N 的长度差控制在 5 mil 以内这样 skey 不会太大。对间等长同一个 CSI 接口的所有 lane 长度差控制在 100 mil 以内。其实不用太夸张很多板卡在 200 mil 以内也工作正常但保守点总没错。过孔尽量少打过孔。若必须换层要给差分对加回流地过孔确保信号返回路径连续。远离干扰源MIPI 走线不要和开关电源的 SW 节点、时钟信号、PWM 信号挨着走电磁耦合过来就等着花屏吧。我做 PCB layout 时习惯把 MIPI 整个区域单独包一块地然后用一排过孔围起来形成隔离区。速度不高1Gbps 以下时这招很有效供应商也说这样过 EMC 测试更省心。4. 软件配置与驱动适配4.1 内核配置与设备树软件这一块用的是标准 Linux Mainline 内核STM32MP1 的支持已经很完善。内核配置需要打开以下选项CONFIG_VIDEO_STM32_CSIy CONFIG_VIDEO_OV5640y # 视你的 sensor 而定 CONFIG_VIDEO_V4L2y CONFIG_MEDIA_SUPPORTy CONFIG_VIDEO_DEVy设备树是重点。以 STM32MP157 为例CSI 控制器节点在设备树里长这样csi { status okay; vdd-supply scmi_v3v3; vddq-supply scmi_v3v3; }; i2c4 { status okay; ov5640: ov56403c { compatible ovti,ov5640; reg 0x3c; clocks clk_ext_camera; clock-names xclk; reset-gpios gpioa 0 GPIO_ACTIVE_LOW; powerdown-gpios gpioa 1 GPIO_ACTIVE_HIGH; rotation 180; status okay; port { ov5640_ep: endpoint { remote-endpoint csi_ep; clock-lanes 0; >dmesg | grep ov5640 # 预期输出ov5640 3-003c: ov5640_init_controls然后确认 /dev/video0 有没有生成ls /dev/video*接下来用 v4l2-ctl 工具读一下 sensor 支持的格式v4l2-ctl -d /dev/video0 --list-formats-ext这个命令会列出所有支持的像素格式和分辨率比如[0] YUYV (YUYV 4:2:2) Size: Stepwise 640x480 - 2592x1944如果你的板子串口没接用网口登录系统也行反正能敲命令就行。4.3 V4L2 采集测试与推流驱动有输出之后可以先做单帧抓图确认图像内容是否正常v4l2-ctl -d /dev/video0 --set-fmt-videowidth1920,height1080,pixelformatYUYV --stream-mmap --stream-count1 --stream-to/tmp/frame.raw然后把 raw 文件传到 PC 上用 Python OpenCV 解析import cv2 import numpy as np frame np.fromfile(/tmp/frame.raw, dtypenp.uint8) frame frame.reshape((1080, 1920, 2)) # YUYV bgr cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_YUYV) cv2.imwrite(/tmp/frame.png, bgr)这时候能看到一帧图像如果画面是花的、绿的、有斜纹说明格式配错了或者 lane 配置不对。单帧确认正常后可以上 GStreamer 推流方便实时预览gst-launch-1.0 v4l2src device/dev/video0 ! video/x-raw,width1920,height1080,framerate30/1 ! videoconvert ! fpsdisplaysink跑这个命令时屏幕上如果图像流畅、无撕裂说明整条链路已经通了。接下来才谈得上做图像处理、编码推流这些上层应用。5. 调试实录与常见问题排查5.1 无图像输出先查这三样遇到“sensor 上电了但没图像”我的排查顺序永远是先电后时钟再查 I2C。查电源用万用表量 sensor 的 AVDD、DVDD、IOVDD 电压是否在规格内。注意上电时序sensor 一般要求先 IO 电源再 AVDD最后 MCLK这个顺序乱了有些 sensor 直接罢工。查 MCLK用示波器看 sensor 的 MCLK 引脚有没有时钟频偏要小于 50ppm。没时钟就查 SoC 侧的 MCLK 输出配置或者查 24MHz 晶振有没有起振。查 I2C在 Linux 下用 i2cdetect 扫描 sensor 的 I2C 地址i2cdetect -y 3 # 如果 0x3c 位置显示 UU 或 3c说明设备在线如果 I2C 扫描不到八成是硬件问题——线序接错、地址不对、或者 sensor 的复位脚一直被拉低。不要急着查驱动查硬件更高效。5.2 图像花屏或颜色不对数据通道问题拿到一帧花图首先确认像素格式。V4L2 设置的是 YUYV但 sensor 实际输出的是 RAW10那画面必然花。先看 datasheet 确认 sensor 输出格式然后和设备树、v4l2-ctl 的设置一一对齐。如果格式没错但仍有斜纹我建议检查 lane 映射。用 v4l2-ctl --stream-mmap 采集几帧观察图像中条纹的方向和宽度。横向的细条纹大多是 lane 之间错位纵向条纹可能是 lane 极性反了或者是时钟 lane 和数据 lane 的相位不对。另外要留意clock-noncontinuous属性。有些 sensor 支持 non-continuous clock有些必须用 continuous clock。STM32MP1 的 CSI 控制器默认可能支持后者但 sensor 如果配成前者两边就会对不上出现 intermittent sync loss。5.3 帧率达不到标注值问题可能出在 ISP 带宽帧率不够先算两笔账。第一笔是 MIPI 链路带宽够不够。前面 2.2 节说了计算公式如果 lane 速率已经拉到 1Gbpssensor 输出 1080p60 的 RAW10 数据量就超出了链路 80% 的有效带宽帧率被卡在 45fps 是正常的。这种时候要么降分辨率、要么降位深、要么把帧率需求砍半。第二笔是 SoC 内部 ISP 和 DMA 的带宽。STM32MP1 的 CSI 控制器接收数据后要写到 DDR 里这个过程会占用 AXI 总线带宽。如果系统里还有以太网、USB、GPU 同时在跑总线竞争会导致丢帧。这个可以用perf工具查也可以在驱动里打开帧超时统计。我遇到过一个实际场景系统跑 1080p30fps 预览没问题但只要同时跑以太网传输大文件摄像头预览就卡顿。后来查下去是 DDR 带宽被占满CSI 的 DMA 请求排队超时。最后把 CSI 的 DMA 通道优先级提高才解决。5.4 竖条纹、水波纹和暗光噪点的处理竖条纹一般来自 sensor 电源的开关噪声或者 MIPI 布线串扰。处理办法加强电源滤波给 AVDD 加 LC 滤波MIPI 线缆换成屏蔽 FPC在 sensor 的电源端并联一个 1Ω 电阻加 10μF 电容的 π 型滤波。水波纹多出现在室内灯光环境下这是 sensor 的曝光时间和灯光频闪互相作用产生的 rolling band。解决方法是把 sensor 的曝光时间设为工频周期整数倍比如 50Hz 地区用 10ms、20ms。sensor 驱动里通常有v4l2_ctrl_set_exposure之类的 API可以直接在用户态调整。暗光噪点这个事就复杂了。如果 ISP 的增益调得过高噪点会非常明显。可以在 sensor 的驱动里调整v4l2-ctl -d /dev/video0 -c auto_gain0然后手动调-c gain50。但你要是想让画质真正达到商用水平就得做 3A自动曝光、自动白平衡、自动对焦 tuning这是一个庞大的工程。5.5 热门排查工具与实测技巧调试 MIPI 信号示波器是少不了的。Keysight 的示波器配上 MIPI D-PHY 解码选件可以实时解析 LP 和 HS 状态跳变测 T-LPX、T-HS-SETTLE 等参数。我记得有次调试sensor 和 controller 的 HS exit 时序不一致就是用示波器测到 host 方的 T-HS-EXIT 过长然后改 D-PHY 的 timing register 解决的。除了示波器FPC 排线的连接可靠性也值得注意。MIPI 跑高速时FPC 的插入损耗和回波损耗都会影响信号质量。如果条件允许用网络分析仪测一下 S21或者至少用 TDR 看阻抗连续性。有人说消费级产品没那么严格但真出了问题排查成本远高于前期设计成本。5.6 问题速查表我把这几年遇到的高频问题整理成一张表遇到毛病先对着查能省不少时间现象大概率原因排查/处理无图像I2C 读不到 IDsensor 没上电、复位拉低、I2C 地址错查电源电压、复位脚电平、i2cdetect无图像I2C 正常MCLK 没起振、MIPI lane 配置错示波器量 MCLK、检查>
返回列表