mtk平台充电器检测

本文详细介绍了MTK平台下充电器检测的方法,包括充电器的插入与拔出检测过程,以及如何通过硬件读取充电器电压。此外,还深入探讨了充电电流的计算原理与实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平台: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毫欧,需要根据自己项目使用的值来适配。

<think>好的,我现在需要回答用户关于MTK平台充电电流检测方法的问题。首先,我需要回顾一下用户提供的引用内容,看看里面有没有相关的信息。 用户给出的引用[1]提到,MTK平台使用开路电压和库仑计积分法来计算电量百分比。这可能和电流检测有关联,但具体怎么检测电流还不清楚。然后引用[2]指出,MT6305芯片通过ISENSE信号检测充电电流和VBATSENSE检测电池电压。这里明确提到了电流检测是通过ISENSE信号实现的,这应该是关键点。引用[3]则讨论了电池接触点电阻对充电算法的影响,并提到在mtk_imp_tracking函数中调整FG_METER_RESISTANCE宏来补偿接触电阻。这可能涉及到电流检测的校准或补偿。 接下来,我需要整合这些信息。首先,MTK平台使用MT6305电源管理芯片,其中ISENSE引脚负责电流检测。硬件上会有电流检测电路,将电流转化为电压信号。软件方面,驱动程序会读取ADC转换后的数值,转换成实际电流值。同时,库仑计积分法可能用于累计电流,计算电量。另外,接触电阻的存在会影响大电流充电时的准确性,因此需要在软件中进行补偿,比如调整FG_METER_RESISTANCE宏。 可能还需要考虑校准流程,比如在工厂或调试阶段对电流检测进行校准,确保ADC读取的准确性。同时,温度因素也可能影响检测结果,是否有温度补偿措施? 用户的问题主要关注检测方法,所以需要分硬件和软件两部分说明。硬件部分涉及MT6305的ISENSE信号和相关电路;软件部分包括驱动读取ADC、转换为电流值、库仑计积分以及接触电阻的补偿。此外,可能还需要提到调试时的注意事项,如接触电阻的影响和宏定义的调整。 需要确保回答结构清晰,步骤明确,并且引用正确的内容作为支持。比如,在提到ISENSE时引用[2],在讨论接触电阻时引用[3],库仑计部分引用[1]。还要生成相关问题,比如电流检测的校准方法、接触电阻的影响、如何优化检测精度等。 最后,检查是否符合用户要求:使用中文,行内公式用$...$,独立公式用$$...$$,正确引用标记,结构清晰。例如,在解释库仑积分法时,可能需要公式:$$Q = \int I \, dt$$,这时需要用独立公式格式。 现在组织答案的结构: 1. 硬件检测机制:MT6305的ISENSE信号,电流检测电路,ADC转换。 2. 软件实现方法:驱动读取ADC值,转换为电流,库仑计积分。 3. 校准与补偿:接触电阻的影响,FG_METER_RESISTANCE宏调整。 4. 其他注意事项:温度、调试中的问题。 然后生成相关问题,如校准步骤、优化方法、接触电阻处理等。</think>在MTTK平台上,充电电流检测主要通过硬件电路结合软件算法实现,具体方法如下: --- ### 一、硬件检测机制 1. **MT6305电源管理芯片的电流检测信号(ISENSE)** MT6305芯片通过专用引脚`ISENSE`实时检测充电电流。硬件上采用电流采样电阻(例如$R_{\text{sense}}$),将电流转换为电压信号,再由ADC读取该电压值[^2]。 $$V_{\text{sense}} = I_{\text{charge}} \cdot R_{\text{sense}}$$ 其中,$R_{\text{sense}}$为已知阻值的采样电阻,$I_{\text{charge}}$为待测电流。 2. **ADC转换与校准** 电压信号通过ADC模块转换为数字量,软件通过以下公式计算实际电流: $$I_{\text{charge}} = \frac{V_{\text{sense}}}{R_{\text{sense}}}$$ 校准过程中需考虑ADC精度和电阻温漂,通常在驱动层进行线性补偿[^3]。 --- ### 二、软件实现方法 1. **驱动层读取电流值** 调用MTK提供的电池管理接口`battery_meter_get_charging_current()`,该函数直接读取ADC转换后的原始数据并转换为电流值(单位:mA)[^1]。 ```c signed int battery_meter_get_charging_current(void) { // 通过ADC读取ISENSE电压,并计算电流 return current_mA; } ``` 2. **库仑计积分法** 通过累计电流时间积分计算电量变化,公式为: $$Q = \int I_{\text{charge}} \, dt$$ 该值与开路电压结合,最终确定电池电量百分比[^1]。 --- ### 三、校准与补偿 1. **接触电阻补偿** 电池触点电阻(约$20\text{-}40\,\text{m}\Omega$)会影响大电流检测精度。在`mtk_imp_tracking()`函数中,通过宏定义`FG_METER_RESISTANCE`补偿该电阻值,确保开路电压计算准确。 2. **温度补偿** 温度变化可能影响采样电阻阻值,需在驱动中动态调整补偿系数。 --- ### 四、调试注意事项 - **大电流场景**:当充电电流超过$1.5\,\text{A}$时,需重点关注触点电阻和PCB走线阻抗的影响。 - **算法优化**:调整`FG_BATTERY_CONSERVATION`等参数,平衡检测精度与系统功耗。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值