mtk 电池驱动流程详解

充电算法,充9S停1S

电池温度高于50,充电器电压为>6.5V 停止充电,

充电电压最大值是6500mV 最小值是4400mV 3.4V为开机电压,电压大于3.4V才能开机

// 获得 BATSNS 引脚电压

bat_vol = battery_meter_get_battery_voltage(KAL_TRUE);

/* 获得 PMIC 的 ISENSE 引脚电压*/

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();

/* 通过获得当前 NTC 电压,查表并进行线性插值法,得到当前的温度值 */

temperature = battery_meter_get_battery_temperature();

/* 这里用来获取电池 NTC 的电压 */

temperatureV = battery_meter_get_tempV();

/* 获得 下拉电阻与 NTC 并并联的电压 */

temperatureR = battery_meter_get_tempR(temperatureV);

/* 获得充电电流 */

BMT_status.ICharging = mt_battery_average_method(&batteryCurrentBuffer[0],ICharging, &icharging_sum, batteryIndex);

// 获得 BATSNS 引脚电压

BMT_status.bat_vol = mt_battery_average_method(&batteryVoltageBuffer[0],bat_vol, &bat_sum, batteryIndex);

/* 通过获得当前 NTC 电压,查表并进行线性插值法,得到当前的温度值 */

BMT_status.temperature = mt_battery_average_method(&batteryTempBuffer[0],temperature, &temperature_sum, batteryIndex);

BMT_status.Vsense = Vsense;/* 获得 PMIC 的 ISENSE 引脚电压*/

BMT_status.charger_vol = charger_vol; /* 获得充电器电压 */

BMT_status.temperatureV = temperatureV;/* 这里用来获取电池 NTC 的电压 */

BMT_status.temperatureR = temperatureR;/* 获得 下拉电阻与 NTC 并并联的电压 */

BMT_status.SOC = SOC;

BMT_status.ZCV = ZCV;//开路电压

BMT_status.CURRENT_NOW = BMT_status.IBattery;//当前充电电流

/* bat_thread_wakeup() 每 10s 唤醒一次,唤醒时设置 bat_meter_timeout = KAL_TRUE

这时候更新电池电量百分比 */

/* oam 算法通过两种方式更新电压,去逼近真实的开路电压,最终查表获取近似真实的电量值百分比,方法 1,查表获得电池百分比,方法 2,库伦积分

以方法2获得的参数补偿方法 1 的值,具体方法见 oam_run()*/

// 6582 平台用的计量方法【在 Battery_Charging_Introduction_for_customer_V1.0.pdf】

// SW FG算法和HW FG算法。事实上MTK平台项目通常采用的是混合型算法。

/* SW FG的核心 在于 通过两种方式更新电压,去逼近真实开路电压 最终查表获取近似真实的电量值。

ocv1 被假定为开路电压

ocv2则是闭路电压,

D0 D1 D2 D3 D4 D5 代表不同的放电深度*/

/* 通过当前开路电压 - 负载时电压 = 当前电流 * 电池内阻

获得当前电流值 */

oam_i_1 = (((oam_v_ocv_1 - vol_bat) * 1000) * 10) / oam_r_1;/* 0.1mA */

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 */

oam_car_2 = (oam_i_2 * delta_time / 3600) + oam_car_2;/* 0.1mAh */

/* 这里使用的就是库伦积分法:

D1 = D0 + (-CAR)/Cmax

获得当前的电池容量百分比 */

oam_d_1 = oam_d0 + (oam_car_1 * 100 / 10) / gFG_BATT_CAPACITY_aging;

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;

//

// 整个程序的核心在这里, 他使用了两种方法更新电量:

1. 使用补偿过的闭路电压,查表获得电量 【返回给用户的】

2. 使用软件库伦积分,得到电量值 【用来校正的】

两个方法相对独立,但是在此处,方法 1 使用了 方法 2 的电流来进行较正!!!

//

mtk_imp_tracking() 对闭合电压补偿后,当作开路电压使用

通过对当前有负载的电池电压进行补偿,获得当前开路电压

///

// BC1.1 充电协议,主要用来区分是插入的是 USB 还是充电器,如果是 USB 只能提供 500ma 充电,

// 如果是充电器,则可以大电流充电

/********* Step initial ***************/

hw_bc11_init();

static void hw_bc11_init(void)

