这里采用的是库伦积分计算电量的方式,硬件连接如下
通过cs_p,cs_n接到一个10豪欧的电阻来测量电流,进行电流积分来计算消耗的电量(DOD指放电深度)。
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