QPNP 8909 8916 充电相关(2)【转】
上一篇主要讲电池相关的一些知识,上节忘记讲了,电池一般分为电量计电池和非电流计电池,电量计电池,就不需要用pmu8916的IC,当然这只是只,不需要BMS来计算soc,而jni层也需要读取电流计的电池相关属性。
这一节主要是根据代码进行相关的分析。
- 先看probe的代码:
static int qpnp_vm_bms_probe(struct spmi_device *spmi)
{
...........
..........
...........
..........
//这里把电池的配置文件dtsi的读出来,并存到当前的结构体。
rc = set_battery_data(chip);
rc = config_battery_data(chip->batt_data);
..........
..........
//这个是核心的工作,一个线程,BMS的主要内容在此
INIT_DELAYED_WORK(&chip->monitor_soc_work, monitor_soc_work);
..........
..........
//电池一些常规的检测,主要从PMIC上读到的相关信息
battery_insertion_check(chip);
battery_status_check(chip);
/* character device to pass data to the userspace */
rc = register_bms_char_device(chip);
if (rc) {
pr_err("Unable to regiter '/dev/vm_bms' rc=%d\n", rc);
goto fail_bms_device;
}
the_chip = chip;
//这个也很重要,我们从上节知道,初值last_ocv_soc是非常重要的,决定着后面的soc估值算法
calculate_initial_soc(chip);
//设置和注册电池的power supply
/* setup & register the battery power supply */
chip->bms_psy.name = "bms";
chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;
chip->bms_psy.properties = bms_power_props;
chip->bms_psy.num_properties = ARRAY_SIZE(bms_power_props);
chip->bms_psy.get_property = qpnp_vm_bms_power_get_property;
chip->bms_psy.set_property = qpnp_vm_bms_power_set_property;
chip->bms_psy.external_power_changed = qpnp_vm_bms_ext_power_changed;
chip->bms_psy.property_is_writeable = qpnp_vm_bms_property_is_writeable;
chip->bms_psy.supplied_to = qpnp_vm_bms_supplicants;
chip->bms_psy.num_supplicants = ARRAY_SIZE(qpnp_vm_bms_supplicants);
rc = power_supply_register(chip->dev, &chip->bms_psy);
if (rc < 0) {
pr_err("power_supply_register bms failed rc = %d\n", rc);
goto fail_psy;
}
.....................
....................
....................
//这里启动工作线程
schedule_delayed_work(&chip->monitor_soc_work, 0);
..........................
.......................
}
- 分析如何确定初始的last_ocv_uv:
static int calculate_initial_soc(struct qpnp_bms_chip *chip)
{
........
........
//读当前电池温度
rc = get_batt_therm(chip, &batt_temp);
............
//读PON OCV
rc = read_and_update_ocv(chip, batt_temp, true);
..........
//读关机保存的soc和last_soc_uv
rc = read_shutdown_ocv_soc(chip);
//这里判断是使用估计soc还是估值soc。如果chip->warm_reset 为真
if (chip->warm_reset) {
if (chip->shutdown_soc_invalid) { //这个是dtsi的一个配置选项,若没有配置,
//则不使用关机soc
est_ocv = estimate_ocv(chip); //估值soc
chip->last_ocv_uv = est_ocv;
} else {
chip->last_ocv_uv = chip->shutdown_ocv;//使用关机的soc和ocv
pr_err("Hyan %d : set chip->last_ocv_uv = %d\n", __LINE__, chip->last_ocv_uv);
chip->last_soc = chip->shutdown_soc;
chip->calculated_soc = lookup_soc_ocv(chip,
chip->shutdown_ocv, batt_temp);
}
} else {
if (chip->workaround_flag & WRKARND_PON_OCV_COMP)
adjust_pon_ocv(chip, batt_temp);
/* !warm_reset use PON OCV only if shutdown SOC is invalid */
chip->calculated_soc = lookup_soc_ocv(chip,
chip->last_ocv_uv, batt_temp);
if (!chip->shutdown_soc_invalid &&
(abs(chip->shutdown_soc - chip->calculated_soc) <
chip->dt.cfg_shutdown_soc_valid_limit)) {
chip->last_ocv_uv = chip->shutdown_ocv;
chip->last_soc = chip->shutdown_soc;
chip->calculated_soc = lookup_soc_ocv(chip,
chip->shutdown_ocv, batt_temp);//使用估值soc
} else {
chip->shutdown_soc_invalid = true; //使用关机soc
}
}
.............
............
}
//得到PON OCV
rc = read_and_update_ocv(chip, batt_temp, true);
ocv_uv = convert_vbatt_raw_to_uv(chip, ocv_data, is_pon_ocv);
uv = vadc_reading_to_uv(reading, true); //读ADC值
uv = adjust_vbatt_reading(chip, uv); //转化为soc_uv
rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv, is_pon_ocv); //根据IC的类型,进行温度补偿
//从寄存器中读到储存的soc和ocv
read_shutdown_ocv_soc
rc = qpnp_read_wrapper(chip, (u8 *)&stored_ocv,
chip->base + BMS_OCV_REG, 2);
rc = qpnp_read_wrapper(chip, &stored_soc, chip->base + BMS_SOC_REG, 1);
adjust_pon_ocv(struct qpnp_bms_chip *chip, int batt_temp)
rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result);
pc = interpolate_pc(chip->batt_data->pc_temp_ocv_lut,
batt_temp, chip->last_ocv_uv / 1000); //根据ocv和temp,查表得PC(soc)。
rbatt_mohm = get_rbatt(chip, pc, batt_temp); //根据soc和temp,得电池内阻zhi
/* convert die_temp to DECIDEGC */
die_temp = (int)result.physical / 100;
current_ma = interpolate_current_comp(die_temp); //当前电流
delta_uv = rbatt_mohm * current_ma;
chip->last_ocv_uv += delta_uv; //修正last_ocv_uv
//这个函数主要根据last_ocv_uv,计算出soc的
lookup_soc_ocv(struct qpnp_bms_chip *chip, int ocv_uv, int batt_temp)
//查表得到soc_ocv,soc_cutoff
soc_ocv = interpolate_pc(chip->batt_data->pc_temp_ocv_lut,
batt_temp, ocv_uv / 1000);
soc_cutoff = interpolate_pc(chip->batt_data->pc_temp_ocv_lut,
batt_temp, chip->dt.cfg_v_cutoff_uv / 1000);
soc_final = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_cutoff),
(100 - soc_cutoff));
if (batt_temp > chip->dt.cfg_low_temp_threshold)
iavg_ma = calculate_uuc_iavg(chip);
else
iavg_ma = chip->current_now / 1000;
//查表得到FCC,ACC
fcc = interpolate_fcc(chip->batt_data->fcc_temp_lut,
batt_temp);
acc = interpolate_acc(chip->batt_data->ibat_acc_lut,
batt_temp, iavg_ma);
//计算出UUC
soc_uuc = ((fcc - acc) * 100) / fcc;
if (batt_temp > chip->dt.cfg_low_temp_threshold)
soc_uuc = adjust_uuc(chip, soc_uuc);
//得到soc_acc
soc_acc = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_uuc),
(100 - soc_uuc));
soc_final = soc_acc; //这个为上报的soc
chip->last_acc = acc;
- 看工作线程,monitor_soc_work(struct work_struct *work):
static void monitor_soc_work(struct work_struct *work)
calculate_delta_time(&chip->tm_sec, &chip->delta_time_s);
rc = get_batt_therm(chip, &batt_temp);
new_soc = lookup_soc_ocv(chip, chip->last_ocv_uv,batt_temp);
new_soc = clamp_soc_based_on_voltage(chip, new_soc);
report_vm_bms_soc(chip);//上报事件,上层得到消息,调用qpnp_vm_bms_power_get_property,获取相关的属性,计算出
last_ocv_uv,并通过qpnp_vm_bms_power_set_property方法,设置last_ocv_uv,并启动monitor_soc_work。
- 待续
QPNP 8909 8916 充电相关(2)【转】的更多相关文章
- QPNP 8909 8916 充电相关(1)【转】
最近一直在搞电源管理相关内容,之前是8610的bms,现在8916的bms,发现两者还是有点区别的,8916把对last_ocv_uv的估值算法分装成执行文件,作为服务一直运行. 电源管理方面,应该是 ...
- android电池管理系统从上层的java到底层驱动的调用(转载)
1.概述 随着移动智能设备的快速发屏,电池的续航能力在很大情况下诱导了大众消费者的购买选择,android系统对电源管理的合理与否直接影响到电池的续航能力,而电池系统作为其中的一部分,主要用于对电池状 ...
- Android Framework------之PowerManagerService的功能
自从接触Android系统已经一年多了,这段时间内对于Android系统的Framework层的各个模块都有过接触,有时也做过分析,但是一直没能形成一个总结性的东西.这次下定决心,好好整理整理对于An ...
- 【转】android 电池(三):android电池系统
关键词:android电池系统电池系统架构 uevent power_supply驱动 平台信息: 内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV3 ...
- Druid + Grafana 应用实践
谈到大数据,大家首先想到的肯定是Hadoop,近年来互联网技术的快速增长催生了各类大体量数据的爆发,Hadoop最大的贡献在于帮助企业将那些低价值的事件流数据转化为高价值的聚合数据,为企业的经营决策提 ...
- android 电池(三):android电池系统【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/8709838 一.电池系统结构 Android中的电池使用方式主要有三种:AC.USB. ...
- Android电池驱动【转】
本文转载自:http://blog.sina.com.cn/s/blog_66a6a5ec0100n6ej.html Android的电池的管理分为三个部分:Java部分,JNI部分以及kenel部分 ...
- Bugzilla 系统企业应用案例
目录 一. 概述: - 4 - 二. 目的 - 4 - 三. 执行原则 - 4 - 四. 管理办法 - 4 - 五. BUG处理流程图 - 5 - 六. 主要职责 - 6 - 七. 需求类问题处理 - ...
- android电池管理系统
原文:http://www.2cto.com/kf/201408/326462.html 1.概述 随着移动智能设备的快速发屏,电池的续航能力在很大情况下诱导了大众消费者的购买选择,android系统 ...
随机推荐
- Java设计模式13:责任链模式
前言 来菜鸟这个大家庭10个月了,总得来说比较融入了环境,同时在忙碌的工作中也深感技术积累不够,在优秀的人身边工作必须更加花时间去提升自己的技术能力.技术视野,所以开一个系列文章,标题就轻松一点叫做最 ...
- 收到一个神盾局的offer,怎么样?
漫威十一年系列总结性的电影<复联4>正在热映,而衍生出的一部和漫威宇宙关联的美剧<神盾局特工>,今年我也在陆陆续续地看.一开始预期的是一部特工加一些科幻或魔幻元素的剧集,就图看 ...
- 使用SC命令操作(安装、开启、配置、关闭、删除)Windows下的服务
目录 一.直接使用cmd命令行操作windows服务 二.使用bat批处理-操作windows服务 一.直接使用cmd命令行操作windows服务 1.安装服务 sc create 服务名 binPa ...
- 第1章:C++泛型技术基础:模板——《C++泛型:STL原理和应用》读书笔记整理
第1章:C++泛型技术基础:模板 1.2 关于模板参数 1.2.1 模板参数类型 类型参数 typename声明的参数都属于类型参数,它的实参必须为系统内置或者用户自定义的数据类型,包括类模板实体 ...
- python通过http下载文件的方法
1.通过requests.get方法 r = requests.get("http://200.20.3.20:8080/job/Compile/job/aaa/496/artifact/b ...
- 【THUPC 2018】赛艇
Problem Description Lavender.Caryophyllus.Jasmine.Dianthus现在在玩一款名叫"赛艇"的游戏. 这个游戏的规则是这样的: 玩家 ...
- C#线程学习笔记一:线程基础
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/18/Thread.html,记录一下学习过程以备后续查用. 一.线程的介绍 进程(Proce ...
- How to: Supply Initial Data for the Entity Framework Data Model 如何:为EF数据模型提供初始数据
After you have introduced a data model, you may need to have the application populate the database w ...
- 一个有意思的自我介绍PPT快闪
模版来源:http://ppt.dede58.com/peixunyanjiang/27066.html
- Unity容器<1>
参考地址: https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn170416(v=pandp.10) 总览 Unity是一个轻量级 ...