|
|
@@ -1,162 +1,260 @@
|
|
|
#include "cc_cv_charging.h"
|
|
|
+#include "adc.h"
|
|
|
#include "battery.h"
|
|
|
#include "dac.h"
|
|
|
-#include "adc.h"
|
|
|
#include "ti/devices/msp/m0p/mspm0g350x.h"
|
|
|
#include "ti/driverlib/dl_gpio.h"
|
|
|
+#include "ti_msp_dl_config.h"
|
|
|
#include <stdio.h>
|
|
|
|
|
|
-//#define BATTERY_CAPACITY_MAH (2000)
|
|
|
+// #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)
|
|
|
+// Cut off current has been set for CC-CV charging test simulation with DC Power
|
|
|
+// Supplies
|
|
|
+#define CUTOFF_CURRENT_MA (240)
|
|
|
#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 ChargingState charging_state = STATE_IDLE;
|
|
|
+static uint16_t cycle_count = 0;
|
|
|
|
|
|
+// Functions for Charging and Discharging State
|
|
|
|
|
|
-//Pre Charge
|
|
|
+void CC_CV_UpdateChargingState(uint8_t slot_id) {
|
|
|
+ uint16_t batt_voltage = batteries[slot_id].voltage;
|
|
|
+ int16_t batt_current = batteries[slot_id].current;
|
|
|
+ // Flag for CV charging, the charging mode flips back to CC mode
|
|
|
+ static bool cv_charging_started = false;
|
|
|
|
|
|
-//#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;
|
|
|
+ // Handling condition for STATE_ERROR: When the battery voltage exceeds the
|
|
|
+ // MAXIMUM_VOLTAGE regardless of the current state
|
|
|
+ /*if (batt_voltage > MAX_VOLTAGE_MV) {
|
|
|
+ charging_state = STATE_ERROR;
|
|
|
+ return;
|
|
|
+ }*/
|
|
|
|
|
|
-//Functions for Charging and Discharging
|
|
|
+ if (batt_voltage > batteries[slot_id].max_voltage) {
|
|
|
+ charging_state = STATE_ERROR;
|
|
|
+ }
|
|
|
|
|
|
-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;
|
|
|
- }
|
|
|
+ // if state is IDLE or ERROR then RETURN
|
|
|
+ if (charging_state == STATE_IDLE || charging_state == STATE_ERROR) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- else if(batt_voltage >= MIN_VOLTAGE_MV && batt_voltage < MAX_VOLTAGE_MV - BATTERY_THRESHOLD){
|
|
|
- charging_state= STATE_CC_CHARGING;
|
|
|
- }
|
|
|
+ // 1. Deeply discharged: Pre-charge state
|
|
|
+ /*if ((batt_voltage < MIN_VOLTAGE_MV)) {
|
|
|
+ charging_state = STATE_PRE_CHARGE;
|
|
|
+ cv_charging_started = false;
|
|
|
+ }*/
|
|
|
+ if ((batt_voltage < batteries[slot_id].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 >= 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 (!cv_charging_started &&
|
|
|
+ (batt_voltage >= batteries[slot_id].min_voltage) &&
|
|
|
+ (batt_voltage <
|
|
|
+ batteries[slot_id].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 >= MAX_VOLTAGE_MV - BATTERY_THRESHOLD) {
|
|
|
+ charging_state = STATE_CV_CHARGING;
|
|
|
+ cv_charging_started = true;
|
|
|
+ }*/
|
|
|
|
|
|
- else if(charging_state == STATE_CV_CHARGING && batt_current <= CUTOFF_CURRENT_MA + BATTERY_THRESHOLD){
|
|
|
+ else if (batt_voltage >= batteries[slot_id].max_voltage - BATTERY_THRESHOLD) {
|
|
|
+ charging_state = STATE_CV_CHARGING;
|
|
|
+ cv_charging_started = true;
|
|
|
+ }
|
|
|
|
|
|
- if(cycle_count < MAX_CYCLES){
|
|
|
- charging_state= STATE_DISCHARGING;
|
|
|
- }
|
|
|
- else{
|
|
|
- charging_state = STATE_FINAL_DISCHARGE;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
+ // 4. Cut-off check inside CV
|
|
|
+ /*else if ((charging_state == STATE_CV_CHARGING) &&
|
|
|
+ (batt_current <= CUTOFF_CURRENT_MA + BATTERY_THRESHOLD)) {
|
|
|
|
|
|
- else if(charging_state == STATE_DISCHARGING && batt_voltage <= MIN_VOLTAGE_MV + BATTERY_THRESHOLD) {
|
|
|
- charging_state= STATE_CC_CHARGING;
|
|
|
+ if (cycle_count < MAX_CYCLES) {
|
|
|
+ charging_state = STATE_DISCHARGING;
|
|
|
+ cycle_count++;
|
|
|
+ } else {
|
|
|
+ charging_state = STATE_FINAL_DISCHARGE;
|
|
|
}
|
|
|
-
|
|
|
- else{
|
|
|
- charging_state= STATE_ERROR;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ else if ((charging_state == STATE_CV_CHARGING) &&
|
|
|
+ (batt_current <=
|
|
|
+ batteries[slot_id].cut_off_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 <= MIN_VOLTAGE_MV + BATTERY_THRESHOLD) {
|
|
|
+ charging_state = STATE_CC_CHARGING;
|
|
|
+ cv_charging_started = false;
|
|
|
+ }*/
|
|
|
+
|
|
|
+ else if (charging_state == STATE_DISCHARGING &&
|
|
|
+ batt_voltage <= batteries[slot_id].min_voltage + BATTERY_THRESHOLD) {
|
|
|
+ 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:
|
|
|
-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
|
|
|
+** 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){
|
|
|
- //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;
|
|
|
- static uint16_t dac_channel_VoutA= 2000;
|
|
|
-
|
|
|
- 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);
|
|
|
- //DAC_fastWrite(dac_channel_VoutA);
|
|
|
- DAC_SingleWrite(dac_channel_VoutA);
|
|
|
- //DAC_UpdateOutput();
|
|
|
- if(true){
|
|
|
- printf("[CC-CV] Pre Charging: Slot %d at %d mA.\n", slot_id, dac_channel_VoutA);
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
-
|
|
|
- case STATE_CC_CHARGING:
|
|
|
- DL_GPIO_setPins(GPIO_Battery_Charging_PORT, GPIO_Battery_Charging_PIN_PB4_PIN);
|
|
|
- if(batt_voltage>= 3700) //3.7 Volts of Fast Charging
|
|
|
- {
|
|
|
- printf("[CC-CV] CC Charging Completed!\n");
|
|
|
- break;
|
|
|
- }
|
|
|
- uint16_t target_current_mA= CC_CURRENT_LIMIT_MA;
|
|
|
- //Convert to voltage using Shunt resistor
|
|
|
- uint16_t voltage_mV= target_current_mA * SHUNT_RESISTOR * 1000;
|
|
|
-
|
|
|
- DAC_SingleWrite(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){
|
|
|
- dac_channel_VoutA= (dac_channel_VoutA - 50);
|
|
|
- printf("DAC Channel Value: %d, Battery Current:%d \n", dac_channel_VoutA, batt_current);
|
|
|
- }
|
|
|
- else{
|
|
|
- dac_channel_VoutA= 0;
|
|
|
- charging_state= STATE_FINAL_DISCHARGE;
|
|
|
- }
|
|
|
- DAC_SingleWrite(dac_channel_VoutA);
|
|
|
- printf("[CC-CV] CV Charging: Slot %d at %d mA.\n", slot_id, dac_channel_VoutA);
|
|
|
- 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_SingleWrite(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_SingleWrite(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;
|
|
|
- }
|
|
|
+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;
|
|
|
+ uint16_t charge_current_limit_ma = charge_current_mA / 10;
|
|
|
+
|
|
|
+ // DAC channel value:
|
|
|
+ //static uint16_t dac_channel_VoutA = 1000;
|
|
|
+ // Adding a variable to check the stepness in the voltage drop in CV charging
|
|
|
+ // mode:
|
|
|
+ static uint16_t last_voltage = 0;
|
|
|
+
|
|
|
+ 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_PB4_PIN);
|
|
|
|
|
|
-}
|
|
|
+ //DAC_SingleWrite(dac_channel_VoutA);
|
|
|
+ DAC_SingleWrite(charge_current_limit_ma);
|
|
|
+ if (true) {
|
|
|
+ //printf("PRE CHARGING: Slot %d at %d mA.\n", slot_id, );
|
|
|
+ printf("PRE CHARGING: Slot %d at %d mA.\n", slot_id, charge_current_limit_ma);
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
+ // CC CHARGING STATE: Keeps on checking the condition until battery voltage
|
|
|
+ // reaches to (MAXIMUM_VOLTAGE-BATTERY_THRESHOLD)= 4150 mVolts
|
|
|
+ case STATE_CC_CHARGING:
|
|
|
+ DL_GPIO_setPins(GPIO_Battery_Charging_PORT,
|
|
|
+ GPIO_Battery_Charging_PIN_PB4_PIN);
|
|
|
+ //DAC_SingleWrite(dac_channel_VoutA);
|
|
|
+ DAC_SingleWrite(charge_current_limit_ma);
|
|
|
+ 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:
|
|
|
+ DL_GPIO_setPins(GPIO_Battery_Charging_PORT,
|
|
|
+ GPIO_Battery_Charging_PIN_PB4_PIN);
|
|
|
+ // battery cut off current usually we get from Pi
|
|
|
+ //if (batt_current >= CUTOFF_CURRENT_MA + BATTERY_THRESHOLD) {
|
|
|
+ if(batt_current >= batteries[slot_id].cut_off_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. DAC "
|
|
|
+ "value: %d\n",
|
|
|
+ last_voltage, batt_voltage, charge_current_limit_ma);
|
|
|
+ }
|
|
|
+ // Clamping the DAC to avoid going too low too fast, causing the battery
|
|
|
+ // voltage to dip
|
|
|
+ //if (dac_channel_VoutA > 825) {
|
|
|
+ // dac_channel_VoutA -= 25;
|
|
|
+ //} else {
|
|
|
+ // dac_channel_VoutA = 825;
|
|
|
+ //}
|
|
|
|
|
|
+ printf("CV CHARGING: Slot: %d, DAC_Value: %d, Battery Voltage: %d, "
|
|
|
+ "Battery Current:%d \n",
|
|
|
+ slot_id, charge_current_limit_ma, batt_voltage, batt_current);
|
|
|
+ } else {
|
|
|
+ //dac_channel_VoutA = 0;
|
|
|
+ charging_state = STATE_FINAL_DISCHARGE;
|
|
|
+ }
|
|
|
+ last_voltage = batt_voltage;
|
|
|
+ //DAC_SingleWrite(dac_channel_VoutA);
|
|
|
+ DAC_SingleWrite(charge_current_limit_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);
|
|
|
+ // TODO: DAC channel value need to recheck
|
|
|
+ DAC_SingleWrite(charge_current_limit_ma);
|
|
|
+ printf("DISCHARGING: Slot %d at %d mA.\n", slot_id, batt_voltage);
|
|
|
+ DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT,
|
|
|
+ GPIO_Battery_Discharging_PIN_PB12_PIN);
|
|
|
+ if (batt_voltage < MIN_VOLTAGE_MV) {
|
|
|
+ charging_state = STATE_PRE_CHARGE;
|
|
|
+ }
|
|
|
+ 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("FINAL DISCHARGE: Slot %d..\n", slot_id);
|
|
|
+ DAC_SingleWrite(0);
|
|
|
+ // Added a new state in the Final Discharge so that the state transition
|
|
|
+ // does not gets stuck in a loop.
|
|
|
+ charging_state = STATE_IDLE;
|
|
|
+ break;
|
|
|
|
|
|
+ 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("ERROR: Slot %d.\n", slot_id);
|
|
|
+ break;
|
|
|
|
|
|
+ case STATE_IDLE:
|
|
|
+ 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);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|