summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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