void BAT_thread(void)
{
static kal_bool battery_meter_initilized = KAL_FALSE;
if (battery_meter_initilized == KAL_FALSE) {
battery_meter_initial(); /* move from battery_probe() to decrease booting time */
BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
battery_meter_initilized = KAL_TRUE;
}
dodprint();
mt_battery_charger_detect_check();
mt_battery_GetBatteryData();
if (BMT_status.charger_exist == KAL_TRUE) {
check_battery_exist();
}
mt_battery_thermal_check();
mt_battery_notify_check();
if (BMT_status.charger_exist == KAL_TRUE) {
mt_battery_CheckBatteryStatus();
mt_battery_charging_algorithm();
}
mt_battery_update_status();
mt_kpoc_power_off_check();
}
BAT_thread()是battery系统核心的一个函数,每10秒钟被调用一次(通过hrtimer定时器来实现)。
跟充电相关的首先是mt_battery_charger_detect_check()函数,这个函数首先是检测充电器是否存在,如果充电器存在然后再检测充电器的类型。
static void mt_battery_charger_detect_check(void)
{
if (upmu_is_chr_det() == KAL_TRUE) {
wake_lock(&battery_suspend_lock);
#if !defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
BMT_status.charger_exist = KAL_TRUE;
#endif
#if defined(CONFIG_MTK_WIRELESS_CHARGER_SUPPORT)
mt_charger_type_detection();
if ((BMT_status.charger_type == STANDARD_HOST)
|| (BMT_status.charger_type == CHARGING_HOST)) {
mt_usb_connect();
}
#else
#if !defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
if (BMT_status.charger_type == CHARGER_UNKNOWN) {
#else
if ((BMT_status.charger_type == CHARGER_UNKNOWN) &&
(DISO_data.diso_state.cur_vusb_state == DISO_ONLINE)) {
#endif
mt_charger_type_detection();
if ((BMT_status.charger_type == STANDARD_HOST)
|| (BMT_status.charger_type == CHARGING_HOST)) {
mt_usb_connect();
}
}
#endif
battery_log(BAT_LOG_CRTI, "[BAT_thread]Cable in, CHR_Type_num=%d\r\n",
BMT_status.charger_type);
} else {
wake_unlock(&battery_suspend_lock);
BMT_status.charger_exist = KAL_FALSE;
BMT_status.charger_type = CHARGER_UNKNOWN;
BMT_status.bat_full = KAL_FALSE;
BMT_status.bat_in_recharging_state = KAL_FALSE;
BMT_status.bat_charging_state = CHR_PRE;
BMT_status.total_charging_time = 0;
BMT_status.PRE_charging_time = 0;
BMT_status.CC_charging_time = 0;
BMT_status.TOPOFF_charging_time = 0;
BMT_status.POSTFULL_charging_time = 0;
battery_log(BAT_LOG_CRTI, "[BAT_thread]Cable out \r\n");
mt_usb_disconnect();
}
}
检测充电器是否存在调用的是upmu_is_chr_det()函数,这个函数调用的是get_charger_detect_status()函数去检测的,最终这个函数会去读取pmic mt6328芯片的CHR_CON0寄存器,而这个寄存器的第5位标明了是否有充电器的插入。
void mt_battery_GetBatteryData(void)
{
kal_uint32 bat_vol, charger_vol, Vsense, ZCV;
kal_int32 ICharging, temperature, temperatureR, temperatureV, SOC;
static kal_int32 bat_sum, icharging_sum, temperature_sum;
static kal_int32 batteryVoltageBuffer[BATTERY_AVERAGE_SIZE];
static kal_int32 batteryCurrentBuffer[BATTERY_AVERAGE_SIZE];
static kal_int32 batteryTempBuffer[BATTERY_AVERAGE_SIZE];
static kal_uint8 batteryIndex = 0;
static kal_int32 previous_SOC = -1;
bat_vol = battery_meter_get_battery_voltage(KAL_TRUE);
Vsense = battery_meter_get_VSense();
if( upmu_is_chr_det() == KAL_TRUE ) {
ICharging = battery_meter_get_charging_current();
} else {
ICharging = 0;
}
charger_vol = battery_meter_get_charger_voltage();
temperature = battery_meter_get_battery_temperature();
temperatureV = battery_meter_get_tempV();
temperatureR = battery_meter_get_tempR(temperatureV);
if (bat_meter_timeout == KAL_TRUE || bat_spm_timeout == TRUE || fg_wake_up_bat== KAL_TRUE)
{
SOC = battery_meter_get_battery_percentage();
//if (bat_spm_timeout == true)
//BMT_status.UI_SOC = battery_meter_get_battery_percentage();
bat_meter_timeout = KAL_FALSE;
bat_spm_timeout = FALSE;
} else {
if (previous_SOC == -1)
SOC = battery_meter_get_battery_percentage();
else
SOC = previous_SOC;
}
ZCV = battery_meter_get_battery_zcv();
BMT_status.ICharging =
mt_battery_average_method(BATTERY_AVG_CURRENT, &batteryCurrentBuffer[0], ICharging, &icharging_sum,
batteryIndex);
if (previous_SOC == -1 && bat_vol <= V_0PERCENT_TRACKING) {
battery_log(BAT_LOG_CRTI,
"battery voltage too low, use ZCV to init average data.\n");
BMT_status.bat_vol =
mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], ZCV, &bat_sum,
batteryIndex);
} else {
BMT_status.bat_vol =
mt_battery_average_method(BATTERY_AVG_VOLT, &batteryVoltageBuffer[0], bat_vol, &bat_sum,
batteryIndex);
}
if (battery_cmd_thermal_test_mode == 1)
{
battery_log(BAT_LOG_CRTI,
"test mode , battery temperature is fixed.\n");
}
else
{
BMT_status.temperature =
mt_battery_average_method(BATTERY_AVG_TEMP, &batteryTempBuffer[0], temperature, &temperature_sum,
batteryIndex);
}
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;
#if !defined(CUST_CAPACITY_OCV2CV_TRANSFORM)
if (BMT_status.charger_exist == KAL_FALSE) {
if (BMT_status.SOC > previous_SOC && previous_SOC >= 0)
BMT_status.SOC = previous_SOC;
}
#endif
previous_SOC = BMT_status.SOC;
batteryIndex++;
if (batteryIndex >= BATTERY_AVERAGE_SIZE)
batteryIndex = 0;
if (g_battery_soc_ready == KAL_FALSE)
g_battery_soc_ready = KAL_TRUE;
battery_log(BAT_LOG_CRTI,
"AvgVbat=(%d),bat_vol=(%d),AvgI=(%d),I=(%d),VChr=(%d),AvgT=(%d),T=(%d),pre_SOC=(%d),SOC=(%d),ZCV=(%d)\n",
BMT_status.bat_vol, bat_vol, BMT_status.ICharging, ICharging,
BMT_status.charger_vol, BMT_status.temperature, temperature,
previous_SOC, BMT_status.SOC, BMT_status.ZCV);
}
这里获取的参数有:电池电压、充电电流、充电器的电压、电池温度等等。
kal_int32 battery_meter_get_charger_voltage(void)
{
int ret = 0;
int val = 0;
val = 5; /* set avg times */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_CHARGER, &val);
/* val = (((R_CHARGER_1+R_CHARGER_2)*100*val)/R_CHARGER_2)/100; */
return val;
}
这个电压值是pmic mt6328通过adc采样得到的,最终调用的是PMIC_IMM_GetOneChannelValue()函数,adc通道是通道2。
void chrdet_int_handler(void)
{
PMICLOG("[chrdet_int_handler]CHRDET status = %d....\n",pmic_get_register_value(PMIC_RGS_CHRDET));
#ifdef CONFIG_MTK_KERNEL_POWER_OFF_CHARGING
if (!upmu_get_rgs_chrdet())
{
int boot_mode = 0;
boot_mode = get_boot_mode();
if(boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT || boot_mode == LOW_POWER_OFF_CHARGING_BOOT)
{
PMICLOG("[chrdet_int_handler] Unplug Charger/USB In Kernel Power Off Charging Mode! Shutdown OS!\r\n");
mt_power_off();
}
}
#endif
pmic_set_register_value(PMIC_RG_USBDL_RST,1);
do_chrdet_int_task();
}
充电器的插入、拔出都会调用该函数,这个检测都是通过硬件来完成的,只要插入充电器的电压值在合适范围内都会被认为有充电器插入,反之则不会检测到充电器。
// 2016-11-11 add
如何支持12充电器充电呢?
// 2017-03-31 add
充电电流的获取
前面只说了充电器电压的获取,在电池系统里面,充电电流也是一个很重要的参数,那么充电电流如何得到呢?
我们知道电流计算公式为:I = (V / R),那么在mtk平台里面呢,电流的检测也是通过这个公式得来的。
计算流程是这样的,首先在电池VBAT引脚和充电IC之间串联一个电阻,通过ADC读取这个电阻两端的电压值,这个差值再除以电阻值,就得到充电电流值,在mt6735平台上,这个电阻的阻值默认为68毫欧姆。
注意,这个电阻的两端分别接到MT6328的BATSNS、ISENSE引脚上的,分别对应ADC通道的0和1,同时电池的电压也是通过ADC通道0读取的。
来看代码,在mt_battery_GetBatteryData()函数里面调用battery_meter_get_charging_current()来获取充电电流值:
kal_int32 battery_meter_get_charging_current(void)
{
#ifdef DISABLE_CHARGING_CURRENT_MEASURE
return 0;
#elif !defined (EXTERNAL_SWCHR_SUPPORT)
kal_int32 ADC_BAT_SENSE_tmp[20] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
kal_int32 ADC_BAT_SENSE_sum = 0;
kal_int32 ADC_BAT_SENSE = 0;
kal_int32 ADC_I_SENSE_tmp[20] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
kal_int32 ADC_I_SENSE_sum = 0;
kal_int32 ADC_I_SENSE = 0;
int repeat = 20;
int i = 0;
int j = 0;
kal_int32 temp = 0;
int ICharging = 0;
int ret = 0;
int val = 1;
for (i = 0; i < repeat; i++) {
val = 1; /* set avg times */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &val);
ADC_BAT_SENSE_tmp[i] = val;
val = 1; /* set avg times */
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_I_SENSE, &val);
ADC_I_SENSE_tmp[i] = val;
ADC_BAT_SENSE_sum += ADC_BAT_SENSE_tmp[i];
ADC_I_SENSE_sum += ADC_I_SENSE_tmp[i];
}
/* sorting BAT_SENSE */
for (i = 0; i < repeat; i++) {
for (j = i; j < repeat; j++) {
if (ADC_BAT_SENSE_tmp[j] < ADC_BAT_SENSE_tmp[i]) {
temp = ADC_BAT_SENSE_tmp[j];
ADC_BAT_SENSE_tmp[j] = ADC_BAT_SENSE_tmp[i];
ADC_BAT_SENSE_tmp[i] = temp;
}
}
}
bm_print(BM_LOG_FULL, "[g_Get_I_Charging:BAT_SENSE]\r\n");
for (i = 0; i < repeat; i++) {
bm_print(BM_LOG_FULL, "%d,", ADC_BAT_SENSE_tmp[i]);
}
bm_print(BM_LOG_FULL, "\r\n");
/* sorting I_SENSE */
for (i = 0; i < repeat; i++) {
for (j = i; j < repeat; j++) {
if (ADC_I_SENSE_tmp[j] < ADC_I_SENSE_tmp[i]) {
temp = ADC_I_SENSE_tmp[j];
ADC_I_SENSE_tmp[j] = ADC_I_SENSE_tmp[i];
ADC_I_SENSE_tmp[i] = temp;
}
}
}
bm_print(BM_LOG_FULL, "[g_Get_I_Charging:I_SENSE]\r\n");
for (i = 0; i < repeat; i++) {
bm_print(BM_LOG_FULL, "%d,", ADC_I_SENSE_tmp[i]);
}
bm_print(BM_LOG_FULL, "\r\n");
ADC_BAT_SENSE_sum -= ADC_BAT_SENSE_tmp[0];
ADC_BAT_SENSE_sum -= ADC_BAT_SENSE_tmp[1];
ADC_BAT_SENSE_sum -= ADC_BAT_SENSE_tmp[18];
ADC_BAT_SENSE_sum -= ADC_BAT_SENSE_tmp[19];
ADC_BAT_SENSE = ADC_BAT_SENSE_sum / (repeat - 4);
bm_print(BM_LOG_FULL, "[g_Get_I_Charging] ADC_BAT_SENSE=%d\r\n", ADC_BAT_SENSE);
ADC_I_SENSE_sum -= ADC_I_SENSE_tmp[0];
ADC_I_SENSE_sum -= ADC_I_SENSE_tmp[1];
ADC_I_SENSE_sum -= ADC_I_SENSE_tmp[18];
ADC_I_SENSE_sum -= ADC_I_SENSE_tmp[19];
ADC_I_SENSE = ADC_I_SENSE_sum / (repeat - 4);
bm_print(BM_LOG_FULL, "[g_Get_I_Charging] ADC_I_SENSE(Before)=%d\r\n", ADC_I_SENSE);
bm_print(BM_LOG_FULL, "[g_Get_I_Charging] ADC_I_SENSE(After)=%d\r\n", ADC_I_SENSE);
if (ADC_I_SENSE > ADC_BAT_SENSE) {
ICharging = (ADC_I_SENSE - ADC_BAT_SENSE + g_I_SENSE_offset) * 1000 / CUST_R_SENSE;
} else {
ICharging = 0;
}
return ICharging;
#else
return 0;
#endif
}
在battery_meter_get_charging_current()函数里面,首先是使用ADC采样电压值,都读取20次,同时计算出20次采样的总和。