日期:2015.11.02 星期一
平台:MTK6735m, android 5.1
项目:K561WP-2
一、导言
前几天得到一个项目任务,要将最新测试出来的电池曲线合进到K561WP-2项目中。曲线表部分如下图所示:
![](https://img-blog.csdnimg.cn/4bcf7593e67d4b2080c5b63b0c80747c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5rS8JuW8ig==,size_20,color_FFFFFF,t_70,g_se,x_16)
1,首先要知道在那里合进这个电池曲线参数,是在
cust_battery_meter_table.h
的文件里修改的。具体这个文件在那个路径下,各个平台不尽相同。你可以这样找出来,回到根目录下用如下的shell命令:
find ./ -name "cust_battery_meter_table.h"
android 5.1,MTK6735M 的平台下是在以下目录:
apls/kernel-3.10/drivers/misc/mediatek/mach/mt6735/project_name/power/
2,再回来看看这张电池曲线表,DOD、R(x1000)这两个好理解,分别表示百分点和它所对应的内阻值。那么 OCV和VC呢?要以那一个为准呢?VC应该就是ADC得到的电压值吧,那么OCV呢?在网上查了一下,是这样解释的:OCV是Open circuit voltage = 开路电压,指的是电池不放电开路时,两极之间的电位差。以OCVO为准吗?感觉应该要以ADC的值经过MTK特有的电量算法后得到的值为准啊,怎么会是开路电压呢?这一点是很不理解的,但问同事都说是以OCV的参数为准。那么接下来就是仔细填入对应的参数了。
3,如果出了些比较奇怪的问题首先会去看看 battery_profile_t0[]、battery_profile_t1[]、battery_profile_t2[]、battery_profile_t3[]等各个数组是否等长,这个我一开始时还真没太注意这个问题,后来我一步步去跟读代码才知道为什么。
跟读:
battery_common.c --->
module_init(battery_init); --->
static int __init battery_init(void){.....} ---->
///分别作平台设备和驱动的注册 ---->
ret = platform_device_register(&battery_device); &&
ret = platform_driver_register(&battery_driver); ///这里是battery_driver的动作;
ret = platform_device_register(&MT_batteryNotify_device); &&
ret = platform_driver_register(&mt_batteryNotify_driver); ///这里是对 mt_batteryNotify_driver 的动作。
我们先跟 battery_driver ------->
static struct platform_driver battery_driver = {
.probe = battery_probe,
.remove = battery_remove,
.shutdown = battery_shutdown,
.driver = {
.name = "battery",
.pm = &battery_pm_ops,
},
};
struct platform_device battery_device = {
.name = "battery", ///--------> 它们一匹配成功后就会执行 battery_probe 这个函数.
.id = -1,
};
static int battery_probe(struct platform_device *dev) {......} ---------->
kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); ---------->
int bat_thread_kthread(void *x) {...................} ---------->
BAT_thread(); ---------->
void BAT_thread(void) {....................} ---------->
battery_meter_initial(); ---------->
battery_meter.c ---------->
kal_int32 battery_meter_initial(void) {.....................} ---------->
fgauge_initialization(); && table_init(); ---------->
void table_init(void){..............} ---------->
fgauge_construct_r_table_profile(temperature, profile_p_r_table);---------->
low_profile_p = fgauge_get_profile_r_table(TEMPERATURE_T1);
high_profile_p = fgauge_get_profile_r_table(TEMPERATURE_T2);
void fgauge_initialization(void) {..................} --------->
fgauge_construct_battery_profile_init();
void fgauge_construct_battery_profile_init(void) {............} ---------->
profile_p[0] = fgauge_get_profile(TEMPERATURE_T0); &&
saddles = fgauge_get_saddles(); ---------->
int fgauge_get_saddles(void)
{
return sizeof(battery_profile_t2) / sizeof(BATTERY_PROFILE_STRUC);
--------> 现在明白了吧,为什么这些数组一定要等长呢?
}
BATTERY_PROFILE_STRUC_P fgauge_get_profile(kal_uint32 temperature) {............}
case TEMPERATURE_T0:
return &battery_profile_t0[0];
break;
--------->
cust_battery_mater_table.h
// T0 -10C
BATTERY_PROFILE_STRUC battery_profile_t0[] =
{
{0 , 4328 },
{2 , 4304 },
{3 , 4285 },
{5 , 4266 },
{6 , 4248 },
....................
};
--------------->>>>>>好了,以上这些都只是一些较为疑惑的问题,下面就是真正地一步一步去跟进MTK是如何计算电量的!
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------//
battery_common.c
------>
module_init(battery_init); ------>
static int __init battery_init(void){.....} ------>
分别作平台设备和驱动的注册 ------>
它们一匹配成功后就会执行battery_probe 这个函数
static int battery_probe(struct platform_device *dev) {.........} ------>
kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread"); ------>
int bat_thread_kthread(void *x) {.........} ------>
1,设置10秒钟的内核定时时间。
2,while(1) {
如果系统不在休眠的状态: {BAT_thread();}
wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));
//每10s就会判断一下要不要执行 BAT_thread();
}
void BAT_thread(void)
{
1,如果是刚开机:
{
1, 执行 kal_int32 battery_meter_initial(void)
{
.........
table_init();//这个比较重要了,它的作用是创建和初始化电池曲线表
oam_init();//在这里面会读出各种和电池相关的全局变量
}
2, 执行 BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
//读出电池电量为 15%时的电压值
}
2, 查看是否有连接充电或USB。
3, void mt_battery_GetBatteryData(void)
{//读取各和电压相关的值
1, bat_vol = battery_meter_get_battery_voltage(KAL_TRUE);//读取电池5次的平均ADC电压
2, Vsense = battery_meter_get_VSense();//读取1次 VSense的电压
3, 如果正在充电,即读取一下当前的充电电流
4, charger_vol = battery_meter_get_charger_voltage();//读取5次当前的平均充电电压
5, temperature = battery_meter_get_battery_temperature();//读取当前电池的温度
6, temperatureV = battery_meter_get_tempV();//读取1次当前电池的电压值
7, temperatureR = battery_meter_get_tempR(temperatureV);//读取当前电池的内阻值
如果到了10秒的定时或其它条件:
{
SOC = battery_meter_get_battery_percentage();//读出电池电压百分比
kal_int32 battery_meter_get_battery_percentage(void)
{
…………
oam_run();//这个函数比较重要,主要是更新oam相关的全局变量,
为 mt_battery_update_status();里边的函数调用服务;
#if (OAM_D5 == 1)
return (100 - oam_d_5);
#else
return (100 - oam_d_2);
}
}
8, ZCV = battery_meter_get_battery_zcv();//获取ZCV的值,即 gFG_voltage;
9, 求出BMT_status.ICharging在经过平均算法后的值;
10, 求出 BMT_status.bat_vol 在经过平均算法后的值;
11, 求出 BMT_status.temperature 在经过平均算法后得到的值;
12, 将之前所求得的各种值赋给 BMT_status 全局变量
BMT_status.Vsense = Vsense;
BMT_status.charger_vol = charger_vol;
BMT_status.temperatureV = temperatureV;
BMT_status.temperatureR = temperatureR;
BMT_status.SOC = SOC;
BMT_status.ZCV = ZCV;
}
4, mt_battery_thermal_check();//检查温度是否有过高的,如果有,即会重启关机。
5, mt_battery_notify_check();//检测电池是否有各种异常的通知。
6, 如果当前正在充电,即:
if (BMT_status.charger_exist == KAL_TRUE)
{
mt_battery_CheckBatteryStatus();//检测电池的各个状态是否正常
mt_battery_charging_algorithm();//根据当前是那一类的充电类型去执行它相对应的充电方法
}
7, mt_battery_update_status();//更新电池的各种状态数据
8, mt_kpoc_power_off_check();//轮询查看是否有操作关机键的动作
}
跳到 battery_meter.c文件中的battery_meter_initial();函数。
kal_int32 battery_meter_initial(void) {.........} -------->
table_init(); && oam_init(); -------->
oam_init(void) {..........} 在这里面会读出 gFG_voltage、g_booting_vbat、gFG_capacity_by_v、gFG_BATT_CAPACITY_aging、oam_v_ocv_init等等的全局变量。
oam_init(void) -------->
dod_init(); -------->
void dod_init(void)
{
g_rtc_fg_soc = get_rtc_spare_fg_value();//在这里先读一次rtc上记录的后备电压值,赋给 g_rtc_fg_soc
.....................
这里主要是初始化了一些 gFG_capacity_by_c_init、gFG_capacity、gFG_capacity_by_c、gFG_capacity_by_v 等 battery_meter.c 里边的全局变量。
其中还有一个较为重要的动作,就是算出当前电池剩余 15%电量的电压值 gFG_15_vlot,默认为3700。
}