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

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