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为例,驱动移植其实就三步:

  1. 注册I2C设备:在dts中配好i2c总线、地址、电源。
  2. 实现ops结构体:主要是set_dac()和get_dac()两个接口。
  3. 对接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,马达可能会撞墙,或者进入非线性区。校准的目的,就是找到「可用行程」。

我的校准流程是这样的:

  1. 粗扫:从0开始,每次加50个DAC步长,同时用OTP或AF算法评估图像清晰度。记录下图像开始变清晰和开始变模糊的两个DAC点。
  2. 精扫:在粗扫得到的区间内,每次加5个步长,找到清晰度最高的点。这个点就是「最佳焦点」。
  3. 边界确认:在最佳焦点两侧继续延伸,直到清晰度下降到峰值的一半。这两个边界点就是行程的物理极限。
// 行程校准伪代码
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校准和温度补偿。如果项目预算允许,优先选闭环方案。

AF马达驱动调试流程 VCM驱动移植 I2C通信验证 马达行程校准 线性度测试 说明: 1. 驱动移植和I2C验证是基础,必须优先完成。 2. 行程校准确定物理范围,线性度测试评估控制精度。 3. 如果I2C验证失败(红色虚线),需要返回驱动移植阶段排查。

嗯,到这里,马达驱动调试的四个核心环节就讲完了。驱动移植是地基,I2C验证是质检,行程校准是量体裁衣,线性度测试是性能标定。每一步都踩实了,后面的AF算法才能跑得稳。