QPNP 8909 8916 充電相關(2)【轉】

  • 2019 年 10 月 8 日
  • 筆記

上一篇主要講電池相關的一些知識,上節忘記講了,電池一般分為電量計電池和非電流計電池,電量計電池,就不需要用pmu8916的IC,當然這只是只,不需要BMS來計算soc,而jni層也需要讀取電流計的電池相關屬性。

這一節主要是根據代碼進行相關的分析。

  1. 先看probe的代碼:
static int qpnp_vm_bms_probe(struct spmi_device *spmi)  {      ...........      ..........      ...........      ..........        //這裡把電池的配置文件dtsi的讀出來,並存到當前的結構體。      rc = set_battery_data(chip);      rc = config_battery_data(chip->batt_data);      ..........      ..........      //這個是核心的工作,一個線程,BMS的主要內容在此      INIT_DELAYED_WORK(&chip->monitor_soc_work, monitor_soc_work);      ..........      ..........        //電池一些常規的檢測,主要從PMIC上讀到的相關信息      battery_insertion_check(chip);      battery_status_check(chip);        /* character device to pass data to the userspace */      rc = register_bms_char_device(chip);      if (rc) {          pr_err("Unable to regiter '/dev/vm_bms' rc=%dn", rc);          goto fail_bms_device;      }        the_chip = chip;      //這個也很重要,我們從上節知道,初值last_ocv_soc是非常重要的,決定着後面的soc估值算法      calculate_initial_soc(chip);        //設置和註冊電池的power supply      /* setup & register the battery power supply */      chip->bms_psy.name = "bms";      chip->bms_psy.type = POWER_SUPPLY_TYPE_BMS;      chip->bms_psy.properties = bms_power_props;      chip->bms_psy.num_properties = ARRAY_SIZE(bms_power_props);      chip->bms_psy.get_property = qpnp_vm_bms_power_get_property;      chip->bms_psy.set_property = qpnp_vm_bms_power_set_property;      chip->bms_psy.external_power_changed = qpnp_vm_bms_ext_power_changed;      chip->bms_psy.property_is_writeable = qpnp_vm_bms_property_is_writeable;      chip->bms_psy.supplied_to = qpnp_vm_bms_supplicants;      chip->bms_psy.num_supplicants = ARRAY_SIZE(qpnp_vm_bms_supplicants);        rc = power_supply_register(chip->dev, &chip->bms_psy);      if (rc < 0) {          pr_err("power_supply_register bms failed rc = %dn", rc);          goto fail_psy;      }      .....................      ....................      ....................      //這裡啟動工作線程      schedule_delayed_work(&chip->monitor_soc_work, 0);      ..........................      .......................    }
  1. 分析如何確定初始的last_ocv_uv:
static int calculate_initial_soc(struct qpnp_bms_chip *chip)  {      ........      ........      //讀當前電池溫度      rc = get_batt_therm(chip, &batt_temp);      ............      //讀PON OCV      rc = read_and_update_ocv(chip, batt_temp, true);      ..........      //讀關機保存的soc和last_soc_uv        rc = read_shutdown_ocv_soc(chip);        //這裡判斷是使用估計soc還是估值soc。如果chip->warm_reset 為真      if (chip->warm_reset) {          if (chip->shutdown_soc_invalid) { //這個是dtsi的一個配置選項,若沒有配置,                          //則不使用關機soc              est_ocv = estimate_ocv(chip); //估值soc              chip->last_ocv_uv = est_ocv;          } else {              chip->last_ocv_uv = chip->shutdown_ocv;//使用關機的soc和ocv              pr_err("Hyan %d : set chip->last_ocv_uv = %dn", __LINE__, chip->last_ocv_uv);              chip->last_soc = chip->shutdown_soc;              chip->calculated_soc = lookup_soc_ocv(chip,                          chip->shutdown_ocv, batt_temp);          }      } else {            if (chip->workaround_flag & WRKARND_PON_OCV_COMP)              adjust_pon_ocv(chip, batt_temp);             /* !warm_reset use PON OCV only if shutdown SOC is invalid */          chip->calculated_soc = lookup_soc_ocv(chip,                      chip->last_ocv_uv, batt_temp);          if (!chip->shutdown_soc_invalid &&              (abs(chip->shutdown_soc - chip->calculated_soc) <                  chip->dt.cfg_shutdown_soc_valid_limit)) {              chip->last_ocv_uv = chip->shutdown_ocv;              chip->last_soc = chip->shutdown_soc;              chip->calculated_soc = lookup_soc_ocv(chip,                          chip->shutdown_ocv, batt_temp);//使用估值soc            } else {              chip->shutdown_soc_invalid = true; //使用關機soc            }      }      .............      ............  }        //得到PON OCV      rc = read_and_update_ocv(chip, batt_temp, true);          ocv_uv = convert_vbatt_raw_to_uv(chip, ocv_data, is_pon_ocv);                  uv = vadc_reading_to_uv(reading, true); //讀ADC值                  uv = adjust_vbatt_reading(chip, uv);   //轉化為soc_uv                  rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv, is_pon_ocv); //根據IC的類型,進行溫度補償      //從寄存器中讀到儲存的soc和ocv      read_shutdown_ocv_soc          rc = qpnp_read_wrapper(chip, (u8 *)&stored_ocv,                  chip->base + BMS_OCV_REG, 2);          rc = qpnp_read_wrapper(chip, &stored_soc, chip->base + BMS_SOC_REG, 1);        adjust_pon_ocv(struct qpnp_bms_chip *chip, int batt_temp)          rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result);          pc = interpolate_pc(chip->batt_data->pc_temp_ocv_lut,                      batt_temp, chip->last_ocv_uv / 1000); //根據ocv和temp,查表得PC(soc)。          rbatt_mohm = get_rbatt(chip, pc, batt_temp); //根據soc和temp,得電池內阻zhi          /* convert die_temp to DECIDEGC */          die_temp = (int)result.physical / 100;          current_ma = interpolate_current_comp(die_temp);  //當前電流          delta_uv = rbatt_mohm * current_ma;          chip->last_ocv_uv += delta_uv;   //修正last_ocv_uv        //這個函數主要根據last_ocv_uv,計算出soc的      lookup_soc_ocv(struct qpnp_bms_chip *chip, int ocv_uv, int batt_temp)              //查表得到soc_ocv,soc_cutoff              soc_ocv = interpolate_pc(chip->batt_data->pc_temp_ocv_lut,                      batt_temp, ocv_uv / 1000);              soc_cutoff = interpolate_pc(chip->batt_data->pc_temp_ocv_lut,                  batt_temp, chip->dt.cfg_v_cutoff_uv / 1000);                soc_final = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_cutoff),                              (100 - soc_cutoff));                if (batt_temp > chip->dt.cfg_low_temp_threshold)                  iavg_ma = calculate_uuc_iavg(chip);              else                  iavg_ma = chip->current_now / 1000;              //查表得到FCC,ACC              fcc = interpolate_fcc(chip->batt_data->fcc_temp_lut,                                  batt_temp);              acc = interpolate_acc(chip->batt_data->ibat_acc_lut,                              batt_temp, iavg_ma);              //計算出UUC              soc_uuc = ((fcc - acc) * 100) / fcc;                if (batt_temp > chip->dt.cfg_low_temp_threshold)                  soc_uuc = adjust_uuc(chip, soc_uuc);              //得到soc_acc              soc_acc = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_uuc),                              (100 - soc_uuc));                soc_final = soc_acc;   //這個為上報的soc              chip->last_acc = acc;
  1. 看工作線程,monitor_soc_work(struct work_struct *work):
static void monitor_soc_work(struct work_struct *work)      calculate_delta_time(&chip->tm_sec, &chip->delta_time_s);      rc = get_batt_therm(chip, &batt_temp);      new_soc = lookup_soc_ocv(chip, chip->last_ocv_uv,batt_temp);      new_soc = clamp_soc_based_on_voltage(chip, new_soc);      report_vm_bms_soc(chip);//上報事件,上層得到消息,調用qpnp_vm_bms_power_get_property,獲取相關的屬性,計算出                  last_ocv_uv,並通過qpnp_vm_bms_power_set_property方法,設置last_ocv_uv,並啟動monitor_soc_work。
  1. 待續