高通QCOM 8610平台电量计算

一: SOC(荷电状态)计算方法

公式:

SOC = RUC / (FCC-UUC)

名词:

术语

全称

注释

FCC

Full-Charge Capacity

满电荷电量

UC

Remaining Capacity

RC 剩余电量

CC

Coulumb Counter

电量计

UUC

Unusable Capacity

不可用电量

RUC

Remaining Usable Capacity

RUC=RC-CC-UUC,剩余可用电量

OCV

Open Circuit Voltage

开路电压,电池在开路状态下的端电压称为开路电压

SoC

State of Charge

电量百分比

PC

Percentage Charge

剩余电荷占FCC百分比

二:各参数计算方法:

1.FCC:根据电池温度temp通过查找表(lut)来计算

static int calculate_fcc(struct qpnp_bms_chip *chip, int batt_temp)
{
	int fcc_uah; 

	if (chip->adjusted_fcc_temp_lut == NULL) { // log显示,没有对温度lut进行修正;
		/* interpolate_fcc returns a mv value. */
		fcc_uah = interpolate_fcc(chip->fcc_temp_lut,
		batt_temp) * 1000;  // 不修正直接返回对应温度的FCC值
		printk("fcc = %d uAh\n", fcc_uah);
		return fcc_uah;
	} else {
		return 1000 * interpolate_fcc(chip->adjusted_fcc_temp_lut,
		batt_temp);
	}
} 

lut:fcc_temp,x轴温度,y轴电量:

static struct single_row_lut fcc_temp = {
	.x		= {-20, 0, 25, 40, 65},
	.y		= {4526, 4594, 4691, 4687, 4664},
	.cols	= 5
};

2. RC: 依赖ocv,通过ocv计算;单位uAh

/* calculate remaining charge at the time of ocv */
static int calculate_ocv_charge(struct qpnp_bms_chip *chip,
		struct raw_soc_params *raw,
		int fcc_uah)
{
	int  ocv_uv, pc;
	// RAW - 存在pm?PM里读出来的未经修正的原始数据?
	// read_soc_params_raw -> qpnp_read_wrapper(chip, (u8 *)&raw->last_good_ocv_raw,
	// chip->base + BMS1_OCV_FOR_SOC_DATA0, 2);
	ocv_uv = raw->last_good_ocv_uv; // 1. 上次关机时存储的ocv;2. 电池新插入时会更新该值;3. 模拟电池新插入,手动更新:chip->insertion_ocv_uv;最终会更新raw->last_good_ocv_uv;
	pc = calculate_pc(chip, ocv_uv, chip->last_ocv_temp); // 上次ocv占FCC的百分比,受温度影响
	printk("ocv_uv = %d pc = %d\n", ocv_uv, pc);
	return (fcc_uah * pc) / 100;
} 

static int calculate_pc(struct qpnp_bms_chip *chip, int ocv_uv,
		int batt_temp)
{
	int pc; 

	pc = interpolate_pc(chip->pc_temp_ocv_lut,
	batt_temp / 10, ocv_uv / 1000); // 根据lut查找百分比
	printk("pc = %u %% for ocv = %d uv batt_temp = %d\n",
	pc, ocv_uv, batt_temp);
	/* Multiply the initial FCC value by the scale factor. */
	return pc;
} 

有时开机时的ocv和关机时的ocv(raw->last_good_ocv_raw?)差距太大就明显影响百分比计算了;

所以就需要做修正了;

pc-lut:

static struct pc_temp_ocv_lut pc_temp_ocv = {
	.rows		= 29,
	.cols		= 5,
	.temp		= {-20, 0, 25, 40, 65},
	.percent	= {100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
	.ocv		= {
				{4240, 4223, 4237, 4234, 4229},
				{4169, 4172, 4185, 4183, 4178},
				{4115, 4125, 4138, 4136, 4131},
				{4068, 4080, 4091, 4089, 4085},
				{3995, 4036, 4053, 4048, 4042},
				{3941, 3981, 3989, 3999, 4000},
				{3905, 3942, 3950, 3958, 3959},
				{3874, 3907, 3913, 3915, 3916},
				{3848, 3877, 3880, 3881, 3881},
				{3825, 3852, 3854, 3855, 3854},
				{3806, 3829, 3831, 3832, 3832},
				{3788, 3810, 3811, 3812, 3811},
				{3771, 3792, 3793, 3795, 3794},
				{3755, 3774, 3776, 3777, 3774},
				{3739, 3758, 3759, 3757, 3748},
				{3722, 3742, 3744, 3738, 3725},
				{3703, 3726, 3728, 3721, 3707},
				{3677, 3707, 3707, 3700, 3686},
				{3641, 3689, 3691, 3684, 3670},
				{3631, 3687, 3688, 3681, 3667},
				{3621, 3685, 3686, 3679, 3665},
				{3610, 3683, 3684, 3677, 3663},
				{3600, 3680, 3681, 3674, 3660},
				{3590, 3672, 3674, 3668, 3655},
				{3580, 3657, 3659, 3655, 3642},
				{3565, 3630, 3633, 3629, 3618},
				{3547, 3595, 3597, 3594, 3585},
				{3526, 3553, 3554, 3552, 3547},
				{3500, 3500, 3500, 3500, 3500}
	}
};

3、CC:将bms电量计读值转换成uAh,coulomb counter有两种, 没有手册不知道shadow型具体含义,不知是否和80x86里的影子寄存器是否为相同设计?:

/* Coulomb counter data */
#define BMS1_CC_DATA0 0x8A
/* Shadow Coulomb counter data */
#define BMS1_SW_CC_DATA0 0xA8
/**
 * calculate_cc() - converts a hardware coulomb counter reading into uah
 * @chip: the bms chip pointer
 * @cc: the cc reading from bms h/w
 * @cc_type: calcualte cc from regular or shadow coulomb counter
 * @clear_cc: whether this function should clear the hardware counter
 * after reading
 *
 * Converts the 64 bit hardware coulomb counter into microamp-hour by taking
 * into account hardware resolution and adc errors.
 *
 * Return: the coulomb counter based charge in uAh (micro-amp hour)
 */
static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc,
		int cc_type, int clear_cc)
{
	struct qpnp_iadc_calib calibration;
	struct qpnp_vadc_result result;
	int64_t cc_voltage_uv, cc_pvh, cc_uah, *software_counter;
	int rc; 

	// chip->software_shdw_cc_uah == 0; chip->software_cc_uah == 0;
	software_counter = cc_type == SHDW_CC ?
	&chip->software_shdw_cc_uah : &chip->software_cc_uah;
	rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result);
	if (rc) {
		pr_err("could not read pmic die temperature: %d\n", rc);
		return *software_counter;
	} 

	qpnp_iadc_get_gain_and_offset(chip->iadc_dev, &calibration); // 获得平台相关的增益修正参数,msm8610,msm8912;
	printk("%scc = %lld, die_temp = %lld\n",
	cc_type == SHDW_CC ? "shdw_" : "",
	cc, result.physical);
	cc_voltage_uv = cc_reading_to_uv(cc);
	cc_voltage_uv = cc_adjust_for_gain(cc_voltage_uv,
	calibration.gain_raw
	- calibration.offset_raw);
	cc_pvh = cc_uv_to_pvh(cc_voltage_uv);  // 为减小cc的精度损失;
	cc_uah = div_s64(cc_pvh, chip->r_sense_uohm); // i = u / r;算出cc电流
	rc = qpnp_iadc_comp_result(chip->iadc_dev, &cc_uah); // 根据QPNP不同版本ID,比如PM8110:QPNP_IADC_REV_ID_8110_1_0,做增益补偿
	if (rc)
	printk("error compensation failed: %d\n", rc);
	if (clear_cc == RESET) {  //1. calculate_state_of_charge -> calculate_soc_params中有RESET调用;
							// 2. load_shutdown_data(probe获取上次关机时的一些参数,比如ocv) -> recalculate_raw_soc -> recalculate_soc ->calculate_soc_params有调用(先cc、后shadow_cc);
							// 3. calculate_soc_work(calculate_soc_work会延时调用自身) -> recalculate_soc -> calculate_state_of_charge -> calculate_soc_params;
							// 4. recalculate_work(电池充电高压、检查电池状态、电池插入检查、ocv阈值中断、sw_cc中断、高温死机中断都会重新sched_work) -> recalculate_soc;
		printk("software_%scc = %lld, added cc_uah = %lld\n",
		cc_type == SHDW_CC ? "sw_" : "",
		*software_counter, cc_uah);
		*software_counter += cc_uah;
		reset_cc(chip, cc_type == SHDW_CC ? CLEAR_SHDW_CC : CLEAR_CC);
		return (int)*software_counter;
	} else {
		printk("software_%scc = %lld, cc_uah = %lld, total = %lld\n",
		cc_type == SHDW_CC ? "shdw_" : "",
		*software_counter, cc_uah,
		*software_counter + cc_uah);
		return *software_counter + cc_uah;
	}
}