{

msleep(300);

Charger_Detect_Init();

//RG_BC11_BIAS_EN=1

upmu_set_rg_bc11_bias_en(0x1);

//RG_BC11_VSRC_EN[1:0]=00

upmu_set_rg_bc11_vsrc_en(0x0);

//RG_BC11_VREF_VTH = [1:0]=00

upmu_set_rg_bc11_vref_vth(0x0);

//RG_BC11_CMP_EN[1.0] = 00

upmu_set_rg_bc11_cmp_en(0x0);

//RG_BC11_IPU_EN[1.0] = 00

upmu_set_rg_bc11_ipu_en(0x0);

//RG_BC11_IPD_EN[1.0] = 00

upmu_set_rg_bc11_ipd_en(0x0);

//BC11_RST=1

upmu_set_rg_bc11_rst(0x1);

//BC11_BB_CTRL=1

upmu_set_rg_bc11_bb_ctrl(0x1);

//msleep(10);

mdelay(50);

/********* Step DCD ***************/

if(1 == hw_bc11_DCD())

{

/********* Step A1 ***************/

if(1 == hw_bc11_stepA1())

{

*(CHARGER_TYPE*)(data) = APPLE_2_1A_CHARGER;

battery_xlog_printk(BAT_LOG_CRTI, "step A1 : Apple 2.1A CHARGER!\r\n");

}

else

{

*(CHARGER_TYPE*)(data) = NONSTANDARD_CHARGER;

battery_xlog_printk(BAT_LOG_CRTI, "step A1 : Non STANDARD CHARGER!\r\n");

}

}

else

{

/********* Step A2 ***************/

if(1 == hw_bc11_stepA2())

{

/********* Step B2 ***************/

if(1 == hw_bc11_stepB2())

{

*(CHARGER_TYPE*)(data) = STANDARD_CHARGER;

battery_xlog_printk(BAT_LOG_CRTI, "step B2 : STANDARD CHARGER!\r\n");

}

else

{

*(CHARGER_TYPE*)(data) = CHARGING_HOST;

battery_xlog_printk(BAT_LOG_CRTI, "step B2 : Charging Host!\r\n");

}

}

else

{

*(CHARGER_TYPE*)(data) = STANDARD_HOST;

battery_xlog_printk(BAT_LOG_CRTI, "step A2 : Standard USB Host!\r\n");

}

}

/********* Finally setting *******************************/

hw_bc11_done();

static void hw_bc11_done(void)

{

//RG_BC11_VSRC_EN[1:0]=00

upmu_set_rg_bc11_vsrc_en(0x0);

//RG_BC11_VREF_VTH = [1:0]=0

upmu_set_rg_bc11_vref_vth(0x0);

//RG_BC11_CMP_EN[1.0] = 00

upmu_set_rg_bc11_cmp_en(0x0);

//RG_BC11_IPU_EN[1.0] = 00

upmu_set_rg_bc11_ipu_en(0x0);

//RG_BC11_IPD_EN[1.0] = 00

upmu_set_rg_bc11_ipd_en(0x0);

//RG_BC11_BIAS_EN=0

upmu_set_rg_bc11_bias_en(0x0);

Charger_Detect_Release();

void Charger_Detect_Release(void)

{

/* RG_USB20_BC11_SW_EN = 1'b0 */

USBPHY_CLR8(0x1a, 0x80);

udelay(1);

//4 14. turn off internal 48Mhz PLL.

usb_enable_clock(false);

printk("Charger_Detect_Release\n");

}

if(Enable_BATDRV_LOG == BAT_LOG_FULL)

{

battery_xlog_printk(BAT_LOG_FULL, "hw_bc11_done() \r\n");

hw_bc11_dump_register();

}

}

charging_type_det_done = KAL_TRUE;

g_charger_type = *(CHARGER_TYPE*)(data);

#endif

return status;

}

BMT_status.charger_type = CHR_Type_num;

}

#endif

mutex_unlock(&charger_type_mutex);

return BMT_status.charger_type;

}

/*

概念:

ZCV:开路电压

OCV: 开路电压

VC:闭路电压

CAR:库伦计

DOD: 放电深度,100-DOD 即电容容量

Cmax/Qmax: 电池容量

初始化init------------pre_cc mode/CC Mode topoff mode(CV mode)切换模式 Battery Full Battery hold

1 初始化安全 1。做充电器的保护, 1。做充电器的保护 2>, 1电池百分比总是显示100% 当充电器存在时,检查调用状态,

充电器 2。如果(1)失败如果充电器电压为>6.5V 2。如果(1)失败如果充电器电压为>6.5V 注意:当充电,电池百分比仍然是100%。 1。如果呼叫活动,Vbat>4.05V停止充电注意:避免热的问题,

2 检查V_bat电压 如果电池温度为>60c,则停止充电 如果电池温度为>60C,则停止充电

是否大于3.4V决定 3.如果(2)通过,做充电算法:充电9秒,3.如果(2)通过,做充电算法。:充电10S

进入CC模式,停止充电1秒。

检查UI SOC是否等于100

决定进入电池满电状态

相关文件关系:

Battery_common.c (s:\i841\mediatek\kernel\drivers\power) // 充电逻辑文件

Charging_hw_pmic.c (s:\i841\mediatek\platform\mt6582\kernel\drivers\power) // 具体的充电芯片,相关电池参数检测

Linear_charging.c (s:\i841\mediatek\kernel\drivers\power) // 充电状态控制,内部 PMIC

Switch_charging.c (s:\i841\mediatek\kernel\drivers\power) // 充电状态控制,外部 Charge IC

//

// 【核心充电线程】

kthread_run(bat_thread_kthread, NULL, "bat_thread_kthread");

// 设置定时器超时时间

ktime_t ktime = ktime_set(3, 0); // 10s, 10* 1000 ms

while (1) {

// 这个是核心算法

BAT_thread();

///

// 0. 第一次执行时运行,获得开机显示电量,初始化电池算法 oam 参数

// 开机时就会运行,只会运行一次,对电池算法 oam 方案进行初始化, 并获得开机显示电量百分比

if(battery_meter_initilized == KAL_FALSE)

{

// 进行的一系列的电池参数与温度对应关系的表格的初始化,并根据电池当前电压,hw ocv 取一个较合适值,

// 取合适值对应容量,再与 RTC 保存容量比较,选择一个合适量,为开机电池容量,最后初始化 oam 算法参数

battery_meter_initial()

MTK_MULTI_BAT_PROFILE_SUPPORT

//电池曲线电池容量和在这里调用

fgauge_get_profile_id();

//开adc通道取电压值 时间单位是us

IMM_GetOneChannelValue_Cali(BATTERY_ID_CHANNEL_NUM, &id_volt)

//开adc通道读取通过adc通道把模拟信号转换成数字信号

return IMM_auxadc_GetOneChannelValue_Cali(Channel, voltage)

IMM_auxadc_GetOneChannelValue(Channel, data, &rawvalue);/* HAL API */

