干这行快十年了,做过的无线充电项目没二十个也有十五个,但NU1680这颗芯片在我心里的地位一直很特殊。TWS耳机充电仓的无线化方案我前后试过好几套,有的方案外围电路复杂得能塞下半块木板,有的方案协议栈封装得太死,想调整输出都得重新流片一般。NU1680的出现算是把这中间的平衡点找到了——它把QI协议栈和整流稳压全集成进去,又留了I2C接口让你能动态调压,刚好踩在TWS耳机这类小体积、高集成度产品的刚需上。这篇就结合我个人实际跑过的项目,把NU1680在TWS耳机里的应用从头到尾拆一遍,重点讲I2C调压怎么实现、QI协议怎么适配、硬件怎么布局不出问题,最后把调试中踩过的坑一一罗列出来。打算做无线耳机、智能手表充电底座、或者其他Qi标准小功率接收端的工程师朋友,这篇应该能帮你少走不少弯路。
1. NU1680这颗芯片到底解决了什么问题
1.1 从TWS耳机充电仓的无线化说起
TWS耳机这波浪潮起来之后,充电仓的形态经历过好几次迭代。最早是Micro-USB,后来换成Type-C,再往后大家发现耳机仓本身就是一个天然的“无线充电接收端”——你把它放在一个发射板上,仓里的接收线圈就能给耳机仓内部的电池充电。这个场景听起来简单,但实现起来很拧巴:耳机仓内部空间多一毫米都挤,电池要占大头,电路板要薄,线圈还要贴在壳子上。你不可能像做手机无线充电底座那样堆一个大功率方案进去,5W以内才是这个场景的安全区。
而且耳机仓的电量管理逻辑比手机复杂:耳机放进去要充电,耳机仓本身要给手机反哺电量(部分高端产品),还要兼顾充电仓自身的MCU、灯效、霍尔传感器这些外设的供电。这就要求无线充电接收端不仅能稳定输出,还得能动态调整输出电压,配合后级充电管理IC完成不同阶段的充电策略。早期做法是接收端固定输出5V,后面再挂一颗升降压和一个充电IC,但这套方案在外围面积和成本上都吃亏。NU1680这类高度集成的接收芯片,把整流、稳压、协议处理全收进去,通过I2C直接动态配置输出电压,自然就成了更优解。
1.2 NU1680内部架构与核心资源
我第一次拿到NU1680的规格书时,第一反应是“这芯片把系统设计师的活抢了”。它内部集成了同步整流控制器、线性稳压或者DC-DC调整管、QI协议物理层和协议栈、以及一个I2C从机接口。从外面看,你只需要接一个接收线圈、一个谐振电容、一个输出滤波电容,再加一个I2C总线连接到主控MCU,整个无线充电接收路径就齐了。
具体到信号链路上:接收线圈感应到高频磁场,产生交流电压,经过内部同步整流变成直流,再通过内部调整管稳定输出。QI协议的部分由芯片内部的协议引擎自动处理,包括数字ping的应答、信号强度上报、通信握手、控制误差包响应和异物检测(FOD)相关计算。这些原本需要MCU实时处理的流程,NU1680自己就完成了,主控MCU只需要定期通过I2C查询状态、读取功率数值、配置输出电压即可。
1.3 为什么不用普通整流+充电方案
可能有朋友会问:我直接用二极管整流桥加一颗LDO,再接一颗充电IC不行吗?答案是不行,而且差很远。二极管整流的压降在低电压大电流场景下损失太惨,无线充电接收线圈输出的交流电压通常只有几伏,二极管每路压降按0.4V算,全桥就是0.8V,效率直接掉到70%以下,5W输入最后能充到电池里的大概只有3W多,一大半变成热量。
更重要的是,QI协议需要一个完整的物理层通信机制:接收端要通过调制线圈负载来向发射端“说话”,这个过程叫ASK(幅移键控),发射端则通过改变磁场频率来给接收端“回话”,叫FSK(频移键控)。这些通信全部要按QI标准协议栈的时序来走。你自己用MCU实现,需要实时监控线圈上的信号变化,在几毫秒甚至几微秒的时间窗口内完成解调与应答,普通MCU做起来非常吃力,实时性和稳定性都不好保证。NU1680把这件事固化在硬件逻辑里,可靠性完全不是一个量级。
2. QI协议适配是第一步:从握手到功率传输
2.1 QI协议的关键包结构
现实的工程经验是:先把QI协议跑通了,后面的I2C调压才有意义。NU1680虽然集成协议栈,但你不了解协议流程,出了问题连排查方向都没有。QI协议最核心的阶段可以理解为握手与会话:
- 模拟ping阶段:发射端检测到接收端放在上面,尝试建立连接。
- 数字ping阶段:发射端发出更大的能量脉冲,接收端必须在这个窗口内返回信号强度包(SSP),否则发射端会认为没有合法接收设备,重新回到待机。
- 识别与配置阶段:接收端发送ID包、配置包,发射端据此确认功率等级(BPP 5W或者EPP更高功率档位)。
- 功率传输阶段:接收端持续发送控制误差包(CE)来告诉发射端“功率太强了减一点”或“太弱了加一点”,同时定期发送电量包(RP)汇报接收功率,用于FOD异物检测。
- 结束阶段:接收端发送结束功率传输包(EPT),正常结束充电。
NU1680在握手阶段的表现很稳,但前提是外围谐振参数要对,否则接收端线圈在当前工作频率上得不到足够的电压,SSP包的数字就不对,发射端会认为接收端“不存在”。这个坑我踩过一次,后面会展开说。
2.2 谐振网络参数匹配实战
谐振网络是无线充电接收端最容易出问题的地方。接收线圈本身有一个电感量,通常会在接收端并联一颗谐振电容,让线圈和电容在某个目标频率上产生并联谐振,这样在磁场作用下可以感应出更高的电压。
选电容的计算很直接,就是用LC谐振公式:
f = 1 / (2×π×√(L×C))
比如说,你用的接收线圈在100kHz附近电感量实测为12μH,把频率定在110kHz左右,求C:
C = 1 / (4×π²×f²×L) = 1 / (4×9.8696×(110000)²×0.000012) ≈ 174nF
实际取值可以选择两颗普通X7R电容并联凑整,比如100nF+68nF=168nF,或者120nF+47nF=167nF,误差完全可以接受。这里注意不要用高容量的MLCC直接单颗怼上去,陶瓷电容的直流偏压特性会让容量在电压升高后大幅下降。我习惯用两个并联,既调整容量,又分摊电流应力。
注意:线圈电感会受周边金属件影响而漂移。耳机仓内电池、屏蔽罩、结构件都会改变等效电感。所以一定要把线圈贴在最终结构件上实测电感,再反推谐振电容,不要看规格书的标称值直接算。
2.3 功率协商与FOD调试要点
功率协商这部分,NU1680内部已经闭环了,发射端发来的功率调整命令,它会在内部自动更新CE包。但FOD(异物检测)是一个需要应用层介入的点。发射端会默认接收端上报的功率和发射端自己送出的功率是吻合的,如果差值超过阈值,就认为中间有金属异物在吸收功率,立即停止充电。
问题出现在哪里呢?接收端实际接收到的功率和发射端计算出的功率,本身就存在误差。线圈对位偏移、接收端负载突变、甚至是充电仓内电池充饱后负载变小,都会让差值变大。如果你的产品放在金属桌面上充电,误报FOD的概率会更高。
我处理FOD问题的方法是:在NU1680的应用层配置里,把FOD阈值根据实测结果做校准。具体做法是,在正常充电场景下,用电流探头和功率计同时测发射端输入功率和接收端输出功率,把差值数据记录下来,然后对应调整阈值。NU1680允许通过I2C读取实时接收功率,配合上位机建立一份“功率差基线表”,再把阈值设定为基线值加一点余量(比如+0.5W),这样既能防异物又不会频繁误停。
3. I2C调压机制深度拆解
3.1 I2C在NU1680里的角色
I2C总线在本项目里的角色,一句话概括就是“应用层与协议层之间的桥梁”。主控MCU不需要也不可能直接干涉QI物理层的实时时序,它只需要通过I2C向NU1680询问“你现在输出的是多少伏”“功率如何”“温度多少”,以及下发“把输出电压调到4.35V”这样的指令。
对比一下常见的几种串行总线就明白了:UART是收发双方的异步传输,没有时钟线,靠波特率对齐,适合点对点;SPI是主从同步全双工,速度快,但至少4根线,还要片选;I2C只需要两根线(SDA和SCL),用地址区分设备,适合一条总线上挂多个从机。NU1680在耳机仓系统里往往和触摸IC、霍尔传感器、电量计IC串在一条I2C总线上,这种多设备共享总线的场景,I2C天然合适。而且7位地址模式下能挂128个设备,一个耳机仓主板上那点外设绰绰有余。
3.2 开漏输出与上拉电阻的底层逻辑
I2C总线物理层采用“开漏输出+上拉电阻”结构,这算得上是最经典也最容易被轻视的设计。开漏的意思是,芯片内部的MOS管只负责把总线拉低(灌电流),不负责主动输出高电平;高电平完全依靠外部上拉电阻把总线拉到供电电压。这样的好处有两个:第一,支持多设备“线与”操作,任何一个设备拉低总线,整条总线就是低电平,不会发生两个设备同时输出高低电平导致短路;第二,可以通过选择不同上拉电阻值,改变总线上升沿时间,从而适配不同通信速率和总线长度。
上拉电阻怎么选,不能拍脑袋。I2C协议的快速模式(Fast Mode,400kHz)要求上升时间不超过300ns,上升时间由总线等效电容和上拉电阻共同决定,公式是:
tR = 0.8473 × R_pullup × C_bus
如果总线上挂的设备多、走线长,总线电容可能在100pF到200pF。按150pF算,要求tR不超过300ns,那么:
R_pullup ≤ 300ns / (0.8473 × 150pF) ≈ 2.36kΩ
这是上限。下限则由灌电流能力决定:低电平时芯片要能扛住上拉电阻流过来的电流,Fast Mode要求IOL最大为3mA,供电电压3.3V,VOL最大0.4V:
R_pullup ≥ (3.3V - 0.4V) / 3mA ≈ 967Ω
综合上面两个约束,1kΩ到2.2kΩ是Fast Mode下的合理区间。我实际项目里,NU1680和主控MCU距离很短(同一块板子上不超过5cm),总线电容很小,用2.2kΩ没问题;如果中间有FPC软排线连接,总线电容变大,就换1.5kΩ甚至1kΩ。很多人图省事直接上4.7kΩ,低速场景没问题,但在400kHz以上或者总线上多挂几个设备时容易出现上升沿过缓,波形边缘圆滚滚,严重时斜率不够触发阈值,通信就时好时坏。
提示:如果MCU的I2C外设内部有上拉电阻可选,建议直接禁用,依靠外部上拉。内部上拉一般20kΩ到50kΩ,等效并联后对外部上拉影响不大,但内部上拉的温度漂移和工艺偏差不好控制,不如彻底关掉来得干净。而且有些MCU在I2C模式下内部上拉逻辑复杂,开着反而容易出现莫名奇妙的电流倒灌。
3.3 输出电压配置流程与寄存器操作
NU1680输出电压调节的基本思路,是通过I2C写寄存器来改变内部调整管的参考电压。不同批次、不同封装的NU1680寄存器映射存在差异,我这里只讲通用思路,具体寄存器的偏移地址和bit定义务必以官方最新数据手册为准。
典型流程如下:
- 主控MCU发起I2C写操作,向NU1680的电压配置寄存器写入目标档位。
- 芯片内部DAC更新参考电压,稳压环路经过短暂过渡后把输出电压切换到新目标值。
- 主控MCU通过I2C读取电压状态寄存器,确认实际输出电压与目标一致。
在TWS耳机场景里,我会把调压逻辑和充电状态机绑定:电池电量低时,需要大电流充电,可以把接收端输出电压调高一点,给后级充电IC更充裕的压差;电量接近充满时,电压可以略微降低,减少充电电流,保护电池。这个策略并不复杂,关键是在切换电压时加入延时和保护判断,防止热插拔或负载突变造成输出过冲。
4. 驱动代码开发与I2C时序验证
4.1 通用I2C驱动框架(基于MCU)
如果你用的是STM32的HAL库,I2C底层驱动不需要自己操作寄存器,HAL已经把时序细节封装好了。问题在于HAL库默认的I2C模式可能是推挽输出,而I2C总线要求开漏。如果MCU引脚配置为推挽,而外部又有上拉电阻,那么MCU输出高电平时总线被拉高,输出低电平时总线被拉低,逻辑上看起来也能工作,一旦总线上有另一个设备也在驱动同一根线,就存在短路风险。
正确的配置是:把SDA和SCL引脚设置为开漏输出(GPIO_MODE_AF_OD),开启上拉或者依靠外部上拉。以STM32HAL库为例:
GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_I2C1_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; // SCL, SDA GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // 开漏复用功能 GPIO_InitStruct.Pull = GPIO_NOPULL; // 外部已接上拉,内部不上拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);注意GPIO_NOPULL这个选项,前面说过,外部已经有2.2kΩ上拉,内部上拉没意义反而可能引入不确定性。
4.2 NU1680读写时序的完整代码
下面这段代码是我从项目里简化出来的,功能是设置NU1680输出电压并读回确认。注意I2C数据帧的完整时序我写在了注释里,方便对照逻辑分析仪抓包验证。
#define NU1680_I2C_ADDR 0x24 // 7位从机地址,具体以手册为准 #define NU1680_REG_VOUT 0x20 // 输出电压配置寄存器 #define NU1680_REG_STATUS 0x21 // 状态寄存器 #define NU1680_VOUT_4P20V 0x0A // 档位定义示例:4.20V #define NU1680_VOUT_4P35V 0x0B // 档位定义示例:4.35V static HAL_StatusTypeDef nu1680_write_reg(uint8_t reg, uint8_t val) { // 完整时序: // START -> 地址(7bit)+W(0) -> ACK -> 寄存器地址 -> ACK -> 数据 -> ACK -> STOP uint8_t buf[2] = {reg, val}; return HAL_I2C_Master_Transmit(&hi2c1, NU1680_I2C_ADDR << 1, buf, 2, 100); } static HAL_StatusTypeDef nu1680_read_reg(uint8_t reg, uint8_t *val) { // 完整时序: // START -> 地址(7bit)+W(0) -> ACK -> 寄存器地址 -> ACK // REPEATED START -> 地址(7bit)+R(1) -> ACK -> 数据 -> NACK -> STOP HAL_StatusTypeDef status; status = HAL_I2C_Master_Transmit(&hi2c1, NU1680_I2C_ADDR << 1, ®, 1, 100); if (status != HAL_OK) return status; return HAL_I2C_Master_Receive(&hi2c1, (NU1680_I2C_ADDR << 1) | 1, val, 1, 100); } int nu1680_set_vout(float voltage) { uint8_t reg_val; uint8_t readback; if (voltage > 4.35f) voltage = 4.35f; if (voltage < 3.50f) voltage = 3.50f; // 电压到寄存器值的映射,具体的量化步进要看芯片手册 // 这里假设步进50mV,起点3.50V对应0x00 if (voltage <= 4.20f) { reg_val = NU1680_VOUT_4P20V; } else { reg_val = NU1680_VOUT_4P35V; } if (nu1680_write_reg(NU1680_REG_VOUT, reg_val) != HAL_OK) return -1; // 回读确认 if (nu1680_read_reg(NU1680_REG_VOUT, &readback) != HAL_OK) return -1; // 加一点回读校验,防止写失败导致输出电压停留在错误档位 if (readback != reg_val) return -2; return 0; }关于写多个字节,比如一次配置输出电压、输出限流、工作模式三个寄存器,I2C时序是连在一起的:START后,先发设备地址+写位,再连续发送多个数据字节,中间只有寄存器地址和连续数据,最后才发STOP。这种“组合写”的方式比多次重复“START-写-写-STOP”效率高,也避免总线中途被其他设备抢占。
4.3 用逻辑分析仪验证时序的实操方法
代码写完不要急着上板联调,先抓波形。我常用的是几十元价位的逻辑分析仪加配套PC软件,采样率开到10MHz以上,通道一接SCL,通道二接SDA,地线一定要和板子共地。
抓到的波形怎么看?首先是起始条件:SCL为高电平期间,SDA发生高到低的跳变。然后是地址字节:前7位是地址,第8位是读写标志,之后是ACK位,从机拉低SDA表示应答。如果逻辑分析仪解码出来的设备地址跟你代码里设置的不一致,大概率是地址位数搞错了——很多芯片手册给的是8位地址(已经包含读写位),而栈代码里写的是7位地址,转换时漏掉左移一位,这是最典型的低级错误。
上升沿的观察同样重要。在波形视图里直接把时间轴拉细,看SDA和SCL的上升沿是不是陡峭。如果上升沿弧度很大,甚至有个明显的斜坡,说明上拉电阻偏大,总线电容也偏大,可以考虑换小阻值的上拉电阻。另外,如果从机发送的ACK一直读不到,即第九个时钟周期SDA没有被拉低,优先检查地址和电源,然后看波形上有没有字节间空隙过大导致的超时。
5. 硬件设计实战:原理图、布局与协同
5.1 典型应用电路详解
NU1680的典型应用电路比很多电源芯片还精简。电源路径上:接收线圈两端接芯片的AC1/AC2输入脚,线圈两端并联谐振电容,整流输出脚接输出滤波电容和负载。I2C部分:SDA和SCL各接一颗2.2kΩ上拉电阻到3.3V主控电源,两个引脚各对地加一颗100pF的小电容,用于滤除无线充电时的电磁干扰。
有人觉得100pF滤波电容会影响I2C上升沿,其实在400kHz下影响很小。上拉电阻2.2k,100pF对地电容带来的时间常数约220ns,配合上升沿公式计算,增加的延迟在可接受范围内,收益是显著降低了空间耦合进来的噪声。
还有一个容易忽视的器件是TVS管。无线充电线圈在耦合瞬间可能产生很高的尖峰电压,即使芯片内部有保护,外部在交流输入脚对地加一颗双向TVS更保险。TVS的结电容选小一点的,几十pF以内即可,太大并联在谐振回路上会影响谐振频率。
5.2 PCB布局的散热与抗干扰
TWS耳机充电仓的PCB往往是异形板,留给无线充电接收部分的空间非常有限。但布局上有几个原则必须遵循:
第一,接收线圈的走线要短粗。线圈到芯片AC脚之间的走线尽量短,走线太细太长会引入额外的串联电阻和寄生电感,导致接收效率下降。我用0.3mm以上的线宽,走线直接在底层铺铜加宽。
第二,芯片底部的散热焊盘要真正连到地铜皮。NU1680的输出功率虽然只有几瓦,但在小空间内热阻大,散热焊盘不接地铜皮,芯片温度会很容易超过规格。在PCB上把底层铺铜作为散热面,多打过孔连接。
第三,I2C走线远离线圈和功率路径。线圈工作时周围有强磁场,I2C线上的感应电压轻则导致通信毛刺,重则把SDA钳死。我习惯让I2C走线走内层,两侧包地,地平面隔离。
5.3 与TWS耳机充电仓整体的配合
硬件设计不能只看芯片本身,还要看它在整个耳机仓系统里的位置。线圈的位置直接决定用户把耳机仓放上充电板时的对位效果。线圈中心最好对准充电仓外壳上标识的充电区域,而且线圈下面不能有大面积金属支架或者磁铁,否则无线充电磁场的耦合效率会下降,FOD误报率升高。
电池位置也值得留意。NU1680输出给后级充电IC,充电IC放在电池旁边,避免长距离大电流走线。主控MCU放在NU1680的另一侧,I2C走线不跨过电池和线圈区域。耳机仓的霍尔传感器如果用了磁铁方案,磁铁位置要远离接收线圈,不然磁铁会吸收磁场能量,导致线圈感应电压虚高,触发芯片过压保护。
从结构角度讲,耳机仓上盖一般压着线圈,下壳里是电池和主板。这样线圈距离充电板的外壳表面近,耦合效率高。但上盖如果是金属材质,整个无线充电方案就要重新评估,金属会屏蔽磁场。做结构方案之前,一定先用实测线圈测试壳料对效率的影响,别等到开模了才发现效率不够。
6. 常见问题排查与调试经验速查
6.1 I2C通信不稳定的典型现象与对策
我在多个项目里都遇到过I2C通信“时好时坏”的情况,表现是:上电第一次读写成功,之后偶尔失败,复位后又好。排查思路按优先级排列:
最先是推挽与开漏的冲突。MCU引脚配置成了推挽输出,而总线上拉了电阻。推挽输出高电平时直接强驱动,外部上拉电阻变成负担,低电平时又可能和其他设备抢线,表现为偶发通信错误。把引脚改成开漏输出,问题立即解决的概率很高。
其次是上拉电阻阻值问题。之前已经算过,400kHz下4.7kΩ已经偏大,如果总线上还挂了其他设备,总线电容更大,上升沿超时更明显。把上拉电阻从4.7k换成2.2k或者1.5k,一般都能改善。
最后是电源噪声。NU1680是无线充电芯片,工作时线圈切换会在电源上产生毛刺,如果MCU的3.3V电源域和NU1680的电路共用一个LDO,I2C高电平也会被拉出毛刺。解决办法是给MCU电源单独加一个RC滤波,或者在I2C线上加100pF对地电容。
注意:I2C的SDA线被长时间拉低,通常是某个从机在应答后进入异常状态,把SDA锁住。排查时先断开所有从机的供电,上电看SDA线上是否还有持续低电平。如果有,就是总线某一端的开漏驱动没有释放。没有的话,逐个接回从机,锁定问题设备。
6.2 QI充电异常的处理思路
QI充电异常最常见的现象是放上充电板完全没有反应,指示灯不亮。设备连上逻辑分析仪,抓发射端输出的数字ping窗口,看接收端是否返回了SSP包。如果没有,检查三个地方:一是接收线圈是否谐振在发射端工作频率附近,如果谐振频率偏了太多,感应电压过低,芯片无法工作;二是接收端输出电压是否稳定,如果芯片的LDO输出没有建立起来,协议引擎也无法启动;三是线圈与发射端的距离,TWS充电仓外壳太厚也会导致耦合不足。
另一种常见现象是充电一开始,过几秒就停止。这种情况多半是FOD误触发。解决办法是校准FOD阈值,或者在结构上改善线圈对位。有时候接收端的负载变化也会引起功率差突变,比如耳机仓内电池接近充满时电流下降,接收功率突然减少,发射端会认为功率异常,触发保护。可以在配置里增加FOD检测的时间窗口,让短时波动不被误判。
6.3 批量生产和软件联调中的坑
批量生产阶段最容易出现的问题是同一批板子,有的I2C正常,有的不正常。这种问题基本都是上拉电阻取值处在临界状态,或者焊接不良导致的上拉电阻虚焊。我遇到过一整批板子SDA波形都是“斜坡状”,最后发现是贴片厂把2.2kΩ电阻错贴成了22kΩ,上拉能力差了十倍。所以批量产线最好增加一道I2C通信测试工位,让产测程序连续读写100次,统计失败率,比单纯看功能通过更可靠。
软件联调阶段,还有一个常见BUG是主控MCU在初始化I2C外设时,先对总线上电,而NU1680此时还没有完成内部初始化。MCU发出的第一个I2C操作发生在芯片没有准备好应答的状态下,收到NACK,代码就直接返回错误,导致整个初始化流程中断。解决办法是在初始化NU1680之前加一个延时,或者MCU读不到ACK时自动重试几次。
另外,多个从设备挂在同一条总线上时,要注意地址冲突。有些触摸IC和电量计IC的默认地址和NU1680相同,或者地址距离过近导致寻址错乱。设计阶段一定要汇总所有I2C设备的7位地址,确认没有冲突,量产阶段如果有物料替代,地址也要重新核对。
最后分享一个实际的调压心得:NU1680的I2C调压不是改完寄存器就万事大吉。输出电压跳变时,后级充电IC的输入电容会瞬间吸收大量电流,可能触发输出过流保护。我在实际项目里做了一个软件斜坡,把电压从3.6V逐步升到4.35V,每次升一个档位间隔10毫秒,既避开了浪涌,又不会让充电IC误判输入异常。这种小细节在产品稳定性上的提升,比你去改电路还明显。