一、模组硬件接口与通信协议
做结构光模组驱动开发,说白了就是跟硬件打交道。你得知道怎么把数据从传感器拿过来,怎么给模组发指令,怎么处理中断信号。这些基础打不牢,后面调试起来会非常痛苦。我个人习惯先把接口协议吃透,再动手写代码。
1.1 MIPI CSI-2 接口详解
MIPI CSI-2 是摄像头模组和处理器之间的高速数据传输通道。结构光模组采集到的深度图、红外图、彩色图,最终都是通过这个接口传出去的。
物理层:D-PHY
CSI-2 的物理层用的是 MIPI D-PHY。一组 Lane 包含一对差分信号:DP 和 DN。时钟 Lane 是独立的,数据 Lane 可以配置 1 到 4 条。
我记得第一次调 CSI-2 的时候,示波器一测,波形乱七八糟。后来发现是 PCB 走线没做等长处理。嗯,这里要注意:高速信号对走线长度非常敏感。
| 参数 | 典型值 | 说明 |
|---|---|---|
| 每 Lane 速率 | 400 Mbps - 2.5 Gbps | 取决于模组和 SoC 支持 |
| Lane 数量 | 1/2/4 | 结构光模组通常用 2 或 4 Lane |
| 电压摆幅 | 200 mV - 1.2 V | 差分信号,低功耗模式更低 |
协议层:长包与短包
CSI-2 的数据传输分两种包:短包(Short Packet)和长包(Long Packet)。短包只有 32 位,用来传帧开始、帧结束、行开始、行结束这些控制信息。长包包含包头、数据负载和包尾校验。
你想想看,一帧图像数据量很大,必须分包传输。CSI-2 协议规定得很细,但驱动开发时我们更关心的是:
- 帧同步信号是否正确
- 数据格式是否匹配(RAW10、RAW12、YUV 等)
- 虚拟通道号是否对应
避坑指南
我曾经遇到一个坑:模组输出的是 RAW10 格式,但 SoC 的 CSI 控制器配置成了 RAW8。结果图像全是错位的。调试了两天才发现是格式不匹配。所以拿到模组第一件事,确认数据格式。
1.2 I2C 控制协议
I2C 是结构光模组最常用的控制接口。模组的寄存器配置、工作模式切换、参数读取,全靠它。
标准 I2C 速率是 100 kHz 或 400 kHz。有些模组支持高速模式,能跑到 1 MHz 甚至 3.4 MHz。但我建议:除非特别需要,否则别用高速模式。为什么?因为高速模式对信号质量要求更高,长线缆容易出问题。
典型的 I2C 读写流程:
// 写寄存器
START + 设备地址(写) + ACK + 寄存器地址 + ACK + 数据 + ACK + STOP
// 读寄存器
START + 设备地址(写) + ACK + 寄存器地址 + ACK +
START + 设备地址(读) + ACK + 数据 + NACK + STOP
我个人习惯在驱动里加一个 I2C 读写超时机制。有些模组在特定状态下会不响应 I2C 请求,如果没有超时处理,驱动会卡死在那里。
小技巧
调试 I2C 时,用逻辑分析仪抓波形是最快的。看 START 条件、地址、ACK/NACK 信号,一眼就能发现问题。我曾经靠这个在半小时内找到了一个地址写错的 bug。
1.3 SPI 配置接口
有些结构光模组用 SPI 作为配置接口,尤其是那些需要高速配置的。SPI 是全双工通信,速率可以跑到几十 MHz。
SPI 有四种模式,由 CPOL(时钟极性)和 CPHA(时钟相位)决定。模组手册里会明确写支持哪种模式。我见过最坑的是:手册写 Mode 0,实际要配 Mode 3 才能正常工作。
| 模式 | CPOL | CPHA | 说明 |
|---|---|---|---|
| Mode 0 | 0 | 0 | 空闲低电平,第一个边沿采样 |
| Mode 1 | 0 | 1 | 空闲低电平,第二个边沿采样 |
| Mode 2 | 1 | 0 | 空闲高电平,第一个边沿采样 |
| Mode 3 | 1 | 1 | 空闲高电平,第二个边沿采样 |
SPI 配置接口通常用来:
- 下载固件到模组的 Flash
- 配置激光驱动器的参数
- 读取模组的校准数据
注意
SPI 的片选信号(CS)一定要处理好。有些模组要求 CS 在整包数据传输期间保持低电平,中间不能拉高。否则模组会认为传输中断,数据就丢了。
1.4 GPIO 与中断机制
GPIO 在结构光模组驱动里扮演着「信号兵」的角色。复位、使能、中断,都靠它。
常见的 GPIO 功能:
- RESET:模组复位,低电平有效
- PWDN:掉电控制,高电平进入低功耗模式
- INT:中断输出,模组有事件时触发
- FSYNC:帧同步信号,用于多模组同步
中断机制这块,我建议用边缘触发而不是电平触发。为什么?因为电平触发容易产生重复中断,处理不好会把 CPU 占满。边缘触发只在信号跳变时产生一次中断,干净利落。
我曾经遇到一个情况:模组的中断引脚默认是低电平,初始化后一直拉高。结果 SoC 检测到电平变化,不断触发中断。后来加了去抖处理才解决。
经验之谈
GPIO 的驱动能力也要注意。有些模组的复位引脚需要较大的灌电流,如果 SoC 的 GPIO 驱动能力不够,复位信号可能拉不到低电平。这时候需要加一个三极管或电平转换芯片。
1.5 电源管理时序
电源管理是结构光模组驱动里最容易出问题的地方。模组内部有多个电源域:模拟电源、数字电源、IO 电源、激光驱动电源。上电和下电的顺序必须严格遵循手册要求。
典型的上电时序:
- 先给模拟电源(AVDD)上电
- 再给数字电源(DVDD)上电
- 然后给 IO 电源(IOVDD)上电
- 最后给激光驱动电源(VCSEL)上电
- 等待所有电源稳定后,拉高复位引脚
下电时序正好相反:先断激光电源,再断 IO 电源,最后断模拟电源。
你想想看,如果顺序搞反了,模组内部的 ESD 保护二极管可能会正向导通,产生大电流,直接把芯片烧掉。这不是开玩笑的。
严重警告
激光驱动电源(VCSEL)必须在其他电源都稳定后才能上电。否则激光器可能在没有正确偏置的情况下工作,导致输出功率异常,甚至损坏激光器。我见过一个案例,就是因为电源时序没做好,模组用了三天就坏了。
实际开发中,我习惯在驱动初始化函数里加上电源状态检查。每次上电前先读取电源监控寄存器的值,确认所有电源都稳定了再继续。虽然多花了几毫秒,但安全第一。
好了,这一章的内容就这些。接口协议是驱动开发的地基,地基打不牢,上层建筑再漂亮也没用。下一章我们会深入模组的初始化流程,到时候会用到这些接口知识。
公众号:蓝海资料掘金营,微信deep3321