/* * MIN_VOLTAGE_MV, MAXIMUM_VOLTAGE will be replaced by the value a slot gets from Pi * Article referred: * https://www.monolithicpower.com/learning/resources/battery-charger-fundamentals * https://www.instructables.com/Programming-a-Lithium-ion-Battery-Charger-Using-a-/ */ #include "cc_cv_charging.h" #include "battery.h" #include "dac.h" #include "adc.h" #include "ti/devices/msp/m0p/mspm0g350x.h" #include "ti/driverlib/dl_gpio.h" #include //#define BATTERY_CAPACITY_MAH (2000) #define MAX_VOLTAGE_MV (4200) #define MIN_VOLTAGE_MV (3000) #define CC_CURRENT_LIMIT_MA (500) #define CUTOFF_CURRENT_MA (50) #define MAX_CYCLES (2) #define CONSTANT_VALUE (1) #define SHUNT_RESISTOR (0.1) //********** Not used ************************** // if the battery is deeply discharged then 50mA of trickle charge is given for a set timer //#define TRICKLE_CHARGE_CURRENT_MA (50) //#define TRICKLE_CHARGE_VOLTAGE_MV (2100) //#define TRICKLE_CHARGE_TIMEOUT_MS (5000) //5 mseconds //Pre Charge //#define PRE_CHARGE_CURRENT_MA (BATTERY_CAPACITY_MAH/ 10) static ChargingState charging_state= STATE_PRE_CHARGE; static uint16_t cycle_count= 0; static uint32_t pre_charge_start_time= 0; //Functions for Charging and Discharging void CC_CV_UpdateChargingState(uint8_t slot_id){ uint16_t batt_voltage= batteries[slot_id].voltage; int16_t batt_current= batteries[slot_id].current; if(batt_voltage < MIN_VOLTAGE_MV){ charging_state= STATE_PRE_CHARGE; } else if(batt_voltage >= MIN_VOLTAGE_MV && batt_voltage < MAX_VOLTAGE_MV - BATTERY_THRESHOLD){ charging_state= STATE_CC_CHARGING; } else if(batt_voltage >= MAX_VOLTAGE_MV - BATTERY_THRESHOLD){ charging_state= STATE_CV_CHARGING; } else if(charging_state == STATE_CV_CHARGING && batt_current <= CUTOFF_CURRENT_MA + BATTERY_THRESHOLD){ if(cycle_count < MAX_CYCLES){ charging_state= STATE_DISCHARGING; } else{ charging_state = STATE_FINAL_DISCHARGE; } } else if(charging_state == STATE_DISCHARGING && batt_voltage <= MIN_VOLTAGE_MV + BATTERY_THRESHOLD) { charging_state= STATE_CC_CHARGING; } else{ charging_state= STATE_ERROR; } } /* Function for Battery Charging and Discharging: Trickle Charge: Only used when the battery voltage < ~2.1 V. - In this state, the batteries internal protection may have been previously disconnected. 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 volatge starts once the maximum voltage threshold is obtained */ void CC_CV_ControlCharging(uint8_t slot_id){ //Calling function to get all the conditional states CC_CV_UpdateChargingState(slot_id); uint16_t batt_voltage= batteries[slot_id].voltage; int16_t batt_current= batteries[slot_id].current; uint16_t batt_cutoff_current= batteries[slot_id].cut_off_current; uint16_t charge_current_mA= (batteries[slot_id].capacitance * batteries[slot_id].charge_fraction)/100; int16_t dac_channel_VoutA; switch(charging_state){ case STATE_PRE_CHARGE: DL_GPIO_setPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN); uint16_t pre_charge_current_limit_ma = charge_current_mA/10; DAC_fastWrite(pre_charge_current_limit_ma); printf("[CC-CV] Pre Charging: Slot %d at %d mA.\n", slot_id, pre_charge_current_limit_ma); break; case STATE_CC_CHARGING: DL_GPIO_setPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN); DAC_fastWrite(charge_current_mA); printf("[CC-CV] CC Charging: Slot %d at %d mA.\n", slot_id, CC_CURRENT_LIMIT_MA); break; case STATE_CV_CHARGING: DL_GPIO_setPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN); if(batt_current >= batt_cutoff_current+BATTERY_THRESHOLD){ //Reducing by 5% dac_channel_VoutA= (batt_current - (batt_current-0.05)); } else{ dac_channel_VoutA= 0; charging_state= STATE_FINAL_DISCHARGE; } DAC_fastWrite(dac_channel_VoutA); printf("[CC-CV] CV Charging: Slot %d at %d mA.\n", slot_id, CUTOFF_CURRENT_MA); break; case STATE_DISCHARGING: DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN); DL_GPIO_setPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB12_PIN); //still unsure about the value for channel VoutA: DAC_fastWrite(batt_voltage); printf("[CC-CV] Discharging: Slot %d at %d mA.\n", slot_id, batt_voltage); break; case STATE_FINAL_DISCHARGE: DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN); DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB12_PIN); printf("[CC-CV] Final Discharge: Slot %d..\n", slot_id); DAC_fastWrite(0); case STATE_ERROR: DL_GPIO_clearPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN); DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB12_PIN); printf("[CC-CV] Error: Slot %d.\n", slot_id); default: break; } }