summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Hannikainen <hessuh@rockbox.org>2002-08-12 12:19:25 +0000
committerHeikki Hannikainen <hessuh@rockbox.org>2002-08-12 12:19:25 +0000
commita4cb4aff7ba5546183e221687830f4d72abb8512 (patch)
tree793d3352bed62e842d624fade19bef021801b083
parent77e05c680388838b489e53f621c987b531d968dd (diff)
downloadrockbox-a4cb4aff7ba5546183e221687830f4d72abb8512.tar.gz
rockbox-a4cb4aff7ba5546183e221687830f4d72abb8512.zip
Tune charging algorithm: use more voltage samples (4 per minute) and discard
samples taken while the disk is spinning. If no 'disk idle' samples are available, use the ones we have anyway (yeah, maybe we could interpolate too). Also tuned the deltas detection too, and fixed some comments. This seems to work quite a bit better for me. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1682 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/powermgmt.c71
-rw-r--r--firmware/powermgmt.h5
2 files changed, 44 insertions, 32 deletions
diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c
index 3f919fa177..41bd1c4dec 100644
--- a/firmware/powermgmt.c
+++ b/firmware/powermgmt.c
@@ -26,6 +26,7 @@
26#include "adc.h" 26#include "adc.h"
27#include "string.h" 27#include "string.h"
28#include "sprintf.h" 28#include "sprintf.h"
29#include "ata.h"
29#include "power.h" 30#include "power.h"
30#include "powermgmt.h" 31#include "powermgmt.h"
31 32
@@ -71,11 +72,6 @@ int battery_level(void)
71 else /* history was empty, get a fresh sample */ 72 else /* history was empty, get a fresh sample */
72 level = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000; 73 level = (adc_read(ADC_UNREG_POWER) * BATTERY_SCALE_FACTOR) / 10000;
73 74
74#ifdef HAVE_CHARGE_CTRL
75 if (charger_enabled)
76 level -= 10; /* the charger raises the voltage 0.05-0.2v */
77#endif
78
79 if(level > BATTERY_LEVEL_FULL) 75 if(level > BATTERY_LEVEL_FULL)
80 level = BATTERY_LEVEL_FULL; 76 level = BATTERY_LEVEL_FULL;
81 77
@@ -89,13 +85,15 @@ int battery_level(void)
89bool battery_level_safe(void) 85bool battery_level_safe(void)
90{ 86{
91 /* I'm pretty sure we don't want an average over a long time here */ 87 /* I'm pretty sure we don't want an average over a long time here */
92 return adc_read(ADC_UNREG_POWER) > (BATTERY_LEVEL_DANGEROUS * 10000) / BATTERY_SCALE_FACTOR; 88 if (power_history[POWER_HISTORY_LEN-1])
89 return power_history[POWER_HISTORY_LEN-1] > BATTERY_LEVEL_DANGEROUS;
90 else
91 return adc_read(ADC_UNREG_POWER) > (BATTERY_LEVEL_DANGEROUS * 10000) / BATTERY_SCALE_FACTOR;
93} 92}
94 93
95/* 94/*
96 * This power thread maintains a history of battery voltage 95 * This power thread maintains a history of battery voltage
97 * and should, in the future, enable charging when it's needed 96 * and implements a charging algorithm.
98 * and power is available, and disable it when the battery is full.
99 * Battery 'fullness' can be determined by the voltage drop, see: 97 * Battery 'fullness' can be determined by the voltage drop, see:
100 * 98 *
101 * http://www.nimhbattery.com/nimhbattery-faq.htm questions 3 & 4 99 * http://www.nimhbattery.com/nimhbattery-faq.htm questions 3 & 4
@@ -120,7 +118,7 @@ bool battery_level_safe(void)
120static void power_thread(void) 118static void power_thread(void)
121{ 119{
122 int i; 120 int i;
123 int avg; 121 int avg, ok_samples, spin_samples;
124#ifdef HAVE_CHARGE_CTRL 122#ifdef HAVE_CHARGE_CTRL
125 int delta; 123 int delta;
126 int charged_time = 0; 124 int charged_time = 0;
@@ -128,22 +126,35 @@ static void power_thread(void)
128 126
129 while (1) 127 while (1)
130 { 128 {
131 DEBUGF("power_thread woke up\n"); 129 /* Make POWER_AVG measurements and calculate an average of that to
132 /* make POWER_AVG measurements and calculate an average of that to 130 * reduce the effect of backlights/disk spinning/other variation.
133 * reduce the effect of backlights/disk spinning/other variation
134 */ 131 */
135 avg = 0; 132 ok_samples = spin_samples = avg = 0;
136 for (i = 0; i < POWER_AVG; i++) { 133 for (i = 0; i < POWER_AVG_N; i++) {
137 avg += adc_read(ADC_UNREG_POWER); 134 if (ata_disk_is_active()) {
138 sleep(15); 135 if (!ok_samples) {
136 /* if we don't have any good non-disk-spinning samples,
137 * we take a sample anyway in case the disk is going
138 * to spin all the time.
139 */
140 avg += adc_read(ADC_UNREG_POWER);
141 spin_samples++;
142 }
143 } else {
144 if (spin_samples) /* throw away disk-spinning samples */
145 spin_samples = avg = 0;
146 avg += adc_read(ADC_UNREG_POWER);
147 ok_samples++;
148 }
149 sleep(HZ*POWER_AVG_SLEEP);
139 } 150 }
140 avg = avg / POWER_AVG; 151 avg = avg / ((ok_samples) ? ok_samples : spin_samples);
141 152
142 /* rotate the power history */ 153 /* rotate the power history */
143 for (i = 0; i < POWER_HISTORY_LEN-1; i++) 154 for (i = 0; i < POWER_HISTORY_LEN-1; i++)
144 power_history[i] = power_history[i+1]; 155 power_history[i] = power_history[i+1];
145 156
146 /* insert new value in the end, in decivolts 8-) */ 157 /* insert new value in the end, in centivolts 8-) */
147 power_history[POWER_HISTORY_LEN-1] = (avg * BATTERY_SCALE_FACTOR) / 10000; 158 power_history[POWER_HISTORY_LEN-1] = (avg * BATTERY_SCALE_FACTOR) / 10000;
148 159
149#ifdef HAVE_CHARGE_CTRL 160#ifdef HAVE_CHARGE_CTRL
@@ -163,25 +174,25 @@ static void power_thread(void)
163 /* have charged continuously over the minimum charging time, 174 /* have charged continuously over the minimum charging time,
164 * so we monitor for deltaV going negative. Multiply things 175 * so we monitor for deltaV going negative. Multiply things
165 * by 100 to get more accuracy without floating point arithmetic. 176 * by 100 to get more accuracy without floating point arithmetic.
166 * power_history[] contains decivolts. 177 * power_history[] contains centivolts so after multiplying by 100
178 * the deltas are in tenths of millivolts (delta of 5 is
179 * 0.0005 V).
167 */ 180 */
168 delta = 0; 181 delta = ( power_history[POWER_HISTORY_LEN-1] * 100
169 for (i = 0; i < CHARGE_END_NEGD; i++) 182 - power_history[POWER_HISTORY_LEN-1-CHARGE_END_NEGD] * 100 )
170 delta += power_history[POWER_HISTORY_LEN-1-i]*100 - power_history[POWER_HISTORY_LEN-1-i-1]*100; 183 / CHARGE_END_NEGD;
171 delta = delta / CHARGE_END_NEGD;
172 184
173 if (delta < -50) { /* delta < -0.3 V */ 185 if (delta < -100) { /* delta < -10 mV */
174 DEBUGF("power: short-term negative delta, enough!\n"); 186 DEBUGF("power: short-term negative delta, enough!\n");
175 charger_enable(false); 187 charger_enable(false);
176 snprintf(power_message, POWER_MESSAGE_LEN, "end negd %d %dmin", delta, charged_time); 188 snprintf(power_message, POWER_MESSAGE_LEN, "end negd %d %dmin", delta, charged_time);
177 } else { 189 } else {
178 /* if we didn't disable the charger in the previous test, check for low positive delta */ 190 /* if we didn't disable the charger in the previous test, check for low positive delta */
179 delta = 0; 191 delta = ( power_history[POWER_HISTORY_LEN-1] * 100
180 for (i = 0; i < CHARGE_END_ZEROD; i++) 192 - power_history[POWER_HISTORY_LEN-1-CHARGE_END_ZEROD] * 100 )
181 delta += power_history[POWER_HISTORY_LEN-1-i]*100 - power_history[POWER_HISTORY_LEN-1-i-1]*100; 193 / CHARGE_END_ZEROD;
182 delta = delta / CHARGE_END_ZEROD;
183 194
184 if (delta <= 5) { /* delta of <= 0.005 V */ 195 if (delta < 1) { /* delta < 0.1 mV */
185 DEBUGF("power: long-term small positive delta, enough!\n"); 196 DEBUGF("power: long-term small positive delta, enough!\n");
186 charger_enable(false); 197 charger_enable(false);
187 snprintf(power_message, POWER_MESSAGE_LEN, "end lowd %d %dmin", delta, charged_time); 198 snprintf(power_message, POWER_MESSAGE_LEN, "end lowd %d %dmin", delta, charged_time);
@@ -212,7 +223,7 @@ static void power_thread(void)
212#endif /* HAVE_CHARGE_CTRL*/ 223#endif /* HAVE_CHARGE_CTRL*/
213 224
214 /* sleep for roughly a minute */ 225 /* sleep for roughly a minute */
215 sleep(HZ*(60-POWER_AVG*15)); 226 sleep(HZ*(60 - POWER_AVG_N * POWER_AVG_SLEEP));
216 } 227 }
217} 228}
218 229
diff --git a/firmware/powermgmt.h b/firmware/powermgmt.h
index bfee5bf4a3..74116fa74c 100644
--- a/firmware/powermgmt.h
+++ b/firmware/powermgmt.h
@@ -29,10 +29,11 @@
29#define BATTERY_RANGE (BATTERY_LEVEL_FULL - BATTERY_LEVEL_EMPTY) 29#define BATTERY_RANGE (BATTERY_LEVEL_FULL - BATTERY_LEVEL_EMPTY)
30 30
31#define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */ 31#define POWER_HISTORY_LEN 2*60 /* 2 hours of samples, one per minute */
32#define POWER_AVG 3 /* how many samples to take for each measurement */ 32#define POWER_AVG_N 4 /* how many samples to take for each measurement */
33#define POWER_AVG_SLEEP 10 /* how long do we sleep between each measurement */
33 34
34#define CHARGE_END_NEGD 6 /* stop when N minutes have passed with 35#define CHARGE_END_NEGD 6 /* stop when N minutes have passed with
35 * avg delta being < -0.3 V */ 36 * avg delta being < -0.05 V */
36#define CHARGE_END_ZEROD 30 /* stop when N minutes have passed with 37#define CHARGE_END_ZEROD 30 /* stop when N minutes have passed with
37 * avg delta being < 0.005 V */ 38 * avg delta being < 0.005 V */
38 39