一: 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 || invalid_stored_soc || offmode_battery_replaced || 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;// 250@dts else correction_limit_uv = chip->low_ocv_correction_limit_uv; // 100@dts 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 

高通QCOM 8610平台电量计算相关推荐

  1. 高通(QCOM.US)一颗820A,撼动汽车芯片市场的开年之战

    高通(QCOM.US)一颗820A,撼动汽车芯片市场的开年之战 参考链接:高通(QCOM.US)一颗820A,撼动汽车芯片市场的开年之战_凤凰网 消费电子芯片巨头上车这件事,终于有了"关键突 ...

  2. Android图形合成和显示系统---基于高通MSM8k MDP4平台

    介绍了Android SurfaceFlinger层次以下的图形合成和显示系统,主要基于高通MSM8k MDP4x平台. 做为Android Display专题.SurfaceFlinger的详细介绍 ...

  3. 高通Android智能平台环境搭建_编译流程分析

    高通Android智能平台环境搭建_编译流程分析 高通平台环境搭建,编译,系统引导流程分析 TOC \o \h \z \u 1. 高通平台android开发总结. 7 1.1 搭建高通平台环境开发环境 ...

  4. 高通Android智能平台开发总结

    高通Android智能平台开发总结 1. 高通平台android开发总结. 7 1.1 搭建高通平台环境开发环境. 7 1.2 搭建高通平台环境开发环境. 7 1.2.1 高通android智能平台概 ...

  5. 智能座舱更看重「性能冗余」,4家中国供应商领跑高通两代平台

    高通8155,未必是智能座舱的真正王者,但至少在当下,是所有车企可以拿得出手吸引消费者的,为数不多的筹码.而到了明年,5nm的高通第四代座舱平台8295也有机会延续8155的强势地位. 要知道,在国内 ...

  6. 高通5G智能平台概述

    高通5G智能平台概述 高通 android 智能手机解决方案的软件包括两个部分 以linux 操作系统为基础的 android 系统 以 L4,REX为基础的 Modem 部分 在高通系列的架构中,一 ...

  7. 高通写号工具_高通推出桌面平台新ARM处理器并认为我们的电脑性能没必要那么高...

    高通公司在日前举办的骁龙技术峰会上宣布推出骁龙7c / 8c处理器 , 这些处理器全部都是面向笔记本电脑推出的. 这也是高通和微软合作推出 Windows 10 ARM 设备的组成部分 , 高通希望能 ...

  8. 高通骁龙平台芯片处理器(SoC)指南

    Android Authority制作了一份高通现役主流骁龙SoC指南,划分成三个级别并做了对比解析,一起来看看. 旗舰级800系 表中并未出现骁龙850,因为到目前为止还没有公开终端发布,且这颗So ...

  9. 高通android智能平台环境搭建_编译流程分析,高通平台环境搭建,编译,系统引导流程分析参考...

    高通有两个cpu,他们分别跑不同的系统,应用程序(ap)端是android系统,modem 端是高通自己的系统. 要编译出可供烧写使用的镜像文件需要三部分代码: 1) 获取经过高通打补丁的 andro ...

  10. 玩机搞机-----带你了解高通刷机平台中的一些选项释义 玩转平台

    很多刷机工具玩家都使用过,但对于一些新手来说.有些选项所表达的意义不太了解,选择与否严重会导致机型固件刷完个别功能出现故障,今天的这个博文对有些刷机平台中的选项做个简单的说明. 一 小米刷机平台 Mi ...

最新文章

  1. pandas基于条件判断更新dataframe中特定数据列数值内容的值(Conditionally updating values in specific pandas Dataframe )
  2. Redis在windows下的安装
  3. 基于自然语言的软件工程和程序设计(下)
  4. lLinux 下 Stress 压力测试工具
  5. Java 理论与实践: 非阻塞算法简介--转载
  6. Linux ping不通百度的解决方法
  7. 学数据库还不会Select,SQL Select详解,单表查询完全解析?
  8. 机械制图国家标准的绘图模板_如何使用p5js构建绘图应用
  9. 倒计时 5 天!年度开发者盛会 Unite Shanghai 2019 全日程揭晓(附表)
  10. 深入学习JavaScript: apply 方法 详解
  11. 编程中、遇到问题、bug多思考
  12. 超图高性能分布式渲染技术解密与应用
  13. 如何长久维持远距离恋情?
  14. KUKA机器人使用PLC外部自动运行配置使用方法
  15. matlab 优化 小于,科学网—matlab全局优化与局部优化 - 张凌的博文
  16. Leco题目:回文数
  17. CSS表格与浮动定位
  18. 有什么合适个体商户及小微企业的入门级进销存管理软件?
  19. 积木报表JimuReport支持的15种数据库类型介绍
  20. 没的选择时,存在就是合理的::与李旭科书法字QQ聊天记录

热门文章

  1. 【深度学习--图像分类】imageAI自定义模型训练
  2. 单片机c语言出租车计时程序,基于单片机的出租车计费(c语言
  3. c语言函数 java,C语言函数
  4. 全世界国家中英文名称以及地区区号json格式【资源】
  5. HTTP与HTTPS请求过程
  6. (详解)----冒泡排序---(图解)
  7. imageJ下载 安装插件
  8. Blender2.9入门篇
  9. R语言绘图-解决坐标轴测度问题
  10. 三极管开关电路_简析三极管开关电路设计