summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2015-01-24 14:38:11 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-26 19:45:42 +0000
commit6fb8ab3369f454e51fa2ef6bcbf14dc0a9919912 (patch)
tree6adf5fe33c19a1aee60821cffd0df0ecc4d00d92
parent342499a6d001eb6a442f0b6a8ea333d495da8f85 (diff)
downloadchrome-ec-6fb8ab3369f454e51fa2ef6bcbf14dc0a9919912.tar.gz
samus: modify fast charging profile to avoid charge problems
Several modifications to samus fast charging to fix bug where charging circuit stops charging the battery. - Fix bug: if we have a bad temperature reading, fast charging should ignore it. - Change the fast charging high temperature profile to set a charging voltage equal to the maximum of 8.3V and the current battery voltage. - Divide the normal temperature profile into two phases, low voltage charging and high voltage charging. Once we transition to second phase, don't allow it to go back to phase 1 unless AC is removed. On samus, we have to make sure we never command the BQ to a charging voltage that is below the present battery voltage or else the INA will lose power and we will not be able to charge the battery until AC is disconnected. This also changes charge_state_v2 so that the fast charging profile override is called even when AC is disconnected to avoid jumps in temperature as seen by the fast charging code. Also changes the voltage threshold for transitioning from phase 1 to phase 2 of normal temp charging so that the transition is taken a little earlier to match the desired profile slightly better. BUG=chrome-os-partner:35491 BRANCH=samus TEST=Added custom console command to be able to directly control the battery temperature that charger_profile_override() uses: static int command_chgtemp(int argc, char **argv) { char *e; if (argc < 2) return EC_ERROR_PARAM_COUNT; chg_temp = strtoi(argv[1], &e, 10); if (*e) return EC_ERROR_PARAM1; return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(chgtemp, command_chgtemp, "", "", NULL); Using this command, I jumped back and forth between all three temperature fast charging regions and made sure that (1) we never set a charging voltage below the present battery voltage and (2) we never stop charging the battery. I ran this test at low battery and high battery percentage and with low load (G3) and high load (S0 with webgl aquarium). Change-Id: I035603a4ab48a156ab43f8c93f21200c4b664aab Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/243143 Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
-rw-r--r--common/charge_state_v2.c6
-rw-r--r--driver/battery/samus.c120
2 files changed, 93 insertions, 33 deletions
diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c
index 894faed8b6..0f48d2482f 100644
--- a/common/charge_state_v2.c
+++ b/common/charge_state_v2.c
@@ -744,24 +744,22 @@ void charger_task(void)
* out of that state, even if the charge level is full.
*/
if (curr.batt.state_of_charge >= BATTERY_LEVEL_FULL &&
- !battery_seems_to_be_disconnected) {
+ !battery_seems_to_be_disconnected)
/* Full up. Stop charging */
curr.state = ST_IDLE;
- goto wait_for_it;
- }
/*
* TODO(crosbug.com/p/27643): Quit trying if charging too long
* without getting full (CONFIG_CHARGER_TIMEOUT_HOURS).
*/
+wait_for_it:
#ifdef CONFIG_CHARGER_PROFILE_OVERRIDE
sleep_usec = charger_profile_override(&curr);
if (sleep_usec < 0)
problem(PR_CUSTOM, sleep_usec);
#endif
-wait_for_it:
/* Keep the AP informed */
if (need_static)
need_static = update_static_battery_info();
diff --git a/driver/battery/samus.c b/driver/battery/samus.c
index 88ee48310d..ff57369d07 100644
--- a/driver/battery/samus.c
+++ b/driver/battery/samus.c
@@ -60,65 +60,127 @@ static int fast_charging_allowed = 1;
int charger_profile_override(struct charge_state_data *curr)
{
/* temp in 0.1 deg C */
- int temp_c = curr->batt.temperature - 2731;
+ int temp_c;
+ const struct charger_info *info;
+
/* keep track of last temperature range for hysteresis */
static enum {
TEMP_LOW,
TEMP_NORMAL,
TEMP_HIGH
- } temp_range = TEMP_NORMAL;
+ } temp_range = TEMP_NORMAL, prev_temp_range = TEMP_NORMAL;
- /* We only want to override how we charge, nothing else. */
- if (curr->state != ST_CHARGE)
- return 0;
+ /* charging voltage to use at high temp */
+ static int high_temp_charging_voltage;
+
+ /* custom profile phase at normal temp */
+ static int normal_temp_phase;
+
+ /* battery voltage and current and previous voltage and current */
+ int batt_voltage, batt_current;
+ static int prev_batt_voltage, prev_batt_current;
- /* Do we want to mess with the charge profile too? */
- if (!fast_charging_allowed)
+ /*
+ * Determine temperature range:
+ * Low: Battery is <15C
+ * Normal: Battery is 15-45C
+ * High: Battery is >45C
+ *
+ * Add 0.2 degrees of hysteresis.
+ * If temp reading was bad use last range.
+ */
+ if (!(curr->batt.flags & BATT_FLAG_BAD_TEMPERATURE)) {
+ temp_c = curr->batt.temperature - 2731;
+ if (temp_c < 149)
+ temp_range = TEMP_LOW;
+ else if (temp_c > 151 && temp_c < 449)
+ temp_range = TEMP_NORMAL;
+ else if (temp_c > 451)
+ temp_range = TEMP_HIGH;
+ }
+
+ /*
+ * Treat voltage and current as a pair, if either is bad fall back to
+ * previous reading.
+ */
+ if (curr->batt.flags &
+ (BATT_FLAG_BAD_VOLTAGE | BATT_FLAG_BAD_CURRENT)) {
+ batt_voltage = prev_batt_voltage;
+ batt_current = prev_batt_current;
+ } else {
+ batt_voltage = prev_batt_voltage = curr->batt.voltage;
+ batt_current = prev_batt_current = curr->batt.current;
+ }
+
+ /*
+ * If we are not charging or we aren't using fast charging profiles,
+ * then do not override desired current and voltage and reset some
+ * fast charging profile static variables.
+ */
+ if (curr->state != ST_CHARGE || !fast_charging_allowed) {
+ prev_temp_range = TEMP_NORMAL;
+ normal_temp_phase = 0;
return 0;
+ }
/*
* Okay, impose our custom will:
- * When battery is 15-45C:
- * CC at 9515mA @ 8.3V
- * CV at 8.3V until current drops to 4759mA
- * CC at 4759mA @ 8.7V
- * CV at 8.7V
+ * Normal temp:
+ * Phase 0: CC at 9515mA @ 8.3V
+ * CV at 8.3V until current drops to 4759mA
+ * Phase 1: CC at 4759mA @ 8.7V
+ * CV at 8.7V
*
- * When battery is <15C:
+ * Low temp:
* CC at 2854mA @ 8.7V
* CV at 8.7V
*
- * When battery is >45C:
- * CC at 6660mA @ 8.3V
- * CV at 8.3V (when battery is hot we don't go to fully charged)
- *
- * Add 0.2 degrees of hysteresis.
+ * High temp:
+ * If battery voltage < 8.3V then:
+ * CC at 6660mA @ 8.3V
+ * CV at 8.3V (when battery is hot we don't go to fully charged)
+ * else:
+ * CV at just above battery voltage which will essentially
+ * terminate the charge and allow battery to cool.
+ * Note that if we ever request a voltage below the present battery
+ * voltage, then we will stop the BQ switching, which will power off
+ * the INA and we won't be able to charge again until AC is
+ * disconnected. see crbug.com/p/35491.
*/
- if (temp_c < 149)
- temp_range = TEMP_LOW;
- else if (temp_c > 151 && temp_c < 449)
- temp_range = TEMP_NORMAL;
- else if (temp_c > 451)
- temp_range = TEMP_HIGH;
-
switch (temp_range) {
case TEMP_LOW:
curr->requested_current = 2854;
curr->requested_voltage = 8700;
break;
case TEMP_NORMAL:
- curr->requested_current = 9515;
- curr->requested_voltage = 8300;
- if (curr->batt.current <= 4759 && curr->batt.voltage >= 8250) {
+ if (normal_temp_phase == 0) {
+ curr->requested_current = 9515;
+ curr->requested_voltage = 8300;
+ if (batt_current <= 4759 && batt_voltage >= 8200)
+ normal_temp_phase = 1;
+ }
+ if (normal_temp_phase == 1) {
curr->requested_current = 4759;
curr->requested_voltage = 8700;
}
break;
case TEMP_HIGH:
+ /*
+ * First time TEMP_HIGH is used, get the closest voltage
+ * just above the battery voltage. If it is above 8.3V, we
+ * will use that as the target, otherwise we will use 8.3V.
+ */
+ if (prev_temp_range != TEMP_HIGH) {
+ info = charger_get_info();
+ high_temp_charging_voltage = MAX(8300,
+ charger_closest_voltage(batt_voltage +
+ info->voltage_step));
+ }
curr->requested_current = 6660;
- curr->requested_voltage = 8300;
+ curr->requested_voltage = high_temp_charging_voltage;
break;
}
+ prev_temp_range = temp_range;
return 0;
}