第4章:AF驱动与马达控制——VCM马达类型与I2C控制时序
各位好,我是你们的老朋友。今天咱们聊聊AF系统里最“接地气”的部分——VCM马达。说白了,镜头能不能动、动得快不快、停得准不准,全看它。
我刚开始接触高通平台时,总觉得AF算法是核心,马达不过是执行指令的“小兵”。后来踩过几次坑才明白——马达控制不好,算法再牛也白搭。你想想看,算法算出来要走到DAC值500,结果马达抖到了520,画面就糊了。
4.1 VCM马达的三种主流类型
目前手机摄像头里,VCM马达主要分三类:开环、闭环、中置。我按个人习惯,把它们比作三种性格的人。
| 类型 | 控制方式 | 位置反馈 | 典型精度 | 成本 |
|---|---|---|---|---|
| 开环(Open Loop) | 开环电压驱动 | 无 | ±10~15μm | 低 |
| 闭环(Closed Loop) | 闭环PID控制 | 霍尔传感器 | ±1~3μm | 中 |
| 中置(Middle / Ball-type) | 开环+机械中置 | 无(机械限位) | ±5~8μm | 中低 |
4.1.1 开环马达
开环马达,说白了就是“给电压就动,不给就停”。没有反馈,你给多少DAC值,它跑到哪算哪。我在项目里遇到过一个问题:同一批马达,个体差异导致同样的DAC值,镜头位置能差出20μm。嗯,这就是开环的代价。
4.1.2 闭环马达
闭环马达就聪明多了。它内部有个霍尔传感器,实时检测镜头位置,然后通过PID控制让镜头精准停在目标位置。我个人习惯在闭环马达上做“位置环+速度环”双环控制,收敛速度比单环快30%以上。
为什么会这样?因为霍尔传感器能告诉你“现在在哪”,控制器就能算出“还差多少”。不像开环,只能靠猜。
4.1.3 中置马达
中置马达是个“混血儿”。它本质上还是开环控制,但机械结构上做了优化——镜头在中间位置时有一个机械“休息区”。平时镜头停在中置位,需要对焦时往两边走。好处是响应快,坏处是行程短。
我记得有一次做超薄机型,镜头模组空间受限,只能用中置马达。结果发现近摄端(Macro)行程不够,最后靠算法做了“数字补偿”才勉强过关。
4.2 DAC值与镜头位置的映射关系
DAC值,就是驱动马达的数字量。但DAC值和镜头位置之间,不是简单的线性关系。我画了一张图,帮你理清这个映射逻辑。
实际项目中,我们通常会在产线做“DAC校准”。具体做法是:给马达一组DAC值,用激光测距仪记录实际镜头位置,然后拟合出一条曲线。我习惯用分段线性拟合,精度够用,计算量也小。
Position = K * DAC + Offset + Hysteresis(DAC, direction)其中K是增益,Offset是零位偏移,Hysteresis是迟滞项(与当前DAC和运动方向相关)。
4.3 I2C控制时序与实战要点
VCM马达的控制接口,99%都是I2C。高通平台通过CCI(Camera Control Interface)总线来读写马达的寄存器。说白了,就是往马达芯片里写DAC值,让它动起来。
4.3.1 标准I2C写时序
一个典型的I2C写操作包含:起始位、设备地址、寄存器地址、数据、停止位。我直接给你看代码,这是高通平台常用的驱动片段。
// 高通平台VCM马达I2C写操作示例
static int vcm_i2c_write(struct i2c_client *client, uint16_t reg, uint16_t val)
{
int rc;
struct i2c_msg msg;
uint8_t buf[3];
buf[0] = (reg >> 8) & 0xFF; // 寄存器高字节
buf[1] = reg & 0xFF; // 寄存器低字节
buf[2] = val & 0xFF; // DAC值
msg.addr = client->addr;
msg.flags = 0; // 写操作
msg.len = 3;
msg.buf = buf;
rc = i2c_transfer(client->adapter, &msg, 1);
if (rc < 0) {
pr_err("VCM I2C write failed: %d\n", rc);
return rc;
}
return 0;
}
这段代码看起来简单,但坑不少。我曾经遇到过一个问题:连续快速写DAC值时,I2C总线会卡死。后来发现是马达芯片的“写周期时间”(tWR)没满足——两次写操作之间至少要等500μs。
4.3.2 高通平台CCI时序配置
高通平台的CCI控制器,可以配置I2C的时钟频率、上升时间、下降时间。我一般这样配:
| 参数 | 典型值 | 说明 |
|---|---|---|
| 时钟频率 | 400kHz | 标准模式,兼容性好 |
| 上升时间 | 300ns | 根据总线电容调整 |
| 下降时间 | 100ns | 一般保持默认 |
| 写周期时间 | 500μs | 两次写操作的最小间隔 |
嗯,这里要注意:如果总线电容太大(比如接了多个从设备),上升时间不够会导致波形畸变。我遇到过一例,就是因为马达和EEPROM共用一条I2C总线,上升时间从300ns改到500ns才稳定。
4.3.3 多马达同步控制
现在很多旗舰机有双摄、三摄,每个摄像头都有自己的VCM马达。高通平台支持多路CCI总线,可以同时控制多个马达。但有个细节:不同马达的I2C地址不能冲突。
我建议的做法是:在驱动初始化时,先扫描所有马达的I2C地址,确认唯一性。如果发现地址冲突,通过马达的“地址配置引脚”来区分。
4.4 实战:从DAC值到镜头移动的完整流程
我把整个流程串起来,给你一个完整的闭环视角。
- AF算法计算目标位置:比如算法算出镜头需要走到DAC值500。
- 查映射表:根据马达类型,查表得到对应的DAC值(开环)或目标位置(闭环)。
- I2C写操作:通过CCI总线,把DAC值写入马达寄存器。
- 马达响应:VCM驱动线圈,推动镜头移动。
- 位置确认:闭环马达通过霍尔传感器读取实际位置;开环马达则等待固定时间(Settle Time)。
- AF算法确认:检查对焦评价函数是否达到峰值,如果没达到,继续调整。
这个流程看起来简单,但每一步都有优化空间。我个人习惯在“I2C写操作”和“位置确认”之间加一个状态机,用来处理异常情况——比如I2C写失败、马达卡住、霍尔传感器读数异常等。