赞
踩
https://blog.csdn.net/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 | #define MT6392_PMIC_REG_BASE (0x0000) |
1.电池检测
电池的NTC引脚需要接到MT6350的BATON引脚上,preloader中的检测代码如下:
/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6580/src/drivers/pmic.c
1 | int hw_check_battery(void) |
如果需要去掉电池检测,则在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 | #define BAT_NTC_10 1 |
我们来看一下代码:
如果是使用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 | typedef struct { |
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 | int __batt_meter_init_cust_data_from_dt(void) |
获取电池温度函数如下:
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 | signed int battery_meter_get_battery_temperature(void) |
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 | int force_get_tbat(kal_bool update) |
/kernel-4.9-lc/drivers/misc/mediatek/power/mt6580/battery_meter_hal.c
1 | signed int bm_ctrl_cmd(BATTERY_METER_CTRL_CMD cmd, void *data) |
/kernel-4.9-lc/drivers/misc/mediatek/include/mt-plat/mt6580/include/mach/upmu_sw.h
1 | /* ADC Channel Number */ |
/kernel-4.9-lc/drivers/misc/mediatek/power/mt6580/battery_meter_hal.c
1 | static signed int read_adc_v_bat_temp(void *data) |
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 | int BattVoltToTemp(int dwVolt) |
TRes为计算得到的阻值,然后通过BattThermistorConverTemp,转换为对应温度:
/kernel-4.9-lc/drivers/power/supply/mediatek/battery_meter.c
1 | int BattThermistorConverTemp(int Res) |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。