fix(battery): detect TP4056 charging and full states on new board

This commit is contained in:
chenjintao
2026-10-23 16:23:39 +08:00
parent 415c75b0e6
commit 6116a67d5f
13 changed files with 617 additions and 249 deletions
+10
View File
@@ -52,6 +52,8 @@ typedef enum {
DOMAIN_BATTERY_CHARGE_UNKNOWN = 0,
DOMAIN_BATTERY_CHARGE_NOT_CHARGING,
DOMAIN_BATTERY_CHARGE_CHARGING,
DOMAIN_BATTERY_CHARGE_FULL,
DOMAIN_BATTERY_CHARGE_FAULT,
} domain_battery_charge_state_t;
typedef enum {
@@ -67,6 +69,9 @@ typedef struct {
int latest_sample_mv;
uint8_t percentage;
domain_battery_charge_state_t charge_state;
bool charge_inputs_valid;
bool charge_signal_active;
bool full_signal_active;
domain_battery_level_state_t level_state;
bool valid;
bool latest_sample_valid;
@@ -83,6 +88,11 @@ esp_err_t domain_battery_init(void);
/** 获取并处理一次电池采样,不执行产品策略。 / Process one battery sample without product policy. */
esp_err_t domain_battery_sample(void);
/** 每100ms调用;两路输入连续采样稳定1秒后更新充电状态,间隔>250ms重新确认。
* 不访问ADC;两把锁各最多等待100ms,失败不会后台继续。并发调用安全。
*/
esp_err_t domain_battery_poll_charge(void);
/** 复制最新电池 SSOT 快照。 / Copy the latest battery SSOT snapshot into `out_status`. */
esp_err_t domain_battery_get_status(domain_battery_status_t *out_status);
@@ -100,17 +100,66 @@ static void unlock_state(void)
(void)xSemaphoreGive(s_lock);
}
static domain_battery_charge_state_t map_charge_state(
platform_battery_charge_state_t state)
/* 只有领域层解释 TP4056 CHRG#/STDBY#。两个低电平同时出现视为异常,
* 两个高电平只表示未充电,不能证明 USB 是否接入或电池是否存在。 */
static domain_battery_charge_state_t s_charge_candidate;
static int64_t s_charge_candidate_since_ms;
static int64_t s_charge_last_poll_ms;
static bool s_charge_candidate_valid;
static int64_t s_charge_last_confirmed_ms;
static domain_battery_charge_state_t decode_charge_inputs(bool charging, bool full)
{
switch (state) {
case PLATFORM_BATTERY_CHARGE_CHARGING:
return DOMAIN_BATTERY_CHARGE_CHARGING;
case PLATFORM_BATTERY_CHARGE_NOT_CHARGING:
return DOMAIN_BATTERY_CHARGE_NOT_CHARGING;
default:
return DOMAIN_BATTERY_CHARGE_UNKNOWN;
if (charging && full) {
return DOMAIN_BATTERY_CHARGE_FAULT;
}
if (charging) {
return DOMAIN_BATTERY_CHARGE_CHARGING;
}
return full ? DOMAIN_BATTERY_CHARGE_FULL : DOMAIN_BATTERY_CHARGE_NOT_CHARGING;
}
esp_err_t domain_battery_poll_charge(void)
{
/* 在领域锁内读取原始输入,保证并发采样不会倒序发布状态。
* 数字输入独立于ADC:ADC失败或电机负载抑制不影响充电状态更新。 */
if (!lock_state()) {
return ESP_ERR_TIMEOUT;
}
platform_battery_charge_inputs_t inputs = {0};
esp_err_t err = platform_battery_read_charge_inputs(&inputs);
int64_t now_ms = esp_timer_get_time() / 1000;
if (err != ESP_OK || !inputs.valid) {
s_charge_candidate_valid = false;
s_status.charge_inputs_valid = false;
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
unlock_state();
return err != ESP_OK ? err : ESP_ERR_INVALID_RESPONSE;
}
s_status.charge_inputs_valid = true;
s_status.charge_signal_active = inputs.charge_level == CONFIG_TQ_BATTERY_CHARGE_ACTIVE_LEVEL;
s_status.full_signal_active = inputs.full_level == CONFIG_TQ_BATTERY_FULL_ACTIVE_LEVEL;
domain_battery_charge_state_t candidate = decode_charge_inputs(
s_status.charge_signal_active, s_status.full_signal_active);
if (!s_charge_candidate_valid || candidate != s_charge_candidate ||
now_ms - s_charge_last_poll_ms > 250 || now_ms < s_charge_last_poll_ms) {
if (s_charge_candidate_valid && now_ms - s_charge_last_poll_ms > 250) {
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
}
s_charge_candidate = candidate;
s_charge_candidate_since_ms = now_ms;
s_charge_candidate_valid = true;
}
s_charge_last_poll_ms = now_ms;
if (now_ms - s_charge_candidate_since_ms >= 1000) {
s_status.charge_state = candidate;
s_charge_last_confirmed_ms = now_ms;
} else if (now_ms - s_charge_last_confirmed_ms >= 2000) {
/* 持续抖动不能无限沿用旧的“充电中”,否则可能长期屏蔽低压保护。 */
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
}
unlock_state();
return ESP_OK;
}
static uint8_t voltage_to_percentage(int voltage_mv)
@@ -221,14 +270,8 @@ esp_err_t domain_battery_init(void)
return ESP_OK;
}
esp_err_t err = platform_battery_init();
if (err != ESP_OK) {
unlock_state();
return err;
}
memset(&s_status, 0, sizeof(s_status));
s_status.charge_state = DOMAIN_BATTERY_CHARGE_UNKNOWN;
/* ADC由电压采样路径幂等初始化;失败时充电输入仍能独立工作。 */
/* 允许启动保护在 ADC 初始化前独立轮询充电输入,不能清掉已确认状态。 */
s_status.level_state = DOMAIN_BATTERY_LEVEL_UNKNOWN;
s_initialized = true;
unlock_state();
@@ -264,7 +307,6 @@ esp_err_t domain_battery_sample(void)
s_status.latest_adc_mv = sample.adc_voltage_mv;
s_status.latest_sample_mv = sample.voltage_mv;
s_status.latest_sample_valid = sample.voltage_valid;
s_status.charge_state = map_charge_state(sample.charge_state);
s_status.high_load_active = sample.high_load_active;
s_status.cooldown_active = sample.cooldown_active;
s_status.measurement_suppressed = sample.high_load_active || sample.cooldown_active;
@@ -385,6 +427,11 @@ esp_err_t domain_battery_init(void)
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t domain_battery_poll_charge(void)
{
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t domain_battery_sample(void)
{
return ESP_ERR_NOT_SUPPORTED;