对于影子寄存器(Shadow Register):

"It depends on the context. Even my friend named something as shadow
register in his security

architecture. Usually shadow somthing means a backup. Whenever a misprediction or a wrong path

execution is detected, the shadows one can be used to restore the correct status in architecture."

“即对用户不可见的,有时候叫投影寄存器,比如linux中,ES,CS,SS等段寄存器存放的是段选择子,每个都有对应的影子寄存器用来存放段描述符,cpu会根据段寄存器内容自动装载对应的影子寄存器,所以访问同一个段的时候不用总是访问内存来读段描述符来确定段基址。”

4.UUC:不可使用电量,受温度影响;

static int calculate_termination_uuc(struct qpnp_bms_chip *chip,
		struct soc_params *params,
		int batt_temp, int uuc_iavg_ma,
		int *ret_pc_unusable)
{
	int unusable_uv, pc_unusable, uuc_uah;
	int i = 0;
	int ocv_mv;
	int batt_temp_degc = batt_temp / 10;
	int rbatt_mohm;
	int delta_uv;
	int prev_delta_uv = 0;
	int prev_rbatt_mohm = 0;
	int uuc_rbatt_mohm; 

	for (i = 0; i <= 100; i++) {
		ocv_mv = interpolate_ocv(chip->pc_temp_ocv_lut, // 根据temp通过lut获得ocv,
		batt_temp_degc, i);
		rbatt_mohm = get_rbatt(chip, i, batt_temp); // batt_temp用于获得对应温度下的比例因子来得到对应温度下的rbatt;
		unusable_uv = (rbatt_mohm * uuc_iavg_ma)
		+ (chip->v_cutoff_uv);  // UUC = cutoff_uv + rbatt * iavg;
		delta_uv = ocv_mv * 1000 - unusable_uv; 

		if (delta_uv > 0)
		break; 

		prev_delta_uv = delta_uv;
		prev_rbatt_mohm = rbatt_mohm;
	} 

	uuc_rbatt_mohm = linear_interpolate(rbatt_mohm, delta_uv, // 用插值法修正uuc_rbatt_mohm
	prev_rbatt_mohm, prev_delta_uv,
	0); 

	unusable_uv = (uuc_rbatt_mohm * uuc_iavg_ma) + (chip->v_cutoff_uv); // 更新uuv 

	pc_unusable = calculate_pc(chip, unusable_uv, batt_temp); // 利用uuv和temp获得不可使用的电量占FCC的百分比;
	uuc_uah = (params->fcc_uah * pc_unusable) / 100; // 获得UUC
	printk("For uuc_iavg_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d rbatt_pc = %d uuc = %d\n",
	uuc_iavg_ma,
	uuc_rbatt_mohm, unusable_uv,
	pc_unusable, i, uuc_uah);
	*ret_pc_unusable = pc_unusable;
	return uuc_uah;
} 

以上只是获得bms对应参数的函数调用,高通还添加了针对soc和ocv的校正方法;

三、调用流程

