More aggressive Recorder V1 charging (patch #1116884 from Jerry Van Baren)

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6105 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jörg Hohensohn 2005-03-03 07:25:43 +00:00
parent 384de10246
commit 2584896920
7 changed files with 541 additions and 528 deletions

View file

@ -968,7 +968,7 @@ bool dbg_mas_codec(void)
* The power_history array is updated in power_thread of powermgmt.c. * The power_history array is updated in power_thread of powermgmt.c.
*/ */
#define BAT_FIRST_VAL MAX(POWER_HISTORY_LEN - LCD_WIDTH - 1, 0) #define BAT_LAST_VAL MIN(LCD_WIDTH, POWER_HISTORY_LEN)
#define BAT_YSPACE (LCD_HEIGHT - 20) #define BAT_YSPACE (LCD_HEIGHT - 20)
bool view_battery(void) bool view_battery(void)
@ -986,30 +986,32 @@ bool view_battery(void)
switch (view) { switch (view) {
case 0: /* voltage history graph */ case 0: /* voltage history graph */
/* Find maximum and minimum voltage for scaling */ /* Find maximum and minimum voltage for scaling */
maxv = minv = 0; maxv = 0;
for (i = BAT_FIRST_VAL; i < POWER_HISTORY_LEN; i++) { minv = 65535;
for (i = 0; i < BAT_LAST_VAL; i++) {
if (power_history[i] > maxv) if (power_history[i] > maxv)
maxv = power_history[i]; maxv = power_history[i];
if ((minv == 0) || ((power_history[i]) && if (power_history[i] && (power_history[i] < minv))
(power_history[i] < minv)) )
{ {
minv = power_history[i]; minv = power_history[i];
} }
} }
if (minv < 1) if ((minv < 1) || (minv >= 65535))
minv = 1; minv = 1;
if (maxv < 2) if (maxv < 2)
maxv = 2; maxv = 2;
lcd_clear_display(); lcd_clear_display();
lcd_puts(0, 0, "Battery voltage:"); snprintf(buf, 30, "Battery %d.%02d", power_history[0] / 100,
power_history[0] % 100);
lcd_puts(0, 0, buf);
snprintf(buf, 30, "scale %d.%02d-%d.%02d V", snprintf(buf, 30, "scale %d.%02d-%d.%02d V",
minv / 100, minv % 100, maxv / 100, maxv % 100); minv / 100, minv % 100, maxv / 100, maxv % 100);
lcd_puts(0, 1, buf); lcd_puts(0, 1, buf);
x = 0; x = 0;
for (i = BAT_FIRST_VAL+1; i < POWER_HISTORY_LEN; i++) { for (i = BAT_LAST_VAL - 1; i >= 0; i--) {
y = (power_history[i] - minv) * BAT_YSPACE / (maxv - minv); y = (power_history[i] - minv) * BAT_YSPACE / (maxv - minv);
lcd_clearline(x, LCD_HEIGHT-1, x, 20); lcd_clearline(x, LCD_HEIGHT-1, x, 20);
lcd_drawline(x, LCD_HEIGHT-1, x, lcd_drawline(x, LCD_HEIGHT-1, x,
@ -1035,31 +1037,15 @@ bool view_battery(void)
snprintf(buf, 30, "Charger: %s", snprintf(buf, 30, "Charger: %s",
charger_inserted() ? "present" : "absent"); charger_inserted() ? "present" : "absent");
lcd_puts(0, 3, buf); lcd_puts(0, 3, buf);
#endif
#ifdef HAVE_CHARGE_CTRL #ifdef HAVE_CHARGE_CTRL
snprintf(buf, 30, "Charging: %s", snprintf(buf, 30, "Charging: %s",
charger_enabled ? "yes" : "no"); charger_enabled ? "yes" : "no");
lcd_puts(0, 4, buf); lcd_puts(0, 4, buf);
#endif snprintf(buf, 30, "short delta: %d", short_delta);
#endif
y = ( power_history[POWER_HISTORY_LEN-1] * 100
+ power_history[POWER_HISTORY_LEN-2] * 100
- power_history[POWER_HISTORY_LEN-1-CHARGE_END_NEGD+1] * 100
- power_history[POWER_HISTORY_LEN-1-CHARGE_END_NEGD] * 100 )
/ CHARGE_END_NEGD / 2;
snprintf(buf, 30, "short delta: %d", y);
lcd_puts(0, 5, buf); lcd_puts(0, 5, buf);
snprintf(buf, 30, "long delta: %d", long_delta);
y = ( power_history[POWER_HISTORY_LEN-1] * 100
+ power_history[POWER_HISTORY_LEN-2] * 100
- power_history[POWER_HISTORY_LEN-1-CHARGE_END_ZEROD+1] * 100
- power_history[POWER_HISTORY_LEN-1-CHARGE_END_ZEROD] * 100 )
/ CHARGE_END_ZEROD / 2;
snprintf(buf, 30, "long delta: %d", y);
lcd_puts(0, 6, buf); lcd_puts(0, 6, buf);
#ifdef HAVE_CHARGE_CTRL
lcd_puts(0, 7, power_message); lcd_puts(0, 7, power_message);
#endif #endif
break; break;
@ -1069,8 +1055,7 @@ bool view_battery(void)
lcd_puts(0, 0, "Voltage deltas:"); lcd_puts(0, 0, "Voltage deltas:");
for (i = 0; i <= 6; i++) { for (i = 0; i <= 6; i++) {
y = power_history[POWER_HISTORY_LEN-1-i] - y = power_history[i] - power_history[i+i];
power_history[POWER_HISTORY_LEN-1-i-1];
snprintf(buf, 30, "-%d min: %s%d.%02d V", i, snprintf(buf, 30, "-%d min: %s%d.%02d V", i,
(y < 0) ? "-" : "", ((y < 0) ? y * -1 : y) / 100, (y < 0) ? "-" : "", ((y < 0) ? y * -1 : y) / 100,
((y < 0) ? y * -1 : y ) % 100); ((y < 0) ? y * -1 : y ) % 100);
@ -1088,19 +1073,19 @@ bool view_battery(void)
snprintf(buf, 30, "Cycle time: %d m", powermgmt_last_cycle_startstop_min); snprintf(buf, 30, "Cycle time: %d m", powermgmt_last_cycle_startstop_min);
lcd_puts(0, 1, buf); lcd_puts(0, 1, buf);
snprintf(buf, 30, "Lev.at cycle start: %d%%", powermgmt_last_cycle_level); snprintf(buf, 30, "Lvl@cyc st: %d%%", powermgmt_last_cycle_level);
lcd_puts(0, 2, buf); lcd_puts(0, 2, buf);
#endif #endif
snprintf(buf, 30, "Last PwrHist val: %d.%02d V", snprintf(buf, 30, "Last PwrHist: %d.%02d V",
power_history[POWER_HISTORY_LEN-1] / 100, power_history[0] / 100,
power_history[POWER_HISTORY_LEN-1] % 100); power_history[0] % 100);
lcd_puts(0, 3, buf); lcd_puts(0, 3, buf);
snprintf(buf, 30, "battery level: %d%%", battery_level()); snprintf(buf, 30, "battery level: %d%%", battery_level());
lcd_puts(0, 5, buf); lcd_puts(0, 5, buf);
snprintf(buf, 30, "Est. remaining: %d m", battery_time()); snprintf(buf, 30, "Est. remain: %d m", battery_time());
lcd_puts(0, 6, buf); lcd_puts(0, 6, buf);
#ifdef HAVE_CHARGE_CTRL #ifdef HAVE_CHARGE_CTRL

View file

@ -763,8 +763,7 @@ void settings_apply(void)
set_poweroff_timeout(global_settings.poweroff); set_poweroff_timeout(global_settings.poweroff);
#ifdef HAVE_CHARGE_CTRL #ifdef HAVE_CHARGE_CTRL
charge_restart_level = global_settings.discharge ? enable_deep_discharge(global_settings.discharge);
CHARGE_RESTART_LO : CHARGE_RESTART_HI;
enable_trickle_charge(global_settings.trickle_charge); enable_trickle_charge(global_settings.trickle_charge);
#endif #endif

View file

@ -727,8 +727,7 @@ static bool deep_discharge(void)
{ {
bool result; bool result;
result = set_bool( str(LANG_DISCHARGE), &global_settings.discharge ); result = set_bool( str(LANG_DISCHARGE), &global_settings.discharge );
charge_restart_level = global_settings.discharge ? enable_deep_discharge(global_settings.discharge);
CHARGE_RESTART_LO : CHARGE_RESTART_HI;
return result; return result;
} }
static bool trickle_charge(void) static bool trickle_charge(void)

View file

@ -8,12 +8,13 @@ miss some information here, write to mail@uwe-freese.de.
[INTRODUCTION] [INTRODUCTION]
This doc describes how the charging works for the recorder. The algorithm can This doc describes how the charging works for the recorder. The algorithm
be found in firmware/powermgmt.[c|h]. Debug output is done in can be found in firmware/powermgmt.[c|h]. Debug output is done in
apps/debug_menu.c. apps/debug_menu.c.
Charging for the player and the FM/V2 recorder is done by the hardware and Charging for the player and the FM/V2 recorder is done by the hardware and
therefore isn't implemented in rockbox. Only the functions that calculate the therefore isn't implemented in rockbox. Only the functions that
battery level are also used for these models. calculate the battery level are also used for these models.
All following information is related to the recorder. All following information is related to the recorder.
@ -38,15 +39,13 @@ voltage. Both voltage curves (charging and decharging) are used here.
[CHARGE OVERVIEW] [CHARGE OVERVIEW]
- If voltage drops under a certain value (with "deep discharge" option on the - If voltage drops under a certain value (with "deep discharge" option on the
value is lower), charging is started. value is a lot lower), charging is started.
- If end of charge is detected, go to top off charge. - If end of charge is detected, go to top off charge.
- Make the batteries completely full. 90 minutes of top off charge (voltage - Make the batteries completely full. 90 minutes of top off charge (voltage
regulation at a high value). regulation at a higher value).
- After that, do trickle charge (max. 12 hours with voltage regulation at a - After that, trickle charge (voltage regulation at a nominal battery value).
lower value). The trickle charge will continue as long as the charger is plugged in (this
- When trickle charge is done and you did not disconnect or shut off your AJB is a change from the original charge algorithm).
by now, the AJB decharges normally since it reaches a low voltage and
everything starts from the beginning.
[NORMAL CHARGE] [NORMAL CHARGE]
@ -89,7 +88,7 @@ Two facts on batteries are the reason why this works:
goes down when the temperature goes up. goes down when the temperature goes up.
NiMH batteries have a smaller delta peak than NiCd, but is is enough for NiMH batteries have a smaller delta peak than NiCd, but is is enough for
Rockbox to detect that the batteries are full. Rockbox to detect that the batteries are full (in theory :-).
Related documents on the web: Related documents on the web:
@ -114,20 +113,33 @@ It goes on again and then the archos firmware charger code would charge again.
So we have trickle charge in rockbox. So we have trickle charge in rockbox.
In simple words, rockbox charges about 15 seconds per minute in trickle mode. In simple words, rockbox charges about 15 seconds per minute in trickle mode.
An AJB consumes 100 mA when it's on and the charging current is about 300mA. An AJB consumes 100 mA when it's on and the charging current is about 350mA.
So charging 15 s and decharge 45 s will keep the batteries full. So charging 15 s and decharge 45 s will keep the batteries full.
But the number of seconds the charger is on in trickle charge mode is also But the number of seconds the charger is on in trickle charge mode is
adjusted dynamically (between 1 and 24 sec). Rockbox tries to hold the battery also adjusted dynamically. Rockbox tries to hold the battery level at
level at 5,65 V (top off charge, that means "make the batteries completely 5,65 V (top off charge, that means "make the batteries completely full")
full") for 90 minutes, then a level of 5,45 V. If the voltage drops below the for 90 minutes, then a level of 5,45 V. If the voltage drops below the
wanted value, rockbox will charge one second more the next minute. If is is desired value, rockbox will charge one second more the next minute. If
greater than this value, is will charge one second less. is is greater than this value, is will charge one second less.
Trickle charging runs 12 hours after finishing the normal charging. That The number of seconds the charger is on in top off and trickle charge
should be enough for charging the AJB over night and then unplug the charger modes is also dependant on the charger's output voltage: if the charger
sometime in this 12 hour trickle charge time. It is not recommended to trickle supplies less than about 10v, the current into the batteries is less and
charge over days, that's because it is stopped after 12 hours. thus the percentage on is increased to maintain the proper current into
the batteries.
The original recharging algorithm stopped trickle charging after 12 hours,
at which time the battery would be discharged until the the batteries
fell below the "start charging" level. At that time the charge cycle
would be repeated.
The time limit was removed by Jerry Van Baren (along with other changes)
in the February, 2005 timeframe. The rationale for this is that the
trickle charge level is very low. In addition, it is disconcerting to
have a AJR plugged in and "recharged" only to find out that the battery
is only 86% full. This was giving the Rockbox recharging algorithm a
bad name and frustrating our users.
Many chargers do top off and trickle charge by feeding a constant (low) Many chargers do top off and trickle charge by feeding a constant (low)
current to the batteries. Rockbox, as described, makes a voltage regulation. current to the batteries. Rockbox, as described, makes a voltage regulation.
@ -177,25 +189,23 @@ because it uses the raw voltages):
always set the battery level to 100% always set the battery level to 100%
- the battery level is only allowed to change 1% per minute (exception: when - the battery level is only allowed to change 1% per minute (exception: when
usb is connected, it is allowed to go 3% down/min) usb is connected, it is allowed to go 3% down/min)
- if charging just started (or stopped), ignore the battery voltage for the
first 25 minutes
- after turning on the device, add another 5% to the battery level, because - after turning on the device, add another 5% to the battery level, because
the drive is used heavily when booting and the voltage usually gets a the drive is used heavily when booting and the voltage usually gets a
little higher after that little higher after that (rebounds)
[WHICH CHARGING MODE TO USE] [WHICH CHARGING MODE TO USE]
If you use your AJB connected to the power supply the whole time, select "deep Jerry Van Baren's revised recommendation: Select "deep discharge OFF"
discharge on" and "trickle charge off". and "trickle charge ON". This will keep your batteries charged up and
IMHO will not damage them.
If you want to charge your AJB over night and take it with you the next day, Original recommendation:
select "deep discharge off" (that it starts charging immediately) and "trickle
charge on" (that the batteries remain full).
A special case: If you fill up the batteries that are still nearly full every A special case: If you use your AJR connected to the power supply all
the time or if you fill up the batteries that are still nearly full every
night, it is recommended that you make a complete charge cycle from time to night, it is recommended that you make a complete charge cycle from time to
time. Select "deep discharge on" and "trickle charge on" and wait till the time. Select "deep discharge ON" and "trickle charge OFF" and wait till the
whole cycle is over (you can speed up the discharging a little bit by turning whole cycle is over (you can speed up the discharging a little bit by turning
on the LED backlight). Even if the battery sellers say NiMH cells don't show a on the LED backlight). Even if the battery sellers say NiMH cells don't show a
memory effect, I recommend making this procedure from time to time (every 10th memory effect, I recommend making this procedure from time to time (every 10th

View file

@ -63,7 +63,7 @@
#define ADC_BUTTON_ROW2 5 /* Used for scanning the keys, different #define ADC_BUTTON_ROW2 5 /* Used for scanning the keys, different
voltages for different keys */ voltages for different keys */
#define ADC_UNREG_POWER 6 /* Battery voltage with a better scaling */ #define ADC_UNREG_POWER 6 /* Battery voltage with a better scaling */
#define ADC_EXT_POWER 7 /* The external power voltage, V=X*0.0148 */ #define ADC_EXT_POWER 7 /* The external power voltage, 0v or 2.7v */
#endif #endif

View file

@ -48,13 +48,12 @@
#define BATTERY_RANGE (BATTERY_LEVEL_FULL - BATTERY_LEVEL_EMPTY) #define BATTERY_RANGE (BATTERY_LEVEL_FULL - BATTERY_LEVEL_EMPTY)
#define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */ #define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */
#define POWER_AVG_N 4 /* how many samples to take for each measurement */
#define POWER_AVG_SLEEP 9 /* how long do we sleep between each measurement */
#define CHARGE_END_NEGD 6 /* stop when N minutes have passed with #define CHARGE_END_NEGD 6 /* stop when N minutes have passed with
* avg delta being < -0.05 V */ * avg delta being < -0.05 V */
#define CHARGE_END_ZEROD 50 /* stop when N minutes have passed with #define CHARGE_END_ZEROD 50 /* stop when N minutes have passed with
* avg delta being < 0.005 V */ * avg delta being < 0.005 V */
#ifndef SIMULATOR #ifndef SIMULATOR
#ifdef HAVE_CHARGE_CTRL #ifdef HAVE_CHARGE_CTRL
@ -65,27 +64,40 @@
#define CHARGE_RESTART_HI 85 /* %: when to restart charging in 'charge' mode */ #define CHARGE_RESTART_HI 85 /* %: when to restart charging in 'charge' mode */
/* attention: if set too high, normal charging is started in trickle mode */ /* attention: if set too high, normal charging is started in trickle mode */
#define CHARGE_RESTART_LO 10 /* %: when to restart charging in 'discharge' mode */ #define CHARGE_RESTART_LO 10 /* %: when to restart charging in 'discharge' mode */
#define CHARGE_PAUSE_LEN 60 /* how many minutes to pause between charging cycles */
#define TOPOFF_MAX_TIME 90 /* After charging, go to top off charge. How long should top off charge be? */ #define TOPOFF_MAX_TIME 90 /* After charging, go to top off charge. How long should top off charge be? */
#define TOPOFF_VOLTAGE 565 /* which voltage is best? (centivolts) */ #define TOPOFF_VOLTAGE 565 /* which voltage is best? (centivolts) */
#define TRICKLE_MAX_TIME 12*60 /* After top off charge, go to trickle charge. How long should trickle charge be? */ #define TRICKLE_MAX_TIME 12*60 /* After top off charge, go to trickle charge. How long should trickle charge be? */
#define TRICKLE_VOLTAGE 545 /* which voltage is best? (centivolts) */ #define TRICKLE_VOLTAGE 545 /* which voltage is best? (centivolts) */
#define START_TOPOFF_SEC 25 /* initial trickle_sec for topoff */
#define START_TRICKLE_SEC 15 /* initial trickle_sec for trickle */
extern char power_message[POWER_MESSAGE_LEN]; extern char power_message[POWER_MESSAGE_LEN];
extern char charge_restart_level;
extern int long_delta; /* long term delta battery voltage */
extern int short_delta; /* short term delta battery voltage */
extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */ extern int powermgmt_last_cycle_startstop_min; /* how many minutes ago was the charging started or stopped? */
extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */ extern int powermgmt_last_cycle_level; /* which level had the batteries at this time? */
extern int battery_lazyness[20]; /* how does the battery react when plugging in/out the charger */ void enable_deep_discharge(bool on); /* deep discharge the battery */
void enable_trickle_charge(bool on); void enable_trickle_charge(bool on);
extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */ extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */
#endif /* HAVE_CHARGE_CTRL */ #endif /* HAVE_CHARGE_CTRL */
#if defined(HAVE_CHARGE_CTRL) || CONFIG_BATTERY == BATT_LIION2200 #if defined(HAVE_CHARGE_CTRL) || (CONFIG_BATTERY == BATT_LIION2200)
extern int charge_state; /* tells what the charger is doing (for info display): 0: decharging/charger off, 1: charge, 2: top-off, 3: trickle */ typedef enum {
#endif DISCHARGING,
CHARGING,
TOPOFF,
TRICKLE
} charge_state_type;
/* tells what the charger is doing */
extern charge_state_type charge_state;
#endif /* defined(HAVE_CHARGE_CTRL) || (CONFIG_BATTERY == BATT_LIION2200) */
#ifdef HAVE_MMC /* Values for Ondio */ #ifdef HAVE_MMC /* Values for Ondio */
#define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */ #define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */
@ -95,9 +107,14 @@ extern int charge_state; /* tells what the charger is doing (for info di
#define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */ #define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */
#define CURRENT_USB 500 /* usual current in mA in USB mode */ #define CURRENT_USB 500 /* usual current in mA in USB mode */
#define CURRENT_BACKLIGHT 30 /* additional current when backlight is always on */ #define CURRENT_BACKLIGHT 30 /* additional current when backlight is always on */
#define CURRENT_CHARGING 300 /* charging current */
#endif
#define CURRENT_MIN_CHG 70 /* minimum charge current */
#define MIN_CHG_V 8500 /* at 8.5v charger voltage get CURRENT_MIN_CHG */
#define CURRENT_MAX_CHG 350 /* maximum charging current */
#define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */
#endif /* HAVE_MMC */
extern unsigned int bat; /* filtered battery voltage, centivolts */
extern unsigned short power_history[POWER_HISTORY_LEN]; extern unsigned short power_history[POWER_HISTORY_LEN];
/* Start up power management thread */ /* Start up power management thread */
@ -114,7 +131,7 @@ bool battery_level_safe(void);
void set_poweroff_timeout(int timeout); void set_poweroff_timeout(int timeout);
void set_battery_capacity(int capacity); /* set local battery capacity value */ void set_battery_capacity(int capacity); /* set local battery capacity value */
void set_battery_type(int type); /* set local battery type */ void set_battery_type(int type); /* set local battery type */
void set_sleep_timer(int seconds); void set_sleep_timer(int seconds);
int get_sleep_timer(void); int get_sleep_timer(void);

File diff suppressed because it is too large Load diff