mt6737电池电量计算

这里采用的是库伦积分计算电量的方式,硬件连接如下




通过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

扫描二维码关注公众号,回复: 461583 查看本文章

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

猜你喜欢

转载自blog.csdn.net/mike8825/article/details/72809712