//使能一个时钟信号

clk_prepare_enable(clk_auxadc);

/* step1 check con2 if auxadc is busy step1如果auxadc忙,就检查con2*/

while (AUXADC_DRV_ReadReg16((u16 *)AUXADC_CON2) & 0x01)

mdelay(1);

idle_count++;

if (idle_count > 30) {//当大于30us时

/* wait for idle time out/* wait for idle time out 等待空闲时间*/

pr_err("[adc_api]: wait for auxadc idle time out\n");

/* step2 clear bit 清除位*/

if (adc_auto_set == 0) {

/* clear bit */

AUXADC_DRV_ClearBits16((u16 *)AUXADC_CON1, (1 << dwChannel));

}

/* step3 read channel and make sure old ready bit ==0

/* step3读取通道,确保老的就绪位==0*/

while (AUXADC_DRV_ReadReg16(AUXADC_DAT0 + dwChannel * 0x04) & (1 << 12)) {

pr_debug("[adc_api]: wait for channel[%d] ready bit clear\n", dwChannel);

mdelay(1);

data_ready_count++;

if (data_ready_count > 30) {

/* wait for idle time out等待空闲时间*/

pr_err("[adc_api]: wait for channel[%d] ready bit clear time out\n",

dwChannel);

/* step4 set bit to trigger sample

4 设置位触发样本 */

if (adc_auto_set == 0)

AUXADC_DRV_SetBits16((u16 *)AUXADC_CON1, (1 << dwChannel));

/* step5 read channel and make sure ready bit ==1

5 读取通道并确保准备位==1*/

udelay(25);/* we must dealay here for hw sample cahnnel data 我们必须在此处理cahnnel样本数据*/

while (0 == (AUXADC_DRV_ReadReg16(AUXADC_DAT0 + dwChannel * 0x04) & (1 << 12))) {

pr_debug("[adc_api]: wait for channel[%d] ready bit ==1\n", dwChannel);

mdelay(1);

data_ready_count++;

if (data_ready_count > 30) {

/* wait for idle time out 等待空闲时间*/

pr_err("[adc_api]: wait for channel[%d] data ready time out\n", dwChannel);

mutex_unlock(&mutex_get_cali_value);

return -3;

}

}

/* step6 read data 读取数据*/

channel[dwChannel] = AUXADC_DRV_ReadReg16(AUXADC_DAT0 + dwChannel * 0x04) & 0x0FFF;

//得到通过的数据

mt_auxadc_get_cali_data(channel[dwChannel], data, true);

SOC_BY_AUXADC

//电池曲线的表的数据调用

table_init();

//合电池曲线两个表的结构体,电池曲线 一个是百分比和电压 一个是电阻和电压

struct battery_profile_struct *profile_p;

struct r_profile_struct *profile_p_r_table;

//获取当前温度

int temperature = force_get_tbat(KAL_FALSE);

/* Re-constructure r-table profile according to current temperature */

//根据当前温度重新构造r-table剖面

profile_p_r_table = fgauge_get_profile_r_table(batt_meter_cust_data.temperature_t);

struct r_profile_struct *fgauge_get_profile_r_table(unsigned int temperature)

switch (temperature) {

case batt_meter_cust_data.temperature_t0:

return &r_profile_t0[g_fg_battery_id][0];

/*break;*/

case batt_meter_cust_data.temperature_t1:

return &r_profile_t1[g_fg_battery_id][0];

/*break;*/

case batt_meter_cust_data.temperature_t2:

return &r_profile_t2[g_fg_battery_id][0];

/*break;*/

case batt_meter_cust_data.temperature_t3:

return &r_profile_t3[g_fg_battery_id][0];

/*break;*/

case batt_meter_cust_data.temperature_t:

return &r_profile_temperature[0];

/*break;*/

default:

return NULL;

/*break;*/

}

if (profile_p_r_table == NULL)

bm_print(BM_LOG_CRTI,

"[FGADC] fgauge_get_profile_r_table : create table fail !\r\n");

//根据当前温度重新构造r-table剖面

fgauge_construct_r_table_profile(temperature, profile_p_r_table);

SOC_BY_HW_FG

//电池容量的初始化

fgauge_initialization();

/* 1. HW initialization HW初始化 */

ret = battery_meter_ctrl(BATTERY_METER_CMD_HW_FG_INIT, NULL);

/* 2. SW algorithm initialization SW算法初始化 */

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);//电池控制函数ocv开路电压

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);//电流

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);

