#include "cc_cv_charging.h" #include "src/config.h" #include "src/battery_data/battery.h" #include #include "ti/driverlib/dl_gpio.h" #include "ti_msp_dl_config.h" #include "src/controller/controller.h" static ChargingState charging_state= STATE_IDLE; static uint16_t cycle_count = 0; // declaring static global variables static uint16_t batt_voltage; static int16_t batt_current; static uint16_t batt_min_voltage; static uint16_t batt_max_voltage; static uint16_t batt_cutoff_current; static uint16_t batt_capacitance; static int16_t batt_charge_discharge; // Functions for Charging and Discharging State void CC_CV_UpdateChargingState(uint8_t slot_id) { // Flag for CV charging, the charging mode flips back to CC mode static bool cv_charging_started = false; batt_voltage = battery_data[slot_id].battery_measurement.voltage; batt_current = battery_data[slot_id].battery_measurement.current; batt_min_voltage = battery_data[slot_id].min_voltage; batt_max_voltage = battery_data[slot_id].max_voltage; batt_cutoff_current = battery_data[slot_id].cut_off_current; batt_capacitance = battery_data[slot_id].capacitance; batt_charge_discharge= battery_data[slot_id].charge_discharge; //Check if the slot is empty or if the battery limits are not set if (battery_data[slot_id].battery_state == STATE_EMPTY || (batt_min_voltage == 0 && batt_max_voltage == 0 && batt_cutoff_current== 0 && batt_capacitance== 0)) { charging_state = STATE_IDLE; return; } //Check if the battery is overcharged if (batt_voltage > batt_max_voltage) { charging_state = STATE_ERROR; return; } //1. Pre Charge: if the battery is deeply discharged if ((batt_voltage < batt_min_voltage)) { charging_state = STATE_PRE_CHARGE; cv_charging_started = false; } // 2. Fast Charging Condition: CC Charging: cv_charging_started condition // added to avoid toggling back to CC after CV state is reached else if (!cv_charging_started && (batt_voltage >= batt_min_voltage) && (batt_voltage < batt_max_voltage - BATTERY_THRESHOLD)) { charging_state = STATE_CC_CHARGING; } // 3. CV Charging condition: Changing the cv_charging_state to True, once the // CV mode is reached else if (batt_voltage >= batt_max_voltage - BATTERY_THRESHOLD) { charging_state = STATE_CV_CHARGING; cv_charging_started = true; } // 4. Cut-off check inside CV else if ((charging_state == STATE_CV_CHARGING) && (batt_current <= batt_cutoff_current + BATTERY_THRESHOLD)) { if (cycle_count < MAX_CYCLES) { charging_state = STATE_DISCHARGING; cycle_count++; } else { charging_state = STATE_FINAL_DISCHARGE; } } // 5. State Discharging condition else if (charging_state == STATE_DISCHARGING && batt_voltage <= batt_min_voltage + BATTERY_THRESHOLD) { DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB7_PIN); charging_state = STATE_CC_CHARGING; cv_charging_started = false; } // 6. Hold previous state if none of the condition matches (Previously, // CV_STATE was jumping directly to STATE_ERROR in else statement, to handle // the condition better, else condition is being changed). else { printf("[CC-CV] Current state: Voltage= %d mV, Current= %d mA\n", batt_voltage, batt_current); } } /* Function for Battery Charging and Discharging: ** Pre Charge: Once the battery is in discharged state, pre-charging begins. Starts charging safely with a typically low current C/10 ** Constant Current: Continues until the battery voltage has reached the "full" or floating voltage level ** Constant Voltage: CV voltage starts once the maximum voltage threshold is obtained. */ void CC_CV_ControlCharging(uint8_t slot_id, int16_t charge_current) { // Calling function to get all the conditional states CC_CV_UpdateChargingState(slot_id); batt_voltage = battery_data[slot_id].battery_measurement.voltage; batt_current= battery_data[slot_id].battery_measurement.current; batt_min_voltage= battery_data[slot_id].min_voltage; batt_max_voltage= battery_data[slot_id].max_voltage; batt_cutoff_current = battery_data[slot_id].cut_off_current; batt_capacitance= battery_data[slot_id].capacitance; batt_charge_discharge= battery_data[slot_id].charge_discharge; // DAC channel value: // dac_channel_value is for CV mode where the charge current is calibrated till battery current is less than (cutoff current+threshold) // Adding a variable to check the stepness in the voltage drop in CV charging // mode: static uint16_t last_voltage = 0; //flag for DAC: so that the dac value is initialized only once and then can be decremented rather than resetting to the initial value static bool dac_initialized= false; switch (charging_state) { // PRE CHARGE STATE: Battery Voltage is lesser than 3000 mVolts case STATE_PRE_CHARGE: DL_GPIO_setPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB6_PIN); controller_SetCurrent(TARGET_MCU_ADDRESS, slot_id, charge_current); if (true) { printf("PRE CHARGING: Slot %d at %d mA.\n", slot_id, charge_current); } break; // CC CHARGING STATE: Keeps on checking the condition until battery voltage // reaches to (MAXIMUM_VOLTAGE-BATTERY_THRESHOLD)= 4150 mVolts case STATE_CC_CHARGING: controller_SetCurrent(TARGET_MCU_ADDRESS, slot_id, charge_current); printf("CC CHARGING: Slot %d, Current: %d mA, Voltage: %d mV.\n", slot_id, batt_current, batt_voltage); break; // CV CHARGING STATE: Keeps on checking the condition until battery current // decreases till it exceeds (CUTOFF_CURRENT_MA + BATTERY_THRESHOLD)= 290 mAs case STATE_CV_CHARGING: if (batt_current >= batt_cutoff_current + BATTERY_THRESHOLD) { // Detect steep voltage drop: if (last_voltage != 0 && (last_voltage - batt_voltage) > 100) { printf("!!! CV CHARGING: Voltage dropped too fast: %d -> %d mV.\n", last_voltage, batt_voltage); } }else { charging_state = STATE_FINAL_DISCHARGE; dac_initialized= false; } last_voltage = batt_voltage; controller_SetCurrent(TARGET_MCU_ADDRESS, slot_id, charge_current); break; case STATE_DISCHARGING: //DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB6_PIN); DL_GPIO_setPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB7_PIN); controller_SetCurrent(TARGET_MCU_ADDRESS, slot_id, charge_current); printf("DISCHARGING: Slot %d at %d mA.\n", slot_id, batt_voltage); break; case STATE_FINAL_DISCHARGE: //Once the cycle gets done, the battery state transitions to "STATE_MEASUREMENT_DONE" battery_data[slot_id].battery_state= STATE_MEASUREMENT_DONE; DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB6_PIN); DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB7_PIN); controller_SetCurrent(TARGET_MCU_ADDRESS, slot_id, 0); charging_state = STATE_IDLE; break; case STATE_ERROR: DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB6_PIN); DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB7_PIN); printf("ERROR: Slot %d.\n", slot_id); break; case STATE_IDLE: DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB6_PIN); DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB7_PIN); charging_state = STATE_PRE_CHARGE; break; default: break; } } // End of the file