简介:英集芯IP5365寄存器手册面向移动电源与快充类产品的嵌入式开发者、硬件工程师,聚焦IP5365这颗集成Type-C、UFCS、PD3.0等协议的电源SoC在寄存器层面的配置与调试需求。压缩包内含1个PDF文档,约3.52MB,章节划分清晰,可作为设计阶段的对照查阅资料。目前已有677人学习下载。文档从I2C接口讲起,说明LED1、LED2复用为I2C的默认连接方式、最高300kHz通信频率、8位寄存器地址与数据高位在前的格式,并给出0xE8/0xE9与0xEA/0xEB两组设备地址的读写时序示例与信号流程图。应用笔记部分还涉及VCC总电容不超过3.3uF、MCU侧电容与串阻、大电流场景外加LDO等供电约束,以及休眠转工作状态时的I2C检测、INT拉高100ms后再读写、SDA与SCK配置为高阻等实操要点。另附LED3、INT引脚的电气特性与中断复用说明,并强调寄存器须按读—修改—写逐位操作,避免误改保留位。
1. 一颗 SoC 的 I2C 藏在 LED 引脚里
翻开 IP5365 寄存器手册,很多人第一反应是找那张地址表,但真正决定这颗移动电源 SoC 能不能被 MCU 管起来的,是两颗 LED 引脚上的 3.3k 上拉电阻。它把充电、升压、多口快充协议、电量计全塞进单颗 die,引脚数量是硬通货,所以 I2C 的 SDA/SCK 没有独立管脚,而是和 LED1、LED2 复用。代价很直接:芯片每次从休眠醒过来,都要先看一眼 LED1、LED2 是不是同时被拉到 3.3V,才决定自己当一颗只管灯效的芯片,还是当一颗可被寄存器操控的电源。这套握手没搞明白,地址表背得再熟也会在第一个 ACK 上翻车。
2. 进 I2C 模式靠两根 LED 引脚投票:上拉检测、VCC 电容与时序窗口
IP5365 默认就是支持 I2C 的,不需要烧配置、不需要发特殊命令,只要按手册给的方式把 LED1、LED2 通过 3.3k 电阻上拉到 VCC,上电后其他功能自动关闭,直接进 I2C 模式。听起来像是"硬件一接就通",但真正的机制藏在"什么时候检测"和"检测到什么"这两个细节里,而这两个细节决定了你 90% 的调试时间花在哪里。
2.1 每次唤醒都重跑一遍的引脚投票
芯片从休眠转入工作状态只有三种触发源:按键、负载接入、5V 充电接入。每一次触发,内部都会先把 LED1、LED2 这两个脚当普通 GPIO 读一遍电平,只有两者同时为高(即同时被上拉到 VCC 的 3.3V),才判定"外部挂了数字接口",切进 I2C 模式,并把 LED3 拉出一个 3.1V 的高电平;只要有一个没被拉高,就退回 LED 灯显模式。注意手册里的措辞是"每次从休眠进入工作状态都会进行检测",不是上电检测一次就完事,这意味着运行期间任何一次状态回落都会重新投票。
这个设计的好处很实在:同一颗芯片、同一套固件,焊到带 MCU 的板子上就是智能电源,焊到不带 MCU 的板子上就是普通充电宝,产线不用分型号。而 LED3 那一路 3.1V 高电平,在多数原理图里会串一颗 510k 电阻引出去当 INT 用,MCU 拿它判断"有按键了、有负载插入了、有 5V 接入了"。510k 这个阻值选得很大,既能把 3.1V 电平送出去,又不会在芯片休眠时反向灌电流。
真正容易出问题的是"投票"的物理含义:所谓上拉,本质是要求这两根线上没有别的东西在往下拽。MCU 休眠时如果把 SDA/SCK 配成推挽输出低,外部 3.3k 上拉根本拽不住一个几十欧输出阻抗的引脚,芯片采样到的就是低电平,于是判定"没有 I2C",切回灯显模式。这就是手册第 5 条反复强调 MCU 休眠时必须把这两根线配成输入或高阻的全部原因——不是建议,是硬性前提。
2.2 VCC 上的电容预算:3.3uF 和 1uF 是从哪来的
手册给了一条很硬的约束:VCC 上总电容容量必须小于 3.3uF,超过这个阈值会影响 IC 的上电速度。这个数字背后是两种失效模式。常见的实现思路是,VCC 既是内部数字域的供电轨,也是上电复位(POR)的参考点,上电瞬间的充电电流由芯片内部决定,容性负载越大,VCC 爬升越慢;爬升慢本身不致命,致命的是 POR 释放点和 LED 上拉检测的采样窗口都挂在 VCC 电压上——电压还在 1.x V 徘徊时数字逻辑已经开始跑,此刻采样到的电平无效,结果就是随机的"有时进 I2C、有时不进"。
针对挂 MCU 的场景,手册给了三张图,对应三种功耗等级的解法。MCU 附近那颗 VCC 电容必须 ≤1uF,这是图 a;MCU 确实需要更大容量的储能电容时,先用 R1 ≥ 2Ω 串在中间,再接 2.2uF 的大电容,让 RC 把大电容的充电电流限住,主轨该快还是快,这是图 b;MCU 自身耗电超过 30mA 时,直接外挂一颗 3.3V LDO 单独喂 MCU,VCC 只负责 IP5365,这是图 c。
这里有一对看起来互相矛盾的条款需要一起读。手册第 6 条说 MCU 供电必须由 VCC 来,因为 IP5365 内部数字电平就是 3.3V;如果 MCU 走外部 LDO,当电池没电或低于 2V、VIN 接入 5V 时,VCC 有电会启动 I2C 检测,但 MCU 那边还没上电,SDA/SCK 状态不定,可能把线拉低导致检测失败。图 c 又明确允许外挂 LDO。我一般会这么理解:手册允许 LDO,但要求 LDO 的输入取自 VCC 或与 VCC 同源同时序,保证"IP5365 在采样时,MCU 的引脚已经处于高阻态"这个前提成立。如果 LDO 直接从 VIN 取电、上电斜率比 VCC 慢,那就是踩着这条坑走。
2.3 MCU 侧的上电时序:INT 为高之后还要再等 100ms
手册写得很清楚:MCU 在休眠时要把 SDA 和 SCK 配成输入或高阻,直到检测到 INT 为高后持续 100ms 以上,才开始读写 I2C 数据。这 100ms 不是随手拍的延时,它覆盖的是"芯片完成模式判定 + 内部状态机就绪 + 数字域稳定"这一段窗口。很多实现里把它当成可省的冗余,结果就是首次读寄存器偶发 NACK,重试一次又好了——这种玄学问题的根源就在这。
/* 前提:SCK/SDA 已由 3.3k 上拉到 VCC,INT 由 LED3 经 510k 引出 */ static int ip5365_bringup(void) { /* 1. 第一步先把两根线放开,别让 MCU 把上拉拽低。 这一步必须在配置 I2C 外设之前,因为唤醒瞬间芯片就在采样 */ gpio_config_input(SDA_PORT, SDA_PIN); gpio_config_input(SCK_PORT, SCK_PIN); /* 2. 等 INT 稳定为高,再额外等 100ms。 加超时是为了区分"没进 I2C 模式"和"进了但还没就绪" */ uint32_t t0 = millis(); while (gpio_read(INT_PIN) == 0) { if (millis() - t0 > 500) return -1; /* 500ms 还没高,基本是硬件没上拉 */ } delay_ms(100); /* 3. 确认握手完成,才把引脚切成 I2C 复用功能 */ i2c_pinmux_enable(); i2c_init(200000); /* 手册上限 300K,工程上留余量 */ return 0; }三个动作的顺序不能换。第一步放在最前,是因为从休眠唤醒的那一刻芯片就在读引脚电平;如果先调i2c_init(),多数 HAL 会把引脚配成复用推挽,采样窗口正好落在推挽阶段,芯片看到的是低电平。第二步的 100ms 是硬等待,不是可优化项。第三步的频率之所以取 200K 而不是手册标称的 300K,是因为 MCU 侧的时钟源通常是 RC 振荡器,几个百分点的偏差叠加在 300K 上就可能越过从机的时序容限,手册自己也建议应用时用 200K 左右。
3. 两组从地址与一帧事务:0xE8 和 0xEA 为什么必须分开记
地址表上最容易被扫过去的一行,是"IP5365 有两组 I2C 地址"。一组写 0xE8、读 0xE9,另一组写 0xEA、读 0xEB。同一颗芯片、同一条总线,却有两个门牌,而且寄存器分散在这两组里——这是整份手册里最容易写错的地方,也是"读得到但读错"这类问题的源头。
3.1 一帧里到底发了什么:8bit 地址 + 8bit 数据 + MSB first
IP5365 的寄存器寻址非常朴素:8bit 寄存器地址,8bit 寄存器数据,地址和数据都是高位在前(MSB)。写一个寄存器的事务序列是:Start → 从机写地址 → ACK → 寄存器地址 → ACK → 数据 → ACK → Stop。手册给的例子是往 0xEA 这组的 0x05 寄存器写 0x5A:Start、0xEA、ACK、0x05、ACK、0x5A、ACK、Stop。没有页寄存器、没有地址自增、没有 CRC,简单到几乎不会出错——除非你把 8bit 地址直接喂给了只认 7bit 地址的 HAL。
这是第一个高频翻车点。0xE8 的二进制是 1110 1000,最低位就是 I2C 协议里的 R/W 位,真正的 7bit 从机地址是 0x74;0xEA 对应 0x75。很多 MCU 的 I2C 驱动接口要求传 7bit 地址并在内部自己拼 R/W 位,如果你把 0xE8 原样传进去,驱动会左移一位变成 0x1D0,溢出成 0xD0 发到总线上,然后你收获一个干脆利落的 NACK。两组地址的换算关系如下:
| 访问组 | 写地址(8bit,含 R/W=0) | 读地址(8bit,含 R/W=1) | 7bit 从机地址 |
|---|---|---|---|
| 主组 | 0xE8 | 0xE9 | 0x74 |
| 扩展组 | 0xEA | 0xEB | 0x75 |
有意思的是,切换读写只需要把最低位翻转,这和标准 I2C 完全一致,说明这两个"门牌"其实是同一物理器件的两个 7bit 地址,只不过这组相邻地址被用来扩展寄存器空间,把 8bit 地址空间从 256 个扩到 512 个。这个做法在引脚紧张、又不想引入页寄存器的芯片里非常常见。
3.2 读操作必须 Restart:地址指针为什么不能跨 Stop 保留
读一个寄存器不是"发读地址然后收数据",因为从机不知道自己该从哪个地址读。手册给的读时序是:Start → 0xEA(写)→ ACK → 0x05(寄存器地址)→ ACK → Restart → 0xEB(读)→ ACK → 数据 → NACK → Stop。中间那个 Restart 是关键:它不发 Stop,直接重新发 Start,从而在不释放总线的前提下切换方向。
为什么不干脆先写地址、Stop、再 Start 读?因为一旦发 Stop,从机内部的地址指针就可能被复位,第二次 Start 时它不知道你要读哪儿。而且 Stop 意味着总线控制权交还,理论上其他主机可以插进来。Restart 在协议上就是为了解决"我需要连续两段方向不同的传输、但不允许中间被打断"这个场景而存在的。
还有一个容易忽略的细节:读的最后一个字节,主机必须回 NACK 而不是 ACK。ACK 的意思是"我还要继续读",从机会把下一个地址的数据推上来;只有 NACK 才告诉从机"到此为止"。如果你回错了 ACK 再发 Stop,多数从机会继续驱动数据线,表现为总线偶发卡死。
3.3 把读-改-写封成一个函数
手册里那句"必须按照读-修改-写来进行"出现了不止一次,这不是保守建议,而是这颗芯片的寄存器里大量存在 Reserved 位,而且这些位的复位值标的是 XX——也就是出厂值不确定。直接整字节写,等于把不认识的位一起覆盖掉,后果是不可预期的行为异常。
#define IP5365_ADDR_MAIN_W 0xE8 #define IP5365_ADDR_MAIN_R 0xE9 #define IP5365_ADDR_EXT_W 0xEA #define IP5365_ADDR_EXT_R 0xEB /* 单字节写:返回 0 成功,-1 表示某个 ACK 没等到 */ int ip5365_write_reg(uint8_t dev_w, uint8_t reg, uint8_t val) { i2c_start(); if (i2c_send_byte(dev_w) != ACK) goto fail; /* 写地址,R/W=0 */ if (i2c_send_byte(reg) != ACK) goto fail; /* 8bit 寄存器地址 */ if (i2c_send_byte(val) != ACK) goto fail; /* 8bit 数据,MSB 先出 */ i2c_stop(); return 0; fail: i2c_stop(); return -1; } /* 单字节读:中途必须 Restart,不能先 Stop 再 Start */ int ip5365_read_reg(uint8_t dev_w, uint8_t dev_r, uint8_t reg, uint8_t *val) { i2c_start(); if (i2c_send_byte(dev_w) != ACK) goto fail; /* 先立地址指针 */ if (i2c_send_byte(reg) != ACK) goto fail; i2c_start(); /* Restart,保持总线 */ if (i2c_send_byte(dev_r) != ACK) goto fail; /* 读地址,R/W=1 */ *val = i2c_recv_byte(NACK); /* 最后一字节回 NACK */ i2c_stop(); return 0; fail: i2c_stop(); return -1; } /* 读-改-写:只动 mask 覆盖的位,其余位保留读回值 */ int ip5365_update_bits(uint8_t dev_w, uint8_t dev_r, uint8_t reg, uint8_t mask, uint8_t value) { uint8_t old; if (ip5365_read_reg(dev_w, dev_r, reg, &old) != 0) return -1; uint8_t neu = (uint8_t)((old & ~mask) | (value & mask)); if (neu == old) return 0; /* 值没变就不写,省总线也省寄存器写寿命 */ return ip5365_write_reg(dev_w, reg, neu); }mask描述"哪些位归我管",value是这些位的目标值,两者按位与之后再或上原值,未被 mask 覆盖的位原样保留。函数末尾那句"值没变就不写"值得保留:I2C 总线在移动电源这种强干扰环境里不是绝对可靠的,少一次写就少一次翻车机会,而且寄存器写次数本身也不是无限的。
dev_w和dev_r成对传入,而不是让函数内部自己算dev_w + 1,是有意的。因为这颗芯片的寄存器分散在两组地址上,调用点必须明确写清楚"这个寄存器属于哪一组",把地址归属做成调用签名的一部分,比在注释里写一行"注意本寄存器在 0xEA 组"要可靠得多。
4. 寄存器不是配置表而是控制树:从总闸到端口的三级开关
把 60 多个寄存器按地址顺序读一遍,很容易觉得这是一堆平铺的开关。实际上它们组成了一棵三层控制树:最上面是系统级的使能与策略,中间是轻载关机的判定逻辑,最下面才是每个输出口的独立开关。理解这个分层,比记住任何一个寄存器的地址都有用,因为你调任何一个口的行为,都要先确认上面两层没有把它覆盖掉。
4.1 总闸与拔电策略:En_Boost、En_Charger、En_C2B_Det
SYS_CTL0(0x00,主组 0xE8)是整个芯片的总闸,低三位分别是 En_Charger(bit0,充电使能)、En_Boost(bit1,升压输出使能)和 En_C2B_Det(bit3:2,拔掉输入充电后是否自动转 Boost)。前两个是布尔开关,复位值都是 1,也就是上电默认既能充也能放。第三个才是真正带策略的字段。
En_C2B_Det 的编码是 00、01、1X 三档:00 表示无论输出有没有负载,拔掉充电器后都自动开 Boost;01 表示只有输出口检测到负载才开 Boost,没负载就进关机;以 1 开头的两个值行为相同,都是不转 Boost、直接进待机。这种"1X"的写法是省寄存器位的老手段,两个编码合并成一个语义,读取的时候不要以为是文档写漏了。
这个字段的默认值是 00,也就是"拔线即升压"。对常开的移动电源产品这是合理默认,但对带小电流负载的产品就是功耗陷阱:设备拔走后 Boost 还在空转,直到轻载关机逻辑把它关掉。所以调这块的时候,00 和 01 的选择实际上是在"响应速度"和"待机功耗"之间做取舍,而不是在调一个功能开关。
4.2 轻载关机:系统级与端口级的双重判定
轻载关机是这颗芯片里逻辑最绕的一块,因为它有两套并行的判定,一套看整机,一套看单个口。
系统级在 SYS_CTL1(0x03)和两个阈值寄存器上。首先要选"看什么":En_Ipow_Low(bit3)让系统看 VSYS 功率,En_Isys_Low(bit2)让系统看 VSYS 电流,默认只开电流这一路。然后是"阈值多少":POW_LOW(0x44)的 6 个 bit 定义POW_LOW = 17.7 * N毫瓦,ISYS_LOW(0x45)的 6 个 bit 定义ISYS_LOW = 5.4 * N毫安,N 最大 63,也就是功率阈值最高约 1.1W、电流阈值最高约 340mA。最后是"多久算轻载":Set_Ilow_Time(bit5:4)给 8S、16S、32S、64S 四档,默认 10 对应 32S。
端口级在每个输出口的 CTL1 寄存器里。VOUT1_CTL1(0x13)、VOUT2_CTL1(0x17)、VBUS_CTL1(0x1B)、VIN_CTL1(0x53)结构几乎一致:bit3:2 是本口的轻载关断时间,2S、4S、8S、16S 四档,比系统级的档位更短更细;bit1 和 bit0 分别是"充电状态下轻载关本口"和"放电状态下轻载关本口"的独立使能。阈值则在各口的 IMOSLOW 寄存器里,IMOS_LOW = 2.68 * N毫安,8 个 bit 覆盖 0 到 683mA,步进比系统级的 5.4mA 细一倍。
为什么要做两级?因为它们的职责完全不同。系统级回答"整机是不是该睡了",它关心的是电池别被白白耗光;端口级回答"这个口上还有没有设备",多口输出时哪个口空了就关哪个口的 MOS,把开关损耗和静态电流省下来。步进做得更细也是同一个原因:手表、耳机这类设备的充电电流只有几十毫安,2.68mA 的分辨率才能把它们和"真的空载"区分开,用 5.4mA 的步进容易误杀。
4.3 端口三件套 DCP / QC / MOS 为什么拆成三个位
每个输出口都有三个独立开关:En_VoutX_Dcp 控制普通 5V DCP 输出,En_VoutX_qc 控制快充能力,En_VoutX_mos 控制 MOS 输出通路。以 VOUT1_CTL0(0x10)为例,bit3 是 DCP、bit2 是 QC、bit0 是 MOS,复位值全是 1。VOUT2 在 0x14,VBUS 在 0x18,VIN 在 0x50(扩展组 0xEA),结构完全对称。
拆成三个位而不是一个"口使能",是因为它们处在协议栈的不同层。MOS 是物理层,关掉等于把这个口从电路上断开,后面挂什么设备都测不到;QC 是协议层,关掉之后口上还有 5V,但不会走快充握手;DCP 是基础充电能力,关掉就只剩协议不通的裸电压。调试时最典型的症状是"口上有 5V,但手机就是不快充"——这种时候先看 QC 位是不是被清了,而不是怀疑协议芯片坏了。
再往下还有两个检测使能,容易混淆。En_VoutX_DmDp_Det 在 VOUT1_CTL2(0x1C)、VOUT2_CTL2(0x1D)、VBUS_CTL2(0x1E)里,走的是 D+/D- 上的负载识别;而 En_VoutX_VDet 在扩展组的 0x4D 里,手册专门注明"不控制 DM DP 检测"。更省空间的是,VOUT1_CTL3 和 VOUT2_CTL3 共用 0x4D 这一个字节,bit0 归 VOUT1、bit1 归 VOUT2。写这个寄存器的时候如果用了整字节写,顺手就把隔壁口的配置改了——这正是读-改-写必须贯彻到每一次写操作的原因。
4.4 欠压环路与充电超时:把"能充"约束成"不出事"
CHG_CTL0 到 CHG_CTL2 三个寄存器管的是输入欠压环路电压,也就是输入电压跌到多少时开始回退充电电流。12V 输入有 8 档,从 10.7V 到 11.8V,默认 011 对应 11.4V;9V 输入 8 档,7.98V 到 8.80V,默认 100 对应 8.58V;5V 输入的 5V_Uvloop 也是 8 档,4.46V 到 4.92V,默认 001 对应 4.54V。这些档位的存在意义在于线材:劣质线缆的内阻在 2A 电流下能压掉几百毫伏,环路点定得太高会频繁触发降流,定得太低又会让适配器被拉到保护点以下。
CHG_CTL2 里还多一个 Ppath_Uvloop(bit5:3),默认 111 对应 4.92V。这个值比同寄存器的 5V_Uvloop 高,因为同充同放时输入要同时喂系统和电池,环路点必须留更大余量,否则一插充电器就掉压。
超时控制分在两个寄存器。CHG_CTL3(0x21)的 Set_chg_time 是总充电超时,0 为关闭,1 到 7 分别对应 12、18、24、30、36、42、48 小时,默认 100 即 30 小时。CHG_CTL4(0x22)拆得更细:bit6:4 是 CV 阶段超时,默认 011 即 4 小时;bit3:1 是涓流阶段超时,默认 001 即 2 小时。涓流超时是最容易被忽略的一项,但它的安全意义最大:电芯长期停在低压区时,涓流会一直往里灌,超时机制就是防止这种状态无限持续。
4.5 25mA 步进背后的校准语义:寄存器值是相对量
所有充电电流寄存器用的都是同一个公式:I = 25mA * N。但每个寄存器的描述后面还跟了一句"校准值为 X 左右,如需要调整时可在校准值上增加或者减小相应档位"。这句话是全篇最重要的设计事实:寄存器值描述的是相对量,不是绝对量。
清单摊开看就很清楚:CHG_CTL5(0x26)的同充同放电流校准值约 0.5A,CHG_CTL6(0x27)的 12V VIN 约 1.5A,CHG_CTL7(0x28)的 5V VIN 约 2.9A,CHG_CTL8(0x29)的 5V VBUS 约 2.9A,CHG_CTL10(0x2B)的 9V VIN 约 2A,CHG_CTL11(0x6E)的 12V VBUS 约 1.5A,CHG_CTL12(0x6F)的 9V VBUS 约 2A。7bit 上限 127,对应 3.175A,这是单路电流的硬顶。"校准值"三个字意味着出厂时这颗芯片的实际
本文还有配套的精品资源,点击获取