gFG_temp = force_get_tbat(KAL_FALSE);//获取温度

gFG_capacity = fgauge_read_capacity(0);//读取容量

gFG_capacity_by_c_init = gFG_capacity;//初始化容量

gFG_capacity_by_c = gFG_capacity;

gFG_capacity_by_v = gFG_capacity;

gFG_DOD0 = 100 - gFG_capacity;//放电深度的算法

bm_print(BM_LOG_CRTI, "[fgauge_initialization] gFG_DOD0 =%d %d\n", gFG_DOD0, gFG_capacity);

gFG_BATT_CAPACITY = fgauge_get_Q_max(gFG_temp);//获取最大容量

gFG_BATT_CAPACITY_init_high_current = fgauge_get_Q_max_high_current(gFG_temp);//初始化最大容量的高电流值

gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(gFG_temp);//获取最大容量

ret = battery_meter_ctrl(BATTERY_METER_CMD_DUMP_REGISTER, NULL);//控制函数控制

bm_print(BM_LOG_CRTI,

"[fgauge_initialization] Done HW_OCV:%d FG_Current:%d FG_CAR:%d tmp=%d capacity=%d Qmax=%d\n",

gFG_voltage, gFG_current, gFG_columb, gFG_temp, gFG_capacity, gFG_BATT_CAPACITY);

//电池容量算法运行的初始化

fgauge_algo_run_init();

#ifdef INIT_SOC_BY_SW_SOC //如没插充电器或者处于关机状态 则停止为vbat测量充电

kal_bool charging_enable = KAL_FALSE; //没插充电器

#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) && !defined(SWCHR_POWER_PATH)//处于关机

if (get_boot_mode() != LOW_POWER_OFF_CHARGING_BOOT)//

#endif

/*stop charging for vbat measurement 停止为vbat测量充电*/

battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);

msleep(50);

#endif

/* 1. Get Raw Data 得到原始数据*/

gFG_voltage = battery_meter_get_battery_voltage(KAL_TRUE);//获取原始数据的电压

gFG_voltage_init = gFG_voltage;//电压赋值

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);//电流控制

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &gFG_Is_Charging);//充电控制

//以下是电压的一些算法

gFG_voltage = gFG_voltage + fgauge_compensate_battery_voltage_recursion(gFG_voltage, 5);/* mV */

gFG_voltage = gFG_voltage + batt_meter_cust_data.ocv_board_compesate;

bm_print(BM_LOG_CRTI, "[FGADC] SWOCV : %d,%d,%d,%d,%d,%d\n",

gFG_voltage_init, gFG_voltage, gFG_current, gFG_Is_Charging, gFG_resistance_bat,

gFG_compensate_value);//初始化的电压,电压,充电电流 电阻 抵消值

#ifdef INIT_SOC_BY_SW_SOC

charging_enable = KAL_TRUE;

battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable); //如果有插充电器,开始充电

#endif

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CAR, &gFG_columb);

/* 1.1 Average FG_voltage FG的平均电压*/

for (i = 0; i < batt_meter_cust_data.fg_vbat_average_size; i++)

FGvbatVoltageBuffer[i] = gFG_voltage;

FGbatteryVoltageSum = gFG_voltage * batt_meter_cust_data.fg_vbat_average_size;

gFG_voltage_AVG = gFG_voltage;

#ifdef Q_MAX_BY_CURRENT

/* 1.2 Average FG_currentFG平均电流 */

for (i = 0; i < FG_CURRENT_AVERAGE_SIZE; i++)

FGCurrentBuffer[i] = gFG_current;

FGCurrentSum = gFG_current * FG_CURRENT_AVERAGE_SIZE;

gFG_current_AVG = gFG_current;

#endif

/* 2. Calculate battery capacity by VBAT 用VBAT计算电池容量*/

gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);

gFG_capacity_by_v_init = gFG_capacity_by_v;

/* 3. Calculate battery capacity by Coulomb Counter 用库仑计数器计算电池容量 */

gFG_capacity_by_c = fgauge_read_capacity(1);

/* 4. update DOD0 更新DOD0 */

dod_init();

gFG_current_auto_detect_R_fg_count = 0;

for (i = 0; i < 10; i++) {

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);

gFG_current_auto_detect_R_fg_total += gFG_current;

gFG_current_auto_detect_R_fg_count++;

}

/* double check 再次确认*/

if (gFG_current_auto_detect_R_fg_total <= 0) {

bm_print(BM_LOG_CRTI, "gFG_current_auto_detect_R_fg_total=0, need double check\n");

gFG_current_auto_detect_R_fg_count = 0;

for (i = 0; i < 10; i++) {

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &gFG_current);

gFG_current_auto_detect_R_fg_total += gFG_current;

gFG_current_auto_detect_R_fg_count++;

}

}