recalculate_soc -> qpnp_vadc_read -> read_soc_params_raw -> calculate_state_of_charge(adjust_soc对soc进行修正):

1. rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result);

通过热敏电阻获得电池的温度batt_temp = (int)result.physical;后面计算FCC时需要;

2. read_soc_params_raw(chip, &raw, batt_temp);

“ Add functions necessary for driver initialization and

exported CHARGE_FULL_DESIGN and CURRENT_NOW properties in the

bms power supply.“

“power:
qpnp-bms: remember the temperature when ocv was taken

The code looks up the percent charge based on ocv at the

current temperature. The ocv could have been recorded earlier

under different temperature conditions. Looking it up at the

current temperature is wrong.

Hence remember the temperature when the ocv was first seen. And

use that to lookup the ocv values.“

“power: qpnp-bms: estimate OCV when a new battery is inserted

When a new battery is inserted, the BMS will continue to use its old

OCV value until a new OCV is taken. This is clearly wrong, as the new

battery can have a completely different state of charge than the old

one.

Fix this by making BMS driver estimate a new OCV based on the close

circuit battery voltage and IR drop across the battery when a battery

insertion is detected.“

“ power: qpnp-bms: detect warm resets

During warm PMIC resets, the BMS will not take a new OCV. This may

cause the SOC upon reboot to be completely wrong if no recent OCVs

have been taken.

Fix this by checking for invalid OCVs and warm resets. If either

occur, estimate a new OCV based on vbat and use that instead.“

“power: qpnp-bms: fake a high OCV when charging completes

When charging is finished and the battery is considered full, the BMS

does not necessarily report 100%. Fix this by faking a high OCV when

the charger notifies BMS of EOC.“

“power: qpnp-bms: export shadow coulomb counter value

Export the shadow coulomb counter register value to userspace in

order to assist in recording power consumption."

3.充电检测:

static void power_supply_changed_work(struct work_struct *work)// 该工作会定期检查电源状态:插入DC充电,并遍历已注册supply的pst->external_power_changed,如果有就调用;更新系统LED;最后发送kobject_uevent;

external_power_changed:

会检查1、是否有电池插入;2、电源路径是否发生变化(BATFET);3、检查电池状态:未充电、充电、充电结束,调度recalc_work重新计算SoC;

4. 关机保存SOC和iavg:

report_state_of_charge -> report_cc_based_soc -> backup_soc_and_iavg
-> qpnp_masked_write_base(chip, chip->soc_storage_addr,

SOC_STORAGE_MASK, (soc + 1) << 1);

开始充电、充电结束、计算soc(calculate_state_of_charge)时都会调用report_state_of_charge;

也就是每次新的SOC都会存到bms中;

5.开机时probe会加载上次关机时保存的soc:

load_shutdown_data -> read_shutdown_soc -> rc = qpnp_read_wrapper(chip,
&stored_soc, chip->soc_storage_addr, 1);

6. 当dts中有如下配置会忽略关机时的SoC:

