summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorBarry Wardell <rockbox@barrywardell.net>2006-11-11 01:18:57 +0000
committerBarry Wardell <rockbox@barrywardell.net>2006-11-11 01:18:57 +0000
commit8d2711b7d2d9f19dc2375bd9395359ed725375ab (patch)
tree788f6dc4e010f7cf6eac2e3a5d3eebe2427fe06e /firmware
parentb3d2017057a47b1a5863d4e18e8d3eaf6a2fb63a (diff)
downloadrockbox-8d2711b7d2d9f19dc2375bd9395359ed725375ab.tar.gz
rockbox-8d2711b7d2d9f19dc2375bd9395359ed725375ab.zip
Improved power management (FS#3001). Shutdown rockbox when the battery gets to a level where the device doesn't function properly. Calculate remaining charging time while charging (rather than remaining running time). Show "Low Battery" and "Battery Empty" warnings. Also fixes FS#4786.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11507 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/powermgmt.h34
-rw-r--r--firmware/powermgmt.c358
-rwxr-xr-xfirmware/target/arm/iriver/h10/adc-h10.c6
3 files changed, 322 insertions, 76 deletions
diff --git a/firmware/export/powermgmt.h b/firmware/export/powermgmt.h
index ba2cc02318..fc7a0de171 100644
--- a/firmware/export/powermgmt.h
+++ b/firmware/export/powermgmt.h
@@ -94,13 +94,25 @@ extern charger_input_state_type charger_input_state;
94# define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */ 94# define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */
95# define CURRENT_BACKLIGHT 0 /* no backlight */ 95# define CURRENT_BACKLIGHT 0 /* no backlight */
96#else /* Values for HD based jukeboxes */ 96#else /* Values for HD based jukeboxes */
97# ifdef IRIVER_H100_SERIES 97#ifdef IRIVER_H100_SERIES
98# define CURRENT_NORMAL 80 98# define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */
99# else 99# define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */
100# define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */
101#else
100# define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */ 102# define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */
101# endif /* not IRIVER_H100_SERIES */ 103# define CURRENT_BACKLIGHT 30 /* additional current when backlight always on */
102# define CURRENT_USB 500 /* usual current in mA in USB mode */ 104#endif /* not IRIVER_H100_SERIES */
103# define CURRENT_BACKLIGHT 30 /* additional current when backlight is always on */ 105#define CURRENT_USB 500 /* usual current in mA in USB mode */
106#ifdef IRIVER_H100_SERIES
107# define CURRENT_RECORD 105 /* additional current while recording */
108#elif defined(IRIVER_H300_SERIES)
109# define CURRENT_RECORD 110
110#elif defined(HAVE_RECORDING)
111# define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
112#endif
113#ifdef HAVE_REMOTE_LCD
114# define CURRENT_REMOTE 8 /* add. current when H100-remote connected */
115#endif
104 116
105# define CURRENT_MIN_CHG 70 /* minimum charge current */ 117# define CURRENT_MIN_CHG 70 /* minimum charge current */
106# define MIN_CHG_V 8500 /* at 8.5v charger voltage get CURRENT_MIN_CHG */ 118# define MIN_CHG_V 8500 /* at 8.5v charger voltage get CURRENT_MIN_CHG */
@@ -112,7 +124,6 @@ extern charger_input_state_type charger_input_state;
112# define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */ 124# define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */
113#endif /* not HAVE_MMC */ 125#endif /* not HAVE_MMC */
114 126
115extern unsigned int bat; /* filtered battery voltage, centivolts */
116extern unsigned short power_history[POWER_HISTORY_LEN]; 127extern unsigned short power_history[POWER_HISTORY_LEN];
117 128
118/* Start up power management thread */ 129/* Start up power management thread */
@@ -120,10 +131,10 @@ void powermgmt_init(void);
120 131
121#endif /* SIMULATOR */ 132#endif /* SIMULATOR */
122 133
123/* Returns battery level in percent */ 134/* Returns battery statust */
124int battery_level(void); 135int battery_level(void); /* percent */
125int battery_time(void); /* minutes */ 136int battery_time(void); /* minutes */
126 137int battery_adc_voltage(void); /* voltage from ADC in centivolts */
127unsigned int battery_voltage(void); /* filtered batt. voltage in centivolts */ 138unsigned int battery_voltage(void); /* filtered batt. voltage in centivolts */
128 139
129/* read unfiltered battery info */ 140/* read unfiltered battery info */
@@ -132,6 +143,9 @@ void battery_read_info(int *adc, int *voltage, int *level);
132/* Tells if the battery level is safe for disk writes */ 143/* Tells if the battery level is safe for disk writes */
133bool battery_level_safe(void); 144bool battery_level_safe(void);
134 145
146/* Tells if battery is in critical power saving state */
147bool battery_level_critical(void);
148
135void set_poweroff_timeout(int timeout); 149void set_poweroff_timeout(int timeout);
136void set_battery_capacity(int capacity); /* set local battery capacity value */ 150void set_battery_capacity(int capacity); /* set local battery capacity value */
137void set_battery_type(int type); /* set local battery type */ 151void set_battery_type(int type); /* set local battery type */
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 2ca176d072..d30a31897e 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -49,10 +49,15 @@
49#include "wm8758.h" 49#include "wm8758.h"
50#elif defined(HAVE_WM8975) 50#elif defined(HAVE_WM8975)
51#include "wm8975.h" 51#include "wm8975.h"
52#elif defined(HAVE_WM8731)
53#include "wm8731l.h"
52#endif 54#endif
53#ifdef HAVE_LCD_BITMAP 55#ifdef HAVE_LCD_BITMAP
54#include "font.h" 56#include "font.h"
55#endif 57#endif
58#if defined(HAVE_RECORDING) && (CONFIG_CODEC == SWCODEC)
59#include "pcm_record.h"
60#endif
56#include "logf.h" 61#include "logf.h"
57#include "lcd-remote.h" 62#include "lcd-remote.h"
58#ifdef SIMULATOR 63#ifdef SIMULATOR
@@ -149,6 +154,11 @@ bool battery_level_safe(void)
149 return battery_level() >= 10; 154 return battery_level() >= 10;
150} 155}
151 156
157bool battery_level_critical(void)
158{
159 return false;
160}
161
152void set_poweroff_timeout(int timeout) 162void set_poweroff_timeout(int timeout)
153{ 163{
154 (void)timeout; 164 (void)timeout;
@@ -173,41 +183,57 @@ static const int poweroff_idle_timeout_value[15] =
173 183
174static const unsigned int battery_level_dangerous[BATTERY_TYPES_COUNT] = 184static const unsigned int battery_level_dangerous[BATTERY_TYPES_COUNT] =
175{ 185{
176#if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder, LiIon */ 186#if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder, LiIon */
177 280 187 280
178#elif CONFIG_BATTERY == BATT_3AAA /* Ondio */ 188#elif CONFIG_BATTERY == BATT_3AAA /* Ondio: Alkaline, NiHM */
179 310, 345 /* alkaline, NiHM */ 189 310, 345
180#elif CONFIG_BATTERY == BATT_1AA /* iRiver iFP */ 190#elif CONFIG_BATTERY == BATT_1AA /* iRiver iFP: Alkaline, NiHM */
181 105, 115 /* alkaline, NiHM */ 191 105, 115
182#elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver H1x0 */ 192#elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver H1x0: LiPolymer */
183 339 193 338
184#elif CONFIG_BATTERY == BATT_IAUDIO_X5 194#elif CONFIG_BATTERY == BATT_IAUDIO_X5 /* iAudio X5 */
185 354 195 354
186#elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */ 196#elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB: LiPolymer*/
187 376 197 376
188#elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB */ 198#elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB: LiPolymer */
189 372 199 372
190#else /* Player/recorder, NiMH */ 200#else /* Player/recorder: NiMH */
191 475 201 475
192#endif 202#endif
193}; 203};
194 204
195static const short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = 205static const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
206{
207#if CONFIG_BATTERY == BATT_LIION2200 /* FM Recorder */
208 258
209#elif CONFIG_BATTERY == BATT_3AAA /* Ondio */
210 270, 280
211#elif CONFIG_BATTERY == BATT_LIPOL1300 /* iRiver Hxxx */
212 299
213#elif CONFIG_BATTERY == BATT_IAUDIO_X5 /* iAudio X5 */
214 350
215#elif CONFIG_BATTERY == BATT_LPCS355385 /* iriver H10 20GB */
216 365
217#elif CONFIG_BATTERY == BATT_BP009 /* iriver H10 5/6GB */
218 365
219#else /* Player/recorder: NiMH */
220 440
221#endif
222};
223
196/* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */ 224/* voltages (centivolt) of 0%, 10%, ... 100% when charging disabled */
225static const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
197{ 226{
198#if CONFIG_BATTERY == BATT_LIION2200 227#if CONFIG_BATTERY == BATT_LIION2200
199 /* measured values */ 228 /* measured values */
200 { 260, 285, 295, 303, 311, 320, 330, 345, 360, 380, 400 } 229 { 260, 285, 295, 303, 311, 320, 330, 345, 360, 380, 400 }
201#elif CONFIG_BATTERY == BATT_3AAA 230#elif CONFIG_BATTERY == BATT_3AAA
202 /* measured values */ 231 /* measured values */
203 { 280, 325, 341, 353, 364, 374, 385, 395, 409, 427, 475 }, /* alkaline */ 232 { 280, 325, 341, 353, 364, 374, 385, 395, 409, 427, 475 }, /* Alkaline */
204 { 310, 355, 363, 369, 372, 374, 376, 378, 380, 386, 405 } /* NiMH */ 233 { 310, 355, 363, 369, 372, 374, 376, 378, 380, 386, 405 } /* NiMH */
205#elif CONFIG_BATTERY == BATT_LIPOL1300 234#elif CONFIG_BATTERY == BATT_LIPOL1300
206 /* Below 337 the backlight starts flickering during HD access */ 235 /* Below 337 the backlight starts flickering during HD access */
207 /* Calibrated for Ionity 1900 mAh battery. If necessary, re-calibrate 236 { 337, 365, 370, 374, 378, 382, 387, 393, 400, 408, 416 }
208 * for the 1300 mAh stock battery. */
209// { 337, 358, 365, 369, 372, 377, 383, 389, 397, 406, 413 }
210 { 337, 366, 372, 374, 378, 381, 385, 392, 399, 408, 417 }
211#elif CONFIG_BATTERY == BATT_IAUDIO_X5 237#elif CONFIG_BATTERY == BATT_IAUDIO_X5
212 /* iAudio x5 series - still experimenting with best curve */ 238 /* iAudio x5 series - still experimenting with best curve */
213// Lithium ion discharge curve 239// Lithium ion discharge curve
@@ -238,12 +264,11 @@ static const short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
238charger_input_state_type charger_input_state IDATA_ATTR; 264charger_input_state_type charger_input_state IDATA_ATTR;
239 265
240/* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */ 266/* voltages (centivolt) of 0%, 10%, ... 100% when charging enabled */
241static const short percent_to_volt_charge[11] = 267static const unsigned short percent_to_volt_charge[11] =
242{ 268{
243#if CONFIG_BATTERY == BATT_LIPOL1300 269#if CONFIG_BATTERY == BATT_LIPOL1300
244 /* Calibrated for 1900 mAh Ionity battery (estimated 90% charge when 270 /* values measured over one full charging cycle */
245 entering in trickle-charging). We will never reach 100%. */ 271 354, 386, 393, 398, 400, 402, 404, 408, 413, 418, 423 /* LiPo */
246 340, 390, 394, 399, 400, 404, 407, 413, 417, 422, 426
247#elif CONFIG_BATTERY == BATT_LPCS355385 272#elif CONFIG_BATTERY == BATT_LPCS355385
248 /* iriver H10 20GB */ 273 /* iriver H10 20GB */
249 399, 403, 406, 408, 410, 412, 415, 418, 422, 426, 431 274 399, 403, 406, 408, 410, 412, 415, 418, 422, 426, 431
@@ -289,9 +314,15 @@ int pid_i = 0; /* PID integral term */
289 * Average battery voltage and charger voltage, filtered via a digital 314 * Average battery voltage and charger voltage, filtered via a digital
290 * exponential filter. 315 * exponential filter.
291 */ 316 */
292static unsigned int battery_centivolts;/* filtered battery voltage, centvolts */
293static unsigned int avgbat; /* average battery voltage (filtering) */ 317static unsigned int avgbat; /* average battery voltage (filtering) */
294#define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */ 318static unsigned int battery_centivolts;/* filtered battery voltage, centvolts */
319#ifdef HAVE_CHARGE_CTRL
320#define BATT_AVE_SAMPLES 32 /* filter constant / @ 2Hz sample rate */
321#elif CONFIG_BATTERY == BATT_LIPOL1300
322#define BATT_AVE_SAMPLES 128 /* slow filter for iriver */
323#else
324#define BATT_AVE_SAMPLES 64 /* medium filter constant for all others */
325#endif
295 326
296/* battery level (0-100%) of this minute, updated once per minute */ 327/* battery level (0-100%) of this minute, updated once per minute */
297static int battery_percent = -1; 328static int battery_percent = -1;
@@ -301,11 +332,12 @@ static int battery_type = 0;
301/* Power history: power_history[0] is the newest sample */ 332/* Power history: power_history[0] is the newest sample */
302unsigned short power_history[POWER_HISTORY_LEN]; 333unsigned short power_history[POWER_HISTORY_LEN];
303 334
304static char power_stack[DEFAULT_STACK_SIZE + DEBUG_STACK]; 335static char power_stack[DEFAULT_STACK_SIZE/2 + DEBUG_STACK];
305static const char power_thread_name[] = "power"; 336static const char power_thread_name[] = "power";
306 337
307static int poweroff_timeout = 0; 338static int poweroff_timeout = 0;
308static int powermgmt_est_runningtime_min = -1; 339static int powermgmt_est_runningtime_min = -1;
340static bool low_battery = false;
309 341
310static bool sleeptimer_active = false; 342static bool sleeptimer_active = false;
311static long sleeptimer_endtick; 343static long sleeptimer_endtick;
@@ -331,11 +363,6 @@ void battery_read_info(int *adc, int *voltage, int *level)
331 *level = voltage_to_battery_level(centivolts); 363 *level = voltage_to_battery_level(centivolts);
332} 364}
333 365
334unsigned int battery_voltage(void)
335{
336 return battery_centivolts;
337}
338
339void reset_poweroff_timer(void) 366void reset_poweroff_timer(void)
340{ 367{
341 last_event_tick = current_tick; 368 last_event_tick = current_tick;
@@ -372,12 +399,30 @@ int battery_level(void)
372 return battery_percent; 399 return battery_percent;
373} 400}
374 401
402/* Returns filtered battery voltage [centivolts] */
403unsigned int battery_voltage(void)
404{
405 return battery_centivolts;
406}
407
408/* Returns battery voltage from ADC [centivolts] */
409int battery_adc_voltage(void)
410{
411 return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR + 5000) / 10000;
412}
413
375/* Tells if the battery level is safe for disk writes */ 414/* Tells if the battery level is safe for disk writes */
376bool battery_level_safe(void) 415bool battery_level_safe(void)
377{ 416{
378 return battery_centivolts > battery_level_dangerous[battery_type]; 417 return battery_centivolts > battery_level_dangerous[battery_type];
379} 418}
380 419
420/* Tells if the battery is in critical powersaving state */
421bool battery_level_critical(void)
422{
423 return ((battery_capacity * battery_percent / BATTERY_CAPACITY_MIN) < 10);
424}
425
381void set_poweroff_timeout(int timeout) 426void set_poweroff_timeout(int timeout)
382{ 427{
383 poweroff_timeout = timeout; 428 poweroff_timeout = timeout;
@@ -403,8 +448,7 @@ int get_sleep_timer(void)
403 return 0; 448 return 0;
404} 449}
405 450
406/* look into the percent_to_volt_* table and get a realistic battery level 451/* look into the percent_to_volt_* table and get a realistic battery level */
407 percentage */
408static int voltage_to_percent(int voltage, const short* table) 452static int voltage_to_percent(int voltage, const short* table)
409{ 453{
410 if (voltage <= table[0]) 454 if (voltage <= table[0])
@@ -430,7 +474,33 @@ static int voltage_to_battery_level(int battery_centivolts)
430{ 474{
431 int level; 475 int level;
432 476
433#if CONFIG_CHARGING >= CHARGING_MONITOR 477#if defined(CONFIG_CHARGER) && CONFIG_BATTERY == BATT_LIPOL1300
478 if (charger_input_state == NO_CHARGER) {
479 /* discharging. calculate new battery level and average with last */
480 level = voltage_to_percent(battery_centivolts,
481 percent_to_volt_discharge[battery_type]);
482 if (level != (battery_percent - 1))
483 level = (level + battery_percent + 1) / 2;
484 }
485 else if (charger_input_state == CHARGER_UNPLUGGED) {
486 /* just unplugged. adjust filtered values */
487 battery_centivolts -= percent_to_volt_charge[battery_percent/10] -
488 percent_to_volt_discharge[0][battery_percent/10];
489 avgbat = battery_centivolts * 10000 * BATT_AVE_SAMPLES;
490 level = battery_percent;
491 }
492 else if (charger_input_state == CHARGER_PLUGGED) {
493 /* just plugged in. adjust battery values */
494 battery_centivolts += percent_to_volt_charge[battery_percent/10] -
495 percent_to_volt_discharge[0][battery_percent/10];
496 avgbat = battery_centivolts * 10000 * BATT_AVE_SAMPLES;
497 level = MIN(12 * battery_percent / 10, 99);
498 }
499 else { /* charging. calculate new battery level */
500 level = voltage_to_percent(battery_centivolts,
501 percent_to_volt_charge);
502 }
503#elif CONFIG_CHARGING >= CHARGING_MONITOR
434 if (charge_state == DISCHARGING) { 504 if (charge_state == DISCHARGING) {
435 level = voltage_to_percent(battery_centivolts, 505 level = voltage_to_percent(battery_centivolts,
436 percent_to_volt_discharge[battery_type]); 506 percent_to_volt_discharge[battery_type]);
@@ -440,7 +510,7 @@ static int voltage_to_battery_level(int battery_centivolts)
440 level = MIN(voltage_to_percent(battery_centivolts, 510 level = MIN(voltage_to_percent(battery_centivolts,
441 percent_to_volt_charge), 99); 511 percent_to_volt_charge), 99);
442 } 512 }
443 else { /* in topoff/trickle charge, the battery is by definition 100% full */ 513 else { /* in topoff/trickle charge, battery is by definition 100% full */
444 level = 100; 514 level = 100;
445 } 515 }
446#else 516#else
@@ -456,35 +526,71 @@ static void battery_status_update(void)
456{ 526{
457 int level = voltage_to_battery_level(battery_centivolts); 527 int level = voltage_to_battery_level(battery_centivolts);
458 528
459#ifndef HAVE_MMC /* this adjustment is only needed for HD based */
460 if (battery_percent == -1) { /* first run of this procedure */
461 /* The battery voltage is usually a little lower directly after
462 turning on, because the disk was used heavily. Raise it by 5. % */
463 level = (level > 95) ? 100 : level + 5;
464 }
465#endif
466 battery_percent = level;
467 529
468 /* calculate estimated remaining running time */ 530 /* calculate estimated remaining running time */
469 /* discharging: remaining running time */ 531 /* discharging: remaining running time */
470 /* charging: remaining charging time */ 532 /* charging: remaining charging time */
471#if CONFIG_CHARGING >= CHARGING_MONITOR 533#if CONFIG_CHARGING >= CHARGING_MONITOR
472 if (charge_state == CHARGING) { 534 if (charge_state == CHARGING) {
473 powermgmt_est_runningtime_min = (100 - level) * battery_capacity / 100 535 powermgmt_est_runningtime_min = (100 - level) * battery_capacity * 60
474 * 60 / (CURRENT_MAX_CHG - runcurrent()); 536 / 100 / (CURRENT_MAX_CHG - runcurrent());
475 } 537 }
476 else 538 else
539#elif defined(CONFIG_CHARGING) && CONFIG_BATTERY == BATT_LIPOL1300
540 if (charger_inserted()) {
541#ifdef IRIVER_H300_SERIES
542 /* H300_SERIES use CURRENT_MAX_CHG for basic charge time (80%)
543 * plus 110 min top off charge time */
544 powermgmt_est_runningtime_min = ((100-level) * battery_capacity * 80
545 /100 / CURRENT_MAX_CHG) + 110;
546#else
547 /* H100_SERIES scaled for 160 min basic charge time (80%) on
548 * 1600 mAh battery plus 110 min top off charge time */
549 powermgmt_est_runningtime_min = ((100 - level) * battery_capacity
550 / 993) + 110;
551#endif
552 level = (level * 80) / 100;
553 if (level > 72) { /* > 91% */
554 int i = POWER_HISTORY_LEN;
555 int d = 1;
556#ifdef HAVE_CHARGE_STATE
557 if (charge_state == DISCHARGING)
558 d = -2;
477#endif 559#endif
560 while ((i > 2) && (d > 0)) /* search zero or neg. delta */
561 d = power_history[0] - power_history[--i];
562 if ((((d == 0) && (i > 6)) || (d == -1)) && (i < 118)) {
563 /* top off charging */
564 level = MIN(80 + (i*19 / 113), 99); /* show 81% .. 99% */
565 powermgmt_est_runningtime_min = MAX(116 - i, 0);
566 }
567 else if ((d < 0) || (i > 117)) {
568 /* charging finished */
569 level = 100;
570 powermgmt_est_runningtime_min = battery_capacity * 60
571 / runcurrent();
572 }
573 }
574 }
575 else
576#endif /* BATT_LIPOL1300 */
478 { 577 {
479 powermgmt_est_runningtime_min = level * battery_capacity / 100 578 if ((battery_centivolts + 2) > percent_to_volt_discharge[0][0])
480 * 60 / runcurrent(); 579 powermgmt_est_runningtime_min = (level + battery_percent) * 60 *
580 battery_capacity / 200 / runcurrent();
581 else
582 powermgmt_est_runningtime_min = (battery_centivolts -
583 battery_level_shutoff[0]) / 2;
481 } 584 }
585
586 battery_percent = level;
482} 587}
483 588
484/* 589/*
485 * We shut off in the following cases: 590 * We shut off in the following cases:
486 * 1) The unit is idle, not playing music 591 * 1) The unit is idle, not playing music
487 * 2) The unit is playing music, but is paused 592 * 2) The unit is playing music, but is paused
593 * 3) The battery level has reached shutdown limit
488 * 594 *
489 * We do not shut off in the following cases: 595 * We do not shut off in the following cases:
490 * 1) The USB is connected 596 * 1) The USB is connected
@@ -507,6 +613,41 @@ static void handle_auto_poweroff(void)
507 } 613 }
508#endif 614#endif
509 615
616 /* For low battery condition do some power-saving stuff */
617 if (!low_battery && battery_level_critical()) {
618#if CONFIG_BACKLIGHT == BL_IRIVER_H100
619 backlight_set_fade_in(0);
620 backlight_set_fade_out(0);
621#endif
622#if defined(CONFIG_BACKLIGHT) && !defined(BOOTLOADER)
623 if (backlight_get_current_timeout() > 2)
624#endif
625 backlight_set_timeout(2);
626#ifdef HAVE_REMOTE_LCD
627 remote_backlight_set_timeout(2);
628#endif
629 ata_spindown(3);
630#ifdef HAVE_ATA_POWER_OFF
631 ata_poweroff(true);
632#endif
633 low_battery = true;
634 } else if (low_battery && (battery_percent > 11)) {
635 backlight_set_timeout(10);
636 ata_spindown(10);
637 low_battery = false;
638 }
639
640 /* switch off unit if battery level is too low for reliable operation */
641#if (CONFIG_BATTERY!=BATT_4AA_NIMH) && (CONFIG_BATTERY!=BATT_3AAA)&& \
642 (CONFIG_BATTERY!=BATT_1AA)
643 if(battery_centivolts < battery_level_shutoff[battery_type]) {
644 if(!shutdown_timeout) {
645 backlight_on();
646 sys_poweroff();
647 }
648 }
649#endif
650
510 if(timeout && 651 if(timeout &&
511#if defined(CONFIG_TUNER) && !defined(BOOTLOADER) 652#if defined(CONFIG_TUNER) && !defined(BOOTLOADER)
512 (!(get_radio_status() & FMRADIO_PLAYING)) && 653 (!(get_radio_status() & FMRADIO_PLAYING)) &&
@@ -581,6 +722,30 @@ static int runcurrent(void)
581 current += CURRENT_BACKLIGHT; 722 current += CURRENT_BACKLIGHT;
582#endif 723#endif
583 724
725#if defined(HAVE_RECORDING) && defined(CURRENT_RECORD)
726#if CONFIG_CODEC == SWCODEC
727 unsigned int audio_stat = pcm_rec_status();
728#else
729 int audio_stat = audio_status();
730#endif
731 if (audio_stat & AUDIO_STATUS_RECORD)
732 current += CURRENT_RECORD;
733#endif
734
735#ifdef HAVE_SPDIF_POWER
736#ifdef SPDIF_POWER_INVERTED
737 if (GPIO1_OUT & 0x01000000)
738#else
739 if (!(GPIO1_OUT & 0x01000000))
740#endif
741 current += CURRENT_SPDIF_OUT;
742#endif
743
744#ifdef HAVE_REMOTE_LCD
745 if ((GPIO_READ & 0x40000000) == 0)
746 current += CURRENT_REMOTE;
747#endif
748
584 return(current); 749 return(current);
585} 750}
586 751
@@ -689,17 +854,31 @@ static void power_thread_sleep(int ticks)
689 * likely always be spinning in USB mode). 854 * likely always be spinning in USB mode).
690 */ 855 */
691 if (!ata_disk_is_active() || usb_inserted()) { 856 if (!ata_disk_is_active() || usb_inserted()) {
692 avgbat = avgbat - (avgbat / BATT_AVE_SAMPLES) + 857 avgbat += adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR
693 adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR; 858 - (avgbat / BATT_AVE_SAMPLES);
694 /* 859 /*
695 * battery_centivolts is the centivolt-scaled filtered battery value. 860 * battery_centivolts is the centivolt-scaled filtered battery value.
696 */ 861 */
697 battery_centivolts = avgbat / BATT_AVE_SAMPLES / 10000; 862 battery_centivolts = (avgbat / BATT_AVE_SAMPLES + 5000) / 10000;
698
699 /* update battery status every time an update is available */
700 battery_status_update();
701
702 } 863 }
864 else if (battery_percent < 8) {
865 /* If battery is low, observe voltage during disk activity.
866 * Shut down if voltage drops below shutoff level and we are not
867 * using NiMH or Alkaline batteries.
868 */
869 battery_centivolts = (battery_adc_voltage() +
870 battery_centivolts + 1) / 2;
871#if (CONFIG_BATTERY!=BATT_4AA_NIMH) && (CONFIG_BATTERY!=BATT_3AAA)&& \
872 (CONFIG_BATTERY!=BATT_1AA)
873 if (!shutdown_timeout &&
874 (battery_centivolts < battery_level_shutoff[battery_type]))
875 sys_poweroff();
876 else
877#endif
878 avgbat += battery_centivolts * 10000
879 - (avgbat / BATT_AVE_SAMPLES);
880 }
881
703#if CONFIG_CHARGING == CHARGING_CONTROL 882#if CONFIG_CHARGING == CHARGING_CONTROL
704 if (ata_disk_is_active()) { 883 if (ata_disk_is_active()) {
705 /* flag hdd use for charging calculation */ 884 /* flag hdd use for charging calculation */
@@ -711,8 +890,7 @@ static void power_thread_sleep(int ticks)
711 * If we have a lot of pending writes or if the disk is spining, 890 * If we have a lot of pending writes or if the disk is spining,
712 * fsync the debug log file. 891 * fsync the debug log file.
713 */ 892 */
714 if((wrcount > 10) || 893 if((wrcount > 10) || ((wrcount > 0) && ata_disk_is_active())) {
715 ((wrcount > 0) && ata_disk_is_active())) {
716 fsync(fd); 894 fsync(fd);
717 wrcount = 0; 895 wrcount = 0;
718 } 896 }
@@ -745,10 +923,35 @@ static void power_thread(void)
745#endif 923#endif
746 924
747 /* initialize the voltages for the exponential filter */ 925 /* initialize the voltages for the exponential filter */
748 avgbat = adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR * 926 avgbat = adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR + 15000;
749 BATT_AVE_SAMPLES; 927
928#ifndef HAVE_MMC /* this adjustment is only needed for HD based */
929 /* The battery voltage is usually a little lower directly after
930 turning on, because the disk was used heavily. Raise it by 5% */
931#ifdef HAVE_CHARGING
932 if(!charger_inserted()) /* only if charger not connected */
933#endif
934 avgbat += (percent_to_volt_discharge[battery_type][6] -
935 percent_to_volt_discharge[battery_type][5]) * 5000;
936#endif /* not HAVE_MMC */
937
938 avgbat = avgbat * BATT_AVE_SAMPLES;
750 battery_centivolts = avgbat / BATT_AVE_SAMPLES / 10000; 939 battery_centivolts = avgbat / BATT_AVE_SAMPLES / 10000;
751 940
941#ifdef CONFIG_CHARING
942 if(charger_inserted()) {
943 battery_percent = voltage_to_percent(battery_centivolts,
944 percent_to_volt_charge);
945#if CONFIG_BATTERY == BATT_LIPOL1300
946 charger_input_state = CHARGER;
947#endif
948 } else
949#endif
950 { battery_percent = voltage_to_percent(battery_centivolts,
951 percent_to_volt_discharge[battery_type]);
952 battery_percent += (battery_percent < 100);
953 }
954
752#if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL) 955#if defined(DEBUG_FILE) && (CONFIG_CHARGING == CHARGING_CONTROL)
753 fd = -1; 956 fd = -1;
754 wrcount = 0; 957 wrcount = 0;
@@ -954,7 +1157,7 @@ static void power_thread(void)
954 pid_p = pid_p * PID_PCONST; 1157 pid_p = pid_p * PID_PCONST;
955 else 1158 else
956 pid_p = 0; 1159 pid_p = 0;
957 if(battery_centivolts < target_voltage) { 1160 if((unsigned) battery_centivolts < target_voltage) {
958 if(pid_i < 60) { 1161 if(pid_i < 60) {
959 pid_i++; /* limit so it doesn't "wind up" */ 1162 pid_i++; /* limit so it doesn't "wind up" */
960 } 1163 }
@@ -1067,7 +1270,18 @@ void sys_poweroff(void)
1067 /* If the main thread fails to shut down the system, we will force a 1270 /* If the main thread fails to shut down the system, we will force a
1068 power off after an 20 second timeout */ 1271 power off after an 20 second timeout */
1069 shutdown_timeout = HZ*20; 1272 shutdown_timeout = HZ*20;
1070 1273#if defined(HAVE_RECORDING)
1274#if CONFIG_CODEC == SWCODEC
1275 unsigned int audio_stat = pcm_rec_status();
1276#else
1277 int audio_stat = audio_status();
1278#endif
1279 if (audio_stat & AUDIO_STATUS_RECORD) {
1280 audio_stop_recording();
1281 shutdown_timeout += 8*HZ;
1282 }
1283#endif
1284
1071 queue_post(&button_queue, SYS_POWEROFF, NULL); 1285 queue_post(&button_queue, SYS_POWEROFF, NULL);
1072} 1286}
1073 1287
@@ -1095,30 +1309,42 @@ void shutdown_hw(void)
1095 } 1309 }
1096#endif 1310#endif
1097 audio_stop(); 1311 audio_stop();
1312 if (!battery_level_critical()) { /* do not save on critical battery */
1098#ifdef HAVE_LCD_BITMAP 1313#ifdef HAVE_LCD_BITMAP
1099 glyph_cache_save(); 1314 glyph_cache_save();
1100#endif 1315#endif
1101 ata_spindown(1); 1316 if(ata_disk_is_active())
1317 ata_spindown(1);
1318 }
1102 while(ata_disk_is_active()) 1319 while(ata_disk_is_active())
1103 sleep(HZ/10); 1320 sleep(HZ/10);
1104 1321
1322#ifndef IAUDIO_X5
1323#if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
1324 backlight_set_fade_out(0);
1325#endif
1326 backlight_off();
1327#endif /* IAUDIO_X5 */
1328#ifdef HAVE_REMOTE_LCD
1329 remote_backlight_off();
1330#endif
1331
1105 mp3_shutdown(); 1332 mp3_shutdown();
1106#ifdef HAVE_UDA1380 1333#ifdef HAVE_UDA1380
1107 uda1380_close(); 1334 uda1380_close();
1108#elif defined(HAVE_TLV320) 1335#elif defined(HAVE_TLV320)
1109 tlv320_close(); 1336 tlv320_close();
1110#elif defined(HAVE_WM8758) || defined(HAVE_WM8975) 1337#elif defined(HAVE_WM8758) || defined(HAVE_WM8975) | defined(HAVE_WM8731)
1111 wmcodec_close(); 1338 wmcodec_close();
1112#endif 1339#endif
1340 /* If HD is still active we try to wait for spindown, otherwise the
1341 shutdown_timeout in power_thread_sleep will force a power off */
1342 while(ata_disk_is_active())
1343 sleep(HZ/10);
1113#ifndef IAUDIO_X5 1344#ifndef IAUDIO_X5
1114#if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
1115 backlight_set_fade_out(0);
1116#endif
1117 backlight_off();
1118 lcd_set_contrast(0); 1345 lcd_set_contrast(0);
1119#endif /* IAUDIO_X5 */ 1346#endif /* IAUDIO_X5 */
1120#ifdef HAVE_REMOTE_LCD 1347#ifdef HAVE_REMOTE_LCD
1121 remote_backlight_off();
1122 lcd_remote_set_contrast(0); 1348 lcd_remote_set_contrast(0);
1123#endif 1349#endif
1124 power_off(); 1350 power_off();
diff --git a/firmware/target/arm/iriver/h10/adc-h10.c b/firmware/target/arm/iriver/h10/adc-h10.c
index cf937851b9..8a4e24dd64 100755
--- a/firmware/target/arm/iriver/h10/adc-h10.c
+++ b/firmware/target/arm/iriver/h10/adc-h10.c
@@ -88,5 +88,11 @@ void adc_init(void)
88 adc_scan(ADC_REMOTE); 88 adc_scan(ADC_REMOTE);
89 adc_scan(ADC_SCROLLPAD); 89 adc_scan(ADC_SCROLLPAD);
90 90
91 /* FIXME: The ADC sometimes reads 0 for the battery
92 voltage for the first few seconds. It would be better to fix this by
93 figuring out how to use the ADC properly. Until then, work around the
94 problem by waiting until it reads a proper value*/
95 while(adc_scan(ADC_UNREG_POWER)==0);
96
91 tick_add_task(adc_tick); 97 tick_add_task(adc_tick);
92} 98}