//自动检测电池曲线表中的电阻和电压 结果值

gFG_current_auto_detect_R_fg_result =

gFG_current_auto_detect_R_fg_total / gFG_current_auto_detect_R_fg_count;

#if !defined(DISABLE_RFG_EXIST_CHECK)

if (gFG_current_auto_detect_R_fg_result <= batt_meter_cust_data.current_detect_r_fg) {

g_auxadc_solution = 1;

bm_print(BM_LOG_CRTI,

"[FGADC] Detect NO Rfg, use AUXADC report. (%d=%d/%d)(%d)\r\n",

gFG_current_auto_detect_R_fg_result, gFG_current_auto_detect_R_fg_total,

gFG_current_auto_detect_R_fg_count, g_auxadc_solution);

} else {

if (g_auxadc_solution == 0) {

g_auxadc_solution = 0;

bm_print(BM_LOG_CRTI,

"[FGADC] Detect Rfg, use FG report. (%d=%d/%d)(%d)\r\n",

gFG_current_auto_detect_R_fg_result,

gFG_current_auto_detect_R_fg_total,

gFG_current_auto_detect_R_fg_count, g_auxadc_solution);

} else {

bm_print(BM_LOG_CRTI,

"[FGADC] Detect Rfg, but use AUXADC report. due to g_auxadc_solution=%d \r\n",

g_auxadc_solution);

}

}

#endif

/* 5. Logging 记录*/

bm_print(BM_LOG_CRTI,

"[FGADC] %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",

gFG_Is_Charging, gFG_current, gFG_columb, gFG_voltage, gFG_capacity_by_v,

gFG_capacity_by_c, gFG_capacity_by_c_init, gFG_BATT_CAPACITY,

gFG_BATT_CAPACITY_aging, gFG_compensate_value, gFG_ori_voltage,

batt_meter_cust_data.ocv_board_compesate, batt_meter_cust_data.r_fg_board_slope,

gFG_voltage_init, batt_meter_cust_data.minerroroffset, gFG_DOD0, gFG_DOD1,

batt_meter_cust_data.car_tune_value, batt_meter_cust_data.aging_tuning_value);

update_fg_dbg_tool_value();

g_fg_dbg_bat_volt = gFG_voltage_init;

if (gFG_Is_Charging == KAL_TRUE)

g_fg_dbg_bat_current = 1 - gFG_current - 1;

else

g_fg_dbg_bat_current = gFG_current;

g_fg_dbg_bat_zcv = gFG_voltage;

g_fg_dbg_bat_temp = gFG_temp;

g_fg_dbg_bat_r = gFG_resistance_bat;

g_fg_dbg_bat_car = gFG_columb;

g_fg_dbg_bat_qmax = gFG_BATT_CAPACITY_aging;

g_fg_dbg_d0 = gFG_DOD0;

g_fg_dbg_d1 = gFG_DOD1;

g_fg_dbg_percentage = bat_get_ui_percentage();

g_fg_dbg_percentage_fg = gFG_capacity_by_c;

g_fg_dbg_percentage_voltmode = gfg_percent_check_point;

SOC_BY_SW_FG

table_init();//电池曲线的表的数据调用

oam_init();//oam算法的初始化

int ret = 0;

signed int vbat_capacity = 0;

kal_bool charging_enable = KAL_FALSE;

/*stop charging for vbat measurement 停止为vbat测量充电*/

battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable);

msleep(50);

g_booting_vbat = 5;/* set avg times 设置avg时间*/

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_OCV, &gFG_voltage);

ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &g_booting_vbat);

gFG_capacity_by_v = fgauge_read_capacity_by_v(gFG_voltage);

vbat_capacity = fgauge_read_capacity_by_v(g_booting_vbat);

if (bat_is_charger_exist() == KAL_TRUE) {

bm_print(BM_LOG_CRTI, "[oam_init_inf] gFG_capacity_by_v=%d, vbat_capacity=%d,\n",

gFG_capacity_by_v, vbat_capacity);

/* to avoid plug in cable without battery, then plug in battery to make hw soc = 100% */

//为了避免没有电池的情况下插入电缆,然后插入电池使hw soc = 100%

/* if the difference bwtween ZCV and vbat is too large, using vbat instead ZCV */

//如果ZCV和vbat之间的差异太大,用vbat代替ZCV

if (((gFG_capacity_by_v == 100)

&& (vbat_capacity < batt_meter_cust_data.cust_poweron_max_vbat_tolrance))

|| (abs(gFG_capacity_by_v - vbat_capacity) >

batt_meter_cust_data.cust_poweron_delta_vbat_tolrance)) {

bm_print(BM_LOG_CRTI,

"[oam_init] fg_vbat=(%d), vbat=(%d), set fg_vat as vat\n",

gFG_voltage, g_booting_vbat);

gFG_voltage = g_booting_vbat;

gFG_capacity_by_v = vbat_capacity;

}

}

gFG_capacity_by_v_init = gFG_capacity_by_v;

dod_init();

gFG_BATT_CAPACITY_aging = fgauge_get_Q_max(force_get_tbat(KAL_FALSE));