/* Invalidate the shutdown SoC if any of these conditions hold true */
if (chip->ignore_shutdown_soc
<span style="white-space:pre">	</span>|| invalid_stored_soc
<span style="white-space:pre">	</span>|| offmode_battery_replaced
<span style="white-space:pre">	</span>|| shutdown_soc_out_of_limit) { 

这意味着开机时不会用上次关机SOC来修正开机时读到的OCV(PON_OCV_UV)

四、SOC校准

上面参数或多或少都和ocv有关,ocv的变化有:

1. 开机时和上次关机存储的ocv有变化;

2. 长时间suspend后的resume会更新ocv;

3. 手动更新ocv;

4. 低电会进入adjust_soc()更新ocv;

“在高通8064平台由于电量计对大电流计算不准确,一直亮屏的情况(没有经历睡眠唤醒的ocv更新与CC RST)会导致关机电压到达3.74V。要想解决这个问题必须使得校准SOC可以正常工作。但是当满电时开机就会记录ocv的值偏高,导致快要低电时不能很好的校准soc。所以有必要在马上进入低电(15%)时做一次模拟开机一次(电量计RERST
CC=0从soc找出ocv )使得last_ocv_uv降下来,才可以完美发挥adjust_soc的作用,使得关机电压能一直能到3.4V左右。”

当bms计算的SoC在98以上、等于soc_est或者soc_est在adjust-soc-low-threshold以上时不做修正直接返回;

static int adjust_soc(struct qpnp_bms_chip *chip, struct soc_params *params,
int soc, int batt_temp)
{
	int ibat_ua = 0, vbat_uv = 0;
	int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
	int delta_ocv_uv = 0;
	int n = 0;
	int rc_new_uah = 0;
	int pc_new = 0;
	int soc_new = 0;
	int slope = 0;
	int rc = 0;
	int delta_ocv_uv_limit = 0;
	int correction_limit_uv = 0; 

	rc = get_simultaneous_batt_v_and_i(chip, &ibat_ua, &vbat_uv);
	if (rc < 0) {
		pr_err("simultaneous vbat ibat failed err = %d\n", rc);
		goto out;
	} 

	very_low_voltage_check(chip, vbat_uv);
	cv_voltage_check(chip, vbat_uv); 

	delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000); 

	ocv_est_uv = vbat_uv + (ibat_ua * params->rbatt_mohm)/1000; 

	pc_est = calculate_pc(chip, ocv_est_uv, batt_temp);
	soc_est = div_s64((s64)params->fcc_uah * pc_est - params->uuc_uah*100,
		(s64)params->fcc_uah - params->uuc_uah);
	soc_est = bound_soc(soc_est); 

	/* never adjust during bms reset mode */
	if (bms_reset) {
		printk("bms reset mode, SOC adjustment skipped\n");
		goto out;
	} 

	if (is_battery_charging(chip)) {
		soc = charging_adjustments(chip, params, soc, vbat_uv, ibat_ua,
			batt_temp);
		/* Skip adjustments if we are in CV or ibat is negative */
		if (chip->soc_at_cv != -EINVAL || ibat_ua < 0)
		goto out;
	} 

	/*
	* do not adjust
	* if soc_est is same as what bms calculated
	* OR if soc_est > adjust_soc_low_threshold
	* OR if soc is above 90
	* because we might pull it low
	* and cause a bad user experience
	*/
	if (!wake_lock_active(&chip->low_voltage_wake_lock) &&
		(soc_est == soc
		|| soc_est > chip->adjust_soc_low_threshold
		|| soc >= NO_ADJUST_HIGH_SOC_THRESHOLD))
		goto out; 

	if (chip->last_soc_est == -EINVAL)
		chip->last_soc_est = soc; 

	n = min(200, max(1 , soc + soc_est + chip->last_soc_est));
	chip->last_soc_est = soc_est; 

	pc = calculate_pc(chip, chip->last_ocv_uv, chip->last_ocv_temp);
	if (pc > 0) {
		pc_new = calculate_pc(chip,
			chip->last_ocv_uv - (++slope * 1000),
			chip->last_ocv_temp);
		while (pc_new == pc) {
			/* start taking 10mV steps */
			slope = slope + 10;
			pc_new = calculate_pc(chip,
			chip->last_ocv_uv - (slope * 1000),
			chip->last_ocv_temp);
		}
	} else {
		/*
		* pc is already at the lowest point,
		* assume 1 millivolt translates to 1% pc
		*/
		pc = 1;
		pc_new = 0;
		slope = 1;
	} 

	delta_ocv_uv = div_s64((soc - soc_est) * (s64)slope * 1000, n * (pc - pc_new)); 

	if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
		printk("limiting delta ocv %d limit = %d\n", delta_ocv_uv, delta_ocv_uv_limit); 

	if (delta_ocv_uv > 0)
		delta_ocv_uv = delta_ocv_uv_limit;
		else
		delta_ocv_uv = -1 * delta_ocv_uv_limit;
		printk("new delta ocv = %d\n", delta_ocv_uv);
	} 

	if (wake_lock_active(&chip->low_voltage_wake_lock)) {
		/* when in the cutoff region, do not correct upwards */
		delta_ocv_uv = max(0, delta_ocv_uv);
		goto skip_limits;
	} 

	if (chip->last_ocv_uv > chip->flat_ocv_threshold_uv)
		correction_limit_uv = chip->high_ocv_correction_limit_uv;// [email protected]
	else
		correction_limit_uv = chip->low_ocv_correction_limit_uv; // [email protected] 

	if (abs(delta_ocv_uv) > correction_limit_uv) {
		printk("limiting delta ocv %d limit = %d\n",
		delta_ocv_uv, correction_limit_uv);
		if (delta_ocv_uv > 0)
			delta_ocv_uv = correction_limit_uv;
		else
			delta_ocv_uv = -correction_limit_uv;
		printk("new delta ocv = %d\n", delta_ocv_uv);
	} 

