diff options
author | Uwe Freese <thebreaker@rockbox.org> | 2002-12-18 18:55:50 +0000 |
---|---|---|
committer | Uwe Freese <thebreaker@rockbox.org> | 2002-12-18 18:55:50 +0000 |
commit | 4bc287d34a40ce387c1c0d2049dc32dcc847f107 (patch) | |
tree | 1ed74a100dca884d608c869eec4f6755e09e9845 /firmware/powermgmt.c | |
parent | 012d1d5f903d5a4b090c3ce3d59bfba545a334c9 (diff) | |
download | rockbox-4bc287d34a40ce387c1c0d2049dc32dcc847f107.tar.gz rockbox-4bc287d34a40ce387c1c0d2049dc32dcc847f107.zip |
battery level 100% when trickle chg, only 1% per minute change allowed, ignore 25 min. after charge start/stop, get rid of old lazyness table (I hope this makes the battery display less confusing to the user, charging algo. is not affected\!)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3017 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/powermgmt.c')
-rw-r--r-- | firmware/powermgmt.c | 132 |
1 files changed, 70 insertions, 62 deletions
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index 0fdf8c8fe0..59d1a2fe7b 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c | |||
@@ -63,35 +63,39 @@ void set_battery_capacity(int capacity) | |||
63 | } | 63 | } |
64 | #else /* not SIMULATOR */ | 64 | #else /* not SIMULATOR */ |
65 | 65 | ||
66 | int battery_capacity = 1500; /* only a default value */ | ||
67 | int battery_level_cached = -1; /* battery level of this minute, updated once per minute */ | ||
68 | |||
66 | static int poweroff_idle_timeout_value[15] = | 69 | static int poweroff_idle_timeout_value[15] = |
67 | { | 70 | { |
68 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60 | 71 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 30, 45, 60 |
69 | }; | 72 | }; |
70 | 73 | ||
71 | static int percent_to_volt_nocharge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ | 74 | static int percent_to_volt_decharge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ |
72 | { | 75 | { |
73 | 450, 481, 491, 497, 503, 507, 512, 514, 517, 528, 560 | 76 | /* original values were taken directly after charging, */ |
77 | /* but it should show 100% after turning off the device for some hours, too */ | ||
78 | 450, 481, 491, 497, 503, 507, 512, 514, 517, 525, 540 /* orig. values: ...,528,560 */ | ||
74 | }; | 79 | }; |
75 | 80 | ||
76 | int battery_capacity = 1500; /* only a default value */ | ||
77 | |||
78 | void set_battery_capacity(int capacity) | 81 | void set_battery_capacity(int capacity) |
79 | { | 82 | { |
80 | battery_capacity = capacity; | 83 | battery_capacity = capacity; |
81 | if ((battery_capacity > BATTERY_CAPACITY_MAX) || (battery_capacity < 1500)) | 84 | if (battery_capacity > BATTERY_CAPACITY_MAX) |
85 | battery_capacity = BATTERY_CAPACITY_MAX; | ||
86 | if (battery_capacity < 1500) | ||
82 | battery_capacity = 1500; | 87 | battery_capacity = 1500; |
83 | } | 88 | } |
84 | 89 | ||
85 | #ifdef HAVE_CHARGE_CTRL | 90 | #ifdef HAVE_CHARGE_CTRL |
86 | 91 | ||
87 | char power_message[POWER_MESSAGE_LEN] = ""; | 92 | char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in debug menu */ |
88 | char charge_restart_level = CHARGE_RESTART_HI; | 93 | char charge_restart_level = CHARGE_RESTART_HI; /* level at which charging starts */ |
89 | 94 | int powermgmt_last_cycle_startstop_min = 25; /* how many minutes ago was the charging started or stopped? */ | |
90 | int powermgmt_last_cycle_startstop_min = 20; /* how many minutes ago was the charging started or stopped? */ | 95 | int powermgmt_last_cycle_level = 0; /* which level had the batteries at this time? */ |
91 | int powermgmt_last_cycle_level = 0; /* which level had the batteries at this time? */ | ||
92 | bool trickle_charge_enabled = true; | 96 | bool trickle_charge_enabled = true; |
93 | int trickle_sec = 0; /* how many seconds should the charger be enabled per minute for trickle charging? */ | 97 | int trickle_sec = 0; /* how many seconds should the charger be enabled per minute for trickle charging? */ |
94 | int charge_state = 0; /* at the beginning, the charger does nothing */ | 98 | int charge_state = 0; /* at the beginning, the charger does nothing */ |
95 | 99 | ||
96 | static int percent_to_volt_charge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ | 100 | static int percent_to_volt_charge[11] = /* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ |
97 | { | 101 | { |
@@ -104,11 +108,6 @@ void enable_trickle_charge(bool on) | |||
104 | } | 108 | } |
105 | #endif /* HAVE_CHARGE_CTRL */ | 109 | #endif /* HAVE_CHARGE_CTRL */ |
106 | 110 | ||
107 | int battery_lazyness[20] = /* how does the battery react when plugging in/out the charger */ | ||
108 | { | ||
109 | 0, 17, 31, 42, 52, 60, 67, 72, 77, 81, 84, 87, 89, 91, 92, 94, 95, 95, 96, 97 | ||
110 | }; | ||
111 | |||
112 | static char power_stack[DEFAULT_STACK_SIZE]; | 111 | static char power_stack[DEFAULT_STACK_SIZE]; |
113 | static char power_thread_name[] = "power"; | 112 | static char power_thread_name[] = "power"; |
114 | 113 | ||
@@ -121,7 +120,6 @@ static unsigned long sleeptimer_endtick; | |||
121 | 120 | ||
122 | unsigned short power_history[POWER_HISTORY_LEN]; | 121 | unsigned short power_history[POWER_HISTORY_LEN]; |
123 | 122 | ||
124 | |||
125 | int battery_time(void) | 123 | int battery_time(void) |
126 | { | 124 | { |
127 | return powermgmt_est_runningtime_min; | 125 | return powermgmt_est_runningtime_min; |
@@ -146,8 +144,8 @@ int voltage_to_percent(int voltage, int* table) | |||
146 | } | 144 | } |
147 | } | 145 | } |
148 | 146 | ||
149 | /* Returns battery level in percent */ | 147 | /* update battery level, called only once per minute */ |
150 | int battery_level(void) | 148 | void battery_level_update(void) |
151 | { | 149 | { |
152 | int level = 0; | 150 | int level = 0; |
153 | int c = 0; | 151 | int c = 0; |
@@ -171,33 +169,42 @@ int battery_level(void) | |||
171 | if(level < BATTERY_LEVEL_EMPTY) | 169 | if(level < BATTERY_LEVEL_EMPTY) |
172 | level = BATTERY_LEVEL_EMPTY; | 170 | level = BATTERY_LEVEL_EMPTY; |
173 | 171 | ||
174 | /* level now stores the voltage in centivolts */ | ||
175 | /* let's calculate a percentage now with using the voltage arrays */ | ||
176 | |||
177 | #ifdef HAVE_CHARGE_CTRL | 172 | #ifdef HAVE_CHARGE_CTRL |
178 | if (powermgmt_last_cycle_startstop_min < 20) { | 173 | if (charge_state == 0) { /* decharge */ |
179 | /* the batteries are lazy, so take a value between the result of the two table lookups */ | 174 | level = voltage_to_percent(level, percent_to_volt_decharge); |
180 | if (charge_state == 1) | 175 | } else if (charge_state == 1) { /* charge */ |
181 | level = (voltage_to_percent(level, percent_to_volt_charge) | 176 | level = voltage_to_percent(level, percent_to_volt_charge); |
182 | * battery_lazyness[powermgmt_last_cycle_startstop_min] | 177 | } else {/* in trickle charge, the battery is per definition 100% full */ |
183 | + voltage_to_percent(level, percent_to_volt_nocharge) | 178 | battery_level_cached = level = 100; |
184 | * (100 - battery_lazyness[powermgmt_last_cycle_startstop_min])) / 100; | ||
185 | else | ||
186 | level = (voltage_to_percent(level, percent_to_volt_nocharge) | ||
187 | * battery_lazyness[powermgmt_last_cycle_startstop_min] | ||
188 | + voltage_to_percent(level, percent_to_volt_charge) | ||
189 | * (100 - battery_lazyness[powermgmt_last_cycle_startstop_min])) / 100; | ||
190 | } else { | ||
191 | if (charge_state == 1) | ||
192 | level = voltage_to_percent(level, percent_to_volt_charge); | ||
193 | else | ||
194 | level = voltage_to_percent(level, percent_to_volt_nocharge); | ||
195 | } | 179 | } |
196 | #else | 180 | #else |
197 | level = voltage_to_percent(level, percent_to_volt_nocharge); /* always use the nocharge table */ | 181 | level = voltage_to_percent(level, percent_to_volt_decharge); /* always use the decharge table */ |
198 | #endif | 182 | #endif |
199 | 183 | ||
200 | return level; | 184 | if (battery_level_cached == -1) { /* first run of this procedure */ |
185 | /* the battery voltage is usually a little lower directly after turning on, because the disk was used heavily */ | ||
186 | /* raise it by 5 % */ | ||
187 | battery_level_cached = (level > 95) ? 100 : level + 5; | ||
188 | } else { | ||
189 | /* the level is allowed to be +1/-1 of the last value when usb not connected */ | ||
190 | /* and to be +1/-3 of the last value when usb is connected */ | ||
191 | if (level > battery_level_cached + 1) | ||
192 | level = battery_level_cached + 1; | ||
193 | if (usb_inserted()) { | ||
194 | if (level < battery_level_cached - 3) | ||
195 | level = battery_level_cached - 3; | ||
196 | } else { | ||
197 | if (level < battery_level_cached - 1) | ||
198 | level = battery_level_cached - 1; | ||
199 | } | ||
200 | battery_level_cached = level; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* Returns battery level in percent */ | ||
205 | int battery_level(void) | ||
206 | { | ||
207 | return battery_level_cached; | ||
201 | } | 208 | } |
202 | 209 | ||
203 | /* Tells if the battery level is safe for disk writes */ | 210 | /* Tells if the battery level is safe for disk writes */ |
@@ -301,7 +308,6 @@ static void handle_auto_poweroff(void) | |||
301 | * docs/CHARGING_ALGORITHM. | 308 | * docs/CHARGING_ALGORITHM. |
302 | */ | 309 | */ |
303 | 310 | ||
304 | |||
305 | static void power_thread(void) | 311 | static void power_thread(void) |
306 | { | 312 | { |
307 | int i; | 313 | int i; |
@@ -310,7 +316,7 @@ static void power_thread(void) | |||
310 | #ifdef HAVE_CHARGE_CTRL | 316 | #ifdef HAVE_CHARGE_CTRL |
311 | int delta; | 317 | int delta; |
312 | int charged_time = 0; | 318 | int charged_time = 0; |
313 | int charge_max_time_now = 0; | 319 | int charge_max_time_now = 0; /* max. charging duration, calculated at beginning of charging */ |
314 | int charge_pause = 0; /* no charging pause at the beginning */ | 320 | int charge_pause = 0; /* no charging pause at the beginning */ |
315 | int trickle_time = 0; /* how many minutes trickle charging already? */ | 321 | int trickle_time = 0; /* how many minutes trickle charging already? */ |
316 | #endif | 322 | #endif |
@@ -340,7 +346,7 @@ static void power_thread(void) | |||
340 | sleep(HZ*POWER_AVG_SLEEP); | 346 | sleep(HZ*POWER_AVG_SLEEP); |
341 | } | 347 | } |
342 | avg = avg / ((ok_samples) ? ok_samples : spin_samples); | 348 | avg = avg / ((ok_samples) ? ok_samples : spin_samples); |
343 | 349 | ||
344 | /* rotate the power history */ | 350 | /* rotate the power history */ |
345 | for (i = 0; i < POWER_HISTORY_LEN-1; i++) | 351 | for (i = 0; i < POWER_HISTORY_LEN-1; i++) |
346 | power_history[i] = power_history[i+1]; | 352 | power_history[i] = power_history[i+1]; |
@@ -348,20 +354,19 @@ static void power_thread(void) | |||
348 | /* insert new value in the end, in centivolts 8-) */ | 354 | /* insert new value in the end, in centivolts 8-) */ |
349 | power_history[POWER_HISTORY_LEN-1] = (avg * BATTERY_SCALE_FACTOR) / 10000; | 355 | power_history[POWER_HISTORY_LEN-1] = (avg * BATTERY_SCALE_FACTOR) / 10000; |
350 | 356 | ||
357 | /* update battery level every minute, ignoring first 15 minutes after start charge/decharge */ | ||
358 | #ifdef HAVE_CHARGE_CTRL | ||
359 | if ((powermgmt_last_cycle_startstop_min > 25) || (charge_state > 1)) | ||
360 | #endif | ||
361 | battery_level_update(); | ||
362 | |||
351 | /* calculate estimated remaining running time */ | 363 | /* calculate estimated remaining running time */ |
352 | /* not charging: remaining running time */ | 364 | /* decharging: remaining running time */ |
353 | /* charging: remaining charging time */ | 365 | /* charging: remaining charging time */ |
354 | 366 | ||
355 | #ifdef HAVE_CHARGE_CTRL | 367 | #ifdef HAVE_CHARGE_CTRL |
356 | if (charge_state == 1) | 368 | if (charge_state == 1) |
357 | /* if taking the nocharge battery level, charging lasts 30% longer than the value says */ | 369 | powermgmt_est_runningtime_min = (100 - battery_level()) * battery_capacity / 100 * 60 / CURRENT_CHARGING; |
358 | /* so consider it because there's the battery lazyness inside the the battery_level */ | ||
359 | if (powermgmt_last_cycle_startstop_min < 20) { | ||
360 | i = (100 - battery_lazyness[powermgmt_last_cycle_startstop_min]) * 30 / 100 ; /* 0..30 */ | ||
361 | powermgmt_est_runningtime_min = (100 - battery_level()) * battery_capacity / 100 * (100 + i) / 100 * 60 / CURRENT_CHARGING; | ||
362 | } else { | ||
363 | powermgmt_est_runningtime_min = (100 - battery_level()) * battery_capacity / 100 * 60 / CURRENT_CHARGING; | ||
364 | } | ||
365 | else { | 370 | else { |
366 | current = CURRENT_NORMAL; | 371 | current = CURRENT_NORMAL; |
367 | if ((backlight_get_timeout() == 1) || (charger_inserted() && backlight_get_on_when_charging())) | 372 | if ((backlight_get_timeout() == 1) || (charger_inserted() && backlight_get_on_when_charging())) |
@@ -479,6 +484,7 @@ static void power_thread(void) | |||
479 | if (trickle_time++ > TRICKLE_MAX_TIME + TOPOFF_MAX_TIME) { | 484 | if (trickle_time++ > TRICKLE_MAX_TIME + TOPOFF_MAX_TIME) { |
480 | trickle_sec = 0; /* show in debug menu that trickle is off */ | 485 | trickle_sec = 0; /* show in debug menu that trickle is off */ |
481 | charge_state = 0; /* 0: decharging/charger off, 1: charge, 2: top-off, 3: trickle */ | 486 | charge_state = 0; /* 0: decharging/charger off, 1: charge, 2: top-off, 3: trickle */ |
487 | powermgmt_last_cycle_startstop_min = 0; | ||
482 | } | 488 | } |
483 | 489 | ||
484 | if ((charge_state == 2) && (trickle_time > TOPOFF_MAX_TIME)) /* change state? */ | 490 | if ((charge_state == 2) && (trickle_time > TOPOFF_MAX_TIME)) /* change state? */ |
@@ -492,13 +498,15 @@ static void power_thread(void) | |||
492 | charger_enable(false); | 498 | charger_enable(false); |
493 | 499 | ||
494 | /* if battery is not full, enable charging */ | 500 | /* if battery is not full, enable charging */ |
495 | if (battery_level() < charge_restart_level) { | 501 | /* make sure charging starts if 1%-lazyness in battery_level_update() is too slow */ |
502 | if ( (battery_level() < charge_restart_level) | ||
503 | || (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS)) { | ||
496 | if (charge_pause) { | 504 | if (charge_pause) { |
497 | DEBUGF("power: batt level < restart level, but charge pause, not enabling\n"); | 505 | DEBUGF("power: batt level < restart level, but charge pause, not enabling\n"); |
498 | snprintf(power_message, POWER_MESSAGE_LEN, "chg pause %d min", charge_pause); | 506 | snprintf(power_message, POWER_MESSAGE_LEN, "chg pause %d min", charge_pause); |
499 | } else { | 507 | } else { |
500 | /* calculate max charge time depending on current battery level */ | 508 | /* calculate max charge time depending on current battery level */ |
501 | /* take 35% more because battery level is not linear */ | 509 | /* take 35% more because some more energy is used for heating up the battery */ |
502 | i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500; | 510 | i = CHARGE_MAX_TIME_1500 * battery_capacity / 1500; |
503 | charge_max_time_now = i * (100 + 35 - battery_level()) / 100; | 511 | charge_max_time_now = i * (100 + 35 - battery_level()) / 100; |
504 | if (charge_max_time_now > i) { | 512 | if (charge_max_time_now > i) { |
@@ -529,10 +537,7 @@ static void power_thread(void) | |||
529 | /* charger not inserted but was enabled */ | 537 | /* charger not inserted but was enabled */ |
530 | DEBUGF("power: charger disconnected, disabling\n"); | 538 | DEBUGF("power: charger disconnected, disabling\n"); |
531 | powermgmt_last_cycle_level = battery_level(); | 539 | powermgmt_last_cycle_level = battery_level(); |
532 | /* if the user only charged some minutes, we don't really have */ | 540 | powermgmt_last_cycle_startstop_min = 0; |
533 | /* a battery level that's usual for charging */ | ||
534 | /* the next line prevents the battery level being too low when the charger is connected for only some minutes */ | ||
535 | powermgmt_last_cycle_startstop_min = (powermgmt_last_cycle_startstop_min > 10) ? 0 : 20; | ||
536 | /* show in debug menu that trickle is off */ | 541 | /* show in debug menu that trickle is off */ |
537 | trickle_sec = 0; | 542 | trickle_sec = 0; |
538 | charger_enable(false); | 543 | charger_enable(false); |
@@ -565,9 +570,11 @@ void power_init(void) | |||
565 | /* initialize the history with a single sample to prevent level | 570 | /* initialize the history with a single sample to prevent level |
566 | flickering during the first minute of execution */ | 571 | flickering during the first minute of execution */ |
567 | power_history[POWER_HISTORY_LEN-1] = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000; | 572 | power_history[POWER_HISTORY_LEN-1] = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000; |
573 | /* calculate the first battery level */ | ||
574 | battery_level_update(); | ||
568 | /* calculate the remaining time to that the info screen displays something useful */ | 575 | /* calculate the remaining time to that the info screen displays something useful */ |
569 | powermgmt_est_runningtime_min = battery_level() * battery_capacity / 100 * 60 / CURRENT_NORMAL; | 576 | powermgmt_est_runningtime_min = battery_level() * battery_capacity / 100 * 60 / CURRENT_NORMAL; |
570 | 577 | ||
571 | #ifdef HAVE_CHARGE_CTRL | 578 | #ifdef HAVE_CHARGE_CTRL |
572 | snprintf(power_message, POWER_MESSAGE_LEN, "Powermgmt started"); | 579 | snprintf(power_message, POWER_MESSAGE_LEN, "Powermgmt started"); |
573 | 580 | ||
@@ -575,6 +582,7 @@ void power_init(void) | |||
575 | if (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS) | 582 | if (power_history[POWER_HISTORY_LEN-1] < BATTERY_LEVEL_DANGEROUS) |
576 | charger_enable(true); | 583 | charger_enable(true); |
577 | #endif | 584 | #endif |
585 | |||
578 | create_thread(power_thread, power_stack, sizeof(power_stack), power_thread_name); | 586 | create_thread(power_thread, power_stack, sizeof(power_stack), power_thread_name); |
579 | } | 587 | } |
580 | 588 | ||