mtk平台充电器检测

平台: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) {
            #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位标明了是否有充电器的插入。

需要注意的是,充电器插入与拔出是通过硬件来检测的。默认充电器的检测电压范围是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();
            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);
     
     
    }

这里获取的参数有:电池电压、充电电流、充电器的电压、电池温度等等。

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

充电器的电压是通过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_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();
    }

充电器的插入、拔出都会调用该函数,这个检测都是通过硬件来完成的,只要插入充电器的电压值在合适范围内都会被认为有充电器插入,反之则不会检测到充电器。

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

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

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

 

 


---------------------
作者:mcgrady_tracy
来源:CSDN
原文:https://blog.csdn.net/mcgrady_tracy/article/details/53036426
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值