skip_limits: 

	chip->last_ocv_uv -= delta_ocv_uv; 

	if (chip->last_ocv_uv >= chip->max_voltage_uv)
		chip->last_ocv_uv = chip->max_voltage_uv; 

	/* calculate the soc based on this new ocv */
	pc_new = calculate_pc(chip, chip->last_ocv_uv, chip->last_ocv_temp);
	rc_new_uah = (params->fcc_uah * pc_new) / 100;
	soc_new = (rc_new_uah - params->cc_uah - params->uuc_uah)*100
		/ (params->fcc_uah - params->uuc_uah);
	soc_new = bound_soc(soc_new); 

	/*
	* if soc_new is ZERO force it higher so that phone doesnt report soc=0
	* soc = 0 should happen only when soc_est is above a set value
	*/
	if (soc_new == 0 && soc_est >= chip->hold_soc_est)
		soc_new = 1; 

	soc = soc_new; 

out:
	printk("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, pc_new = %d, soc_new = %d, rbatt = %d, slope = %d\n",
		 ibat_ua, vbat_uv, ocv_est_uv, pc_est,
		 soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
		 pc_new, soc_new, params->rbatt_mohm, slope); 

	return soc;
} 

参考:

http://blog.csdn.net/linux_devices_driver/article/details/20762839

附件:运行中log

调用栈:

<6>[
406.051003] enabled source qpnp_soc_wake

<6>[  406.075253] batt_temp phy = 301 meas = 0xc090d488c1a153e4 

// 计算CC
<6>[  406.075351] last_good_ocv_raw= 0x922a, last_good_ocv_uv= 3738332uV
<6>[  406.075363] cc_raw= 0xffffffffffd631b1
<6>[  406.075410] tm_sec = 2425, delta_s = 20
<6>[  406.075423] fcc = 4690000 uAh
<6>[  406.075434] FCC = 4690000uAh batt_temp = 301
<6>[  406.075451] pc = 24 % for ocv = 3738332 uv batt_temp = 298
<6>[  406.075464] ocv_uv = 3738332 pc = 24
<6>[  406.075474] ocv_charge_uah = 1125600uAh
<6>[  406.084235] cc = -2739791, die_temp = 37432
<6>[  406.084249] adjusting_uv = -14864325
<6>[  406.084262] adjusting by factor: 3291/3061 = 107%
<6>[  406.084273] result_uv = -15981213
<6>[  406.084286] software_cc = -16133, added cc_uah = -797
<6>[  406.084298] resetting cc manually with flags 128
<6>[  406.093446] shdw_cc = -2738411, die_temp = 37384
<6>[  406.093459] adjusting_uv = -14856838
<6>[  406.093471] adjusting by factor: 3291/3061 = 107%
<6>[  406.093482] result_uv = -15973163
<6>[  406.093494] software_sw_cc = -16131, added cc_uah = -797
<6>[  406.093506] resetting cc manually with flags 64
<6>[  406.093658] cc_uah = -16930uAh raw->cc = ffffffffffd631b1, shdw_cc_uah = -16928uAh raw->shdw_cc = ffffffffffd63715
<6>[  406.093677] rbatt_mohm = 113
<6>[  406.093689] delta_cc = -797 iavg_ua = -143460 

