AC7106 放入2.4V维持电压充电仓内自动关机

AC7106 放入2.4V维持电压充电仓内自动关机

最近在使用杰理AC7106芯片开发TWS耳机项目时,我们遇到了在放入带有2.4V维持电压的充电仓时耳机自动关机的现象。

充电仓维持电压工作机制

维持电压目的:耳机出入仓检测
原理:VOUT输出2.4V电压,J8、J9分别为充电仓的正负极充电顶针,耳机放入充电仓相当于串入一个负载电阻(耳机端设置的下拉电阻),通过检测耳机的分压来确定耳机是否在仓内。

image-20251013092042500

耳机充电检测机制

在AC7106的SDK中,充电检测主要通过 LDO5V_DET 信号来判断。系统会根据电压值将充电状态分为三种情况:

  • 正常插入 (ldoin > VBat):执行 charge_ldo5v_in_deal() 函数

  • 维持电压 (0.6V < ldoin < VBat):执行 ldo5v_keep_deal() 函数

  • 正常拔出 (ldoin < 0.6V):执行 charge_ldo5v_off_deal() 函数

问题出现在第二种情况,即维持电压状态下的处理逻辑。

事件处理流程

当耳机检测到维持电压时,系统会触发CHARGE_EVENT_LDO5V_KEEP事件,并遍历所有注册的app_charge_handler处理函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void ldo5v_keep_deal(void)
{
int abandon = 0;
const struct app_charge_handler *handler;

log_info("%s\n", __func__);

charge_close();

//插入交换
batmgr_send_msg(POWER_EVENT_POWER_CHANGE, 0);

charge_check_and_set_pinr(0);

for_each_app_charge_handler(handler) {
abandon += handler->handler
(CHARGE_EVENT_LDO5V_KEEP, 0);
}

if (get_charge_poweron_en() == 0) {
if (abandon == 0) {
ldo5v_keep_softoff();
}
} else {
batmgr_send_msg(BAT_MSG_CHARGE_ERR, 0);
}
}
charge.c

经过分析代码,发现以下几个关键问题:

1. 模块级事件响应机制

系统使用了模块化的事件响应机制,每个模块可以通过APP_CHARGE_HANDLER宏注册自己的处理函数:

1
2
3
4
5
6
#define APP_CHARGE_HANDLER(name, priority) \
const struct app_charge_handler handler_##name SECTION
("charge_handler") = {
.handler = name,
.priority = priority
}

各模块通过返回1或0来决定是否阻止关机流程:

  • 返回1:表示需要保持系统运行,阻止关机
  • 返回0:表示允许系统关机

所有handler的返回值会累加到abandon变量中,如果abandon最终为0,则执行关机。

2. 默认关机逻辑

在默认情况下,大部分模块对CHARGE_EVENT_LDO5V_KEEP事件的处理都是返回0,不阻止关机流程:

1
2
3
4
5
6
7
8
9
10
11
12
static int dev_manager_charge_handler(int event, u32 
param)
{
switch (event) {
case CHARGE_EVENT_LDO5V_KEEP:
dev_manager_close_gsensor();
dev_manager_close_npu();
break;
// ...
}
return 0; // 不阻止关机
}

解决方案

最直接的方法是修改 ldo5v_keep_deal() 函数,添加对维持电压状态的检测,阻止不必要的关机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void ldo5v_keep_deal(void)
{
int abandon = 0;
const struct app_charge_handler *handler;

log_info("%s\n", __func__);

charge_close();

//插入交换
batmgr_send_msg(POWER_EVENT_POWER_CHANGE, 0);

charge_check_and_set_pinr(0);

for_each_app_charge_handler(handler) {
abandon += handler->handler
(CHARGE_EVENT_LDO5V_KEEP, 0);
}

if (get_charge_poweron_en() == 0) {
// 判断是否处于维持电压状态
if (is_ldo5v_keep_state() && abandon == 0) {
// 不执行关机
// ldo5v_keep_softoff();
return;
}
} else {
batmgr_send_msg(BAT_MSG_CHARGE_ERR, 0);
}
}

额外优化:灯效处理

解决了关机问题后,还发现耳机在维持电压状态下会触发蓝灯亮三秒的效果。这是因为上面的ldo5v_keep_deal()还调用了charge_close(),导致了耳机原本的灯效被覆盖,修改即可。

解决了维持电压状态下会触发蓝灯亮三秒问题后,还发现耳机在维持电压状态下拔出会触发蓝灯亮三秒的效果。这是因触发了CHARGE_LDO5V_OFF,导致了耳机原本的灯效被覆盖,修改即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static int ui_battery_msg_handler(int *msg)
{
switch (msg[0]) {
case BAT_MSG_CHARGE_START:
led_ui_set_state(LED_STA_RED_ON,
DISP_CLEAR_OTHERS);
break;
case BAT_MSG_CHARGE_FULL:
case BAT_MSG_CHARGE_CLOSE:
case BAT_MSG_CHARGE_ERR:
case BAT_MSG_CHARGE_LDO5V_OFF:
led_ui_set_state(LED_STA_BLUE_ON_3S,
DISP_CLEAR_OTHERS);
break;
}
return 0;
}