diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/powermgmt.c | 71 | ||||
-rw-r--r-- | firmware/powermgmt.h | 5 |
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) | |||
89 | bool battery_level_safe(void) | 85 | bool 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) | |||
120 | static void power_thread(void) | 118 | static 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 | ||