// 计算UUC:calculate_unusable_charge_uah -> calculate_termination_uuc
<6>[  406.093701] iavg_samples_ma[0] = 250
<6>[  406.093711] iavg_samples_ma[1] = 250
<6>[  406.093721] iavg_samples_ma[2] = 250
<6>[  406.093731] iavg_samples_ma[3] = 250
<6>[  406.093741] iavg_samples_ma[4] = 250
<6>[  406.093751] iavg_samples_ma[5] = 250
<6>[  406.093761] iavg_samples_ma[6] = 250
<6>[  406.093771] iavg_samples_ma[7] = 250
<6>[  406.093781] iavg_samples_ma[8] = 250
<6>[  406.093791] iavg_samples_ma[9] = 250
<6>[  406.093801] iavg_samples_ma[10] = 250
<6>[  406.093811] iavg_samples_ma[11] = 250
<6>[  406.093821] iavg_samples_ma[12] = 250
<6>[  406.093831] iavg_samples_ma[13] = 250
<6>[  406.093841] iavg_samples_ma[14] = 250
<6>[  406.093851] iavg_samples_ma[15] = 250
<6>[  406.093869] pc = 0 % for ocv = 3400000 uv batt_temp = 301
<6>[  406.093886] For uuc_iavg_ma = 250, unusable_rbatt = 0 unusable_uv = 3400000 unusable_pc = 0 rbatt_pc = 0 uuc = 0
<6>[  406.093901] uuc_iavg_ma = 250 uuc with iavg = 0
<6>[  406.093913] UUC = 0uAh
<6>[  406.093935] RUC = 1142530uAh
<6>[  406.093947] SOC before adjustment = 24
<6>[  406.098457] pc = 18 % for ocv = 3717671 uv batt_temp = 301
<6>[  406.098499] CC CHG SOC 24
<6>[  406.098519] ibat_ua = -169206, vbat_uv = 3736791, ocv_est_uv = 3717671, pc_est = 18, soc_est = 18, n = 0, delta_ocv_uv = 0, last_ocv_uv = 3738332, pc_new = 0, soc_new = 0, rbatt = 113, slope = 0
<6>[  406.108713] mvolts phy = 3737379 meas = 0x390723
<6>[  406.108730] not clamping, using soc = 24, vbat = 3737379 and cutoff = 3400000 // 3737379
<6>[  406.108777] CC based calculated SOC = 24
<6>[  406.113307] batt_temp phy = 302 meas = 0x12d00000012
<6>[  406.113391] last_soc = 24, calculated_soc = 24, soc = 24, time since last change = 402
<6>[  406.113433] Reported SOC = 24
<6>[  406.113471] disabled source qpnp_soc_wake 
时间: 2024-10-27 00:26:32

高通QCOM 8610平台电量计算的相关文章

华登高通区块狗平台开发要多少钱

华登高通区块宠物狗,找蔡生:191电5743微0737详细了解,怎么激活账号?怎么注册?怎么充值微分?很多朋友问华登区块狗怎么赚钱?怎么能抢到宠物狗?区块狗软件开发,区块狗模式定制,区块狗平台定制,区块狗app源码,区块狗系统介绍,开发区块狗系统费用,区块狗系统开发案例,现成区块狗软件,区块狗app源码开发公司 一.华登区块宠物狗是什么? 华登区宠物狗是基于区块链技术开发的一种独有的.可复制的.增值的.可收藏的.可篡改的区块链数字宠物.每只宠物狗都是独一无二的个体,甜美.独有.富有.Block宠

【转】高通平台android 环境配置编译及开发经验总结

原文网址:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流程分析 qcril 流程分析,设置sim卡锁 python scons 语法学习 Python 语言之 scons 工具流程分析: 1.2 搭建高通平台环境开发环境 高通and

高通平台Camera调试(一)【转】

