comparison src/cs/drivers/drv_app/fchg/fchg_process.c @ 0:b6a5e36de839

src/cs: initial import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 15 Jul 2018 04:39:26 +0000
parents
children 5ad7f6a9d7d4
comparison
equal deleted inserted replaced
-1:000000000000 0:b6a5e36de839
1 /*
2 * In this module we are going to implement the main process functions
3 * for FCHG.
4 */
5
6 #include "fchg/fchg_env.h"
7 #include "fchg/fchg_func_i.h"
8 #include "rv/rv_general.h"
9 #include "rvf/rvf_api.h"
10 #include "rvm/rvm_use_id_list.h"
11 #include "abb/abb.h"
12 #include <string.h>
13 #include <stdio.h>
14
15 extern UINT16 madc_vbat_2_physical(UINT16 adc_val);
16 extern UINT16 madc_vbat_inverse(UINT16 mv);
17
18 void pwr_init_discharge(void)
19 {
20 pwr_ctrl->curr_disch_thresh = 0;
21 }
22
23 static void handle_discharge(void)
24 {
25 UINT16 i;
26 char trace[64];
27
28 /* first we need to find the current threshold we are at */
29 i = pwr_ctrl->curr_disch_thresh;
30 /* is there one below? */
31 if (++i == pwr_ctrl->nb_thresholds)
32 return;
33 /* are we crossing it? */
34 if (pwr_ctrl->batt_mv >= pwr_ctrl->batt_thresholds[i].bat_voltage)
35 return;
36 /* yes, we crossed it - see if we fell even further down */
37 while (i < pwr_ctrl->nb_thresholds &&
38 pwr_ctrl->batt_mv < pwr_ctrl->batt_thresholds[i].bat_voltage)
39 i++;
40 /* the last one was it */
41 i--;
42 pwr_ctrl->curr_disch_thresh = i;
43 sprintf(trace, "Battery fell through %u%% mark",
44 pwr_ctrl->batt_thresholds[i].remain_capa);
45 rvf_send_trace(trace, strlen(trace), NULL_PARAM,
46 RV_TRACE_LEVEL_WARNING, FCHG_USE_ID);
47 }
48
49 static void start_i2v_cal(void)
50 {
51 UINT16 bciconf;
52
53 rvf_send_trace("Calibrating i2v offset", 22, NULL_PARAM,
54 RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
55 pwr_ctrl->state = FCHG_STATE_I2V_CAL_2;
56 bciconf = ABB_Read_Register_on_page(PAGE1, BCICONF);
57 bciconf &= 0x3E0;
58 bciconf |= pwr_ctrl->config.bciconf;
59 ABB_Write_Register_on_page(PAGE1, BCICONF, bciconf);
60 /*
61 * Set the CHDISPA bit and start the zero calibration routine
62 * of the I to V converter
63 */
64 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0010);
65 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0019);
66 }
67
68 static void start_ci_charging(void)
69 {
70 rvf_send_trace("Start CI charging", 17, NULL_PARAM,
71 RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
72 pwr_ctrl->state = FCHG_STATE_CI_CHARGING;
73 /* Select constant current charging. The charger is disabled */
74 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0002);
75 /* Program the DAC with the constant current value */
76 ABB_Write_Register_on_page(PAGE0, CHGREG,
77 pwr_ctrl->config.ci_current + pwr_ctrl->i2v_offset);
78 /* Enable the charger */
79 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003);
80 /* The total charging time starts now */
81 pwr_ctrl->start_time = rvf_get_tick_count();
82 }
83
84 static void start_cv_charging(void)
85 {
86 UINT16 code;
87
88 rvf_send_trace("Start CV charging", 17, NULL_PARAM,
89 RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
90 pwr_ctrl->state = FCHG_STATE_CV_CHARGING;
91 /* Select constant voltage charging. The charger is disabled */
92 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
93 /* figure out the DAC code */
94 code = madc_vbat_inverse(pwr_ctrl->config.cv_init_set);
95 rvf_send_trace("Voltage (DAC code) ", 19, code,
96 RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
97 /* Program the DAC with the constant voltage value */
98 ABB_Write_Register_on_page(PAGE0, CHGREG, code);
99 /* Enable the charger */
100 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0001);
101 /* CV control loop state init */
102 pwr_ctrl->cv_dac_init = code;
103 pwr_ctrl->cv_dac_curr = code;
104 pwr_ctrl->cv_high_vbat_count = 0;
105 pwr_ctrl->cv_low_vbat_count = 0;
106 /* Ichg averaging state init */
107 pwr_ctrl->ichg_fill_level = 0;
108 pwr_ctrl->ichg_ring_ptr = 0;
109 pwr_ctrl->ichg_low_count = 0;
110 }
111
112 static void start_charge_condition_met(void)
113 {
114 rvf_send_trace("Charge start condition met", 26, NULL_PARAM,
115 RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
116 if (pwr_ctrl->config.bciconf)
117 start_i2v_cal();
118 else {
119 pwr_ctrl->i2v_offset = 0;
120 start_ci_charging();
121 }
122 }
123
124 static void ci_progress_trace(UINT16 ichg)
125 {
126 char trace[64];
127
128 sprintf(trace, "CI charging: Vbat=%u Ichg=%u i2v=%u",
129 pwr_ctrl->batt_mv, ichg, pwr_ctrl->i2v_offset);
130 rvf_send_trace(trace, strlen(trace), NULL_PARAM,
131 RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
132 }
133
134 static int cv_ichg_process(UINT16 ichg_new)
135 {
136 UINT16 ichg_clip, ichg_entry;
137 UINT32 ichg_accum;
138 UINT16 i;
139 char trace[64];
140
141 if (pwr_ctrl->ichg_fill_level < ICHG_AVG_WINDOW)
142 pwr_ctrl->ichg_avg_buf[pwr_ctrl->ichg_fill_level++] = ichg_new;
143 else {
144 ichg_clip = pwr_ctrl->ichg_average +
145 pwr_ctrl->config.ichg_max_spike;
146 if (ichg_new > ichg_clip)
147 ichg_entry = ichg_clip;
148 else
149 ichg_entry = ichg_new;
150 pwr_ctrl->ichg_avg_buf[pwr_ctrl->ichg_ring_ptr++] = ichg_entry;
151 if (pwr_ctrl->ichg_ring_ptr >= ICHG_AVG_WINDOW)
152 pwr_ctrl->ichg_ring_ptr = 0;
153 }
154 ichg_accum = 0;
155 for (i = 0; i < pwr_ctrl->ichg_fill_level; i++)
156 ichg_accum += pwr_ctrl->ichg_avg_buf[i];
157 pwr_ctrl->ichg_average = ichg_accum / pwr_ctrl->ichg_fill_level;
158 sprintf(trace, "CV charging: Vbat=%u Ichg=%u Ichg_avg=%u i2v=%u",
159 pwr_ctrl->batt_mv, ichg_new, pwr_ctrl->ichg_average,
160 pwr_ctrl->i2v_offset);
161 rvf_send_trace(trace, strlen(trace), NULL_PARAM,
162 RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
163 if (pwr_ctrl->ichg_average >
164 (pwr_ctrl->config.end_current + pwr_ctrl->i2v_offset)) {
165 pwr_ctrl->ichg_low_count = 0;
166 return 0;
167 }
168 pwr_ctrl->ichg_low_count++;
169 if (pwr_ctrl->ichg_low_count < pwr_ctrl->config.ichg_samples_needed)
170 return 0;
171 rvf_send_trace("Stopping charge by low current condition", 40,
172 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
173 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
174 pwr_init_discharge();
175 pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE;
176 return 1;
177 }
178
179 static int overvoltage_end_charge_check(void)
180 {
181 if (pwr_ctrl->batt_mv < pwr_ctrl->config.overvoltage)
182 return 0;
183 if (pwr_ctrl->cv_dac_curr !=
184 (pwr_ctrl->cv_dac_init - pwr_ctrl->config.cv_dac_max_decr))
185 return 0;
186 rvf_send_trace("Stopping charge by overvoltage condition", 40,
187 NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID);
188 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
189 pwr_init_discharge();
190 pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE;
191 return 1;
192 }
193
194 static void cv_ctrl_loop_high_check(void)
195 {
196 if (pwr_ctrl->batt_mv < pwr_ctrl->config.cv_ctrl_loop_high) {
197 pwr_ctrl->cv_high_vbat_count = 0;
198 return;
199 }
200 pwr_ctrl->cv_high_vbat_count++;
201 if (pwr_ctrl->cv_high_vbat_count < pwr_ctrl->config.cv_samples_needed)
202 return;
203 if (pwr_ctrl->cv_dac_curr ==
204 (pwr_ctrl->cv_dac_init - pwr_ctrl->config.cv_dac_max_decr))
205 return;
206 pwr_ctrl->cv_dac_curr--;
207 ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_ctrl->cv_dac_curr);
208 rvf_send_trace("Sub CV DAC", 10, pwr_ctrl->cv_dac_curr,
209 RV_TRACE_LEVEL_DEBUG_MEDIUM, FCHG_USE_ID);
210 pwr_ctrl->cv_high_vbat_count = 0;
211 }
212
213 static void cv_ctrl_loop_low_check(void)
214 {
215 if (pwr_ctrl->batt_mv >= pwr_ctrl->config.cv_ctrl_loop_low) {
216 pwr_ctrl->cv_low_vbat_count = 0;
217 return;
218 }
219 pwr_ctrl->cv_low_vbat_count++;
220 if (pwr_ctrl->cv_low_vbat_count < pwr_ctrl->config.cv_samples_needed)
221 return;
222 if (pwr_ctrl->cv_dac_curr ==
223 (pwr_ctrl->cv_dac_init + pwr_ctrl->config.cv_dac_max_incr))
224 return;
225 pwr_ctrl->cv_dac_curr++;
226 ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_ctrl->cv_dac_curr);
227 rvf_send_trace("Add CV DAC", 10, pwr_ctrl->cv_dac_curr,
228 RV_TRACE_LEVEL_DEBUG_MEDIUM, FCHG_USE_ID);
229 pwr_ctrl->cv_low_vbat_count = 0;
230 }
231
232 static int charging_time_limit_check(void)
233 {
234 if ((rvf_get_tick_count() - pwr_ctrl->start_time) <
235 RVF_SECS_TO_TICKS(pwr_ctrl->config.charge_time_limit))
236 return 0;
237 rvf_send_trace("Stopping charge by time exceeded condition", 42,
238 NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID);
239 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
240 pwr_init_discharge();
241 pwr_ctrl->state = FCHG_STATE_RECHARGE_TIMER;
242 pwr_ctrl->start_time = rvf_get_tick_count();
243 return 1;
244 }
245
246 void pwr_process_adc(struct pwr_adc_ind_s *msg)
247 {
248 pwr_ctrl->batt_mv = madc_vbat_2_physical(msg->data[0]);
249
250 switch (pwr_ctrl->state) {
251 case FCHG_STATE_NO_EXT_PWR:
252 case FCHG_STATE_PWR_PLUG_TIMER:
253 case FCHG_STATE_NO_CHARGING:
254 handle_discharge();
255 return;
256 case FCHG_STATE_READY_TO_CHARGE:
257 handle_discharge();
258 if (!(msg->data[9] & CHGPRES)) {
259 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
260 return;
261 }
262 if (pwr_ctrl->batt_mv < pwr_ctrl->config.start_thresh)
263 start_charge_condition_met();
264 return;
265 case FCHG_STATE_READY_TO_RECHARGE:
266 handle_discharge();
267 if (!(msg->data[9] & CHGPRES)) {
268 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
269 return;
270 }
271 if (pwr_ctrl->batt_mv < pwr_ctrl->config.restart_thresh)
272 start_charge_condition_met();
273 return;
274 case FCHG_STATE_I2V_CAL_1:
275 if (!(msg->data[9] & CHGPRES)) {
276 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
277 return;
278 }
279 if (pwr_ctrl->config.bciconf)
280 start_i2v_cal();
281 else {
282 pwr_ctrl->i2v_offset = 0;
283 start_ci_charging();
284 }
285 return;
286 case FCHG_STATE_I2V_CAL_2:
287 pwr_ctrl->i2v_offset = msg->data[2];
288 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
289 rvf_send_trace("i2v offset (MADC code) ", 23,
290 pwr_ctrl->i2v_offset,
291 RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
292 if (!(msg->data[9] & CHGPRES)) {
293 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
294 return;
295 }
296 start_ci_charging();
297 return;
298 case FCHG_STATE_CI_CHARGING:
299 ci_progress_trace(msg->data[2]);
300 if (!(msg->data[9] & CHGPRES)) {
301 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
302 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
303 return;
304 }
305 if (charging_time_limit_check())
306 return;
307 if (pwr_ctrl->batt_mv >= pwr_ctrl->config.ci2cv_thresh)
308 start_cv_charging();
309 return;
310 case FCHG_STATE_CV_CHARGING:
311 if (!(msg->data[9] & CHGPRES)) {
312 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
313 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
314 return;
315 }
316 if (cv_ichg_process(msg->data[2]))
317 return;
318 if (overvoltage_end_charge_check())
319 return;
320 if (charging_time_limit_check())
321 return;
322 cv_ctrl_loop_high_check();
323 cv_ctrl_loop_low_check();
324 return;
325 case FCHG_STATE_RECHARGE_TIMER:
326 handle_discharge();
327 if ((rvf_get_tick_count() - pwr_ctrl->start_time) <
328 RVF_SECS_TO_TICKS(pwr_ctrl->config.recharge_delay))
329 return;
330 rvf_send_trace("Restart time met, allowing new charging", 39,
331 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH,
332 FCHG_USE_ID);
333 pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE;
334 return;
335 default:
336 rvf_send_trace("Invalid state in pwr_process_adc()", 32,
337 pwr_ctrl->state, RV_TRACE_LEVEL_ERROR,
338 FCHG_USE_ID);
339 }
340 }
341
342 void pwr_handle_timer(void)
343 {
344 if (pwr_ctrl->state != FCHG_STATE_PWR_PLUG_TIMER)
345 return;
346 rvf_send_trace("Timer expired, ready to charge", 30, NULL_PARAM,
347 RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
348 pwr_ctrl->state = FCHG_STATE_READY_TO_CHARGE;
349 }
350
351 void pwr_charger_plug(void)
352 {
353 if (pwr_ctrl->state != FCHG_STATE_NO_EXT_PWR) {
354 rvf_send_trace("Charger plug event in unexpected state", 38,
355 pwr_ctrl->state, RV_TRACE_LEVEL_ERROR,
356 FCHG_USE_ID);
357 return;
358 }
359 if (!pwr_ctrl->config_present) {
360 rvf_send_trace(
361 "Charger plugged in, but no config: won't charge", 47,
362 NULL_PARAM, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID);
363 pwr_ctrl->state = FCHG_STATE_NO_CHARGING;
364 return;
365 }
366 if (pwr_ctrl->config.start_delay) {
367 rvf_send_trace("Charger plug, starting timer", 28, NULL_PARAM,
368 RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
369 rvf_start_timer(FCHG_TIMER,
370 RVF_MS_TO_TICKS(pwr_ctrl->config.start_delay),
371 FALSE);
372 pwr_ctrl->state = FCHG_STATE_PWR_PLUG_TIMER;
373 } else {
374 rvf_send_trace("Charger plug, ready to charge", 29, NULL_PARAM,
375 RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
376 pwr_ctrl->state = FCHG_STATE_READY_TO_CHARGE;
377 }
378 }
379
380 void pwr_charger_unplug(void)
381 {
382 switch (pwr_ctrl->state) {
383 case FCHG_STATE_NO_EXT_PWR:
384 rvf_send_trace("Charger unplug, already handled", 31,
385 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_LOW,
386 FCHG_USE_ID);
387 /* nothing to do */
388 return;
389 case FCHG_STATE_PWR_PLUG_TIMER:
390 case FCHG_STATE_READY_TO_CHARGE:
391 case FCHG_STATE_READY_TO_RECHARGE:
392 case FCHG_STATE_I2V_CAL_1:
393 case FCHG_STATE_RECHARGE_TIMER:
394 case FCHG_STATE_NO_CHARGING:
395 rvf_send_trace("Charger unplug", 14, NULL_PARAM,
396 RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
397 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
398 return;
399 case FCHG_STATE_I2V_CAL_2:
400 case FCHG_STATE_CI_CHARGING:
401 case FCHG_STATE_CV_CHARGING:
402 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
403 rvf_send_trace("Charger unplug, charging stopped", 32,
404 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH,
405 FCHG_USE_ID);
406 pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
407 pwr_init_discharge();
408 return;
409 default:
410 rvf_send_trace("Invalid state in pwr_charger_unplug()", 35,
411 pwr_ctrl->state, RV_TRACE_LEVEL_ERROR,
412 FCHG_USE_ID);
413 }
414 }
415
416 void pwr_charge_start_req(void)
417 {
418 switch (pwr_ctrl->state) {
419 case FCHG_STATE_NO_EXT_PWR:
420 rvf_send_trace("Cannot charge without a power source", 36,
421 NULL_PARAM, RV_TRACE_LEVEL_ERROR, FCHG_USE_ID);
422 return;
423 case FCHG_STATE_NO_CHARGING:
424 if (!pwr_ctrl->config_present) {
425 rvf_send_trace("No config set, cannot charge", 28,
426 NULL_PARAM, RV_TRACE_LEVEL_ERROR,
427 FCHG_USE_ID);
428 return;
429 }
430 /* FALL THRU */
431 case FCHG_STATE_PWR_PLUG_TIMER:
432 case FCHG_STATE_READY_TO_CHARGE:
433 case FCHG_STATE_READY_TO_RECHARGE:
434 case FCHG_STATE_RECHARGE_TIMER:
435 rvf_send_trace("Starting charge on user request", 31,
436 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH,
437 FCHG_USE_ID);
438 pwr_ctrl->state = FCHG_STATE_I2V_CAL_1;
439 return;
440 case FCHG_STATE_I2V_CAL_1:
441 case FCHG_STATE_I2V_CAL_2:
442 case FCHG_STATE_CI_CHARGING:
443 case FCHG_STATE_CV_CHARGING:
444 rvf_send_trace(
445 "Charging already in progress, start request ignored",
446 51, NULL_PARAM, RV_TRACE_LEVEL_WARNING, FCHG_USE_ID);
447 return;
448 default:
449 rvf_send_trace("Invalid state in pwr_charge_start_req()", 37,
450 pwr_ctrl->state, RV_TRACE_LEVEL_ERROR,
451 FCHG_USE_ID);
452 }
453 }
454
455 void pwr_charge_stop_req(void)
456 {
457 switch (pwr_ctrl->state) {
458 case FCHG_STATE_NO_EXT_PWR:
459 case FCHG_STATE_NO_CHARGING:
460 /* nothing to do */
461 return;
462 case FCHG_STATE_PWR_PLUG_TIMER:
463 case FCHG_STATE_READY_TO_CHARGE:
464 case FCHG_STATE_READY_TO_RECHARGE:
465 case FCHG_STATE_I2V_CAL_1:
466 case FCHG_STATE_RECHARGE_TIMER:
467 rvf_send_trace("Charging disabled by user request", 33,
468 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH,
469 FCHG_USE_ID);
470 pwr_ctrl->state = FCHG_STATE_NO_CHARGING;
471 return;
472 case FCHG_STATE_I2V_CAL_2:
473 case FCHG_STATE_CI_CHARGING:
474 case FCHG_STATE_CV_CHARGING:
475 ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
476 rvf_send_trace("Charging stopped by user request", 32,
477 NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH,
478 FCHG_USE_ID);
479 pwr_ctrl->state = FCHG_STATE_NO_CHARGING;
480 pwr_init_discharge();
481 return;
482 default:
483 rvf_send_trace("Invalid state in pwr_charge_stop_req()", 36,
484 pwr_ctrl->state, RV_TRACE_LEVEL_ERROR,
485 FCHG_USE_ID);
486 }
487 }