zoukankan      html  css  js  c++  java
  • MTK平台下Battery驱动分析

    主要涉及代码:

    Kernel:

    kernel-3.10driverspowermediatek

    kernel-3.10driversmiscmediatekmachmt6580<project_name>power


    MTK Battery框架结构图


    通过上层通过读取创建一系列的设备节点获取电池相关的状态信息




    android电源管理系统
    /sys/class/power_supply/ac/online //AC 电源连接状态 交流电 即电源插座


    /sys/class/power_supply/usb/online //USB电源连接状态


    /sys/class/power_supply/battery/status //充电状态


    /sys/class/power_supply/battery/health //电池状态


    /sys/class/power_supply/battery/present //使用状态


    /sys/class/power_supply/battery/capacity //电池 level


    /sys/class/power_supply/battery/batt_vol //电池电压


    /sys/class/power_supply/battery/batt_temp //电池温度


    /sys/class/power_supply/battery/technology //电池技术


    代码框架:


    battery_common.c

    在Battery驱动模块中。battery_probe函数中会创建一些设备节点,而且执行一个线程bat_thread_kthread获取电池相关的数据信息


    battery_kthread_hrtimer_init();//检測电池插入/拔出

    kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread");


    在bat_thread_kthread线程中

    int bat_thread_kthread(void *x)
    {
    	ktime_t ktime = ktime_set(3, 0);	/* 10s, 10* 1000 ms */
    
    #ifdef BATTERY_CDP_WORKAROUND
    	if (is_usb_rdy() == KAL_FALSE) {
    		battery_log(BAT_LOG_CRTI, "CDP, block
    ");
    		wait_event(bat_thread_wq, (is_usb_rdy() == KAL_TRUE));
    		battery_log(BAT_LOG_CRTI, "CDP, free
    ");
    	} else{
    		battery_log(BAT_LOG_CRTI, "CDP, PASS
    ");
    	}
    #endif
    
    	/* Run on a process content */
    	while (1) {
    		mutex_lock(&bat_mutex);
    
    		if (((chargin_hw_init_done == KAL_TRUE) && (battery_suspended == KAL_FALSE)) || ((chargin_hw_init_done == KAL_TRUE) && (fg_wake_up_bat == KAL_TRUE)))
    			BAT_thread();
    
    		mutex_unlock(&bat_mutex);
    
    #ifdef FG_BAT_INT
    		if(fg_wake_up_bat==KAL_TRUE)
    		{
    			wake_unlock(&battery_fg_lock);
    			fg_wake_up_bat=KAL_FALSE;
    			battery_log(BAT_LOG_CRTI, "unlock battery_fg_lock 
    ");
    		}
    #endif //#ifdef FG_BAT_INT
    
    		battery_log(BAT_LOG_FULL, "wait event
    ");
    
    		wait_event(bat_thread_wq, (bat_thread_timeout == KAL_TRUE));
    
    		bat_thread_timeout = KAL_FALSE;
    		hrtimer_start(&battery_kthread_timer, ktime, HRTIMER_MODE_REL);
    		ktime = ktime_set(BAT_TASK_PERIOD, 0);	/* 10s, 10* 1000 ms 设置时间为10秒*/
    		if (chr_wake_up_bat == KAL_TRUE && g_smartbook_update != 1)	/* for charger plug in/ out */
    		{
    			#if defined(CONFIG_MTK_DUAL_INPUT_CHARGER_SUPPORT)
    			if (DISO_data.chr_get_diso_state) {
    				DISO_data.chr_get_diso_state = KAL_FALSE;
    				battery_charging_control(CHARGING_CMD_GET_DISO_STATE, &DISO_data);
    			}
    			#endif
    
    			g_smartbook_update = 0;
    			#if defined(CUST_CAPACITY_OCV2CV_TRANSFORM)
    			battery_meter_set_reset_soc(KAL_FALSE);
    			#endif
    			battery_meter_reset();
    			chr_wake_up_bat = KAL_FALSE;
    
    			battery_log(BAT_LOG_CRTI,
    					    "[BATTERY] Charger plug in/out, Call battery_meter_reset. (%d)
    ",
    					    BMT_status.UI_SOC);
    		}
    
    	}
    
    	return 0;
    
    在这个线程中,每隔10s会去调用函数BAT_Thread去获取电池数据

    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 第一次进该函数会进行一些初始化,如设置D0的值(初始电量,构建电池曲线等) table_init, oam_init*/
    		BMT_status.nPercent_ZCV = battery_meter_get_battery_nPercent_zcv();
    		battery_meter_initilized = KAL_TRUE;
    	}
    
    	mt_battery_charger_detect_check();//充电器型号。是否插入等方面的检測,
    	mt_battery_GetBatteryData();//核心函数获取电池数据
    	if (BMT_status.charger_exist == KAL_TRUE) {
    		check_battery_exist();
    	}
    	mt_battery_thermal_check();//电池温度检測以及开机mode
    	mt_battery_notify_check();//检測电池电压,电流等
    
    	if (BMT_status.charger_exist == KAL_TRUE) {
    		mt_battery_CheckBatteryStatus();//充电异常检測
    		mt_battery_charging_algorithm();//切换充电模式 Pre_CC->CC->CV->Full
    	}
    
    	mt_battery_update_status();//上报电池数据
    	mt_kpoc_power_off_check();
    }


    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 <= batt_cust_data.v_0percent_tracking) {
    		battery_log(BAT_LOG_CRTI,
    				    "battery voltage too low, use ZCV to init average data.
    ");
    		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.
    ");	
    	}
    	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)
    ",
    			    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_battery_percentage:

    kal_int32 battery_meter_get_battery_percentage(void)
    {
    //去掉了一些无效代码
    	if (bat_is_charger_exist() == KAL_FALSE)
    		fg_qmax_update_for_aging_flag = 1;
    
    
    	oam_run();//核心函数
    
    	return (100 - oam_d_5);
    
    }
    
    oam_run:

    void oam_run(void)
    {
    	int vol_bat = 0;
    	/* int vol_bat_hw_ocv=0; */
    	/* int d_hw_ocv=0; */
    	int charging_current = 0;
    	int ret = 0;
    	/* kal_uint32 now_time; */
    	struct timespec now_time;
    	kal_int32 delta_time = 0;
    
    	/* now_time = rtc_read_hw_time(); */
    	get_monotonic_boottime(&now_time);	
    
    	/* delta_time = now_time - last_oam_run_time; */
    	delta_time = now_time.tv_sec - last_oam_run_time.tv_sec;
    
    
    	last_oam_run_time = now_time;
    
    	/* Reconstruct table if temp changed; */
    	fgauge_construct_table_by_temp();
    
    
    	vol_bat = 15;		/* set avg times */
    	ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vol_bat);//首先获取电池Vbat端的电压
    
    	oam_i_1 = (((oam_v_ocv_1 - vol_bat) * 1000) * 10) / oam_r_1;	/* 0.1mA  计算电流oam_v_ocv_1为上一次測得的开路电压*/
    	oam_i_2 = (((oam_v_ocv_2 - vol_bat) * 1000) * 10) / oam_r_2;	/* 0.1mA */
    
    	oam_car_1 = (oam_i_1 * delta_time / 3600) + oam_car_1;	/* 0.1mAh 损失/获取 的电量 = i*t 即为放电深度,oam_car_1>0则为放电,反之则为充电*/
    	oam_car_2 = (oam_i_2 * delta_time / 3600) + oam_car_2;	/* 0.1mAh */
    
    	oam_d_1 = oam_d0 + (oam_car_1 * 100 / 10) / gFG_BATT_CAPACITY_aging;//<span style="font-family: Arial, Helvetica, sans-serif;">gFG_BATT_CAPACITY_aging为电池总的容量。在oam_init的时候赋值</span>
    
    	if (oam_d_1 < 0)
    		oam_d_1 = 0;
    	if (oam_d_1 > 100)
    		oam_d_1 = 100;
    
    	oam_d_2 = oam_d0 + (oam_car_2 * 100 / 10) / gFG_BATT_CAPACITY_aging;
    	if (oam_d_2 < 0)
    		oam_d_2 = 0;
    	if (oam_d_2 > 100)
    		oam_d_2 = 100;
    
    	oam_v_ocv_1 = vol_bat + mtk_imp_tracking(vol_bat, oam_i_2, 5);
    
    	oam_d_3 = fgauge_read_d_by_v(oam_v_ocv_1);//算出的开路电压查表获得放电深度
    	if (oam_d_3 < 0)
    		oam_d_3 = 0;
    	if (oam_d_3 > 100)
    		oam_d_3 = 100;
    
    	oam_r_1 = fgauge_read_r_bat_by_v(oam_v_ocv_1);
    
    	oam_v_ocv_2 = fgauge_read_v_by_d(oam_d_2);
    	oam_r_2 = fgauge_read_r_bat_by_v(oam_v_ocv_2);
    
    
    	oam_d_4 = oam_d_3;
    
    	gFG_columb = oam_car_2 / 10;	/* mAh */
    
    	if ((oam_i_1 < 0) || (oam_i_2 < 0))
    		gFG_Is_Charging = KAL_TRUE;
    	else
    		gFG_Is_Charging = KAL_FALSE;
    
    
    	d5_count_time = 60;
    
    	d5_count = d5_count + delta_time;
    	if (d5_count >= d5_count_time) {
    		if (gFG_Is_Charging == KAL_FALSE) {
    			if (oam_d_3 > oam_d_5) {//在放电状态下。oam_d_3大于上一次电量oam_d_5,则电池电量-1
    				oam_d_5 = oam_d_5 + 1;
    			} else {
    				if (oam_d_4 > oam_d_5) {
    					oam_d_5 = oam_d_5 + 1;
    				}
    			}
    		} else {
    			if (oam_d_5 > oam_d_3) {//<span style="font-family: Arial, Helvetica, sans-serif;">在充电状态下,oam_d_3小于上一次电量oam_d_5。则电池电量+1</span>
    
    				oam_d_5 = oam_d_5 - 1;
    			} else {
    				if (oam_d_4 < oam_d_5) {
    					oam_d_5 = oam_d_5 - 1;
    				}
    			}
    		}
    		d5_count = 0;
    		oam_d_3_pre = oam_d_3;
    		oam_d_4_pre = oam_d_4;
    	}
    
    }
    


    oam_run的整个的一个流程例如以下图所看到的:



    MTK採用的Fuel方案获取剩余电池电量

    首先通过adc读取电池 Vbat脚的电压值,然后通过这个闭路电压值查找 R—Table (cust_battery_meter_table.h )获得当前电压和温度下的电池内阻值。然后通过递归回溯的方法得到开路电压 OCV,然后通过这个OCV电压值查找 放电深度表获取当前的放电深度。从而算出剩余的电池电量。


    调试驱动时应注意的一些关键点

    1、电池曲线

    2、充电电流的一些设置(AC_CHARGER_CURRENT,NON_STD_AC_CHARGER_CURRENT,USB_CHARGER_CURRENT等),是否是高压电池HIGH_BATTERY_VOLTAGE_SUPPORT

    最高温度: MAX_CHARGE_TEMPERATURE
    最高电压: V_CHARGER_MAX

    截止满充电流大小:CHARGING_FULL_CURRENT

    充关机最大电池差异:CUST_POWERON_DELTA_CAPACITY_TOLRANCE(若小于这个值。则下一次开机用RTC里面存储的剩余电池电量值)

    关机电压:SYSTEM_OFF_VOLTAGE

    UI电量同步时间:SYNC_TO_REAL_TRACKING_TIME



  • 相关阅读:
    LeetCode 109 Convert Sorted List to Binary Search Tree
    LeetCode 108 Convert Sorted Array to Binary Search Tree
    LeetCode 107. Binary Tree Level Order Traversal II
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 103 Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 104. Maximum Depth of Binary Tree
    接口和多态性
    C# 编码规范
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7252435.html
Copyright © 2011-2022 走看看