本文转载自:http://www.voidcn.com/blog/Winva/article/p-6044730.html 4.3. Camera 参考文档: 1) 80-NA157-22_PRESENTATION- MSM8974-APQ8074-MSM8X26-APQ8084 LINUX CAMERA OVERVIEW.pdf 2) 80-NE717-1_MSM8974-APQ8074-MSM8X26 LINUX CAMERA SOFTWARE DESIGN DOCUMENT.pdf 3)

华登高通区块狗模式平台开发定制

华登高通区块宠物狗,找蔡生:191电5743微0737详细了解,怎么激活账号?怎么注册?怎么充值微分?很多朋友问华登区块狗怎么赚钱?怎么能抢到宠物狗?区块狗软件开发,区块狗模式定制,区块狗平台定制,区块狗app源码,区块狗系统介绍,开发区块狗系统费用,区块狗系统开发案例,现成区块狗软件,区块狗app源码开发公司 一.华登区块宠物狗是什么? 华登区宠物狗是基于区块链技术开发的一种独有的.可复制的.增值的.可收藏的.可篡改的区块链数字宠物.每只宠物狗都是独一无二的个体,甜美.独有.富有.Block宠

华登高通区块狗开发案例定制平台

华登高通区块宠物狗,找蔡生:191电5743微0737详细了解,怎么激活账号?怎么注册?怎么充值微分?很多朋友问华登区块狗怎么赚钱?怎么能抢到宠物狗?区块狗软件开发,区块狗模式定制,区块狗平台定制,区块狗app源码,区块狗系统介绍,开发区块狗系统费用,区块狗系统开发案例,现成区块狗软件,区块狗app源码开发公司 一.华登区块宠物狗是什么? 华登区宠物狗是基于区块链技术开发的一种独有的.可复制的.增值的.可收藏的.可篡改的区块链数字宠物.每只宠物狗都是独一无二的个体,甜美.独有.富有.Block宠

高通平台MSM8916LCM模块移植(一)-bootloader部分【转】

本文转载自:http://www.mobile-open.com/2016/970947.html 高通平台中的bootloader叫做LK(Little Kernel,对于LCM来说LK部分相当重要,它不仅要负责开机部分的LCD显示任务,还要负责传参给kernel的LCM驱动,指导kernel选择合适的LCM参数. 1.LK中LCM启动流程 注:read_panel_id()和read_panel_id_ddr3()为私有添加,非高通库上代码. 在这个流程图中,需要着重了解的有oem_pane

在高通平台Android环境下编译内核模块【转】

本文转载自:http://blog.xeonxu.info/blog/2012/12/04/zai-gao-tong-ping-tai-androidhuan-jing-xia-bian-yi-nei-he-mo-kuai/ 高通Android环境中Linux内核会作为Android的一部分进行编译,直接使用make即可一次性从头编到尾.而有的平台比如Marvell,内核的编译操作相对比较独立,必须使用标准的内核编译命令进行单独编译.一般来说,用高通的这种方式比较傻瓜化,一步到底的感觉:而用Ma

高通8X16电池BMS算法(一)【转】

本文转载自:http://www.voidcn.com/blog/yanleizhouqing/article/p-6037399.html 最近一直在搞电源管理相关内容,之前是8610的bms,现在8916的bms,发现两者还是有点区别的,8916把对last_ocv_uv的估值算法分装成执行文件,作为服务一直运行. 电源管理方面,应该是android驱动开发的一大难点,主要涉及的方面多,如充.放电.休眠唤醒等.这一部分主要讲BMS相关的一些基本概念.电池这一块刚开始入手时,感觉很难,很复杂,

高通camera结构【转】

本文转载自:http://www.cnblogs.com/whw19818/p/5853407.html 摄像头基础介绍 一.摄像头结构和工作原理. 拍摄景物通过镜头,将生成的光学图像投射到传感器上,然后光学图像被转换成电信号,电信号再经过模数转换变为数字信号,数字信号经过DSP加工处理,再被送到电脑中进行处理,最终转换成手机屏幕上能够看到的图像. 数字信号处理芯片DSP(DIGITAL SIGNAL PROCESSING)功能:主要是通过一系列复杂的数学算法运算,对数字图像信号参数进行优化处理