mtk平台充电器检测

来源:互联网 发布:常见的高速网络有几种 编辑:程序博客网 时间:2024/04/28 04:40
平台:mt6735 5.1

首先来看BAT_thread()。
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) {#elseif ((BMT_status.charger_type == CHARGER_UNKNOWN) &&    (DISO_data.diso_state.cur_vusb_state == DISO_ONLINE)) {#endifmt_charger_type_detection();if ((BMT_status.charger_type == STANDARD_HOST)    || (BMT_status.charger_type == CHARGING_HOST)) {mt_usb_connect();}}#endifbattery_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位标明了是否有充电器的插入。

需要注意的是,充电器插入与拔出是通过硬件来检测的。默认充电器的检测电压范围是4.3v~6.5v,只要插入充电器的电压在这个范围内都是能够检测到充电器插入的。那么这个范围也是可以设置的,在mt6735平台上充电器低电压使用的是该寄存器的默认值4.3v,而高电压定义在cust_charging.h中,即V_CHARGER_MAX,默认值为6.5v,这个值最终是会被设置到mt6328的CHR_CON1寄存器的高4位中。

先回到mt_battery_charger_detect_check()函数这里,如果检测到了有充电器的插入,再调用mt_charger_type_detection()函数去识别充电器的类型,例如是USB充电,还是AC充电器(一般AC充电器的d+、d-是短接的)。

回到BAT_thread()函数,充电器检测完成之后,调用mt_battery_GetBatteryData()函数去读取电池的一些参数。
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();elseSOC = 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;}#endifprevious_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);}
这里获取的参数有:电池电压、充电电流、充电器的电压、电池温度等等。

与充电器相关的是充电器电压和充电电流。

充电器的电压是通过battery_meter_get_charger_voltage()函数得到的。
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。

在PMIC_IMM_GetOneChannelValue()函数里,首先是读取adc采样得到的值,然后再转换成电压值,这个电压值的范围是0~1.8v,注意最后返回的单位是mv,比如说510,那么采样得到的值就是510mv。

注意adc采样电压范围是0~1.8v,所以vbus电压不能直接接到pmic上,mtk参考电路是接两个电阻分压之后接入pmic的,这个两个电阻值分别是330k、39k,电阻值最好不要做更换。

采样得到的那个值,还要经过一个公式计算才能得到实际的充电器电压值,公式为(R1 = 330k,R2 = 39k):
(adc_val / R2) * (R1 + R2)
例如前面采样得到510mv,经过计算得到实际的充电器电压值为4825mv。

如果插入充电器的电压值超过默认的6.5v怎么办,会有两个问题:
1. 识别不了充电器的插入。
2. 这里也会得到充电器的电压值,但是这个电压值超过了6.5v这个门限,那么这里会给出充电器过压的警示。


Ok,BAT_thread()函数只是读取充电器电压、充电电流等信息,真正检测充电器的插入与拔出在pmic.c的chrdet_int_handler()函数中。
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_CHARGINGif (!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();    }}#endifpmic_set_register_value(PMIC_RG_USBDL_RST,1);do_chrdet_int_task();}
充电器的插入、拔出都会调用该函数,这个检测都是通过硬件来完成的,只要插入充电器的电压值在合适范围内都会被认为有充电器插入,反之则不会检测到充电器。

chrdet_int_handler()函数被调用之后,最终还是会去读取pmic的CHR_CON0寄存器,判断是插入还是拔出,最后识别出充电器的类型。


总结:充电器的插入与拔出是通过硬件来检测的,BAT_thread()函数只是将充电器电压、充电电流这些信息读取出来,作为警示作用或者用作其他。


// 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_MEASUREreturn 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次采样的总和。

然后对采样出来的值做一个排序,去掉最小的两个值和最大的两个值,然后计算出平均值。

最后ISENSE通道计算出来的值减去BATSNS除以电阻就得到充电电流值,这个电阻是通过宏CUST_R_SENSE来定义的,默认是68,即68毫欧,需要根据自己项目使用的值来适配。

0 0
原创粉丝点击