https://blog.youkuaiyun.com/mcgrady_tracy/article/details/52818100
NTC 那是當作電池的溫度偵測用, 通常 NTC 是要包裝在電池內部。但是有些電池沒有 NTC,所以就需要外掛 NTC 放置於電池附近去偵測電池溫度。
如果直接使用外部電源而且沒有充電功能,基本上 NTC 是可以拿掉。(但是軟件人員要會改 MTK 的程序代碼,否則會開不機或是其他問題出現)
手机里面电池通常有4个引脚,即电池的+、-极,ID引脚、NTC引脚。
ID引脚用来识别电池的类型,例如是锂电池还是镍氢电池,不过现在手机上基本用的都是锂电池了。
NTC引脚主要用来测量电池温度的,还可以用来检测手机有没有接上电池
PL启动流程:
main
struct bldr_command_handler handler;
->bldr_pre_process //main.c
->platform_pre_init //platform.c
->mtk_timer_init(); //timer.c
->mt_pll_init(); //pll.c
->mtk_uart_init(UART_SRC_CLK_FRQ, CFG_LOG_BAUDRATE); //uart.c CFG_LOG_BAUDRATE :=921600 in default.mak
->mt_gpio_init(); //gpio.c
->i2c_hw_init(); //i2c.c
->pmic_init //pmic.c、pmic_mt6392.c
->pmic_DetectVbatDrop();
->U32 just_rst=0;
->pmic_read_interface( MT6350_PMIC_JUST_PWRKEY_RST_ADDR, (&just_rst), MT6350_PMIC_JUST_PWRKEY_RST_MASK, MT6350_PMIC_JUST_PWRKEY_RST_SHIFT );
->pmic_config_interface(MT6350_PMIC_CLR_JUST_RST_ADDR, 1, MT6350_PMIC_CLR_JUST_RST_MASK, MT6350_PMIC_CLR_JUST_RST_SHIFT);
->if(just_rst) //用这个来判断是normal,还是force reset
vbat_status = PMIC_VBAT_DROP; //force reset
->else
vbat_status = PMIC_VBAT_NOT_DROP; //normal
->hw_check_battery //pmic.c mt8321 only
->FCHR_ENB init //add for FCHR mt8321 only
->g_boot_mode = NORMAL_BOOT; //初始值
->platform_init
->rtc_init(); //rtc.c mt8168 only
->pmic_init_setting(); //pmic_initial_setting.c mt8168 only
->pl_battery_init(false); //battery.c mt8168 only
->fuel_gauge_init(); //battery.c mt8168 only
->if (hw_check_battery() == 1) //charging_bat.c mt8168 only battery exists
->pl_check_bat_protect_status() //charging_bat.c mt8168 only
->while (bat_val < BATTERY_LOWVOL_THRESOLD) //charging_bat.c mt8168 only #define BATTERY_LOWVOL_THRESOLD 3300
->pchr_turn_on_charging(KAL_TRUE); //charging_bat.c mt8168 only PL充电
->mtk_wdt_init(); //wdt.c init watch dog, will enable AP watch dog
->Dump RGU regisers
->mtk_wdt_check_trig_reboot_reason();
->mtk_wdt_boot_check(); //wdt.c check bypass power key info
->set_kpd_pmic_mode(); //mtk_key.c init kpd PMIC mode support
->g_boot_reason = reason = platform_boot_status() //platform.c
->rtc_boot_check() //rtc.c start of platform_boot_status()
->#if RTC_2SEC_REBOOT_ENABLE
->rtc_save_2sec_stat(); //rtc.c
->rtc_2sec_stat_clear(); //rtc.c
->g_rtc_2sec_stat = false/true;
->#endif
->if ... return BR_RTC/BR_WDT/BR_WDT_BY_PASS_PWK
->if (mtk_detect_key(PL_PMIC_PWR_KEY) && hw_check_battery()) //keypad.c & pmic.c(8321)、pmic_mt6392.c(8167) 8168:if (mtk_detect_key(PL_PMIC_PWR_KEY)) {
->rtc_mark_bypass_pwrkey(); //rtc.c
->return BR_POWER_KEY;
->if (usb_accessory_in()) //platform.c
->if (PMIC_CHRDET_EXIST == pmic_IsUsbCableIn()) //start of usb_accessory_in()
->pmic_read_interface( (U32)(PMIC_RGS_CHRDET_ADDR), (&val), (U32)(PMIC_RGS_CHRDET_MASK), (U32)(PMIC_RGS_CHRDET_SHIFT) //pmic_IsUsbCableIn()相当于upmu_is_chr_det()
->exist = 1;
#if !CFG_USBIF_COMPLIANCE
->platform_set_chrg_cur(450); //platform.c enable charging current as early as possible to avoid can't enter following battery charging flow when low battery
->hw_set_cc(ma); //pmic.c、pmic_6392.c、charging_bat.c
#endif
->return exist; //end of usb_accessory_in()
->return BR_USB //USB/charger boot
->if (rtc_2sec_reboot_check()) //rtc.c
#if RTC_2SEC_REBOOT_ENABLE
return g_rtc_2sec_stat;
#else
return false;
#endif
->return BR_2SEC_REBOOT;
->pl_power_off(); //rtc.c Unknown boot 如果前面都没return,那么将跑到这里,强制关机
->rtc_bbpu_power_down() //rtc.c end of platform_boot_status()
->if (reason == BR_RTC || reason == BR_POWER_KEY || reason == BR_USB || reason == BR_WDT || reason ==BR_WDT_BY_PASS_PWK || reason == BR_2SEC_REBOOT) //mt8321 only
->rtc_bbpu_power_on(); //rtc.c mt8321 mt8167 mt8168
->mt_mem_init(); //memory.c init memory
->mt_set_emi //emi.c
->init_dram_buffer();
->ram_console_init();
->ram_console_reboot_reason_save(g_rgu_status);
->boot_device_init(); //platform.c init device storage end of platform_init()
->bldr_handshake(&handler);
->#ifdef MTK_SECURITY_SW_SUPPORT
->mode = seclib_brom_meta_mode(); //get mode type 找不到定义,不开源
->isSBC = seclib_sbc_enabled(); //找不到定义,不开源
->#endif
->switch (mode) { case NORMAL_BOOT:
->#if CFG_USB_TOOL_HANDSHAKE //yes
->if (TRUE == usb_handshake(handler)) //handshake_usb.c //这里可以设置force_download
->uint32 enum_tmo = CFG_USB_ENUM_TIMEOUT_EN ? USB_ENUM_TIMEOUT : 0; //start of usb_handshake()
->if (usb_connect(enum_tmo) == FALSE) { //handshake_usb.c
->if (enum_tmo) { //start of usb_connect()
->ulong start_time = get_timer(0);
->if (get_timer(start_time) > i * 1000) { //cable plugged-out and power key detection each 1 second
->if (!usb_accessory_in() && !pmic_detect_powerkey()) //如果USB没有插入,并且也不是power key press,强制关机
->pl_power_off(); //end of usb_connect() /* ret = pmic_read_interface((U32)(PMIC_PWRKEY_DEB_ADDR), (&val), (U32)(PMIC_PWRKEY_DEB_MASK), (U32)(PMIC_PWRKEY_DEB_SHIFT)); */
->print("%s USB enum timeout!\n", MOD); goto end; //end of usb_handshake()
->g_meta_com_type = META_USB_COM;
->#endif
->case META_BOOT/FACTORY_BOOT/FACTORY_BOOT/ADVMETA_BOOT/ATE_FACTORY_BOOT:
->if(!usb_cable_in())
->if ((g_boot_reason == BR_USB) || usb_accessory_in()) { //start of usb_cable_in()
->ret = mt_charger_type_detection();
->if (ret == STANDARD_HOST || ret == CHARGING_HOST) {
->mt_usb_phy_poweron();
->mt_usb_phy_savecurrent();
->exist = 1;
->} else if (ret == NONSTANDARD_CHARGER || ret == STANDARD_CHARGER) {
->#if CFG_USBIF_COMPLIANCE //not defined
->platform_set_chrg_cur(450);
->#endif
->return exist; //end of usb_cable_in()
//end of bldr_handshake()
->bldr_post_process
->platform_post_init
->#if CFG_BATTERY_DETECT //这个似乎没有定义
->if (g_boot_mode == NORMAL_BOOT && !hw_check_battery() && usb_accessory_in()) {
->pl_close_pre_chr_led(); //pmic.c、pmic_mt6392.c、charging_bat.c disable pmic pre-charging led
->pl_charging(1); //pmic.c、pmic_mt6392.c、charging_bat.c enable force charging mode
->do { mdelay(300); if (hw_check_battery()){break;}platform_wdt_all_kick();} while(1); //check battery exists or not & kick all watchdogs
->pl_charging(0); //end of platform_post_init()
->#endif

/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt8167/src/drivers/inc/upmu_hw.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #define MT6392_PMIC_REG_BASE (0x0000) #define MT6392_CHR_CON0 ((UINT32)(MT6392_PMIC_REG_BASE+0x0000)) #define MT6392_CHR_CON3 ((UINT32)(MT6392_PMIC_REG_BASE+0x0006)) #define MT6392_CHR_CON4 ((UINT32)(MT6392_PMIC_REG_BASE+0x0008)) #define MT6392_CHR_CON7 ((UINT32)(MT6392_PMIC_REG_BASE+0x000E))
#define MT6392_PMIC_RG_CHR_EN_ADDR MT6392_CHR_CON0 //充电使能脚,还需配合其它寄存器使用 #define MT6392_PMIC_RG_CHR_EN_MASK 0x1 #define MT6392_PMIC_RG_CHR_EN_SHIFT 4 #define MT6392_PMIC_RGS_CHRDET_ADDR MT6392_CHR_CON0 //充电器检测脚 #define MT6392_PMIC_RGS_CHRDET_MASK 0x1 #define MT6392_PMIC_RGS_CHRDET_SHIFT 5
#define MT6392_PMIC_RG_VBAT_CV_VTH_ADDR MT6392_CHR_CON3 //恒压充电电压 #define MT6392_PMIC_RG_VBAT_CV_VTH_MASK 0x1F #define MT6392_PMIC_RG_VBAT_CV_VTH_SHIFT 0
#define MT6392_PMIC_RG_CS_VTH_ADDR MT6392_CHR_CON4 //充电电流 #define MT6392_PMIC_RG_CS_VTH_MASK 0xF #define MT6392_PMIC_RG_CS_VTH_SHIFT 0
#define MT6392_PMIC_RG_BATON_EN_ADDR MT6392_CHR_CON7 //电池检测总开关 #define MT6392_PMIC_RG_BATON_EN_MASK 0x1 #define MT6392_PMIC_RG_BATON_EN_SHIFT 0 #define MT6392_PMIC_RG_BATON_HT_EN_ADDR MT6392_CHR_CON7 //HW高温检测开关 #define MT6392_PMIC_RG_BATON_HT_EN_MASK 0x1 #define MT6392_PMIC_RG_BATON_HT_EN_SHIFT 1 #define MT6392_PMIC_BATON_TDET_EN_ADDR MT6392_CHR_CON7 //温度检测开关,应该是打开了这个,BATON ADC才生效 #define MT6392_PMIC_BATON_TDET_EN_MASK 0x1 #define MT6392_PMIC_BATON_TDET_EN_SHIFT 2 #define MT6392_PMIC_RG_BATON_HT_TRIM_ADDR MT6392_CHR_CON7 #define MT6392_PMIC_RG_BATON_HT_TRIM_MASK 0x7 #define MT6392_PMIC_RG_BATON_HT_TRIM_SHIFT 4 #define MT6392_PMIC_RG_BATON_HT_TRIM_SET_ADDR MT6392_CHR_CON7 #define MT6392_PMIC_RG_BATON_HT_TRIM_SET_MASK 0x1 #define MT6392_PMIC_RG_BATON_HT_TRIM_SET_SHIFT 7 #define MT6392_PMIC_RGS_BATON_UNDET_ADDR MT6392_CHR_CON7 //电池检测,0:存在,1:不存在 #define MT6392_PMIC_RGS_BATON_UNDET_MASK 0x1 #define MT6392_PMIC_RGS_BATON_UNDET_SHIFT 12 |
1.电池检测
电池的NTC引脚需要接到MT6350的BATON引脚上,preloader中的检测代码如下:
/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6580/src/drivers/pmic.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | int hw_check_battery(void) { #ifndef MTK_DISABLE_POWER_ON_OFF_VOLTAGE_LIMITATION U32 ret_val; U32 reg_val=0;
ret_val=pmic_config_interface(MT6350_CHR_CON7,0x01, MT6350_PMIC_RG_BATON_EN_MASK, MT6350_PMIC_RG_BATON_EN_SHIFT); //BATON_EN=1 ret_val=pmic_config_interface(MT6350_CHR_CON7, 0x01, MT6350_PMIC_BATON_TDET_EN_MASK, MT6350_PMIC_BATON_TDET_EN_SHIFT); //BATON_TDET_EN=1 ret_val=pmic_read_interface(MT6350_CHR_CON7,®_val, MT6350_PMIC_RGS_BATON_UNDET_MASK, MT6350_PMIC_RGS_BATON_UNDET_SHIFT); //电池检测,0:存在,1:不存在
if (reg_val == 1) { print("No Battery\n");
ret_val=pmic_read_interface(MT6350_CHR_CON7,®_val,0xFFFF,0x0); print("[0x%x]=0x%x\n",MT6350_CHR_CON7,reg_val);
return 0; } else { print("Battery exist\n");
ret_val=pmic_read_interface(MT6350_CHR_CON7,®_val,0xFF,0x0); print("[0x%x]=0x%x\n",MT6350_CHR_CON7,reg_val);
pl_hw_ulc_det();
return 1; } #else return 1; #endif } |
如果需要去掉电池检测,则在preloader和ProjectConfig配置:MTK_DISABLE_POWER_ON_OFF_VOLTAGE_LIMITATION = yes
KernelConfig配置:CONFIG_MTK_DISABLE_POWER_ON_OFF_VOLTAGE_LIMITATION=y
2.电池温度检测
电池的温度也是通过NTC引脚来测量的,如果去掉电池检测,那么温度检测也会去掉
温度检测的等效电路如下:

其中10k(25℃)是一个温敏电阻,随着温度的升高,阻值降低,一般电池厂商会提供一个温度与阻值的曲线图,通过测量baton的电压值计算出阻值,然后根据阻值曲线计算出温度值,这就是温度测量的原理。
NTC阻值曲线如下(tb8321p2_bsp_bat_setting.dtsi/mt_battery_meter_table.h):
上拉参考电压为PMIC TREF提供的1.8v,通过计算可以得到在25℃(即10Khm)下,baton电压值大概为0.669v
/kernel-4.9-lc/drivers/misc/mediatek/include/mt-plat/mt6580/include/mach/mt_battery_meter_table.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #define BAT_NTC_10 1 #define BAT_NTC_47 0
#if (BAT_NTC_10 == 1) #define RBAT_PULL_UP_R 16900 #define RBAT_PULL_DOWN_R 27000 #endif
#if (BAT_NTC_47 == 1) #define RBAT_PULL_UP_R 61900 #define RBAT_PULL_DOWN_R 100000 #endif #define RBAT_PULL_UP_VOLT 1800
#if (BAT_NTC_10 == 1) BATT_TEMPERATURE Batt_Temperature_Table[] = { {-20, 68237}, {-15, 53650}, {-10, 42506}, { -5, 33892}, { 0, 27219}, { 5, 22021}, { 10, 17926}, { 15, 14674}, { 20, 12081}, { 25, 10000}, { 30, 8315}, { 35, 6948}, { 40, 5834}, { 45, 4917}, { 50, 4161}, { 55, 3535}, { 60, 3014} }; #endif
#if (BAT_NTC_47 == 1) BATT_TEMPERATURE Batt_Temperature_Table[] = { {-20, 483954}, {-15, 360850}, {-10, 271697}, { -5, 206463}, { 0, 158214}, { 5, 122259}, { 10, 95227}, { 15, 74730}, { 20, 59065}, { 25, 47000}, { 30, 37643}, { 35, 30334}, { 40, 24591}, { 45, 20048}, { 50, 16433}, { 55, 13539}, { 60, 11210} }; #endif |
我们来看一下代码:
如果是使用dts,那么需要重新获取NTC温度与阻值关系,否则直接使用.h默认值
battery_probe->batt_meter_init_cust_data->__batt_meter_init_cust_data_from_dt
/kernel-4.9-lc/drivers/misc/mediatek/include/mt-plat/battery_meter.h
1 2 3 4 | typedef struct { signed int BatteryTemp; signed int TemperatureR; } BATT_TEMPERATURE; |
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | int __batt_meter_init_cust_data_from_dt(void) { #if (BAT_NTC_10 == 1) batt_meter_cust_data.bat_ntc = 10; #elif (BAT_NTC_47 == 1) batt_meter_cust_data.bat_ntc = 47; #endif
#if defined(RBAT_PULL_UP_R) batt_meter_cust_data.rbat_pull_up_r = RBAT_PULL_UP_R; #endif #if defined(RBAT_PULL_UP_VOLT) batt_meter_cust_data.rbat_pull_up_volt = RBAT_PULL_UP_VOLT; #endif ... __batt_meter_parse_node(np, "batt_temperature_table_num", &num);
idx = 0; while (!of_property_read_u32_index(np, "batt_temperature_table", idx, &addr)) { idx++; if (!of_property_read_u32_index(np, "batt_temperature_table", idx, &val)) { battery_log(BAT_LOG_CRTI, "batt_temperature_table: addr: %d, val: %d\n", addr, val); } Batt_Temperature_Table[idx / 2].BatteryTemp = addr; Batt_Temperature_Table[idx / 2].TemperatureR = val;
idx++; if (idx >= num * 2) break; } ... } |
获取电池温度函数如下:
battery_meter_get_battery_temperature
->force_get_tbat(KAL_TRUE)
->battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_TEMP, &bat_temperature_volt) //获取ADC电压
->BattVoltToTemp(bat_temperature_volt)
->... //根据串并联电阻分压,计算得到热敏电阻阻值TRes
->sBaTTMP = BattThermistorConverTemp((int)TRes) //查表,根据阻值换算温度
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | signed int battery_meter_get_battery_temperature(void) { #ifdef MTK_BATTERY_LIFETIME_DATA_SUPPORT //NO signed int batt_temp = force_get_tbat(KAL_TRUE);
if (batt_temp > gFG_max_temperature) gFG_max_temperature = batt_temp; if (batt_temp < gFG_min_temperature) gFG_min_temperature = batt_temp;
return batt_temp; #else return force_get_tbat(KAL_TRUE); #endif } |
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | int force_get_tbat(kal_bool update) { #if defined(CONFIG_POWER_EXT) || defined(FIXED_TBAT_25) bm_print(BM_LOG_CRTI, "[force_get_tbat] fixed TBAT=25 t\n"); return 25; #else int bat_temperature_volt = 0; int bat_temperature_val = 0; static int pre_bat_temperature_val = -1; int fg_r_value = 0; signed int fg_current_temp = 0; kal_bool fg_current_state = KAL_FALSE; int bat_temperature_volt_temp = 0; int ret = 0;
if (batt_meter_cust_data.fixed_tbat_25) { bm_print(BM_LOG_CRTI, "[force_get_tbat] fixed TBAT=25 t\n"); return 25; }
if (update == KAL_TRUE || pre_bat_temperature_val == -1) { /* Get V_BAT_Temperature */ bat_temperature_volt = 2; ret = /* 获取BATON的adc电压 */ battery_meter_ctrl(BATTERY_METER_CMD_GET_ADC_V_BAT_TEMP, &bat_temperature_volt);
if (bat_temperature_volt != 0) { #if defined(SOC_BY_HW_FG) //NO fg_r_value = get_r_fg_value();
ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT, &fg_current_temp); ret = battery_meter_ctrl(BATTERY_METER_CMD_GET_HW_FG_CURRENT_SIGN, &fg_current_state); fg_current_temp = fg_current_temp / 10;
if (fg_current_state == KAL_TRUE) { bat_temperature_volt_temp = bat_temperature_volt; bat_temperature_volt = bat_temperature_volt - ((fg_current_temp * fg_r_value) / 1000); } else { bat_temperature_volt_temp = bat_temperature_volt; bat_temperature_volt = bat_temperature_volt + ((fg_current_temp * fg_r_value) / 1000); } #endif
bat_temperature_val = BattVoltToTemp(bat_temperature_volt); } #ifdef CONFIG_MTK_BIF_SUPPORT battery_charging_control(CHARGING_CMD_GET_BIF_TBAT, &bat_temperature_val); #endif bm_print(BM_LOG_CRTI, "[force_get_tbat] %d,%d,%d,%d,%d,%d\n", bat_temperature_volt_temp, bat_temperature_volt, fg_current_state, fg_current_temp, fg_r_value, bat_temperature_val); pre_bat_temperature_val = bat_temperature_val;
if (bat_temperature_val > 55) pr_notice("[force_get_tbat] %d,%d,%d,%d,%d,%d\n", bat_temperature_volt_temp, bat_temperature_volt, fg_current_state, fg_current_temp, fg_r_value, bat_temperature_val);
} else { bat_temperature_val = pre_bat_temperature_val; } return bat_temperature_val; #endif } EXPORT_SYMBOL(force_get_tbat); |
/kernel-4.9-lc/drivers/misc/mediatek/power/mt6580/battery_meter_hal.c
1 2 3 4 | signed int bm_ctrl_cmd(BATTERY_METER_CTRL_CMD cmd, void *data) bm_func[BATTERY_METER_CMD_GET_ADC_V_BAT_TEMP] = read_adc_v_bat_temp ... ... } |
/kernel-4.9-lc/drivers/misc/mediatek/include/mt-plat/mt6580/include/mach/upmu_sw.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /* ADC Channel Number */ typedef enum { /* MT6350 */
MT6350_AUX_BATON2 = 0x000, MT6350_AUX_CH6, MT6350_AUX_THR_SENSE2, MT6350_AUX_THR_SENSE1, MT6350_AUX_VCDT, MT6350_AUX_BATON1, MT6350_AUX_ISENSE, MT6350_AUX_BATSNS, MT6350_AUX_ACCDET, MT6350_AUX_CH9, MT6350_AUX_CH10, MT6350_AUX_CH11, MT6350_AUX_CH12, MT6350_AUX_CH13, MT6350_AUX_CH14, MT6350_AUX_CH15, MT6350_AUX_CH16, } pmic_adc_ch_list_enum; |
/kernel-4.9-lc/drivers/misc/mediatek/power/mt6580/battery_meter_hal.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | static signed int read_adc_v_bat_temp(void *data) { #if defined(CONFIG_POWER_EXT) *(signed int *)(data) = 0; #else #if defined(MTK_PCB_TBAT_FEATURE) //no
int ret = 0, data[4], i, ret_value = 0, ret_temp = 0; int Channel = 1;
if (IMM_IsAdcInitReady() == 0) { bm_print(BM_LOG_CRTI, "[get_tbat_volt] AUXADC is not ready"); return 0; }
i = times; while (i--) { ret_value = IMM_GetOneChannelValue(Channel, data, &ret_temp); ret += ret_temp; bm_print(BM_LOG_FULL, "[get_tbat_volt] ret_temp=%d\n", ret_temp); }
ret = ret * 1500 / 4096; ret = ret / times; bm_print(BM_LOG_CRTI, "[get_tbat_volt] Battery output mV = %d\n", ret);
*(signed int *)(data) = ret;
#else bm_print(BM_LOG_FULL, "[read_adc_v_charger] return PMIC_IMM_GetOneChannelValue(4,times,1);\n"); *(signed int *)(data) = PMIC_IMM_GetOneChannelValue(MT6350_AUX_BATON1, *(signed int *)(data), 1); //参数data没用到,返回值才是ADC电压 #endif #endif
return STATUS_OK; } |
PS:PL和LK阶段获取ADC也是int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd)
KERNEL的参数deCount没有任何作用,但PL和LK的参数deCount为获取的次数,比如deCount为5,那就是连续获取5次,最后返回5次的平均值
另外,对于其他平台(比如MT8768/MT8788)
KERNEL用int iio_read_channel_processed(struct iio_channel *chan, int *val)
PL和LK是使用int pmic_get_auxadc_value(PMIC_AUXADC_LIST list)
获取到ADC电压后,然后调用BattVoltToTemp,得到RNTC的阻值
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | int BattVoltToTemp(int dwVolt) { long long TRes_temp; long long TRes; int sBaTTMP = -100; /* 根据串联分压,计算下半部分电阻阻值TRes_temp*/ /* TRes_temp = ((long long)RBAT_PULL_UP_R*(long long)dwVolt) / (RBAT_PULL_UP_VOLT-dwVolt); */ /* 如果下半部分只有一个电阻,那么TRes_temp就是热敏电阻阻值 */ /* 如果热敏电阻并联了一个下拉电阻,那么通过计算得到热敏电阻阻值TRes */ /* TRes = (TRes_temp * (long long)RBAT_PULL_DOWN_R)/((long long)RBAT_PULL_DOWN_R - TRes_temp); */
TRes_temp = (batt_meter_cust_data.rbat_pull_up_r * (long long) dwVolt);
#if defined(__LP64__) || defined(_LP64) do_div(TRes_temp, (batt_meter_cust_data.rbat_pull_up_volt - dwVolt)); #else TRes_temp = div_s64(TRes_temp, (batt_meter_cust_data.rbat_pull_up_volt - dwVolt)); #endif
#ifdef RBAT_PULL_DOWN_R TRes = (TRes_temp * RBAT_PULL_DOWN_R); #if defined(__LP64__) || defined(_LP64) do_div(TRes, abs(RBAT_PULL_DOWN_R - TRes_temp)); #else TRes = div_s64(TRes, abs(RBAT_PULL_DOWN_R - TRes_temp)); #endif #else TRes = TRes_temp; #endif
/* convert register to temperature */ sBaTTMP = BattThermistorConverTemp((int)TRes);
return sBaTTMP; } |
TRes为计算得到的阻值,然后通过BattThermistorConverTemp,转换为对应温度:
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | int BattThermistorConverTemp(int Res) { int i = 0; int RES1 = 0, RES2 = 0; int TBatt_Value = -200, TMP1 = 0, TMP2 = 0;
if (Res >= Batt_Temperature_Table[0].TemperatureR) { TBatt_Value = -20; } else if (Res <= Batt_Temperature_Table[16].TemperatureR) { TBatt_Value = 60; } else { RES1 = Batt_Temperature_Table[0].TemperatureR; TMP1 = Batt_Temperature_Table[0].BatteryTemp;
for (i = 0; i <= 16; i++) { if (Res < Batt_Temperature_Table[i].TemperatureR) { RES1 = Batt_Temperature_Table[i].TemperatureR; //RES1是比Res大,且Batt_Temperature_Table数组里最接近Res的阻值 TMP1 = Batt_Temperature_Table[i].BatteryTemp;
} else { RES2 = Batt_Temperature_Table[i].TemperatureR; //RES2是比Res小,且Batt_Temperature_Table数组里最接近Res的阻值 TMP2 = Batt_Temperature_Table[i].BatteryTemp; break; } } /* 也就是说 RES1>Res>Res2, 通过计算得到Res对应的温度TBatt_Value */ TBatt_Value = (((Res - RES2) * TMP1) + ((RES1 - Res) * TMP2)) / (RES1 - RES2); }
return TBatt_Value; } |