Simplify powermgmt thread loops so it calls functions turn (no more power_thread_sleep). Do other target-friendly simplifications, generic battery switch handling and split sim-specific code. Whoever can, please verify charging on the Archos Recorder (due to change in the charger duty cycle code).

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19579 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2008-12-24 16:58:41 +00:00
parent 0f9729739f
commit 3157e13956
34 changed files with 1337 additions and 1124 deletions

View file

@ -1603,10 +1603,10 @@ static bool view_battery(void)
lcd_puts(0, 2, buf); lcd_puts(0, 2, buf);
#endif #endif
#if CONFIG_CHARGING #if CONFIG_CHARGING
#if CONFIG_CHARGING == CHARGING_CONTROL #if defined ARCHOS_RECORDER
snprintf(buf, 30, "Chgr: %s %s", snprintf(buf, 30, "Chgr: %s %s",
charger_inserted() ? "present" : "absent", charger_inserted() ? "present" : "absent",
charger_enabled ? "on" : "off"); charger_enabled() ? "on" : "off");
lcd_puts(0, 3, buf); lcd_puts(0, 3, buf);
snprintf(buf, 30, "short delta: %d", short_delta); snprintf(buf, 30, "short delta: %d", short_delta);
lcd_puts(0, 5, buf); lcd_puts(0, 5, buf);
@ -1616,13 +1616,11 @@ static bool view_battery(void)
snprintf(buf, 30, "USB Inserted: %s", snprintf(buf, 30, "USB Inserted: %s",
usb_inserted() ? "yes" : "no"); usb_inserted() ? "yes" : "no");
lcd_puts(0, 8, buf); lcd_puts(0, 8, buf);
#if defined IRIVER_H300_SERIES #elif defined IRIVER_H300_SERIES
snprintf(buf, 30, "USB Charging Enabled: %s", snprintf(buf, 30, "USB Charging Enabled: %s",
usb_charging_enabled() ? "yes" : "no"); usb_charging_enabled() ? "yes" : "no");
lcd_puts(0, 9, buf); lcd_puts(0, 9, buf);
#endif #elif defined IPOD_NANO || defined IPOD_VIDEO
#else /* CONFIG_CHARGING != CHARGING_CONTROL */
#if defined IPOD_NANO || defined IPOD_VIDEO
int usb_pwr = (GPIOL_INPUT_VAL & 0x10)?true:false; int usb_pwr = (GPIOL_INPUT_VAL & 0x10)?true:false;
int ext_pwr = (GPIOL_INPUT_VAL & 0x08)?false:true; int ext_pwr = (GPIOL_INPUT_VAL & 0x08)?false:true;
int dock = (GPIOA_INPUT_VAL & 0x10)?true:false; int dock = (GPIOA_INPUT_VAL & 0x10)?true:false;
@ -1644,12 +1642,8 @@ static bool view_battery(void)
snprintf(buf, 30, "Headphone: %s", snprintf(buf, 30, "Headphone: %s",
headphone ? "connected" : "disconnected"); headphone ? "connected" : "disconnected");
lcd_puts(0, 7, buf); lcd_puts(0, 7, buf);
#else #elif defined TOSHIBA_GIGABEAT_S
snprintf(buf, 30, "Charger: %s", int line = 3;
charger_inserted() ? "present" : "absent");
lcd_puts(0, 3, buf);
#if defined TOSHIBA_GIGABEAT_S
int line = 4;
unsigned int st; unsigned int st;
static const unsigned char * const chrgstate_strings[] = static const unsigned char * const chrgstate_strings[] =
@ -1663,6 +1657,10 @@ static bool view_battery(void)
"<unknown>", "<unknown>",
}; };
snprintf(buf, 30, "Charger: %s",
charger_inserted() ? "present" : "absent");
lcd_puts(0, line++, buf);
st = power_input_status() & st = power_input_status() &
(POWER_INPUT_CHARGER | POWER_INPUT_BATTERY); (POWER_INPUT_CHARGER | POWER_INPUT_BATTERY);
snprintf(buf, 30, "%s%s", snprintf(buf, 30, "%s%s",
@ -1730,9 +1728,11 @@ static bool view_battery(void)
} }
lcd_puts(0, line++, buf); lcd_puts(0, line++, buf);
#endif /* defined TOSHIBA_GIGABEAT_S */ #else
#endif /* defined IPOD_NANO || defined IPOD_VIDEO */ snprintf(buf, 30, "Charger: %s",
#endif /* CONFIG_CHARGING != CHARGING_CONTROL */ charger_inserted() ? "present" : "absent");
lcd_puts(0, 3, buf);
#endif /* target type */
#endif /* CONFIG_CHARGING */ #endif /* CONFIG_CHARGING */
break; break;
@ -1750,7 +1750,7 @@ static bool view_battery(void)
case 3: /* remaining time estimation: */ case 3: /* remaining time estimation: */
#if CONFIG_CHARGING == CHARGING_CONTROL #ifdef ARCHOS_RECORDER
snprintf(buf, 30, "charge_state: %d", charge_state); snprintf(buf, 30, "charge_state: %d", charge_state);
lcd_puts(0, 0, buf); lcd_puts(0, 0, buf);
@ -1765,7 +1765,7 @@ static bool view_battery(void)
snprintf(buf, 30, "Trickle sec: %d/60", trickle_sec); snprintf(buf, 30, "Trickle sec: %d/60", trickle_sec);
lcd_puts(0, 4, buf); lcd_puts(0, 4, buf);
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */ #endif /* ARCHOS_RECORDER */
snprintf(buf, 30, "Last PwrHist: %d.%03dV", snprintf(buf, 30, "Last PwrHist: %d.%03dV",
power_history[0] / 1000, power_history[0] / 1000,

View file

@ -27,6 +27,7 @@
#include "lang.h" #include "lang.h"
#include "action.h" #include "action.h"
#include "settings.h" #include "settings.h"
#include "power.h"
#include "powermgmt.h" #include "powermgmt.h"
#include "menu.h" #include "menu.h"
#include "misc.h" #include "misc.h"
@ -199,15 +200,14 @@ static char* info_getname(int selected_item, void *data,
if (charge_state == CHARGING) if (charge_state == CHARGING)
return (char *)str(LANG_BATTERY_CHARGE); return (char *)str(LANG_BATTERY_CHARGE);
else else
#if CONFIG_CHARGING == CHARGING_CONTROL #ifdef ARCHOS_RECORDER
if (charge_state == TOPOFF) if (charge_state == TOPOFF)
return (char *)str(LANG_BATTERY_TOPOFF_CHARGE); return (char *)str(LANG_BATTERY_TOPOFF_CHARGE);
else else if (charge_state == TRICKLE)
#endif
if (charge_state == TRICKLE)
return (char *)str(LANG_BATTERY_TRICKLE_CHARGE); return (char *)str(LANG_BATTERY_TRICKLE_CHARGE);
else else
#endif #endif /* ARCHOS_RECORDER */
#endif /* CONFIG_CHARGING = */
if (battery_level() >= 0) if (battery_level() >= 0)
snprintf(buffer, buffer_len, (char *)str(LANG_BATTERY_TIME), snprintf(buffer, buffer_len, (char *)str(LANG_BATTERY_TIME),
battery_level(), battery_time() / 60, battery_time() % 60); battery_level(), battery_time() / 60, battery_time() % 60);
@ -282,22 +282,21 @@ static int info_speak_item(int selected_item, void * data)
} }
case INFO_BATTERY: /* battery */ case INFO_BATTERY: /* battery */
#if CONFIG_CHARGING == CHARGING_SIMPLE #if CONFIG_CHARGING == CHARGING_SIMPLE
if (charger_input_state == CHARGER) if (charger_inserted())
talk_id(LANG_BATTERY_CHARGE, true); talk_id(LANG_BATTERY_CHARGE, true);
else else
#elif CONFIG_CHARGING >= CHARGING_MONITOR #elif CONFIG_CHARGING >= CHARGING_MONITOR
if (charge_state == CHARGING) if (charge_state == CHARGING)
talk_id(LANG_BATTERY_CHARGE, true); talk_id(LANG_BATTERY_CHARGE, true);
else else
#if CONFIG_CHARGING == CHARGING_CONTROL #ifdef ARCHOS_RECORDER
if (charge_state == TOPOFF) if (charge_state == TOPOFF)
talk_id(LANG_BATTERY_TOPOFF_CHARGE, true); talk_id(LANG_BATTERY_TOPOFF_CHARGE, true);
else else if (charge_state == TRICKLE)
#endif
if (charge_state == TRICKLE)
talk_id(LANG_BATTERY_TRICKLE_CHARGE, true); talk_id(LANG_BATTERY_TRICKLE_CHARGE, true);
else else
#endif #endif /* ARCHOS_RECORDER */
#endif /* CONFIG_CHARGING = */
if (battery_level() >= 0) if (battery_level() >= 0)
{ {
talk_id(LANG_BATTERY_TIME, false); talk_id(LANG_BATTERY_TIME, false);

View file

@ -209,8 +209,7 @@ static void charging_display_info(bool animate)
lcd_puts(0, 7, buf); lcd_puts(0, 7, buf);
} }
#if CONFIG_CHARGING == CHARGING_CONTROL #ifdef ARCHOS_RECORER
snprintf(buf, 32, "Charge mode:"); snprintf(buf, 32, "Charge mode:");
lcd_puts(0, 2, buf); lcd_puts(0, 2, buf);
@ -224,10 +223,9 @@ static void charging_display_info(bool animate)
snprintf(buf, 32, "not charging"); snprintf(buf, 32, "not charging");
lcd_puts(0, 3, buf); lcd_puts(0, 3, buf);
if (!charger_enabled) if (!charger_enabled())
animate = false; animate = false;
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */ #endif /* ARCHOS_RECORER */
/* middle part */ /* middle part */
memset(charging_logo+3, 0x00, 32); memset(charging_logo+3, 0x00, 32);

View file

@ -129,6 +129,11 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
/* define current usage levels */
#define CURRENT_NORMAL 45 /* Should be nearly identical to E200 */
#define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */
#define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/
/** Non-simulator section **/ /** Non-simulator section **/
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -123,6 +123,11 @@
/* Hardware controlled charging? FIXME */ /* Hardware controlled charging? FIXME */
#define CONFIG_CHARGING CHARGING_SIMPLE #define CONFIG_CHARGING CHARGING_SIMPLE
/* define current usage levels */
#define CURRENT_NORMAL 45 /* Mike's measurements in Jan 2008 */
#define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */
#define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER

View file

@ -110,9 +110,16 @@
#define BATTERY_TYPES_COUNT 1 /* only one type */ #define BATTERY_TYPES_COUNT 1 /* only one type */
/* Hardware controlled charging */ /* Hardware controlled charging */
//#define CONFIG_CHARGING CHARGING_SIMPLE
#define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */ #define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */
/* define current usage levels */
#define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */
#define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */
#define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */
#define CURRENT_RECORD 105 /* additional current while recording */
#define CURRENT_REMOTE 8 /* additional current when remote connected */
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a Motorola SCF5249 */ /* Define this if you have a Motorola SCF5249 */

View file

@ -110,9 +110,15 @@
#define BATTERY_TYPES_COUNT 1 /* only one type */ #define BATTERY_TYPES_COUNT 1 /* only one type */
/* Hardware controlled charging */ /* Hardware controlled charging */
//#define CONFIG_CHARGING CHARGING_SIMPLE
#define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */ #define CONFIG_CHARGING CHARGING_MONITOR /* FIXME: remove that once monitoring is fixed properly */
/* define current usage levels */
#define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */
#define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */
#define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */
#define CURRENT_RECORD 105 /* additional current while recording */
#define CURRENT_REMOTE 8 /* additional current when remote connected */
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a Motorola SCF5249 */ /* Define this if you have a Motorola SCF5249 */

View file

@ -112,6 +112,13 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
/* define current usage levels */
#define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery from IriverRuntime wiki page */
#define CURRENT_BACKLIGHT 23 /* FIXME: This needs to be measured, copied from H100 */
#define CURRENT_RECORD 110 /* additional current while recording */
#define CURRENT_MAX_CHG 650 /* maximum charging current */
#define CURRENT_REMOTE 8 /* additional current when remote connected */
/* define this if the unit can have USB charging disabled by user - /* define this if the unit can have USB charging disabled by user -
* if USB/MAIN power is discernable and hardware doesn't compel charging */ * if USB/MAIN power is discernable and hardware doesn't compel charging */
#define HAVE_USB_CHARGING_ENABLE #define HAVE_USB_CHARGING_ENABLE

View file

@ -102,6 +102,9 @@
/* Hardware controlled charging? FIXME */ /* Hardware controlled charging? FIXME */
#define CONFIG_CHARGING CHARGING_SIMPLE #define CONFIG_CHARGING CHARGING_SIMPLE
/* define current usage levels */
#define CURRENT_REMOTE 8 /* additional current when remote connected */
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if your LCD can set contrast */ /* Define this if your LCD can set contrast */

View file

@ -105,6 +105,9 @@
/* Hardware controlled charging? FIXME */ /* Hardware controlled charging? FIXME */
#define CONFIG_CHARGING CHARGING_SIMPLE #define CONFIG_CHARGING CHARGING_SIMPLE
/* define current usage levels */
#define CURRENT_REMOTE 8 /* additional current when remote connected */
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if your LCD can set contrast */ /* Define this if your LCD can set contrast */

View file

@ -122,6 +122,9 @@
/* Hardware controlled charging? FIXME */ /* Hardware controlled charging? FIXME */
#define CONFIG_CHARGING CHARGING_SIMPLE #define CONFIG_CHARGING CHARGING_SIMPLE
/* define current usage levels */
#define CURRENT_REMOTE 8 /* additional current when remote connected */
#ifndef SIMULATOR #ifndef SIMULATOR
/* define this if the backlight thread is used for fade, not for sim, needs /* define this if the backlight thread is used for fade, not for sim, needs

View file

@ -120,6 +120,13 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
/* define current usage levels */
#define CURRENT_NORMAL 100 /* MP3: ~10.5h out of 1100mAh battery */
#define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */
#if defined(HAVE_RECORDING)
#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a PortalPlayer PP5020 */ /* Define this if you have a PortalPlayer PP5020 */

View file

@ -115,6 +115,12 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
#define CURRENT_NORMAL 32 /* MP3: ~9h playback out of 300mAh battery */
#define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */
#if defined(HAVE_RECORDING)
#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a PortalPlayer PP5022 */ /* Define this if you have a PortalPlayer PP5022 */

View file

@ -123,6 +123,13 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
/* define current usage levels */
#define CURRENT_NORMAL 35 /* MP3: ~11h out of 400mAh battery (30GB) or ~17h out of 600mAh (60GB) */
#define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */
#if defined(HAVE_RECORDING)
#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a PortalPlayer PP5022 */ /* Define this if you have a PortalPlayer PP5022 */

View file

@ -69,6 +69,11 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
/* define current usage levels */
#define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */
#define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */
#define CURRENT_BACKLIGHT 0 /* no backlight */
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a SH7034 */ /* Define this if you have a SH7034 */

View file

@ -58,6 +58,11 @@
/* define this if the unit can be powered or charged via USB */ /* define this if the unit can be powered or charged via USB */
#define HAVE_USB_POWER #define HAVE_USB_POWER
/* define current usage levels */
#define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */
#define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */
#define CURRENT_BACKLIGHT 0 /* no backlight */
#ifndef SIMULATOR #ifndef SIMULATOR
/* Define this if you have a SH7034 */ /* Define this if you have a SH7034 */

View file

@ -72,7 +72,7 @@
#define NO_LOW_BATTERY_SHUTDOWN #define NO_LOW_BATTERY_SHUTDOWN
/* Software controlled charging */ /* Software controlled charging */
#define CONFIG_CHARGING CHARGING_CONTROL #define CONFIG_CHARGING CHARGING_TARGET
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -114,11 +114,13 @@
#define X5_REMOTE 3 #define X5_REMOTE 3
/* CONFIG_CHARGING */ /* CONFIG_CHARGING */
/* Generic types */
#define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */ #define CHARGING_SIMPLE 1 /* Simple, hardware controlled charging */
#define CHARGING_MONITOR 2 /* Hardware controlled charging with monitoring */ #define CHARGING_MONITOR 2 /* Hardware controlled charging with monitoring */
#define CHARGING_CONTROL 3 /* Software controlled charging */
#define CHARGING_TARGET 4 /* Anything the target implements that is not /* Mostly target-specific code in the /target tree */
a generic implementation */ #define CHARGING_TARGET 3
/* CONFIG_LCD */ /* CONFIG_LCD */
#define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ #define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */

View file

@ -21,11 +21,6 @@
#ifndef _POWER_H_ #ifndef _POWER_H_
#define _POWER_H_ #define _POWER_H_
#if CONFIG_CHARGING == CHARGING_CONTROL
extern bool charger_enabled;
void charger_enable(bool on);
#endif
#if CONFIG_CHARGING #if CONFIG_CHARGING
enum power_input_flags { enum power_input_flags {
/* No external power source? Default. */ /* No external power source? Default. */
@ -82,9 +77,9 @@ bool power_input_present(void);
void power_off(void); void power_off(void);
void ide_power_enable(bool on); void ide_power_enable(bool on);
# if CONFIG_CHARGING == CHARGING_MONITOR #if CONFIG_CHARGING >= CHARGING_MONITOR
bool charging_state(void); bool charging_state(void);
# endif #endif
#ifndef SIMULATOR #ifndef SIMULATOR
@ -102,4 +97,4 @@ bool spdif_powered(void);
bool tuner_power(bool status); bool tuner_power(bool status);
#endif #endif
#endif #endif /* _POWER_H_ */

View file

@ -25,149 +25,103 @@
#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 CHARGE_END_SHORTD 6 /* stop when N minutes have passed with enum charge_state_type
* avg delta being < -0.05 V */ {
#define CHARGE_END_LONGD 50 /* stop when N minutes have passed with /* sorted by increasing charging current */
* avg delta being < -0.02 V */
typedef enum { /* sorted by increasing charging current */
#if CONFIG_CHARGING >= CHARGING_MONITOR #if CONFIG_CHARGING >= CHARGING_MONITOR
CHARGE_STATE_DISABLED = -2, /* Disable charger use */ CHARGE_STATE_DISABLED = -2, /* Disable charger use (safety measure) */
CHARGE_STATE_ERROR = -1, /* Some error occurred that should not allow CHARGE_STATE_ERROR = -1, /* Some error occurred that should not allow
further attempts without user intervention */ turning on the charger again by software
without user intervention (ie. replug) */
#endif #endif
DISCHARGING = 0, DISCHARGING = 0,
#if CONFIG_CHARGING >= CHARGING_MONITOR #if CONFIG_CHARGING >= CHARGING_MONITOR
TRICKLE, /* Can occur for CONFIG_CHARGING >= CHARGING_MONITOR */ TRICKLE, /* For NiCd, battery maintenence phase */
/* For LiIon, the low-current precharge mode if battery /* For LiIon, low-current precharge phase */
was very low */ TOPOFF, /* For NiCd, waiting for dead zone */
TOPOFF, /* Can occur for CONFIG_CHARGING == CHARGING_CONTROL */
/* For LiIon, constant voltage phase */ /* For LiIon, constant voltage phase */
CHARGING, /* Can occur for all CONFIG_CHARGING options */ CHARGING, /* For NiCd, main charge phase */
/* For LiIon, the constant current phase */ /* For LiIon, constant current phase */
#endif #endif
} charge_state_type; };
/* tells what the charger is doing */ /* tells what the charger is doing */
extern charge_state_type charge_state; extern enum charge_state_type charge_state;
#ifdef CONFIG_CHARGING #ifdef CONFIG_CHARGING
/* /*
* Flag that the charger has been plugged in/removed: this is set for exactly * Flag that the charger has been plugged in/removed: this is set for exactly
* one time through the power loop when the charger has been plugged in. * one time through the power loop when the charger has been plugged in.
*/ */
typedef enum { enum charger_input_state_type
{
NO_CHARGER = 0, /* No charger is present */ NO_CHARGER = 0, /* No charger is present */
CHARGER_UNPLUGGED, /* Transitional state during CHARGER=>NO_CHARGER */ CHARGER_UNPLUGGED, /* Transitional state during CHARGER=>NO_CHARGER */
CHARGER_PLUGGED, /* Transitional state during NO_CHARGER=>CHARGER */ CHARGER_PLUGGED, /* Transitional state during NO_CHARGER=>CHARGER */
CHARGER /* Charger is present */ CHARGER /* Charger is present */
} charger_input_state_type; };
/* tells the state of the charge input */ /* tells the state of the charge input */
extern charger_input_state_type charger_input_state; extern enum charger_input_state_type charger_input_state;
#endif
#ifndef SIMULATOR /* Power input status saved on the power thread each loop */
extern unsigned int power_thread_inputs;
#if CONFIG_CHARGING == CHARGING_CONTROL #endif /* CONFIG_CHARGING */
#define START_TOPOFF_CHG 85 /* Battery % to start at top-off */
#define START_TRICKLE_CHG 95 /* Battery % to start at trickle */
#define POWER_MESSAGE_LEN 32 /* power thread status message */
#define CHARGE_MAX_TIME_1500 450 /* minutes: maximum charging time for 1500 mAh batteries */
/* actual max time depends also on BATTERY_CAPACITY! */
#define CHARGE_MIN_TIME 10 /* minutes: minimum charging time */
#define TOPOFF_MAX_TIME 90 /* After charging, go to top off charge. How long should top off charge be? */
#define TOPOFF_VOLTAGE 5650 /* which voltage is best? (millivolts) */
#define TRICKLE_MAX_TIME 12*60 /* After top off charge, go to trickle charge. How long should trickle charge be? */
#define TRICKLE_VOLTAGE 5450 /* which voltage is best? (millivolts) */
#define START_TOPOFF_SEC 25 /* initial trickle_sec for topoff */
#define START_TRICKLE_SEC 15 /* initial trickle_sec for trickle */
#define PID_DEADZONE 4 /* PID proportional deadzone */
extern char power_message[POWER_MESSAGE_LEN];
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_level; /* which level had the batteries at this time? */
extern int pid_p; /* PID proportional term */
extern int pid_i; /* PID integral term */
extern int trickle_sec; /* trickle charge: How many seconds per minute are we charging actually? */
#endif /* CONFIG_CHARGING == CHARGING_CONTROL */
#if defined(ARCHOS_ONDIOSP) || defined(ARCHOS_ONDIOFM) /* Values for Ondio */
# define CURRENT_NORMAL 95 /* average, nearly proportional to 1/U */
# define CURRENT_USB 1 /* host powered in USB mode; avoid zero-div */
# define CURRENT_BACKLIGHT 0 /* no backlight */
#else /* Values for HD based jukeboxes */
#ifdef IRIVER_H100_SERIES
# define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery */
# define CURRENT_BACKLIGHT 23 /* from IriverBattery twiki page */
# define CURRENT_SPDIF_OUT 10 /* optical SPDIF output on */
# define CURRENT_RECORD 105 /* additional current while recording */
#elif defined(IRIVER_H300_SERIES)
# define CURRENT_NORMAL 80 /* 16h playback on 1300mAh battery from IriverRuntime wiki page */
# define CURRENT_BACKLIGHT 23 /* FIXME: This needs to be measured, copied from H100 */
# define CURRENT_RECORD 110 /* additional current while recording */
#elif defined(IPOD_NANO) /* iPOD Nano */
# define CURRENT_NORMAL 32 /* MP3: ~9h playback out of 300mAh battery */
# define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */
#if defined(HAVE_RECORDING)
# define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#elif defined(IPOD_VIDEO) /* iPOD Video */
# define CURRENT_NORMAL 35 /* MP3: ~11h out of 400mAh battery (30GB) or ~17h out of 600mAh (60GB) */
# define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */
#if defined(HAVE_RECORDING)
# define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#elif defined(SANSA_E200) /* Sandisk E200v1 */
# define CURRENT_NORMAL 45 /* Mike's measurements in Jan 2008 */
# define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */
# define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/
#elif defined(SANSA_C200) /* Sandisk C200v1 */
# define CURRENT_NORMAL 45 /* Should be nearly identical to E200 */
# define CURRENT_BACKLIGHT 40 /* Screen is about 20, blue LEDs are another 20, so 40 if both */
# define CURRENT_RECORD 40 /* flash player, so this is just unboosted current*/
#elif defined(IPOD_4G) /* iPOD 4G */
# define CURRENT_NORMAL 100 /* MP3: ~10.5h out of 1100mAh battery */
# define CURRENT_BACKLIGHT 20 /* FIXME: this needs adjusting */
#if defined(HAVE_RECORDING)
# define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#else /* Not iriver H1x0, H3x0, nor Archos Ondio, nor iPod nano/Video/4G, nor Sansas */
# define CURRENT_NORMAL 145 /* usual current in mA when using the AJB including some disk/backlight/... activity */
# define CURRENT_BACKLIGHT 30 /* additional current when backlight always on */
#if defined(HAVE_RECORDING)
# define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
#endif
#endif /* Not Archos Ondio */
#define CURRENT_USB 500 /* usual current in mA in USB mode */
#ifdef HAVE_REMOTE_LCD
# define CURRENT_REMOTE 8 /* add. current when H100-remote connected */
#endif /* HAVE_REMOTE_LCD */
# define CURRENT_MIN_CHG 70 /* minimum charge current */
# define MIN_CHG_V 8500 /* at 8.5v charger voltage get CURRENT_MIN_CHG */
# ifdef IRIVER_H300_SERIES
# define CURRENT_MAX_CHG 650 /* maximum charging current */
# else
# define CURRENT_MAX_CHG 350 /* maximum charging current */
# endif
# define MAX_CHG_V 10250 /* anything over 10.25v gives CURRENT_MAX_CHG */
#endif /* not ONDIO */
#if CONFIG_CHARGING == CHARGING_TARGET #if CONFIG_CHARGING == CHARGING_TARGET
/* Include target-specific definitions */ /* Include target-specific definitions */
#include "powermgmt-target.h" #include "powermgmt-target.h"
#endif #endif
#ifndef SIMULATOR
/* Generic current values that are really rather meaningless - config header
* should define proper numbers. */
#ifndef CURRENT_NORMAL
#define CURRENT_NORMAL 145 /* usual current in mA */
#endif
#ifndef CURRENT_BACKLIGHT
#define CURRENT_BACKLIGHT 30 /* additional current when backlight always on */
#endif
#ifdef HAVE_RECORDING
#ifndef CURRENT_RECORD
#define CURRENT_RECORD 35 /* additional recording current */
#endif
#endif /* HAVE_RECORDING */
#ifndef CURRENT_USB
#define CURRENT_USB 500 /* usual current in mA in USB mode */
#endif
#ifdef HAVE_REMOTE_LCD
#define CURRENT_REMOTE 8 /* additional current when remote connected */
#endif /* HAVE_REMOTE_LCD */
#if CONFIG_CHARGING
#ifndef CURRENT_MAX_CHG
#define CURRENT_MAX_CHG 350 /* maximum charging current */
#endif
#endif /* CONFIG_CHARGING */
#ifdef CHARGING_DEBUG_FILE
#define POWERMGMT_DEBUG_STACK ((0x1000)/sizeof(long))
#else
#define POWERMGMT_DEBUG_STACK 0
#endif
#ifndef BATT_AVE_SAMPLES
/* slw filter constant unless otherwise specified */
#define BATT_AVE_SAMPLES 128
#endif
#ifndef POWER_THREAD_STEP_TICKS
/* 2HZ sample rate unless otherwise specified */
#define POWER_THREAD_STEP_TICKS (HZ/2)
#endif
extern unsigned short power_history[POWER_HISTORY_LEN]; extern unsigned short power_history[POWER_HISTORY_LEN];
extern const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT]; extern const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT];
extern const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT]; extern const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT];
@ -179,12 +133,6 @@ extern const unsigned short percent_to_volt_charge[11];
/* Start up power management thread */ /* Start up power management thread */
void powermgmt_init(void); void powermgmt_init(void);
/* Do target portion of init (for CHARGING_TARGET) - called on power thread */
void powermgmt_init_target(void);
/* Handle frequent tasks and call charging_algorithm_small_step */
void power_thread_sleep(int ticks);
#endif /* SIMULATOR */ #endif /* SIMULATOR */
/* Returns battery statust */ /* Returns battery statust */
@ -193,9 +141,15 @@ int battery_time(void); /* minutes */
unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */ unsigned int battery_adc_voltage(void); /* voltage from ADC in millivolts */
unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */ unsigned int battery_voltage(void); /* filtered batt. voltage in millivolts */
#ifdef HAVE_BATTERY_SWITCH
unsigned int input_millivolts(void); /* voltage that device is running from */
/* Set the filtered battery voltage (to adjust it before beginning a charge /* Set the filtered battery voltage (to adjust it before beginning a charge
cycle for instance where old, loaded readings will likely be invalid). */ * cycle for instance where old, loaded readings will likely be invalid).
void set_filtered_battery_voltage(int millivolts); * Also readjust when battery switch is opened or closed.
*/
void reset_battery_filter(int millivolts);
#endif /* HAVE_BATTERY_SWITCH */
/* read unfiltered battery info */ /* read unfiltered battery info */
void battery_read_info(int *voltage, int *level); void battery_read_info(int *voltage, int *level);
@ -203,12 +157,9 @@ void battery_read_info(int *voltage, int *level);
/* Tells if the battery level is safe for disk writes */ /* Tells if the battery level is safe for disk writes */
bool battery_level_safe(void); bool battery_level_safe(void);
#ifdef TARGET_POWERMGMT_FILTER_CHARGE_STATE
int powermgmt_filter_charge_state(void);
#endif
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 */
int get_battery_capacity(void); /* get 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);

File diff suppressed because it is too large Load diff

View file

@ -168,7 +168,7 @@ int battery_adc_temp(void)
/* All code has a preference for the main charger being connected over /* All code has a preference for the main charger being connected over
* USB. USB is considered in the algorithm only if it is the sole source. */ * USB. USB is considered in the algorithm only if it is the sole source. */
static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */ static uint32_t int_sense0 = 0; /* Interrupt Sense 0 bits */
static unsigned int power_status = POWER_INPUT_NONE; /* Detect input changes */ static unsigned int last_inputs = POWER_INPUT_NONE; /* Detect input changes */
static int charger_total_timer = 0; /* Total allowed charging time */ static int charger_total_timer = 0; /* Total allowed charging time */
static int icharger_ave = 0; /* Filtered charging current */ static int icharger_ave = 0; /* Filtered charging current */
static bool charger_close = false; /* Shutdown notification */ static bool charger_close = false; /* Shutdown notification */
@ -181,7 +181,7 @@ static int autorecharge_counter = 0 ; /* Battery < threshold debounce */
static int chgcurr_timer = 0; /* Countdown to CHGCURR error */ static int chgcurr_timer = 0; /* Countdown to CHGCURR error */
#define AUTORECHARGE_COUNTDOWN (10*2) /* 10s debounce */ #define AUTORECHARGE_COUNTDOWN (10*2) /* 10s debounce */
#define WATCHDOG_TIMEOUT (10*2) /* If not serviced, poweroff in 10s */ #define WATCHDOG_TIMEOUT (10*2) /* If not serviced, poweroff in 10s */
#define CHGCURR_TIMEOUT (2*2) /* 2s debounce */ #define CHGCURR_TIMEOUT (4*2) /* 4s debounce */
/* Temperature monitoring */ /* Temperature monitoring */
static enum static enum
@ -217,7 +217,7 @@ static bool charger_current_filter_step(void)
/* Return true if the main charger is connected. */ /* Return true if the main charger is connected. */
static bool main_charger_connected(void) static bool main_charger_connected(void)
{ {
return (power_status & return (last_inputs &
POWER_INPUT_MAIN_CHARGER & POWER_INPUT_MAIN_CHARGER &
POWER_INPUT_CHARGER) != 0; POWER_INPUT_CHARGER) != 0;
} }
@ -233,16 +233,14 @@ static unsigned int auto_recharge_voltage(void)
return BATT_USB_VAUTO_RECHARGE; return BATT_USB_VAUTO_RECHARGE;
} }
#ifndef NO_LOW_BATTERY_SHUTDOWN
/* Return greater of supply (BP) or filtered battery voltage. */ /* Return greater of supply (BP) or filtered battery voltage. */
static unsigned int input_millivolts(void) unsigned int input_millivolts(void)
{ {
unsigned int app_millivolts = application_supply_adc_voltage(); unsigned int app_millivolts = application_supply_adc_voltage();
unsigned int bat_millivolts = battery_voltage(); unsigned int bat_millivolts = battery_voltage();
return MAX(app_millivolts, bat_millivolts); return MAX(app_millivolts, bat_millivolts);
} }
#endif
/* Get smoothed readings for initializing filtered data. */ /* Get smoothed readings for initializing filtered data. */
static int stat_battery_reading(int type) static int stat_battery_reading(int type)
@ -292,7 +290,7 @@ static bool update_filtered_battery_voltage(void)
if (millivolts != INT_MIN) if (millivolts != INT_MIN)
{ {
set_filtered_battery_voltage(millivolts); reset_battery_filter(millivolts);
return true; return true;
} }
@ -357,13 +355,13 @@ static bool adjust_charger_current(void)
int usb_select; int usb_select;
uint32_t i; uint32_t i;
usb_select = ((power_status & POWER_INPUT) == POWER_INPUT_USB) usb_select = ((last_inputs & POWER_INPUT) == POWER_INPUT_USB)
? 1 : 0; ? 1 : 0;
if (charge_state == DISCHARGING && usb_select == 1) if (charge_state == DISCHARGING && usb_select == 1)
{ {
/* USB-only, DISCHARGING, = maintaining battery */ /* USB-only, DISCHARGING, = maintaining battery */
int select = (power_status & POWER_INPUT_CHARGER) ? 0 : 1; int select = (last_inputs & POWER_INPUT_CHARGER) ? 0 : 1;
charger_setting = charger_bits[CHARGING+1][select]; charger_setting = charger_bits[CHARGING+1][select];
} }
else else
@ -458,7 +456,7 @@ static bool charging_ok(void)
if (ok) if (ok)
{ {
/* Is the battery even connected? */ /* Is the battery even connected? */
ok = (power_status & POWER_INPUT_BATTERY) != 0; ok = (last_inputs & POWER_INPUT_BATTERY) != 0;
} }
if (ok) if (ok)
@ -591,20 +589,6 @@ void powermgmt_init_target(void)
#endif #endif
} }
/* Returns CHARGING or DISCHARGING since that's all we really do. */
int powermgmt_filter_charge_state(void)
{
switch(charge_state)
{
case TRICKLE:
case TOPOFF:
case CHARGING:
return CHARGING;
default:
return DISCHARGING;
}
}
/* Returns true if the unit is charging the batteries. */ /* Returns true if the unit is charging the batteries. */
bool charging_state(void) bool charging_state(void)
{ {
@ -625,24 +609,6 @@ int battery_charge_current(void)
return icharger_ave / ICHARGER_AVE_SAMPLES; return icharger_ave / ICHARGER_AVE_SAMPLES;
} }
bool query_force_shutdown(void)
{
#ifndef NO_LOW_BATTERY_SHUTDOWN
return input_millivolts() < battery_level_shutoff[0];
#else
return false;
#endif
}
bool battery_level_safe(void)
{
#ifndef NO_LOW_BATTERY_SHUTDOWN
return input_millivolts() > battery_level_dangerous[0];
#else
return true;
#endif
}
static void charger_plugged(void) static void charger_plugged(void)
{ {
adc_enable_channel(ADC_BATTERY_TEMP, true); adc_enable_channel(ADC_BATTERY_TEMP, true);
@ -662,7 +628,7 @@ static void charger_unplugged(void)
} }
/* Might need to reevaluate these bits in charger_none. */ /* Might need to reevaluate these bits in charger_none. */
power_status &= ~(POWER_INPUT | POWER_INPUT_CHARGER); last_inputs &= ~(POWER_INPUT | POWER_INPUT_CHARGER);
temp_state = TEMP_STATE_NORMAL; temp_state = TEMP_STATE_NORMAL;
autorecharge_counter = 0; autorecharge_counter = 0;
chgcurr_timer = 0; chgcurr_timer = 0;
@ -672,15 +638,11 @@ static void charger_unplugged(void)
static void charger_none(void) static void charger_none(void)
{ {
unsigned int pwr = power_input_status(); unsigned int pwr = power_thread_inputs;
if (power_status != pwr) if (last_inputs != pwr)
{ {
/* If battery switch state changed, reset filter. */ last_inputs = pwr;
if ((power_status ^ pwr) & POWER_INPUT_BATTERY)
update_filtered_battery_voltage();
power_status = pwr;
if (charge_state == CHARGE_STATE_DISABLED) if (charge_state == CHARGE_STATE_DISABLED)
return; return;
@ -696,7 +658,7 @@ static void charger_none(void)
else else
{ {
charger_unplugged(); charger_unplugged();
power_status = pwr; /* Restore status */ last_inputs = pwr; /* Restore status */
} }
} }
else if (charger_setting != 0) else if (charger_setting != 0)
@ -716,17 +678,13 @@ static void charger_none(void)
static void charger_control(void) static void charger_control(void)
{ {
unsigned int pwr = power_input_status(); unsigned int pwr = power_thread_inputs;
if (power_status != pwr) if (last_inputs != pwr)
{ {
unsigned int changed = power_status ^ pwr; unsigned int changed = last_inputs ^ pwr;
power_status = pwr; last_inputs = pwr;
/* If battery switch state changed, reset filter. */
if (changed & POWER_INPUT_BATTERY)
update_filtered_battery_voltage();
if (charger_setting != 0) if (charger_setting != 0)
charger_setting = CHARGER_ADJUST; charger_setting = CHARGER_ADJUST;
@ -771,12 +729,11 @@ static void charger_control(void)
{ {
/* Battery voltage may have dropped and a charge cycle should /* Battery voltage may have dropped and a charge cycle should
* start again. Debounced. */ * start again. Debounced. */
if (autorecharge_counter < 0) if (autorecharge_counter < 0 &&
battery_adc_voltage() < BATT_FULL_VOLTAGE)
{ {
/* Try starting a cycle now regardless of battery level to /* Try starting a cycle now if battery isn't already topped
* allow user to ensure the battery is topped off. It * off to allow user to ensure the battery is full. */
* will soon turn off if already full. */
autorecharge_counter = 0;
} }
else if (battery_voltage() > auto_recharge_voltage()) else if (battery_voltage() > auto_recharge_voltage())
{ {
@ -791,6 +748,8 @@ static void charger_control(void)
break; break;
} }
autorecharge_counter = 0;
charging_set_thread_priority(true); charging_set_thread_priority(true);
if (stat_battery_reading(ADC_BATTERY) < BATT_VTRICKLE_CHARGE) if (stat_battery_reading(ADC_BATTERY) < BATT_VTRICKLE_CHARGE)
@ -858,10 +817,12 @@ static void charger_control(void)
} }
/* Main charging algorithm - called from powermgmt.c */ /* Main charging algorithm - called from powermgmt.c */
void charging_algorithm_small_step(void) void charging_algorithm_step(void)
{ {
#ifdef IMX31_ALLOW_CHARGING
if (service_wdt) if (service_wdt)
watchdog_service(); watchdog_service();
#endif
/* Switch by input state */ /* Switch by input state */
switch (charger_input_state) switch (charger_input_state)
@ -909,12 +870,6 @@ void charging_algorithm_small_step(void)
} }
} }
void charging_algorithm_big_step(void)
{
/* Sleep for one minute */
power_thread_sleep(HZ*60);
}
/* Disable the charger and prepare for poweroff - called off-thread so we /* Disable the charger and prepare for poweroff - called off-thread so we
* signal the charging thread to prepare to quit. */ * signal the charging thread to prepare to quit. */
void charging_algorithm_close(void) void charging_algorithm_close(void)

View file

@ -53,6 +53,7 @@
#define BATT_VTRICKLE_CHARGE 2900 /* Must charge slowly */ #define BATT_VTRICKLE_CHARGE 2900 /* Must charge slowly */
#define BATT_VSLOW_CHARGE 3500 /* Lower-current charge mode below #define BATT_VSLOW_CHARGE 3500 /* Lower-current charge mode below
* this level */ * this level */
#define BATT_FULL_VOLTAGE 4161 /* Battery already topped */
#define BATT_VAUTO_RECHARGE 4100 /* When to begin another cycle */ #define BATT_VAUTO_RECHARGE 4100 /* When to begin another cycle */
#define BATT_USB_VAUTO_RECHARGE 4000 /* When to cycle with USB only */ #define BATT_USB_VAUTO_RECHARGE 4000 /* When to cycle with USB only */
#define BATT_USB_VSTOP 4140 /* When to "stop" when USB only */ #define BATT_USB_VSTOP 4140 /* When to "stop" when USB only */
@ -92,23 +93,13 @@
#define BATT_AVE_SAMPLES 32 #define BATT_AVE_SAMPLES 32
#define ICHARGER_AVE_SAMPLES 32 #define ICHARGER_AVE_SAMPLES 32
void powermgmt_init_target(void);
void charging_algorithm_step(void);
void charging_algorithm_close(void);
/* Provide filtered charge current */ /* Provide filtered charge current */
int battery_charge_current(void); int battery_charge_current(void);
#ifndef SIMULATOR #define CURRENT_MAX_CHG battery_charge_current()
/* Indicate various functions that require implementation at the target level.
* This is because the battery could be low or the battery switch is off but
* with the main charger attached which implies safe power for anything. The
* true battery reading is always reported for voltage readings and not the
* value at the application supply. */
#define TARGET_QUERY_FORCE_SHUTDOWN
/* For this the application supply is read out if the charger is attached or
* the battery read if not (completely hardware selected at BP). */
#define TARGET_BATTERY_LEVEL_SAFE
/* The state should be adjusted to CHARGING or DISCHARGING */
#define TARGET_POWERMGMT_FILTER_CHARGE_STATE
#endif /* SIMULATOR */
#endif /* POWERMGMT_TARGET_H */ #endif /* POWERMGMT_TARGET_H */

View file

@ -33,10 +33,6 @@
#include "logf.h" #include "logf.h"
#include "usb.h" #include "usb.h"
#if CONFIG_CHARGING == CHARGING_CONTROL
bool charger_enabled;
#endif
#if CONFIG_TUNER #if CONFIG_TUNER
bool tuner_power(bool status) bool tuner_power(bool status)

View file

@ -29,10 +29,6 @@
#include "logf.h" #include "logf.h"
#include "usb.h" #include "usb.h"
#if CONFIG_CHARGING == CHARGING_CONTROL
bool charger_enabled;
#endif
void power_init(void) void power_init(void)
{ {
/* Enable power-off bit */ /* Enable power-off bit */

View file

@ -29,10 +29,6 @@
#include "logf.h" #include "logf.h"
#include "usb.h" #include "usb.h"
#if CONFIG_CHARGING == CHARGING_CONTROL
bool charger_enabled;
#endif
void power_init(void) void power_init(void)
{ {
/* power off bit */ /* power off bit */

View file

@ -19,9 +19,10 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
#include "config.h" #include "config.h"
#include "system.h"
#include "adc.h" #include "adc.h"
#include "power.h"
#include "powermgmt.h" #include "powermgmt.h"
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
@ -58,3 +59,17 @@ unsigned int battery_adc_voltage(void)
return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10;
} }
unsigned int input_millivolts(void)
{
unsigned int batt_millivolts = battery_voltage();
if ((power_thread_inputs & POWER_INPUT_BATTERY) == 0) {
/* Just return a safe value if battery isn't connected */
return 4050;
}
return batt_millivolts;
}

View file

@ -33,10 +33,6 @@
#include "logf.h" #include "logf.h"
#include "usb.h" #include "usb.h"
#if CONFIG_CHARGING == CHARGING_CONTROL
bool charger_enabled;
#endif
void power_init(void) void power_init(void)
{ {
} }

View file

@ -25,9 +25,10 @@
#include "kernel.h" #include "kernel.h"
#include "system.h" #include "system.h"
#include "power.h" #include "power.h"
#include "powermgmt-target.h"
#include "usb.h" #include "usb.h"
bool charger_enabled; static bool charger_on;
void power_init(void) void power_init(void)
{ {
@ -48,13 +49,18 @@ void charger_enable(bool on)
if(on) if(on)
{ {
and_b(~0x20, &PBDRL); and_b(~0x20, &PBDRL);
charger_enabled = 1;
} }
else else
{ {
or_b(0x20, &PBDRL); or_b(0x20, &PBDRL);
charger_enabled = 0;
} }
charger_on = on;
}
bool charger_enabled(void)
{
return charger_on;
} }
void ide_power_enable(bool on) void ide_power_enable(bool on)

View file

@ -19,9 +19,13 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
#include "config.h" #include "config.h"
#include "system.h"
#include <sprintf.h>
#include "debug.h"
#include "storage.h"
#include "adc.h" #include "adc.h"
#include "power.h"
#include "powermgmt.h" #include "powermgmt.h"
const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
@ -60,3 +64,434 @@ unsigned int battery_adc_voltage(void)
{ {
return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10; return (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) >> 10;
} }
/** Charger control **/
#ifdef CHARGING_DEBUG_FILE
#include "file.h"
#define DEBUG_FILE_NAME "/powermgmt.csv"
#define DEBUG_MESSAGE_LEN 133
static char debug_message[DEBUG_MESSAGE_LEN];
static int fd = -1; /* write debug information to this file */
static int wrcount = 0;
#endif /* CHARGING_DEBUG_FILE */
/*
* For a complete description of the charging algorithm read
* docs/CHARGING_ALGORITHM.
*/
int long_delta; /* long term delta battery voltage */
int short_delta; /* short term delta battery voltage */
bool disk_activity_last_cycle = false; /* flag set to aid charger time
* calculation */
char power_message[POWER_MESSAGE_LEN] = ""; /* message that's shown in
debug menu */
/* percentage at which charging
starts */
int powermgmt_last_cycle_startstop_min = 0; /* how many minutes ago was the
charging started or
stopped? */
int powermgmt_last_cycle_level = 0; /* which level had the
batteries at this time? */
int trickle_sec = 0; /* how many seconds should the
charger be enabled per
minute for trickle
charging? */
int pid_p = 0; /* PID proportional term */
int pid_i = 0; /* PID integral term */
static unsigned int target_voltage = TRICKLE_VOLTAGE; /* desired topoff/trickle
* voltage level */
static int charge_max_time_idle = 0; /* max. charging duration, calculated at
* beginning of charging */
static int charge_max_time_now = 0; /* max. charging duration including
* hdd activity */
static int minutes_disk_activity = 0; /* count minutes of hdd use during
* charging */
static int last_disk_activity = CHARGE_END_LONGD + 1; /* last hdd use x mins ago */
#ifdef CHARGING_DEBUG_FILE
static void debug_file_close(void)
{
if (fd >= 0) {
close(fd);
fd = -1;
}
}
static void debug_file_log(void)
{
if (usb_inserted()) {
/* It is probably too late to close the file but we can try... */
debug_file_close();
}
else if (fd < 0) {
fd = open(DEBUG_FILE_NAME, O_WRONLY | O_APPEND | O_CREAT);
if (fd >= 0) {
snprintf(debug_message, DEBUG_MESSAGE_LEN,
"cycle_min, bat_millivolts, bat_percent, chgr_state"
" ,charge_state, pid_p, pid_i, trickle_sec\n");
write(fd, debug_message, strlen(debug_message));
wrcount = 99; /* force a flush */
}
}
else {
snprintf(debug_message, DEBUG_MESSAGE_LEN,
"%d, %d, %d, %d, %d, %d, %d, %d\n",
powermgmt_last_cycle_startstop_min, battery_voltage(),
battery_level(), charger_input_state, charge_state,
pid_p, pid_i, trickle_sec);
write(fd, debug_message, strlen(debug_message));
wrcount++;
}
}
static void debug_file_sync(void)
{
/*
* If we have a lot of pending writes or if the disk is spining,
* fsync the debug log file.
*/
if (wrcount > 10 || (wrcount > 0 && storage_disk_is_active())) {
if (fd >= 0)
fsync(fd);
wrcount = 0;
}
}
#else /* !CHARGING_DEBUG_FILE */
#define debug_file_close()
#define debug_file_log()
#define debug_file_sync()
#endif /* CHARGING_DEBUG_FILE */
/*
* Do tasks that should be done every step.
*/
static void do_frequent_tasks(void)
{
if (storage_disk_is_active()) {
/* flag hdd use for charging calculation */
disk_activity_last_cycle = true;
}
debug_file_sync();
}
/*
* The charger was just plugged in. If the battery level is
* nearly charged, just trickle. If the battery is low, start
* a full charge cycle. If the battery level is in between,
* top-off and then trickle.
*/
static void charger_plugged(void)
{
int battery_percent = battery_level();
pid_p = 0;
pid_i = 0;
powermgmt_last_cycle_level = battery_percent;
powermgmt_last_cycle_startstop_min = 0;
snprintf(power_message, POWER_MESSAGE_LEN, "Charger plugged in");
if (battery_percent > START_TOPOFF_CHG) {
if (battery_percent >= START_TRICKLE_CHG) {
charge_state = TRICKLE;
target_voltage = TRICKLE_VOLTAGE;
}
else {
charge_state = TOPOFF;
target_voltage = TOPOFF_VOLTAGE;
}
}
else {
/*
* Start the charger full strength
*/
int i = CHARGE_MAX_MIN_1500 * get_battery_capacity() / 1500;
charge_max_time_idle = i * (100 + 35 - battery_percent) / 100;
if (charge_max_time_idle > i)
charge_max_time_idle = i;
charge_max_time_now = charge_max_time_idle;
snprintf(power_message, POWER_MESSAGE_LEN,
"ChgAt %d%% max %dm", battery_percent,
charge_max_time_now);
/*
* Enable the charger after the max time calc is done,
* because battery_level depends on if the charger is
* on.
*/
DEBUGF("power: charger inserted and battery"
" not full, charging\n");
trickle_sec = 60;
long_delta = short_delta = 999999;
charge_state = CHARGING;
}
}
/*
* The charger was just unplugged.
*/
static void charger_unplugged(void)
{
DEBUGF("power: charger disconnected, disabling\n");
charger_enable(false);
powermgmt_last_cycle_level = battery_level();
powermgmt_last_cycle_startstop_min = 0;
trickle_sec = 0;
pid_p = 0;
pid_i = 0;
charge_state = DISCHARGING;
snprintf(power_message, POWER_MESSAGE_LEN, "Charger: discharge");
}
static void charging_step(void)
{
int i;
/* alter charge time max length with extra disk use */
if (disk_activity_last_cycle) {
minutes_disk_activity++;
charge_max_time_now = charge_max_time_idle +
minutes_disk_activity*2 / 5;
disk_activity_last_cycle = false;
last_disk_activity = 0;
}
else {
last_disk_activity++;
}
/*
* Check the delta voltage over the last X minutes so we can do
* our end-of-charge logic based on the battery level change
* (no longer use minimum time as logic for charge end has 50
* minutes minimum charge built in).
*/
if (powermgmt_last_cycle_startstop_min > CHARGE_END_SHORTD) {
short_delta = power_history[0] -
power_history[CHARGE_END_SHORTD - 1];
}
if (powermgmt_last_cycle_startstop_min > CHARGE_END_LONGD) {
/*
* Scan the history: the points where measurement is taken need to
* be fairly static. Check prior to short delta 'area'. Also only
* check first and last 10 cycles (delta in middle OK).
*/
long_delta = power_history[0] -
power_history[CHARGE_END_LONGD - 1];
for (i = CHARGE_END_SHORTD; i < CHARGE_END_SHORTD + 10; i++)
{
if ((power_history[i] - power_history[i+1]) > 50 ||
(power_history[i] - power_history[i+1]) < -50) {
long_delta = 777777;
break;
}
}
for (i = CHARGE_END_LONGD - 11; i < CHARGE_END_LONGD - 1 ; i++)
{
if ((power_history[i] - power_history[i+1]) > 50 ||
(power_history[i] - power_history[i+1]) < -50) {
long_delta = 888888;
break;
}
}
}
snprintf(power_message, POWER_MESSAGE_LEN,
"Chg %dm, max %dm", powermgmt_last_cycle_startstop_min,
charge_max_time_now);
/*
* End of charge criteria (any qualify):
* 1) Charged a long time
* 2) DeltaV went negative for a short time ( & long delta static)
* 3) DeltaV was negative over a longer period (no disk use only)
*
* Note: short_delta and long_delta are millivolts
*/
if (powermgmt_last_cycle_startstop_min >= charge_max_time_now ||
(short_delta <= -50 && long_delta < 50) ||
(long_delta < -20 && last_disk_activity > CHARGE_END_LONGD)) {
int battery_percent = battery_level();
if (powermgmt_last_cycle_startstop_min > charge_max_time_now) {
DEBUGF("power: powermgmt_last_cycle_startstop_min > charge_max_time_now, "
"enough!\n");
/*
* Have charged too long and deltaV detection did not
* work!
*/
snprintf(power_message, POWER_MESSAGE_LEN,
"Chg tmout %d min", charge_max_time_now);
/*
* Switch to trickle charging. We skip the top-off
* since we've effectively done the top-off operation
* already since we charged for the maximum full
* charge time.
*/
powermgmt_last_cycle_level = battery_percent;
powermgmt_last_cycle_startstop_min = 0;
charge_state = TRICKLE;
/*
* Set trickle charge target to a relative voltage instead
* of an arbitrary value - the fully charged voltage may
* vary according to ambient temp, battery condition etc.
* Trickle target is -0.15v from full voltage acheived.
* Topup target is -0.05v from full voltage.
*/
target_voltage = power_history[0] - 150;
}
else {
if(short_delta <= -5) {
DEBUGF("power: short-term negative"
" delta, enough!\n");
snprintf(power_message, POWER_MESSAGE_LEN,
"end negd %d %dmin", short_delta,
powermgmt_last_cycle_startstop_min);
target_voltage = power_history[CHARGE_END_SHORTD - 1] - 50;
}
else {
DEBUGF("power: long-term small "
"positive delta, enough!\n");
snprintf(power_message, POWER_MESSAGE_LEN,
"end lowd %d %dmin", long_delta,
powermgmt_last_cycle_startstop_min);
target_voltage = power_history[CHARGE_END_LONGD - 1] - 50;
}
/*
* Switch to top-off charging.
*/
powermgmt_last_cycle_level = battery_percent;
powermgmt_last_cycle_startstop_min = 0;
charge_state = TOPOFF;
}
}
}
static void topoff_trickle_step(void)
{
unsigned int millivolts;
/*
*Time to switch from topoff to trickle?
*/
if (charge_state == TOPOFF &&
powermgmt_last_cycle_startstop_min > TOPOFF_MAX_MIN) {
powermgmt_last_cycle_level = battery_level();
powermgmt_last_cycle_startstop_min = 0;
charge_state = TRICKLE;
target_voltage = target_voltage - 100;
}
/*
* Adjust trickle charge time (proportional and integral terms).
* Note: I considered setting the level higher if the USB is
* plugged in, but it doesn't appear to be necessary and will
* generate more heat [gvb].
*/
millivolts = battery_voltage();
pid_p = ((signed)target_voltage - (signed)millivolts) / 5;
if (pid_p <= PID_DEADZONE && pid_p >= -PID_DEADZONE)
pid_p = 0;
if ((unsigned)millivolts < target_voltage) {
if (pid_i < 60)
pid_i++; /* limit so it doesn't "wind up" */
}
else {
if (pid_i > 0)
pid_i--; /* limit so it doesn't "wind up" */
}
trickle_sec = pid_p + pid_i;
if (trickle_sec > 60)
trickle_sec = 60;
if (trickle_sec < 0)
trickle_sec = 0;
}
void charging_algorithm_step(void)
{
static int pwm_counter = 0; /* PWM total cycle in steps */
static int pwm_duty = 0; /* PWM duty cycle in steps */
switch (charger_input_state)
{
case CHARGER_PLUGGED:
charger_plugged();
break;
case CHARGER_UNPLUGGED:
charger_unplugged();
break;
case CHARGER:
case NO_CHARGER:
do_frequent_tasks();
if (pwm_counter > 0) {
if (pwm_duty > 0 && --pwm_duty <= 0)
charger_enable(false); /* Duty cycle expired */
if (--pwm_counter > 0)
return;
/* PWM cycle is complete */
powermgmt_last_cycle_startstop_min++;
debug_file_log();
}
break;
}
switch (charge_state)
{
case CHARGING:
charging_step();
break;
case TOPOFF:
case TRICKLE:
topoff_trickle_step();
break;
case DISCHARGING:
default:
break;
}
/* If 100%, ensure pwm_on never expires and briefly disables the
* charger. */
pwm_duty = (trickle_sec < 60) ? trickle_sec*2 : 0;
pwm_counter = 60*2;
charger_enable(trickle_sec > 0);
}
#ifdef CHARGING_DEBUG_FILE
void charging_algorithm_close(void)
{
debug_file_close();
}
#endif /* CHARGING_DEBUG_FILE */
/* Returns true if the unit is charging the batteries. */
bool charging_state(void)
{
return charge_state == CHARGING;
}

View file

@ -0,0 +1,101 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
* Revisions copyright (C) 2005 by Gerald Van Baren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef POWERMGMT_TARGET_H
#define POWERMGMT_TARGET_H
/*
* Define CHARGING_DEBUG_FILE to create a csv (spreadsheet) with battery
* information in it (one sample per minute/connect/disconnect).
*
* This is only for very low level debug.
*/
#undef CHARGING_DEBUG_FILE
/* stop when N minutes have passed with avg delta being < -0.05 V */
#define CHARGE_END_SHORTD 6
/* stop when N minutes have passed with avg delta being < -0.02 V */
#define CHARGE_END_LONGD 50
/* Battery % to start at top-off */
#define START_TOPOFF_CHG 85
/* Battery % to start at trickle */
#define START_TRICKLE_CHG 95
/* power thread status message */
#define POWER_MESSAGE_LEN 32
/* minutes: maximum charging time for 1500 mAh batteries
* actual max time depends also on BATTERY_CAPACITY! */
#define CHARGE_MAX_MIN_1500 450
/* minutes: minimum charging time */
#define CHARGE_MIN_MIN 10
/* After charging, go to top off charge. How long should top off charge be? */
#define TOPOFF_MAX_MIN 90
/* which voltage is best? (millivolts) */
#define TOPOFF_VOLTAGE 5650
/* After top off charge, go to trickle harge. How long should trickle
* charge be? */
#define TRICKLE_MAX_MIN 720 /* 12 hrs */
/* which voltage is best? (millivolts) */
#define TRICKLE_VOLTAGE 5450
/* initial trickle_sec for topoff */
#define START_TOPOFF_SEC 25
/* initial trickle_sec for trickle */
#define START_TRICKLE_SEC 15
#define PID_DEADZONE 4 /* PID proportional deadzone */
extern char power_message[POWER_MESSAGE_LEN];
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_level; /* which level had the batteries
at this time? */
extern int pid_p; /* PID proportional term */
extern int pid_i; /* PID integral term */
extern int trickle_sec; /* how many seconds should the
charger be enabled per
minute for trickle
charging? */
void charger_enable(bool on);
bool charger_enabled(void);
/* Battery filter lengths in samples */
#define BATT_AVE_SAMPLES 32
/* No init to do */
static inline void powermgmt_init_target(void) {}
void charging_algorithm_step(void);
#ifdef CHARGING_DEBUG_FILE
/* Need to flush and close debug file */
void charging_algorithm_close(void);
#else
/* No poweroff operation to do */
static inline void charging_algorithm_close(void) {}
#endif
#endif /* POWERMGMT_TARGET_H */

View file

@ -75,7 +75,7 @@ static void charging_screen(void)
do do
{ {
#if CONFIG_CHARGING == CHARGING_CONTROL #ifdef ARCHOS_RECORDER
if (charge_state == CHARGING) if (charge_state == CHARGING)
msg = "charging"; msg = "charging";
else if (charge_state == TOPOFF) else if (charge_state == TOPOFF)
@ -84,7 +84,6 @@ static void charging_screen(void)
msg = "trickle charge"; msg = "trickle charge";
else else
msg = "not charging"; msg = "not charging";
#else #else
msg = "charging"; msg = "charging";
#endif #endif

View file

@ -7,3 +7,5 @@ lcd-playersim.c
#endif #endif
sim_icons.c sim_icons.c
stubs.c stubs.c
powermgmt-sim.c

View file

@ -0,0 +1,159 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Heikki Hannikainen, Uwe Freese
* Revisions copyright (C) 2005 by Gerald Van Baren
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include <time.h>
#include "kernel.h"
#include "powermgmt.h"
#define BATT_MINMVOLT 2500 /* minimum millivolts of battery */
#define BATT_MAXMVOLT 4500 /* maximum millivolts of battery */
#define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in
minutes */
extern void send_battery_level_event(void);
extern int last_sent_battery_level;
extern int battery_percent;
static unsigned int battery_millivolts = BATT_MAXMVOLT;
/* estimated remaining time in minutes */
static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME;
static void battery_status_update(void)
{
static time_t last_change = 0;
static bool charging = false;
time_t now;
time(&now);
if (last_change < now) {
last_change = now;
/* change the values: */
if (charging) {
if (battery_millivolts >= BATT_MAXMVOLT) {
/* Pretend the charger was disconnected */
charging = false;
queue_broadcast(SYS_CHARGER_DISCONNECTED, 0);
last_sent_battery_level = 100;
}
}
else {
if (battery_millivolts <= BATT_MINMVOLT) {
/* Pretend the charger was connected */
charging = true;
queue_broadcast(SYS_CHARGER_CONNECTED, 0);
last_sent_battery_level = 0;
}
}
if (charging) {
battery_millivolts += (BATT_MAXMVOLT - BATT_MINMVOLT) / 50;
}
else {
battery_millivolts -= (BATT_MAXMVOLT - BATT_MINMVOLT) / 100;
}
battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) /
(BATT_MAXMVOLT - BATT_MINMVOLT);
powermgmt_est_runningtime_min =
battery_percent * BATT_MAXRUNTIME / 100;
}
send_battery_level_event();
}
void battery_read_info(int *voltage, int *level)
{
battery_status_update();
if (voltage)
*voltage = battery_millivolts;
if (level)
*level = battery_percent;
}
unsigned int battery_voltage(void)
{
battery_status_update();
return battery_millivolts;
}
int battery_level(void)
{
battery_status_update();
return battery_percent;
}
int battery_time(void)
{
battery_status_update();
return powermgmt_est_runningtime_min;
}
bool battery_level_safe(void)
{
return battery_level() >= 10;
}
void set_poweroff_timeout(int timeout)
{
(void)timeout;
}
void set_battery_capacity(int capacity)
{
(void)capacity;
}
#if BATTERY_TYPES_COUNT > 1
void set_battery_type(int type)
{
(void)type;
}
#endif
#ifdef HAVE_ACCESSORY_SUPPLY
void accessory_supply_set(bool enable)
{
(void)enable;
}
#endif
void reset_poweroff_timer(void)
{
}
void shutdown_hw(void)
{
}
void sys_poweroff(void)
{
}
void cancel_shutdown(void)
{
}