/* oam_v_ocv_1 = gFG_voltage; */

/* oam_v_ocv_2 = gFG_voltage; */

oam_v_ocv_init = fgauge_read_v_by_d(gFG_DOD0);

oam_v_ocv_2 = oam_v_ocv_1 = oam_v_ocv_init;

g_vol_bat_hw_ocv = gFG_voltage;

/* vbat = 5; //set avg times */

/* ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_SENSE, &vbat); */

/* oam_r_1 = fgauge_read_r_bat_by_v(vbat); */

oam_r_1 = fgauge_read_r_bat_by_v(gFG_voltage);

oam_r_2 = oam_r_1;

oam_d0 = gFG_DOD0;

oam_d_5 = oam_d0;

oam_i_ori = gFG_current;

g_d_hw_ocv = oam_d0;

if (oam_init_i == 0) {

bm_print(BM_LOG_CRTI,

"[oam_init] oam_v_ocv_1,oam_v_ocv_2,oam_r_1,oam_r_2,oam_d0,oam_i_ori\n");

oam_init_i = 1;

}

bm_print(BM_LOG_CRTI, "[oam_init] %d,%d,%d,%d,%d,%d\n",

oam_v_ocv_1, oam_v_ocv_2, oam_r_1, oam_r_2, oam_d0, oam_i_ori);

bm_print(BM_LOG_CRTI, "[oam_init_inf] hw_OCV, hw_D0, RTC, D0, oam_OCV_init, tbat\n");

bm_print(BM_LOG_CRTI,

"[oam_run_inf] oam_OCV1, oam_OCV2, vbat, I1, I2, R1, R2, Car1, Car2,qmax, tbat\n");

bm_print(BM_LOG_CRTI, "[oam_result_inf] D1, D2, D3, D4, D5, UI_SOC\n");

bm_print(BM_LOG_CRTI, "[oam_init_inf] %d, %d, %d, %d, %d, %d\n",

gFG_voltage, (100 - fgauge_read_capacity_by_v(gFG_voltage)), g_rtc_fg_soc,

gFG_DOD0, oam_v_ocv_init, force_get_tbat(KAL_FALSE));

charging_enable = KAL_TRUE;

battery_charging_control(CHARGING_CMD_ENABLE, &charging_enable)

}

// 1. 判断是插入的是否充电器还是电脑 USB,看能不能进行充电

// 如果连接的 USB 线为 USB 充电线,或者电脑 USB 线,则打开 USB,

// 这里会通过 BC1.1 来判断是电脑 USB 还是 USB 充电器,来决定充电电流

// 否则连接的不是充电线或者 USB 作为一个从设备使用,要断开 USB?

mt_battery_charger_detect_check();

// 1. 判断是插入的是否充电器还是电脑 USB,看能不能进行充电

// 如果连接的 USB 线为 USB 充电线,或者电脑 USB 线,则打开 USB,

// 这里会通过 BC1.1 来判断是电脑 USB 还是 USB 充电器,来决定充电电流

// 否则连接的不是充电线或者 USB 作为一个从设备使用,要断开 USB?

#ifdef CONFIG_MTK_BQ25896_SUPPORT

/*New low power feature of MT6531: disable charger CLK without CHARIN.

* MT6351 API abstracted in charging_hw_bw25896.c. Any charger with MT6351 needs to set this.

* Compile option is not limited to CONFIG_MTK_BQ25896_SUPPORT.

* PowerDown = 0

新的低功耗功能的MT6531:禁用充电器CLK没有CHARIN。

* MT6351 API抽象在charging_hw_bw25896.c。任何MT6351的充电器都需要设置这个。

编译选项不限于CONFIG_MTK_BQ25896_SUPPORT。

* PowerDown = 0

*/

unsigned int pwr;

#endif

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)) {

//打开 USB

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

#ifdef CONFIG_MTK_BQ25896_SUPPORT

/*New low power feature of MT6531: disable charger CLK without CHARIN.

* MT6351 API abstracted in charging_hw_bw25896.c. Any charger with MT6351 needs to set this.

* Compile option is not limited to CONFIG_MTK_BQ25896_SUPPORT.

* PowerDown = 0

新的低功耗功能的MT6531:禁用充电器CLK没有CHARIN。

* MT6351 API抽象在charging_hw_bw25896.c。任何MT6351的充电器都需要设置这个。

编译选项不限于CONFIG_MTK_BQ25896_SUPPORT。

* PowerDown = 0

*/

pwr = 0;

battery_charging_control(CHARGING_CMD_SET_CHRIND_CK_PDN, &pwr);

#endif

battery_log(BAT_LOG_FULL, "[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();

#ifdef CONFIG_MTK_BQ25896_SUPPORT

/*New low power feature of MT6531: disable charger CLK without CHARIN.

* MT6351 API abstracted in charging_hw_bw25896.c. Any charger with MT6351 needs to set this.

* Compile option is not limited to CONFIG_MTK_BQ25896_SUPPORT.

* PowerDown = 1

新的低功耗功能的MT6531:禁用充电器CLK没有CHARIN。

* MT6351 API抽象在charging_hw_bw25896.c。任何MT6351的充电器都需要设置这个。

编译选项不限于CONFIG_MTK_BQ25896_SUPPORT。

*关机= 1

*/

pwr = 1;

battery_charging_control(CHARGING_CMD_SET_CHRIND_CK_PDN, &pwr);

#endif

///

// 2. 通过具体的充电芯片来获得电池信息,充电信息, 获得电池电量百分比

// 通过 oam 算法,获得电量百分比

mt_battery_GetBatteryData();

//获得电池信息

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();//获取充电温度V

temperatureR = battery_meter_get_tempR(temperatureV);//获取充电温度R

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.\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;

BMT_status.CURRENT_NOW = BMT_status.IBattery;

if (BMT_status.charger_exist == KAL_FALSE) {

signed int soc_tmp = BMT_status.SOC;

if (soc_tmp > previous_SOC && previous_SOC >= 0)

BMT_status.SOC = previous_SOC;

}

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,%d),AvgI=(%d,%d),VChr=%d,AvgT=(%d,%d),SOC=(%d,%d),UI_SOC=%d,ZCV=%d bcct:%d:%d I:%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.UI_SOC, BMT_status.ZCV,

g_bcct_flag, get_usb_current_unlimited(), get_bat_charging_current_level());

