diff src/cs/drivers/drv_app/fchg/fchg_process.c @ 331:8166b0afcf8c

FCHG: main ADC process implemented
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 14 Dec 2017 16:22:30 +0000
parents
children 8a90038c0173
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/drivers/drv_app/fchg/fchg_process.c	Thu Dec 14 16:22:30 2017 +0000
@@ -0,0 +1,226 @@
+/*
+ * In this module we are going to implement the main process functions
+ * for FCHG.
+ */
+
+#include "fchg/fchg_env.h"
+#include "fchg/fchg_func_i.h"
+#include "rv/rv_general.h"
+#include "rvf/rvf_api.h"
+#include "rvm/rvm_use_id_list.h"
+#include "abb/abb.h"
+#include <string.h>
+#include <stdio.h>
+
+extern UINT16 madc_vbat_2_physical(UINT16 adc_val);
+
+void pwr_init_discharge(void)
+{
+	pwr_ctrl->curr_percent = pwr_ctrl->batt_thresholds[0].remain_capa;
+}
+
+static void handle_discharge(void)
+{
+	UINT16 i;
+	char trace[64];
+
+	/* first we need to find the current threshold we are at */
+	for (i = 0; i < pwr_ctrl->nb_thresholds; i++)
+		if (pwr_ctrl->batt_thresholds[i].remain_capa ==
+		    pwr_ctrl->curr_percent)
+			break;
+	/* is there one below? */
+	if (++i == pwr_ctrl->nb_thresholds)
+		return;
+	/* are we crossing it? */
+	if (pwr_ctrl->batt_mv >= pwr_ctrl->batt_thresholds[i].bat_voltage)
+		return;
+	/* yes, we crossed it - see if we fell even further down */
+	while (i < pwr_ctrl->nb_thresholds &&
+	       pwr_ctrl->batt_mv < pwr_ctrl->batt_thresholds[i].bat_voltage)
+		i++;
+	/* the last one was it */
+	i--;
+	pwr_ctrl->curr_percent = pwr_ctrl->batt_thresholds[i].remain_capa;
+	sprintf(trace, "Battery fell through %u%% mark",
+		pwr_ctrl->curr_percent);
+	rvf_send_trace(trace, strlen(trace), NULL_PARAM,
+			RV_TRACE_LEVEL_WARNING, FCHG_USE_ID);
+}
+
+static void charge_progress_trace(char *mode, UINT16 ichg)
+{
+	char trace[64];
+
+	sprintf(trace, "%s charging: Vbat=%u Ichg=%u i2v=%u", mode,
+		pwr_ctrl->batt_mv, ichg, pwr_ctrl->i2v_offset);
+	rvf_send_trace(trace, strlen(trace), NULL_PARAM,
+			RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
+}
+
+static void start_i2v_cal(void)
+{
+	UINT16 bciconf;
+
+	rvf_send_trace("Calibrating i2v offset", 22, NULL_PARAM,
+			RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
+	pwr_ctrl->state = FCHG_STATE_I2V_CAL_2;
+	bciconf = ABB_Read_Register_on_page(PAGE1, BCICONF);
+	bciconf &= 0x3E0;
+	bciconf |= pwr_ctrl->config.bciconf;
+	ABB_Write_Register_on_page(PAGE1, BCICONF, bciconf);
+	/*
+	 * Set the CHDISPA bit and start the zero calibration routine
+	 * of the I to V converter
+	 */
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0010);
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0019);
+}
+
+static void start_ci_charging(void)
+{
+	rvf_send_trace("Start CI charging", 17, NULL_PARAM,
+			RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
+	pwr_ctrl->state = FCHG_STATE_CI_CHARGING;
+	/* Select constant current charging. The charger is disabled */
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0002);
+	/* Program the DAC with the constant current value */
+	ABB_Write_Register_on_page(PAGE0, CHGREG,
+			pwr_ctrl->config.ci_current + pwr_ctrl->i2v_offset);
+	/* Enable the charger */
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003);
+}
+
+static void start_cv_charging(UINT16 code)
+{
+	rvf_send_trace("Start CV charging", 17, NULL_PARAM,
+			RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
+	pwr_ctrl->state = FCHG_STATE_CV_CHARGING;
+	/* Select constant voltage charging. The charger is disabled */
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
+	/* figure out the DAC code */
+	while (code &&
+	       madc_vbat_2_physical(code) >= pwr_ctrl->config.charge_to_mv)
+		code--;
+	code++;
+	rvf_send_trace("Voltage (DAC code) ", 19, code,
+			RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
+	/* Program the DAC with the constant voltage value */
+	ABB_Write_Register_on_page(PAGE0, CHGREG, code);
+	/* Enable the charger */
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0001);
+}
+
+static void start_charge_condition_met(void)
+{
+	rvf_send_trace("Charge start condition met", 26, NULL_PARAM,
+			RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
+	if (pwr_ctrl->config.bciconf)
+		start_i2v_cal();
+	else {
+		pwr_ctrl->i2v_offset = 0;
+		start_ci_charging();
+	}
+}
+
+static int overvoltage_end_charge_check(void)
+{
+	if (pwr_ctrl->batt_mv < pwr_ctrl->config.overvoltage)
+		return 0;
+	rvf_send_trace("Stopping charge by overvoltage condition", 40,
+			NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH, FCHG_USE_ID);
+	ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
+	pwr_init_discharge();
+	pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE;
+	return 1;
+}
+
+void pwr_process_adc(struct pwr_adc_ind_s *msg)
+{
+	pwr_ctrl->batt_mv = madc_vbat_2_physical(msg->data[0]);
+
+	switch (pwr_ctrl->state) {
+	case FCHG_STATE_NO_EXT_PWR:
+	case FCHG_STATE_PWR_PLUG_TIMER:
+	case FCHG_STATE_NO_CHARGING:
+		handle_discharge();
+		return;
+	case FCHG_STATE_READY_TO_CHARGE:
+		handle_discharge();
+		if (!(msg->data[9] & CHGPRES)) {
+			pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
+			return;
+		}
+		if (pwr_ctrl->batt_mv >= pwr_ctrl->config.start_thresh)
+			start_charge_condition_met();
+		return;
+	case FCHG_STATE_READY_TO_RECHARGE:
+		handle_discharge();
+		if (!(msg->data[9] & CHGPRES)) {
+			pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
+			return;
+		}
+		if (pwr_ctrl->batt_mv >= pwr_ctrl->config.restart_thresh)
+			start_charge_condition_met();
+		return;
+	case FCHG_STATE_I2V_CAL_1:
+		if (!(msg->data[9] & CHGPRES)) {
+			pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
+			return;
+		}
+		if (pwr_ctrl->config.bciconf)
+			start_i2v_cal();
+		else {
+			pwr_ctrl->i2v_offset = 0;
+			start_ci_charging();
+		}
+		return;
+	case FCHG_STATE_I2V_CAL_2:
+		pwr_ctrl->i2v_offset = msg->data[2];
+		ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
+		rvf_send_trace("i2v offset (MADC code) ", 23,
+				pwr_ctrl->i2v_offset,
+				RV_TRACE_LEVEL_DEBUG_LOW, FCHG_USE_ID);
+		if (!(msg->data[9] & CHGPRES)) {
+			pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
+			return;
+		}
+		start_ci_charging();
+		return;
+	case FCHG_STATE_CI_CHARGING:
+		charge_progress_trace("CI", msg->data[2]);
+		if (!(msg->data[9] & CHGPRES)) {
+			ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
+			pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
+			return;
+		}
+		if (overvoltage_end_charge_check())
+			return;
+		if (pwr_ctrl->batt_mv >= pwr_ctrl->config.charge_to_mv)
+			start_cv_charging(msg->data[0]);
+		return;
+	case FCHG_STATE_CV_CHARGING:
+		charge_progress_trace("CV", msg->data[2]);
+		if (!(msg->data[9] & CHGPRES)) {
+			ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
+			pwr_ctrl->state = FCHG_STATE_NO_EXT_PWR;
+			return;
+		}
+		if (overvoltage_end_charge_check())
+			return;
+		if (msg->data[2] >=
+		    pwr_ctrl->config.end_current + pwr_ctrl->i2v_offset)
+			return;
+		rvf_send_trace("Stopping charge by low current condition", 40,
+				NULL_PARAM, RV_TRACE_LEVEL_DEBUG_HIGH,
+				FCHG_USE_ID);
+		ABB_Write_Register_on_page(PAGE0, BCICTL2, 0);
+		pwr_init_discharge();
+		pwr_ctrl->state = FCHG_STATE_READY_TO_RECHARGE;
+		return;
+	default:
+		rvf_send_trace("Invalid state in pwr_process_adc()", 32,
+				pwr_ctrl->state, RV_TRACE_LEVEL_ERROR,
+				FCHG_USE_ID);
+	}
+}