|
|
@@ -1,3 +1,10 @@
|
|
|
+/*
|
|
|
+References:
|
|
|
+https://www.monolithicpower.com/learning/resources/how-to-select-lithium-ion-battery-charge-management-ic
|
|
|
+https://www.monolithicpower.com/learning/resources/battery-charger-fundamentals
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
#include "cc_cv_charging.h"
|
|
|
#include "adc.h"
|
|
|
#include "battery.h"
|
|
|
@@ -8,95 +15,75 @@
|
|
|
#include <stdio.h>
|
|
|
|
|
|
// #define BATTERY_CAPACITY_MAH (2000)
|
|
|
-#define MAX_VOLTAGE_MV (4200)
|
|
|
-#define MIN_VOLTAGE_MV (3000)
|
|
|
-#define CC_CURRENT_LIMIT_MA (500)
|
|
|
+//#define MAX_VOLTAGE_MV (4200)
|
|
|
+//#define MIN_VOLTAGE_MV (3000)
|
|
|
+//#define CC_CURRENT_LIMIT_MA (500)
|
|
|
// Cut off current has been set for CC-CV charging test simulation with DC Power
|
|
|
// Supplies
|
|
|
-#define CUTOFF_CURRENT_MA (240)
|
|
|
+//#define CUTOFF_CURRENT_MA (240)
|
|
|
#define MAX_CYCLES (2)
|
|
|
#define CONSTANT_VALUE (1)
|
|
|
#define SHUNT_RESISTOR (0.1)
|
|
|
|
|
|
// Pre Charge
|
|
|
-#define PRE_CHARGE_CURRENT_MA (BATTERY_CAPACITY_MAH / 10)
|
|
|
-//static ChargingState charging_state = STATE_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;
|
|
|
|
|
|
+//uint16_t charge_current_mA =(batt_capacitance* batteries[slot_id].charge_fraction) /100;
|
|
|
+//uint16_t charge_current_limit_ma = charge_current_mA / 10;
|
|
|
+
|
|
|
+
|
|
|
// Functions for Charging and Discharging State
|
|
|
|
|
|
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;
|
|
|
+ uint16_t batt_voltage = batteries[slot_id].voltage;
|
|
|
+ int16_t batt_current= batteries[slot_id].current;
|
|
|
+ uint16_t batt_min_voltage= batteries[slot_id].min_voltage;
|
|
|
+ uint16_t batt_max_voltage= batteries[slot_id].max_voltage;
|
|
|
+ uint16_t batt_cutoff_current = batteries[slot_id].cut_off_current;
|
|
|
+ uint16_t batt_capacitance= batteries[slot_id].capacitance;
|
|
|
|
|
|
- // 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;
|
|
|
+ if (batteries[slot_id].state == STATE_EMPTY ||
|
|
|
+ (batt_min_voltage == 0 && batt_max_voltage == 0 &&
|
|
|
+ batt_cutoff_current== 0 && batt_capacitance== 0)) {
|
|
|
+ charging_state = STATE_IDLE;
|
|
|
return;
|
|
|
- }*/
|
|
|
-
|
|
|
- if (batt_voltage > batteries[slot_id].max_voltage) {
|
|
|
- charging_state = STATE_ERROR;
|
|
|
}
|
|
|
|
|
|
- // if state is IDLE or ERROR then RETURN
|
|
|
- if (charging_state == STATE_IDLE || charging_state == STATE_ERROR) {
|
|
|
+ if (batt_voltage > batt_max_voltage) {
|
|
|
+ charging_state = STATE_ERROR;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 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)) {
|
|
|
+ //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 >= MIN_VOLTAGE_MV) &&
|
|
|
- (batt_voltage < MAX_VOLTAGE_MV - BATTERY_THRESHOLD)) {
|
|
|
- charging_state = STATE_CC_CHARGING;
|
|
|
- }*/
|
|
|
|
|
|
else if (!cv_charging_started &&
|
|
|
- (batt_voltage >= batteries[slot_id].min_voltage) &&
|
|
|
- (batt_voltage <
|
|
|
- batteries[slot_id].max_voltage - BATTERY_THRESHOLD)) {
|
|
|
+ (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 >= MAX_VOLTAGE_MV - BATTERY_THRESHOLD) {
|
|
|
- charging_state = STATE_CV_CHARGING;
|
|
|
- cv_charging_started = true;
|
|
|
- }*/
|
|
|
|
|
|
- else if (batt_voltage >= batteries[slot_id].max_voltage - BATTERY_THRESHOLD) {
|
|
|
+ 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 <= CUTOFF_CURRENT_MA + BATTERY_THRESHOLD)) {
|
|
|
-
|
|
|
- if (cycle_count < MAX_CYCLES) {
|
|
|
- charging_state = STATE_DISCHARGING;
|
|
|
- cycle_count++;
|
|
|
- } else {
|
|
|
- charging_state = STATE_FINAL_DISCHARGE;
|
|
|
- }
|
|
|
- }*/
|
|
|
|
|
|
else if ((charging_state == STATE_CV_CHARGING) &&
|
|
|
- (batt_current <=
|
|
|
- batteries[slot_id].cut_off_current + BATTERY_THRESHOLD)) {
|
|
|
+ (batt_current <= batt_cutoff_current + BATTERY_THRESHOLD)) {
|
|
|
if (cycle_count < MAX_CYCLES) {
|
|
|
charging_state = STATE_DISCHARGING;
|
|
|
cycle_count++;
|
|
|
@@ -106,14 +93,10 @@ void CC_CV_UpdateChargingState(uint8_t slot_id) {
|
|
|
}
|
|
|
|
|
|
// 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) {
|
|
|
+ batt_voltage <= batt_min_voltage + BATTERY_THRESHOLD) {
|
|
|
+ DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB12_PIN);
|
|
|
charging_state = STATE_CC_CHARGING;
|
|
|
cv_charging_started = false;
|
|
|
}
|
|
|
@@ -141,29 +124,40 @@ 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;
|
|
|
+ int16_t batt_current= batteries[slot_id].current;
|
|
|
+ uint16_t batt_min_voltage= batteries[slot_id].min_voltage;
|
|
|
+ uint16_t batt_max_voltage= batteries[slot_id].max_voltage;
|
|
|
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;
|
|
|
-
|
|
|
+ uint16_t batt_capacitance= batteries[slot_id].capacitance;
|
|
|
+ batteries[slot_id].charge_discharge_current= 1000;
|
|
|
+ //pre charge: charging current C/10
|
|
|
+ uint16_t precharge_current_mA= (batt_capacitance/10);
|
|
|
+ // charge currents between 0.5C and 3C
|
|
|
+ uint16_t fastcharge_current_mA= (batt_capacitance * 0.5);
|
|
|
+
|
|
|
+
|
|
|
// DAC channel value:
|
|
|
- //static uint16_t dac_channel_VoutA = 1000;
|
|
|
+ // 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;
|
|
|
-
|
|
|
+ static uint16_t dac_channel_value;
|
|
|
+ //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;
|
|
|
+ //dac_channel_value= fastcharge_current_mA;
|
|
|
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);
|
|
|
+
|
|
|
+ // DAC_SingleWrite(dac_channel_VoutA);
|
|
|
+ DAC_SingleWrite(precharge_current_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);
|
|
|
+ // printf("PRE CHARGING: Slot %d at %d mA.\n", slot_id, );
|
|
|
+ printf("PRE CHARGING: Slot %d at %d mA.\n", slot_id,
|
|
|
+ precharge_current_mA);
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
@@ -172,8 +166,8 @@ void CC_CV_ControlCharging(uint8_t slot_id) {
|
|
|
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);
|
|
|
+ // DAC_SingleWrite(dac_channel_VoutA);
|
|
|
+ DAC_SingleWrite(fastcharge_current_mA);
|
|
|
printf("CC CHARGING: Slot %d, Current: %d mA, Voltage: %d mV.\n", slot_id,
|
|
|
batt_current, batt_voltage);
|
|
|
break;
|
|
|
@@ -183,33 +177,28 @@ void CC_CV_ControlCharging(uint8_t slot_id) {
|
|
|
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){
|
|
|
+ if(!dac_initialized){
|
|
|
+ dac_channel_value= fastcharge_current_mA;
|
|
|
+ dac_initialized= true;
|
|
|
+ }
|
|
|
+ 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);
|
|
|
+ printf("!!! CV CHARGING: Voltage dropped too fast: %d -> %d mV.\n",
|
|
|
+ last_voltage, batt_voltage);
|
|
|
}
|
|
|
- // 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;
|
|
|
- //}
|
|
|
-
|
|
|
+ dac_channel_value-= 50 ;
|
|
|
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);
|
|
|
+ "Battery Current:%d\n",
|
|
|
+ slot_id, dac_channel_value, batt_voltage, batt_current);
|
|
|
} else {
|
|
|
- //dac_channel_VoutA = 0;
|
|
|
+ // dac_channel_VoutA = 0;
|
|
|
charging_state = STATE_FINAL_DISCHARGE;
|
|
|
+ dac_initialized= false;
|
|
|
}
|
|
|
last_voltage = batt_voltage;
|
|
|
- //DAC_SingleWrite(dac_channel_VoutA);
|
|
|
- DAC_SingleWrite(charge_current_limit_ma);
|
|
|
+ // DAC_SingleWrite(dac_channel_VoutA);
|
|
|
+ DAC_SingleWrite(dac_channel_value);
|
|
|
break;
|
|
|
|
|
|
case STATE_DISCHARGING:
|
|
|
@@ -218,11 +207,13 @@ void CC_CV_ControlCharging(uint8_t slot_id) {
|
|
|
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);
|
|
|
+ DAC_SingleWrite(fastcharge_current_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) {
|
|
|
+ // TODO: This logic handles the condition if voltage drops below the minimum voltage, still to be discussed if required
|
|
|
+ if (batt_voltage <= batteries[slot_id].min_voltage + BATTERY_THRESHOLD) {
|
|
|
+ printf("Clearing discharge relay — Voltage: %d, Min+Thresh: %d\n", batt_voltage, batteries[slot_id].min_voltage + BATTERY_THRESHOLD);
|
|
|
+ DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT, GPIO_Battery_Discharging_PIN_PB12_PIN);
|
|
|
+ dac_initialized= false;
|
|
|
charging_state = STATE_PRE_CHARGE;
|
|
|
}
|
|
|
break;
|
|
|
@@ -252,6 +243,7 @@ void CC_CV_ControlCharging(uint8_t slot_id) {
|
|
|
GPIO_Battery_Charging_PIN_PB4_PIN);
|
|
|
DL_GPIO_clearPins(GPIO_Battery_Discharging_PORT,
|
|
|
GPIO_Battery_Discharging_PIN_PB12_PIN);
|
|
|
+ charging_state = STATE_PRE_CHARGE;
|
|
|
break;
|
|
|
|
|
|
default:
|