// 3. 电池温度保护

// 电池温度检查,如果温度超过 60 度,关机重启

mt_battery_thermal_check();

BMT_status.temperature = battery_cmd_thermal_test_mode_value;//获取当前电池温度

if (BMT_status.temperature >= 60) {// 电池温度检查,如果温度超过 60 度,关机重启

#if defined(CONFIG_MTK_JEITA_STANDARD_SUPPORT)

/* ignore default rule 忽略默认规则*/

#else

if (BMT_status.temperature >= 60) {// 电池温度检查,如果温度超过 60 度,关机重启

#if defined(CONFIG_POWER_EXT)

battery_log(BAT_LOG_CRTI,

"[BATTERY] CONFIG_POWER_EXT, no update battery update power down.\n");

#else

{

if ((g_platform_boot_mode == META_BOOT)

|| (g_platform_boot_mode == ADVMETA_BOOT)

|| (g_platform_boot_mode == ATE_FACTORY_BOOT)) {//绕过温度检查

battery_log(BAT_LOG_FULL,

"[BATTERY] boot mode = %d, bypass temperature check\n",

g_platform_boot_mode);

} else {

struct battery_data *bat_data = &battery_main;

struct power_supply *bat_psy = bat_data->psy;

battery_log(BAT_LOG_CRTI,

"[Battery] Tbat(%d)>=60, system need power down.\n",

BMT_status.temperature);

bat_data->BAT_CAPACITY = 0;

power_supply_changed(bat_psy);

if (BMT_status.charger_exist == KAL_TRUE) {

/* can not power down due to charger exist, so need reset system

忽略由于充电器的存在而导致的断电,因此需要复位 */

orderly_reboot();

}

/* avoid SW no feedback 避免软件无反馈*/

orderly_poweroff(true);

/

// 4. 电池状态检查

// 对电池状态进行检查,如果有问题,则会调用 printk() 进行打印

mt_battery_notify_check();

g_BatteryNotifyCode = 0x0000;

if (g_BN_TestMode == 0x0000) {/* for normal case 对于正常情况*/

battery_log(BAT_LOG_FULL, "[BATTERY] mt_battery_notify_check\n");

mt_battery_notify_VCharger_check();

mt_battery_notify_VBatTemp_check();

mt_battery_notify_ICharging_check();

mt_battery_notify_VBat_check();

mt_battery_notify_TotalChargingTime_check();

} else {/* for UI test */

// 对电池状态进行检查,如果有问题,则会调用 printk() 进行打印

mt_battery_notify_UI_test();

}

//

// 5. 调用具本的硬件相关函数进行充电,充电时会进行 CC/CV 之类的状态机切换就是在这里进行的

// 如果存在充电线,则调用具体充电芯片相关的函数进行充电

if( BMT_status.charger_exist == KAL_TRUE )

{

// 检查电池状态,设置到 BMT_status.bat_charging_state 中

mt_battery_CheckBatteryStatus();

// 检查电池状态,设置到 BMT_status.bat_charging_state 中

static void mt_battery_CheckBatteryStatus(void)

{

battery_log(BAT_LOG_FULL, "[mt_battery_CheckBatteryStatus] cmd_discharging=(%d)\n",

cmd_discharging);

if (cmd_discharging == 1) {//检查到没有插充电器

battery_log(BAT_LOG_CRTI,

"[mt_battery_CheckBatteryStatus] cmd_discharging=(%d)\n",

cmd_discharging);

BMT_status.bat_charging_state = CHR_ERROR;

battery_charging_control(CHARGING_CMD_SET_ERROR_STATE, &cmd_discharging);

return;

} else if (cmd_discharging == 0) {//检查到有插充电器

BMT_status.bat_charging_state = CHR_PRE;

battery_charging_control(CHARGING_CMD_SET_ERROR_STATE, &cmd_discharging);

cmd_discharging = -1;

}

if (mt_battery_CheckBatteryTemp() != PMU_STATUS_OK) {//检查电池温度

BMT_status.bat_charging_state = CHR_ERROR;

return;

}

if (mt_battery_CheckChargerVoltage() != PMU_STATUS_OK) {//检查电压

BMT_status.bat_charging_state = CHR_ERROR;

return;

}

#if defined(STOP_CHARGING_IN_TAKLING)

if (mt_battery_CheckCallState() != PMU_STATUS_OK) {//检查调用状态

BMT_status.bat_charging_state = CHR_HOLD;

return;

}

#endif

if (mt_battery_CheckChargingTime() != PMU_STATUS_OK) {//检查充电时间

BMT_status.bat_charging_state = CHR_ERROR;

return;

}

// 充电策略,这里有两个文件: switch_charging.c 和 linear_charging.c

// 他们的关系是,如果定义了任一外部充电 IC,则选择 switch_charging.c 的函数,否则就是 linear_charging.c 的函数

// 这里就是调用具体的芯片的充电相关函数进行充电

mt_battery_charging_algorithm(); /

mtk 电池曲线_mtk 电池驱动流程详解相关推荐

  1. linux中流设备_[快速上手Linux设备驱动]之块设备驱动流程详解一

    [快速上手Linux设备驱动]之块设备驱动流程详解一 walfred已经在[快速上手Linux设备驱动]之我看字符设备驱动一 文中详细讲解了linux下字符设备驱动,并紧接着用四篇文章描述了Linux ...

  2. 杂志订阅管理系统c++_电池管理系统BMS功能安全开发流程详解

    点击上面 "电动知家"可以订阅哦! BMS功能安全开发流程详解 BMS和ISO26262 - BMS & ISO26262简介 BMS即Battery Management ...

  3. 分享 | 日置3561电池测试仪调零/自校准详解教程

    日置电池测试仪3561产品特点: ●  高精度:电阻±0.5% rdg. ±5dgt., 电压±0.01% rdg. ±3dgt. ●  高分辨率:电阻0.01mΩ(300mΩ量程); 电压0.1mV ...

  4. 【正点原子Linux连载】第三十二章 U-Boot启动流程详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  5. 基于spark mllib_Spark高级分析指南 | 机器学习和分析流程详解(下)

    - 点击上方"中国统计网"订阅我吧!- 我们在Spark高级分析指南 | 机器学习和分析流程详解(上)快速介绍了一下不同的高级分析应用和用力,从推荐到回归.但这只是实际高级分析过程 ...

  6. U-Boot启动流程详解

    参考:U-Boot顶层目录链接脚本文件(u-boot.lds)介绍 作者:一只青木呀 发布时间: 2020-10-23 13:52:23 网址:https://blog.csdn.net/weixin ...

  7. Springboot启动流程详解

    SpringMVC请求流程详解 SpringMVC框架是一个基于请求驱动的Web框架,并且使用了'前端控制器'模型来进行设计,再根据'请求映射规则'分发给相应的页面控制器进行处理. (一)整体流程 每 ...

  8. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  9. linux设备驱动总结,《Linux设备驱动开发详解(第3版)》海量更新总结

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 2015.2.26 几乎完成初稿. [F]是修正或升级:[N]是新增知识点:[D]是删除的内容 第1章 <Linux ...

最新文章

  1. Python循环中的变量作用域的灵异现象
  2. Spark2.1.0之内置RPC框架
  3. MYSQL中TIMESTAMP类型的默认值
  4. optee3.8 qemu_v8的环境搭建篇
  5. Java IO流之内存流
  6. JZOJ 3600. 【CQOI2014】通配符匹配
  7. 端口号被占用时,查找占用该端口号的进程并释放端口号
  8. keycloak集群化的思考
  9. 简单工厂和 工厂设计模式--抽象工厂模式--Java实现
  10. ip netns的使用及network namespace 简介
  11. hdu 5120(求两个圆环相交的面积 2014北京现场赛 I题)
  12. 微信小程序选项卡底线转换滑动动画
  13. pycharm显示中间变量
  14. jenkins如何清缓存,jenkins在结账前清除存储库并强制克隆与清理
  15. java.lang.NoSuchMethodError错误
  16. 公司总经理KPI考核指标
  17. Clover 驱动文件夹_黑苹果(clover文件夹中各个文件的主要功能)
  18. 局部动态地图(LDM)的介绍
  19. 1. PYNQ在ZCU102上的移植【PYNQ】
  20. 市场调研-全球与中国沉鱼饲料市场现状及未来发展趋势

热门文章

  1. 失眠听什么音乐能快速入睡,适合入睡困难听的音乐推荐
  2. 如何让孩子爱上阅读?
  3. 经销商回收旧iPhone 换新机还可获得补贴
  4. PrintWriter和OutPutStream
  5. 你还不会SQL Server数据库吗?一篇让你学会SQL数据库基础(从零开始超详解)
  6. WordPress上传图片提示:服务器无法处理图像
  7. 常用的IDEA 与 eclipse快捷键
  8. 使用SVM对分泌效应蛋白数据集进行分类预测
  9. Android自定义View的四种方式
  10. 19年的个人成长规划。