这里采用的是库伦积分计算电量的方式,硬件连接如下
通过cs_p,cs_n接到一个10豪欧的电阻来测量电流,进行电流积分来计算消耗的电量(DOD指放电深度)。
公式 DOD1 = DOD0 + (-Car/Qmax).
DOD1对应当前的放电深度.
DOD0对应初始的放电深度,通过开路电压得出起始电量值或者为rtc保存的值.
Car 为t时间内, 流过Rfg电阻电流的电量.
其中Car的值直接读寄存器便可得知.
kernel-3.18/drivers/power/mediatek/battery_meter.c
signed int battery_meter_initial(void)
{
#if defined(CONFIG_POWER_EXT)
return 0;
#else
static kal_bool meter_initilized = KAL_FALSE;
mutex_lock(&FGADC_mutex);
if (meter_initilized == KAL_FALSE) {
#ifdef MTK_MULTI_BAT_PROFILE_SUPPORT
fgauge_get_profile_id();
#endif
#if defined(SOC_BY_AUXADC)
g_auxadc_solution = 1;
table_init();
bm_print(BM_LOG_CRTI, "[battery_meter_initial] SOC_BY_AUXADC done\n");
#endif
#if defined(SOC_BY_HW_FG)
fgauge_initialization();
fgauge_algo_run_init();
bm_print(BM_LOG_CRTI, "[battery_meter_initial] SOC_BY_HW_FG done\n");
#endif
#if defined(SOC_BY_SW_FG)
g_auxadc_solution = 1;
table_init();
oam_init();
bm_print(BM_LOG_CRTI, "[battery_meter_initial] SOC_BY_SW_FG done\n");
#endif
meter_initilized = KAL_TRUE;
}
mutex_unlock(&FGADC_mutex);
return 0;
#endif
}
这里用的是SOC_BY_HW_FG这种方式。
void fgauge_algo_run_init(void)
{
int i = 0;
int ret = 0;
#ifdef INIT_SOC_BY_SW_SOC
kal_bool charging_enable = KAL_FALSE;
#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) && !defined(SWCHR_POWER_PATH)
if (LOW_POWER_OFF_CHARGING_BOOT != get_boot_mode())
#endif
/*stop charging for vbat measurement */
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
msleep(50);
#endif
/* 1. Get Raw Data */
gFG_voltage = battery_meter_get_battery_voltage(KAL_TRUE);
gFG_voltage_init = gFG_voltage;
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &gFG_Is_Charging);
gFG_voltage = gFG_voltage + fgauge_compensate_battery_voltage_recursion(gFG_voltage, 5); /* mV */
gFG_voltage = gFG_voltage + batt_meter_cust_data.ocv_board_compesate;
bm_print(BM_LOG_CRTI, "[FGADC] SWOCV : %d,%d,%d,%d,%d,%d\n",
gFG_voltage_init, gFG_voltage, gFG_current, gFG_Is_Charging, gFG_resistance_bat,
gFG_compensate_value);
#ifdef INIT_SOC_BY_SW_SOC
charging_enable = KAL_TRUE;
battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);
#endif
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);
/* 1.1 Average FG_voltage */
for (i = 0; i < batt_meter_cust_data.fg_vbat_average_size; i++)
FGvbatVoltageBuffer[i] = gFG_voltage;
FGbatteryVoltageSum = gFG_voltage * batt_meter_cust_data.fg_vbat_average_size;
gFG_voltage_AVG = gFG_voltage;
#ifdef Q_MAX_BY_CURRENT
/* 1.2 Average FG_current */
for (i = 0; i < FG_CURRENT_AVERAGE_SIZE; i++)
FGCurrentBuffer[i] = gFG_current;
FGCurrentSum = gFG_current * FG_CURRENT_AVERAGE_SIZE;
gFG_current_AVG = gFG_current;
#endif
/* 2. Calculate battery capacity by VBAT */
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
gFG_capacity_by_v_init = gFG_capacity_by_v;
/* 3. Calculate battery capacity by Coulomb Counter */
gFG_capacity_by_c = fgauge_read_capacity(1);
/* 4. update DOD0 */
dod_init();
gFG_current_auto_detect_R_fg_count = 0;
for (i = 0; i < 10; i++) {
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
gFG_current_auto_detect_R_fg_total += gFG_current;
gFG_current_auto_detect_R_fg_count++;
}
/* double check */
if (gFG_current_auto_detect_R_fg_total <= 0) {
bm_print(BM_LOG_CRTI, "gFG_current_auto_detect_R_fg_total=0, need double check\n");
gFG_current_auto_detect_R_fg_count = 0;
for (i = 0; i < 10; i++) {
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
gFG_current_auto_detect_R_fg_total += gFG_current;
gFG_current_auto_detect_R_fg_count++;
}
}
gFG_current_auto_detect_R_fg_result =
gFG_current_auto_detect_R_fg_total / gFG_current_auto_detect_R_fg_count;
#if !defined(DISABLE_RFG_EXIST_CHECK)
if (gFG_current_auto_detect_R_fg_result <= batt_meter_cust_data.current_detect_r_fg) {
g_auxadc_solution = 1;
bm_print(BM_LOG_CRTI,
"[FGADC] Detect NO Rfg, use AUXADC report. (%d=%d/%d)(%d)\r\n",
gFG_current_auto_detect_R_fg_result, gFG_current_auto_detect_R_fg_total,
gFG_current_auto_detect_R_fg_count, g_auxadc_solution);
} else {
if (g_auxadc_solution == 0) {
g_auxadc_solution = 0;
bm_print(BM_LOG_CRTI,
"[FGADC] Detect Rfg, use FG report. (%d=%d/%d)(%d)\r\n",
gFG_current_auto_detect_R_fg_result,
gFG_current_auto_detect_R_fg_total,
gFG_current_auto_detect_R_fg_count, g_auxadc_solution);
} else {
bm_print(BM_LOG_CRTI,
"[FGADC] Detect Rfg, but use AUXADC report. due to g_auxadc_solution=%d \r\n",
g_auxadc_solution);
}
}
#endif
/* 5. Logging */
bm_print(BM_LOG_CRTI,
"[FGADC] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
gFG_Is_Charging, gFG_current, gFG_columb, gFG_voltage, gFG_capacity_by_v,
gFG_capacity_by_c, gFG_capacity_by_c_init, gFG_BATT_CAPACITY,
gFG_BATT_CAPACITY_aging, gFG_compensate_value, gFG_ori_voltage,
batt_meter_cust_data.ocv_board_compesate, batt_meter_cust_data.r_fg_board_slope,
gFG_voltage_init, batt_meter_cust_data.minerroroffset, gFG_DOD0, gFG_DOD1,
batt_meter_cust_data.car_tune_value, batt_meter_cust_data.aging_tuning_value);
update_fg_dbg_tool_value();
}
void fgauge_initialization(void)
{
#if defined(CONFIG_POWER_EXT)
#else
int i = 0;
unsigned int ret = 0;
/* gFG_BATT_CAPACITY_init_high_current = fgauge_get_Q_max_high_current(25); */
/* gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(25); */
/* 1. HW initialization */
ret = battery_meter_ctrl(BATTERY_METER_CMD_HW_FG_INIT, NULL);
/* 2. SW algorithm initialization */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
i = 0;
while (gFG_current == 0) {
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
if (i > 10) {
bm_print(BM_LOG_CRTI, "[fgauge_initialization] gFG_current == 0\n");
break;
}
i++;
}
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);
fgauge_construct_battery_profile_init();
gFG_temp = force_get_tbat(KAL_FALSE);
gFG_capacity = fgauge_read_capacity(0);
gFG_capacity_by_c_init = gFG_capacity;
gFG_capacity_by_c = gFG_capacity;
gFG_capacity_by_v = gFG_capacity;
gFG_DOD0 = 100 - gFG_capacity;
bm_print(BM_LOG_CRTI, "[fgauge_initialization] gFG_DOD0 =%d %d\n", gFG_DOD0, gFG_capacity);
gFG_BATT_CAPACITY = fgauge_get_Q_max(gFG_temp);
gFG_BATT_CAPACITY_init_high_current = fgauge_get_Q_max_high_current(gFG_temp);
gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(gFG_temp);
ret = battery_meter_ctrl(BATTERY_METER_CMD_DUMP_REGISTER, NULL);
bm_print(BM_LOG_CRTI,
"[fgauge_initialization] Done HW_OCV:%d FG_Current:%d FG_CAR:%d tmp=%d capacity=%d Qmax=%d\n",
gFG_voltage, gFG_current, gFG_columb, gFG_temp, gFG_capacity, gFG_BATT_CAPACITY);
#if defined(FG_BAT_INT)
pmic_register_interrupt_callback(FG_BAT_INT_L_NO, fg_bat_int_handler);
pmic_register_interrupt_callback(FG_BAT_INT_H_NO, fg_bat_int_handler);
#endif
#endif
}
根据下面这个打印就能看出电池的关键信息,这里特意注释下。
bm_print(BM_LOG_CRTI,"[FGADC] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
gFG_Is_Charging, gFG_current, gFG_columb, gFG_voltage, gFG_capacity_by_v,
gFG_capacity_by_c, gFG_capacity_by_c_init, gFG_BATT_CAPACITY,
gFG_BATT_CAPACITY_aging, gFG_compensate_value, gFG_ori_voltage,
batt_meter_cust_data.ocv_board_compesate, batt_meter_cust_data.r_fg_board_slope,
gFG_voltage_init, batt_meter_cust_data.minerroroffset, gFG_DOD0, gFG_DOD1,
batt_meter_cust_data.car_tune_value, batt_meter_cust_data.aging_tuning_value);
//是否充电 电流 库伦积分算出的剩余电量gFG_capacity_by_c 开路电压 根据开路电压算出的剩余电量
//根据积分算出的消耗的电量 开路电压算出的初始放电深度(百分比) 电池容量(mAh)
//当前温度下的电池容量(mAh) gFG_compensate_value gFG_ori_voltage
//开路电压修正值 r_fg_board_slope
//测量出的闭路电压 minerroroffset 初始的放电深度 当前放电深度(100-gFG_capacity_by_c)
//库仑计补偿值(需实验修正) aging_tuning_value
dod_init();根据开路电压算出电量,如果rtc保存的电池电量与该电量不超过40%的误差,直接采用rtc保存的电量,提高用户体验。
否则采用开机的闭路电压(开机时的闭路电压作为开路电压)或者计算的开路电压作为起始的电量。
void dod_init(void)
{
int ret = 0;
signed int gFG_capacity_by_sw_ocv = gFG_capacity_by_v;
/* use get_hw_ocv----------------------------------------------------------------- */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
bm_print(BM_LOG_CRTI, "[FGADC] get_hw_ocv=%d, HW_SOC=%d, SW_SOC = %d\n",
gFG_voltage, gFG_capacity_by_v, gFG_capacity_by_v_init);
/* compare with hw_ocv & sw_ocv, check if less than or equal to 5% tolerance */
if ((abs(gFG_capacity_by_v_init - gFG_capacity_by_v) > 5)
&& (bat_is_charger_exist() == KAL_TRUE)) {
gFG_capacity_by_v = gFG_capacity_by_v_init;
}
g_rtc_fg_soc = get_rtc_spare_fg_value();
if (is_battery_remove_pmic() == 0 && (g_rtc_fg_soc != 0)
&& batt_meter_cust_data.vbat_remove_detection) {
bm_print(BM_LOG_CRTI, "[FGADC]is_battery_remove()==0 , use rtc_fg_soc%d\n",
g_rtc_fg_soc);
gFG_capacity_by_v = g_rtc_fg_soc;
} else {
if (((g_rtc_fg_soc != 0)&& (((abs(g_rtc_fg_soc - gFG_capacity_by_v)) <=batt_meter_cust_data.cust_poweron_delta_capacity_tolrance)
|| (abs(gFG_capacity_by_v_init - g_rtc_fg_soc) < abs(gFG_capacity_by_v - gFG_capacity_by_v_init))))
|| ((g_rtc_fg_soc != 0)
&& (get_boot_reason() == BR_WDT_BY_PASS_PWK || get_boot_reason() == BR_WDT
|| get_boot_reason() == BR_TOOL_BY_PASS_PWK
|| get_boot_reason() == BR_2SEC_REBOOT || get_boot_mode() == RECOVERY_BOOT)))
{
gFG_capacity_by_v = g_rtc_fg_soc;
} else {
if (abs(gFG_capacity_by_v - gFG_capacity_by_sw_ocv) >
batt_meter_cust_data.cust_poweron_delta_hw_sw_ocv_capacity_tolrance) {
bm_print(BM_LOG_CRTI,
"[FGADC] gFG_capacity_by_v=%d, gFG_capacity_by_sw_ocv=%d use SWOCV\n",
gFG_capacity_by_v, gFG_capacity_by_sw_ocv);
gFG_capacity_by_v = gFG_capacity_by_sw_ocv;
} else {
bm_print(BM_LOG_CRTI,
"[FGADC] gFG_capacity_by_v=%d, gFG_capacity_by_sw_ocv=%d use HWOCV\n",
gFG_capacity_by_v, gFG_capacity_by_sw_ocv);
}
}
}
bm_print(BM_LOG_CRTI, "[FGADC] g_rtc_fg_soc=%d, gFG_capacity_by_v=%d\n",
g_rtc_fg_soc, gFG_capacity_by_v);
if (gFG_capacity_by_v == 0 && bat_is_charger_exist() == KAL_TRUE) {
gFG_capacity_by_v = 1;
bm_print(BM_LOG_CRTI, "[FGADC] gFG_capacity_by_v=%d\n", gFG_capacity_by_v);
}
gFG_capacity = gFG_capacity_by_v;
gFG_capacity_by_c_init = gFG_capacity;
gFG_capacity_by_c = gFG_capacity;
gFG_DOD0 = 100 - gFG_capacity;
gFG_DOD1 = gFG_DOD0;
gfg_percent_check_point = gFG_capacity;
if (batt_meter_cust_data.change_tracking_point) {
gFG_15_vlot = fgauge_read_v_by_capacity((100 - g_tracking_point));
bm_print(BM_LOG_CRTI, "[FGADC] gFG_15_vlot = %dmV\n", gFG_15_vlot);
} else {
/* gFG_15_vlot = fgauge_read_v_by_capacity(86); //14% */
gFG_15_vlot = fgauge_read_v_by_capacity((100 - g_tracking_point));
bm_print(BM_LOG_CRTI, "[FGADC] gFG_15_vlot = %dmV\n", gFG_15_vlot);
if ((gFG_15_vlot > 3800) || (gFG_15_vlot < 3600)) {
bm_print(BM_LOG_CRTI, "[FGADC] gFG_15_vlot(%d) over range, reset to 3700\n",
gFG_15_vlot);
gFG_15_vlot = 3700;
}
}
}
获取电池电量的函数
signed int battery_meter_get_battery_percentage(void)
{
fgauge_algo_run();
return gFG_capacity_by_c;
}
void fgauge_algo_run(void)
{
int i = 0;
int ret = 0;
#ifdef MTK_BATTERY_LIFETIME_DATA_SUPPORT
int columb_delta = 0;
int charge_current = 0;
#endif
/* Reconstruct table if temp changed; */
fgauge_construct_table_by_temp();
/* 1. Get Raw Data */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &gFG_Is_Charging);
gFG_voltage = battery_meter_get_battery_voltage(KAL_FALSE);
gFG_voltage_init = gFG_voltage;
gFG_voltage = gFG_voltage + fgauge_compensate_battery_voltage_recursion(gFG_voltage, 5); /* mV */
gFG_voltage = gFG_voltage + batt_meter_cust_data.ocv_board_compesate;
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);
/* add by willcai 2014-12-18 begin */
if (BMT_status.charger_exist == KAL_FALSE) {
if (gFG_Is_offset_init == KAL_FALSE) {
for (i = 0; i < batt_meter_cust_data.fg_vbat_average_size; i++)
FGvbatVoltageBuffer[i] = gFG_voltage;
FGbatteryVoltageSum =
gFG_voltage * batt_meter_cust_data.fg_vbat_average_size;
gFG_voltage_AVG = gFG_voltage;
gFG_Is_offset_init = KAL_TRUE;
}
/* 1.1 Average FG_voltage */
/**************** Averaging : START ****************/
if (gFG_voltage >= gFG_voltage_AVG)
gFG_vbat_offset = (gFG_voltage - gFG_voltage_AVG);
else
gFG_vbat_offset = (gFG_voltage_AVG - gFG_voltage);
if (gFG_vbat_offset <= batt_meter_cust_data.minerroroffset) {
FGbatteryVoltageSum -= FGvbatVoltageBuffer[FGbatteryIndex];
FGbatteryVoltageSum += gFG_voltage;
FGvbatVoltageBuffer[FGbatteryIndex] = gFG_voltage;
gFG_voltage_AVG =
FGbatteryVoltageSum / batt_meter_cust_data.fg_vbat_average_size;
gFG_voltage = gFG_voltage_AVG;
FGbatteryIndex++;
if (FGbatteryIndex >= batt_meter_cust_data.fg_vbat_average_size)
FGbatteryIndex = 0;
bm_print(BM_LOG_FULL, "[FG_BUFFER] ");
for (i = 0; i < batt_meter_cust_data.fg_vbat_average_size; i++)
bm_print(BM_LOG_FULL, "%d,", FGvbatVoltageBuffer[i]);
bm_print(BM_LOG_FULL, "\r\n");
} else {
bm_print(BM_LOG_FULL, "[FG] Over MinErrorOffset:V=%d,Avg_V=%d, ",
gFG_voltage, gFG_voltage_AVG);
gFG_voltage = gFG_voltage_AVG;
bm_print(BM_LOG_FULL, "Avg_V need write back to V : V=%d,Avg_V=%d.\r\n",
gFG_voltage, gFG_voltage_AVG);
}
} else
gFG_Is_offset_init = KAL_FALSE;
/* 2. Calculate battery capacity by VBAT */
gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);
/* 3. Calculate battery capacity by Coulomb Counter */
gFG_capacity_by_c = fgauge_read_capacity(1);
/* 4. voltage mode */
if (volt_mode_update_timer >= volt_mode_update_time_out) {
volt_mode_update_timer = 0;
fg_voltage_mode();
} else {
volt_mode_update_timer++;
}
/* 5. Logging */
pr_err(
"[FGADC] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
gFG_Is_Charging, gFG_current, gFG_columb, gFG_voltage, gFG_capacity_by_v,
gFG_capacity_by_c, gFG_capacity_by_c_init, gFG_BATT_CAPACITY,
gFG_BATT_CAPACITY_aging, gFG_compensate_value, gFG_ori_voltage,
batt_meter_cust_data.ocv_board_compesate, batt_meter_cust_data.r_fg_board_slope,
gFG_voltage_init, batt_meter_cust_data.minerroroffset, gFG_DOD0, gFG_DOD1,
batt_meter_cust_data.car_tune_value, batt_meter_cust_data.aging_tuning_value);
update_fg_dbg_tool_value();
}
gFG_capacity_by_c = fgauge_read_capacity(1);
signed int fgauge_read_capacity(signed int type)
{
signed int voltage;
signed int temperature;
signed int dvalue = 0;
signed int temp_val = 0;
if (type == 0) { /* for initialization */
/* Use voltage to calculate capacity */
voltage = battery_meter_get_battery_voltage(KAL_TRUE); /* in unit of mV */
temperature = force_get_tbat(KAL_FALSE);
dvalue = fgauge_get_dod0(voltage, temperature, KAL_FALSE); /* need compensate vbat */
} else {
/* Use DOD0 and columb counter to calculate capacity */
dvalue = fgauge_update_dod(); /* DOD1 = DOD0 + (-CAR)/Qmax */
}
gFG_DOD1 = dvalue;
temp_val = dvalue;
dvalue = 100 - temp_val;
if (dvalue <= 1) {
dvalue = 1;
bm_print(BM_LOG_FULL, "[fgauge_read_capacity] dvalue<=1 and set dvalue=1 !!\r\n");
}
return dvalue;
}
signed int fgauge_update_dod(void)
{
signed int FG_dod_1 = 0;
int adjust_coulomb_counter = batt_meter_cust_data.car_tune_value;
if (gFG_DOD0 > 100) {
gFG_DOD0 = 100;
bm_print(BM_LOG_FULL, "[fgauge_update_dod] gFG_DOD0 set to 100, gFG_columb=%d\r\n",
gFG_columb);
} else if (gFG_DOD0 < 0) {
gFG_DOD0 = 0;
bm_print(BM_LOG_FULL, "[fgauge_update_dod] gFG_DOD0 set to 0, gFG_columb=%d\r\n",
gFG_columb);
} else {
}
gFG_temp = force_get_tbat(KAL_FALSE);
if (temperature_change == 1) {
gFG_BATT_CAPACITY = fgauge_get_Q_max(gFG_temp);
bm_print(BM_LOG_CRTI,
"[fgauge_update_dod] gFG_BATT_CAPACITY=%d, gFG_BATT_CAPACITY_aging=%d, gFG_BATT_CAPACITY_init_high_current=%d\r\n",
gFG_BATT_CAPACITY, gFG_BATT_CAPACITY_aging,
gFG_BATT_CAPACITY_init_high_current);
temperature_change = 0;
}
FG_dod_1 = gFG_DOD0 - ((gFG_columb * 100) / gFG_BATT_CAPACITY_aging);
bm_print(BM_LOG_FULL,
"[fgauge_update_dod] FG_dod_1=%d, adjust_coulomb_counter=%d, gFG_columb=%d, gFG_DOD0=%d, gFG_temp=%d, gFG_BATT_CAPACITY=%d %d\r\n",
FG_dod_1, adjust_coulomb_counter, gFG_columb, gFG_DOD0, gFG_temp,
gFG_BATT_CAPACITY, gFG_BATT_CAPACITY_aging);
if (FG_dod_1 > 100) {
FG_dod_1 = 100;
bm_print(BM_LOG_FULL, "[fgauge_update_dod] FG_dod_1 set to 100, gFG_columb=%d\r\n",
gFG_columb);
} else if (FG_dod_1 < 0) {
FG_dod_1 = 0;
bm_print(BM_LOG_FULL, "[fgauge_update_dod] FG_dod_1 set to 0, gFG_columb=%d\r\n",
gFG_columb);
} else {
}
return FG_dod_1;
}
这里看下客制化参数
&bat_meter {
/* cust_battery_meter.h */
/* ADC resistor */
r_bat_sense = <4 >;
r_i_sense = <4 >;
r_charger_1 = <330 >;
r_charger_2 = <39 >;
temperature_t0 = <110 >;
temperature_t1 = <0 >;
temperature_t2 = <25 >;
temperature_t3 = <50 >;
temperature_t = <255 >; /* this should be fixed, never change the value */
fg_meter_resistance = <0 >;
/* Qmax for 0mA */
q_max_pos_50 = <1463 >;
q_max_pos_25 = <1437 >;
q_max_pos_0 = <1220 >;
q_max_neg_10 = <1137 >;
/* Qmax for 400mA, said high current */
q_max_pos_50_h_current = <1511 >;
q_max_pos_25_h_current = <1462 >;
q_max_pos_0_h_current = <818 >;
q_max_neg_10_h_current = <149 >;
/* Discharge percentage, 1: D5, 0: D2 */
oam_d5 = <1 >;
change_tracking_point = <1 >;
/* SW OCV tracking setting */
cust_tracking_point = <1 >;
cust_r_sense = <68 >;
cust_hw_cc = <0 >;
aging_tuning_value = <103 >;
cust_r_fg_offset = <0 >;
ocv_board_compesate = <0 >;
r_fg_board_base = <1000 >;
r_fg_board_slope = <1000 >;
car_tune_value = <104 >;
/* HW Fuel gague */
current_detect_r_fg = <10 >; /* Unit: mA */
minerroroffset = <1000 >;
fg_vbat_average_size = <18 >;
r_fg_value = <10 >; /* Unit: mOhm */
cust_poweron_delta_capacity_tolrance = <40 >;
cust_poweron_low_capacity_tolrance = <5 >;
cust_poweron_max_vbat_tolrance = <90 >;
cust_poweron_delta_vbat_tolrance = <30 >;
cust_poweron_delta_hw_sw_ocv_capacity_tolrance = <10 >;
/* Fixed battery temperature */
fixed_tbat_25 = <0 >;
/* Battery remove detecton */
vbat_remove_detection = <0>;
battery_profile_t0
battery_profile_t1
battery_profile_t2
battery_profile_t3
其中r_charger_1 r_charger_2是vcdt脚的分压电阻的阻值
要通过实验修正car_tune_value的值,影响积分值的准确性
填写电池厂商提供的110°(-10) 0° 25° 50°下的电池容量与开路电压的关系表,注意数组长度一致以及电池容量值q_max_pos和最大电流值q_max_pos_xx_h_current
r_fg_value库仑计的电阻值(豪欧)
car_tune_value修正的基本方法,给定一个标准电流(如电流1000mA),如果读出cpu读出的电流值(工程模式下的电流值假设是1078mA),那么修正值为1000/1078=0.93,也就是
测量出的电流要乘以系数0.93才是准确的电量值,这里car_tune_value为93。
操作方法,一路电源接电池接口的正极,另一端接任意系统地,这一路电源没有电流经过电阻r_fg。
另一路电源的正极接系统地,负极接电池的负极,限制一个电流的输出。具体的操作方法可参考mtk的文档Fuel Gauge Application Notes_V1.2.pptx
static signed int fgauge_read_current(void *data)
{
...
dvalue = ((dvalue * batt_meter_cust_data.car_tune_value) / 100);
...
}
参考文档
Fuel_Gauge_introduce.pdf
Fuel Gauge Application Notes_V1.2.pptx
http://blog.csdn.net/fdaopeng/article/details/8803996