4、AF马达驱动调试:VCM驱动移植、I2C通信验证、马达行程校准、马达线性度测试
马达驱动,说白了就是AF系统的「手脚」。你算法写得再好,马达不动或者动得不准,一切都是白搭。这一章我们重点聊聊VCM驱动移植、I2C通信验证、行程校准和线性度测试这四个环节。每个环节都有坑,我一个个说。
核心要点:马达调试的最终目标,是让VCM在给定DAC值时,镜头能精准地停在预期位置。任何非线性、回差、迟滞,都会直接毁掉AF的收敛速度和精度。
4.1 VCM驱动移植:从datasheet到代码
拿到一颗新的VCM,第一件事不是写代码,而是读datasheet。我习惯先看这几个关键参数:
- 驱动方式:是开环还是闭环?闭环通常需要额外的Hall sensor反馈。
- I2C地址:7位还是8位?很多驱动IC支持多地址配置,注意硬件上ADDR引脚的接法。
- DAC位数:10位、12位还是16位?这决定了行程的精细度。
- 寄存器映射:控制寄存器、状态寄存器、DAC寄存器分别在哪。
以RK平台上常用的DW9714为例,驱动移植其实就三步:
- 注册I2C设备:在dts中配好i2c总线、地址、电源。
- 实现ops结构体:主要是set_dac()和get_dac()两个接口。
- 对接AF框架:把ops挂到v4l2的subdev上。
// dts配置示例
&i2c4 {
status = "okay";
dw9714: dw9714@c {
compatible = "dongwoon,dw9714";
reg = <0x0c>;
vcc-supply = <&pp2800_cam>;
};
};
// 驱动核心ops
static int dw9714_set_dac(struct v4l2_subdev *sd, u32 val) {
struct dw9714_device *dev = to_dw9714_device(sd);
u8 buf[2];
buf[0] = (val >> 8) & 0x0f; // 高4位
buf[1] = val & 0xff; // 低8位
return i2c_master_send(dev->i2c_client, buf, 2);
}
我的习惯:移植完成后,先别急着跑AF算法。我会写一个简单的测试app,循环写入0和最大值,用耳朵听马达有没有「咔嗒」声。有声音,说明驱动层基本通了。
4.2 I2C通信验证:别被假成功骗了
I2C通信验证,很多人就是写个读写测试,返回0就觉得OK了。我曾经被这个坑过——读写返回成功,但实际写入的值和读回的值对不上。
为什么会这样?因为有些VCM的I2C从机有「影子寄存器」,你写进去的数据它先缓存,要等一个触发条件才会真正生效。所以验证I2C,我建议做三件事:
- 回读校验:写入一个已知值,马上读回来对比。连续测10次,每次换不同值。
- 时序检查:用示波器抓SCL和SDA,确认时钟频率、上升沿、下降沿都在规格内。RK平台的I2C时钟默认100K,有些VCM需要400K,记得调。
- 多设备冲突测试:如果同一条I2C总线上挂了多个设备(比如eeprom、马达驱动),要确认地址不冲突,且每个设备的读写都不会干扰其他设备。
| 验证项 | 方法 | 预期结果 |
|---|---|---|
| 基本读写 | 写0xAA,读回对比 | 读回值 == 0xAA |
| 边界值 | 写0x000和0xFFF | 读回一致,无截断 |
| 连续压力 | 1000次随机读写 | 无NACK,无数据错位 |
| 总线冲突 | 同时操作其他I2C设备 | 各设备数据独立正确 |
注意:RK平台的I2C控制器有DMA模式和非DMA模式。如果遇到读写超时或数据错位,先关掉DMA试试。我遇到过DMA模式下I2C传输长度不对齐导致的问题,换成PIO模式就好了。
4.3 马达行程校准:找到物理极限
行程校准,就是找到马达从最近端到最远端的物理范围。这个范围对应一个DAC值区间,比如[100, 950]。注意,不是0到1023!
为什么不是全范围?因为VCM有机械限位和磁滞区。你强行推到0或1023,马达可能会撞墙,或者进入非线性区。校准的目的,就是找到「可用行程」。
我的校准流程是这样的:
- 粗扫:从0开始,每次加50个DAC步长,同时用OTP或AF算法评估图像清晰度。记录下图像开始变清晰和开始变模糊的两个DAC点。
- 精扫:在粗扫得到的区间内,每次加5个步长,找到清晰度最高的点。这个点就是「最佳焦点」。
- 边界确认:在最佳焦点两侧继续延伸,直到清晰度下降到峰值的一半。这两个边界点就是行程的物理极限。
// 行程校准伪代码
int cali_start = 0, cali_end = 1023;
int best_dac = 0, best_sharpness = 0;
// 粗扫
for (int dac = 0; dac <= 1023; dac += 50) {
set_dac(dac);
msleep(30); // 等待马达稳定
int sharp = get_sharpness();
if (sharp > best_sharpness) {
best_sharpness = sharp;
best_dac = dac;
}
}
// 精扫区间:[best_dac - 100, best_dac + 100]
for (int dac = best_dac - 100; dac <= best_dac + 100; dac += 5) {
// 同上,更新best_dac
}
// 边界确认:从best_dac向两侧找sharpness下降到50%的点
cali_start = find_boundary(best_dac, -1, 0.5);
cali_end = find_boundary(best_dac, 1, 0.5);
避坑指南:我曾经遇到一台设备,粗扫时最佳点在DAC=500,但精扫时发现DAC=480到520之间清晰度几乎一样。后来发现是镜头模组装配有问题,导致焦平面倾斜。这种情况下,行程校准的结果不可靠,需要先解决硬件问题。
4.4 马达线性度测试:你的马达听话吗?
线性度,就是DAC值和实际位移量之间的关系。理想情况下,DAC增加10,镜头就移动10μm。但现实是,VCM的电磁力-位移曲线不是完全线性的,尤其在行程两端。
线性度测试需要借助外部设备——激光位移传感器或者高精度光栅尺。没有这些设备怎么办?可以用图像清晰度间接评估,但精度会差一些。
测试步骤:
- 在行程范围内取N个等间距DAC点(比如20个)。
- 对每个点,用位移传感器记录实际位置。
- 以DAC值为X轴,位移为Y轴,拟合一条直线。
- 计算每个点的实际位移与拟合直线之间的偏差。
线性度的评价指标有两个:
| 指标 | 定义 | 合格标准 |
|---|---|---|
| 最大偏差 | 所有点中,实际值与拟合值之差的最大值 | < 5% of 全行程 |
| 相关系数R² | 拟合直线的决定系数 | > 0.98 |
如果线性度不好,你想想看,AF算法算出来要移动100μm,结果马达只动了80μm,那焦点永远对不准。这时候有两个选择:
- 软件补偿:建立DAC-位移的查找表,做非线性映射。
- 换马达:如果非线性太严重(R² < 0.95),建议直接换VCM型号。
我的经验:闭环VCM的线性度通常比开环好很多,因为有Hall sensor做反馈。但闭环VCM的调试更复杂,需要做Hall校准和温度补偿。如果项目预算允许,优先选闭环方案。
嗯,到这里,马达驱动调试的四个核心环节就讲完了。驱动移植是地基,I2C验证是质检,行程校准是量体裁衣,线性度测试是性能标定。每一步都踩实了,后面的AF算法才能跑得稳。