Browse Source

added logic for CC-CV charging

namrota ghosh 9 months ago
parent
commit
806372a640
9 changed files with 203 additions and 155 deletions
  1. BIN
      Debug/charge_controller_v7.out
  2. BIN
      Debug/i2c_controller.o
  3. 18 2
      adc.c
  4. 2 1
      battery.h
  5. 103 0
      cc_cv_charging.c
  6. 23 0
      cc_cv_charging.h
  7. 47 130
      i2c_controller.c
  8. 9 21
      i2c_target.c
  9. 1 1
      i2c_target.h

BIN
Debug/charge_controller_v7.out


BIN
Debug/i2c_controller.o


+ 18 - 2
adc.c

@@ -149,7 +149,7 @@ int16_t ADC_ReadData(uint8_t slot_id, ADC_PARAMS params)
 
     }
 
-    printf("Gain %d: \n", gain_multiplier);
+    //printf("Gain %d: \n", gain_multiplier);
     printf("Raw ADC Value: 0x%0X (%d)\n", raw_adc, raw_adc);
     return raw_adc;
    
@@ -186,14 +186,30 @@ uint16_t ADC_ConvertToVoltage(int16_t adc_value, ADC_PARAMS params) {
     return (uint16_t)measured_voltage;
 }
 
+/* Function to Convert ADC Reading to Voltage */
+uint16_t ADC_ConvertToCurrent(int16_t adc_value, ADC_PARAMS params) {
+    uint16_t current_mA= 0;
+    //uint8_t r_shunt= 0.1;
+    //Convert ADC value to voltage across shunt resistor:
+    uint16_t voltage_mV= ADC_ConvertToVoltage(adc_value, params);
+    //Convert voltage drop across shunt resistor to current
+    current_mA= (voltage_mV)/ 0.1;
+    printf("Converted Current: %d mA.\n", current_mA);
+    return current_mA;
+}
+
 void Battery_UpdateCurrentVoltage(ADC_PARAMS params){
     for(uint8_t slot=0; slot< NUM_SLOTS; slot++ ){
         //Set Configuration
         //ADC_SetConfigurationBytes(slot, params);
-        //Voltage Setup
+        //CH1: Voltage Setup
         int16_t raw_adc_voltage= ADC_ReadData(slot, params);
         batteries[slot].voltage= ADC_ConvertToVoltage(raw_adc_voltage, params);   
         printf("Battery Voltage for slot %d is %u mV.\n", slot, batteries[slot].voltage);
+        //CH2: Charge Current
+        int16_t raw_adc_current= ADC_ReadData(slot, params);
+        batteries[slot].current= raw_adc_current;
+        printf("Battery current for slot %d is %u mA.\n", slot, batteries[slot].current);
         }
 
 }

+ 2 - 1
battery.h

@@ -4,7 +4,8 @@
 
 //define macro to be used by multiple files in the program witout the variable being overwritten
 
-#define NUM_SLOTS              (1)
+#define NUM_SLOTS (1)
+#define BATTERY_THRESHOLD (50)
 
 typedef enum{
     STATE_EMPTY= 0x01,

+ 103 - 0
cc_cv_charging.c

@@ -0,0 +1,103 @@
+#include "cc_cv_charging.h"
+#include "battery.h"
+#include "cc_cc_charging.h"
+#include "dac.h"
+#include <cstdint>
+#include <stdio.h>
+
+#define MAX_VOLTAGE_MV (4200)
+#define MIN_VOLTAGE_MV (3000)
+#define CC_CURRENT_LIMIT_MA (500)
+#define CUTOFF_CURRENT_MA (50)
+#define MAX_CYCLES (500)
+// 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 BATTERY_CAPACITY_MAH (2000)
+#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;
+
+void CC_CV_UpdateChargingState(uint8_t slot_id){
+    uint16_t batt_voltage= batteries[slot_id].voltage;
+    int16_t batt_current= batteries[slot_id].current;
+    static uint16_t trickle_timeer= 0;
+
+    if(batt_voltage < TRICKLE_CHARGE_VOLTAGE_MV){
+        charging_state= STATE_TRICKLE_CHARGE;
+        trickle_timer= 0;
+    }
+    else if(charging_state== STATE_TRICKLE_CHARGE){
+        trickle_timer ++;
+
+        if(trickle_timer >= TRICKLE_CHARGE_TIMEOUT_MS){
+            charging_state = STATE_ERROR;
+        }
+    }
+    else 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;
+    }
+}
+
+void CC_CV_ControlCharging(uint8 slot_id){
+    
+    CC_CV_UpdateChargingState(slot_id){
+    
+    switch(charging_state){
+        case STATE_TRICKLE_CHARGE:
+            DAC_fastWrite(TRICKLE_CHARGE_CURRENT_MA * 1000);
+            printf("[CC-CV] Trickle Charging: Slot %d at %d mA.\n", slot_id, TRICKLE_CHARGE_CURRENT_MA);
+            break;
+        
+        case STATE_PRE_CHARGE:
+            DAC_fastWrite(PRE_CHARGE_CURRENT_MA * 1000);
+            printf("[CC-CV] Pre Charging: Slot %d at %d mA.\n", slot_id, PRE_CHARGE_CURRENT_MA);
+            break;
+        
+        case STATE_CC_CHARGING:
+            DAC_fastWrite(CC_CURRENT_LIMIT_MA * 1000):
+            printf("[CC-CV] CC Charging: Slot %d at %d mA.\n", slot_id, CC_CURRENT_LIMIT_MA);
+            break;
+        
+        case STATE_CV_CHARGING:
+            DAC_fastWrite(MAX_VOLTAGE_MV);
+            printf("[CC-CV] CV Charging: Slot %d at %d mA.\n", slot_id, PRE_CHARGE_CURRENT_MA);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+

+ 23 - 0
cc_cv_charging.h

@@ -0,0 +1,23 @@
+#ifndef CC_CV_CHARGING_H_
+#define CC_CV_CHARGING_H_
+
+#include <stdint.h>
+#include "battery.h"
+#include "adc.h"
+#include "dac.h"
+
+typedef enum{
+    STATE_PRE_CHARGE,
+    STATE_TRICKLE_CHARGE,
+    STATE_CC_CHARGING,
+    STATE_CV_CHARGING,
+    STATE_DISCHARGING,
+    STATE_FINAL_DISCHARGE,
+    STATE_ERROR
+}ChargingState;
+
+
+void CC_CV_UpdateChargingState(uint8_t slot_id);
+void CC_CV_ControlCharging(uint8 slot_id);
+
+#endif

+ 47 - 130
i2c_controller.c

@@ -201,122 +201,13 @@ void I2C_controller_INST_IRQHandler(void)
     }
 }
 
-//void I2C_target_INST_IRQHandler(void) {
-
-//    static bool DataRx= false;
-//    static uint16_t registerAddress=0;
-
-    //printf("I2C Interrupt Triggered to MCU (TARGET)!\n");
-
-//    uint32_t status = DL_I2C_getPendingInterrupt(I2C_target_INST);
-//    switch (status) {
-
-        /* START condition detected */
-//        case DL_I2C_IIDX_TARGET_START:
-            //printf("START condition detected.\n");
-//            gTxCount= 0;
-//            gRxCount= 0;
-//            DataRx= false;
-//            DL_I2C_flushTargetTXFIFO(I2C_target_INST);
-//            break;
-
-        /* STOP condition detected */
-//        case DL_I2C_IIDX_TARGET_STOP:
-            //printf("STOP condition detected.\n");
-//            if (DataRx == true){
-                //printf("Data received from Pi: ");
-//                for (uint8_t i = 0; i < gRxCount; i++) {
-//                    //printf("0x%02X ", gRxBuffer[i]);
-
-//                }
-                //printf("\n");
-//                DataRx= false;
-//            }
-//            DL_I2C_flushTargetTXFIFO(I2C_target_INST);
-//            break;
-
-        /* RX FIFO trigger (Pi is writing data to MCU) */
-//        case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
-            //printf("receiving data from Pi.\n");
-//            DataRx= true;
-//            while (!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)) {
-//               if (gRxCount == 0) {
-//                    // First byte received is the register address
-//                    registerAddress = DL_I2C_receiveTargetData(I2C_target_INST);
-//                    DL_I2C_flushTargetTXFIFO(I2C_target_INST);
-                    //printf("Register Address Set: 0x%02X\n", registerAddress);
-//                } 
-//                else if (registerAddress < REGISTER_SIZE) {
-                    //Storing the received data from the controller correctly
-//                    registers[registerAddress] = DL_I2C_receiveTargetData(I2C_target_INST);
-                    //printf("Stored 0x%02X in Register 0x%02X\n", registers[registerAddress], registerAddress);
-                    //gRxBuffer[gRxCount++] = DL_I2C_receiveTargetData(I2C_0_INST);
-
-//                } 
-//                else {
-//                    printf("ERROR: RX Buffer Overflow!\n");
-//                    break;
-//                }
-//                gRxCount++;
-//            }
-//            break;
-
-         /* TX FIFO trigger (Pi is reading data from MCU) */
-//        case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:
-            
-            //printf("transmitting data to Pi...\n");
-//            if(!DL_I2C_isTargetTXFIFOFull(I2C_target_INST)) {
-//                  if(registerAddress == 0x01){
-                    //DL_I2C_fillTargetTXFIFO(I2C_target_INST, battery_status, NUM_BATTERY_SLOT);
-//                  }
-//                  else if(registerAddress== 0x02){
-                    //DL_I2C_fillTargetTXFIFO(I2C_target_INST, &value , 1);
-//                  }
-      
-//                  else {
-                    // **Fix: Avoid infinite while loop**
-//                    printf("WARNING: TX Buffer Underflow! Sending default value.\n");
-//                    DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t[]){0x00}, 1);
-//                    break;
-//                 }
-//            }
-//            break;
-
-        /* Arbitration lost or NACK */
-//        case DL_I2C_IIDX_TARGET_ARBITRATION_LOST:
-//            printf("Arbitration Lost.\n");
-//        case DL_I2C_IIDX_CONTROLLER_NACK:
-//            printf("I2C NACK Received! Possible communication failure.\n");
-            //DL_I2C_stopControllerTransfer(I2C_controller_INST);  // Force STOP
-//            break;
-//        default:
-//            printf("Unknown Interrupt.\n");
-//            break;
-//    }
-//}
-
-void I2C_Target_Init(void) {
-    // Set the target address
-    DL_I2C_setTargetOwnAddress(I2C_target_INST, I2C_target_TARGET_OWN_ADDR);
-
-    // Enable target mode
-    DL_I2C_enableTarget(I2C_target_INST);
-
-
-    /* Enable relevant I2C interrupts */
-    DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_START);
-    DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_RXFIFO_TRIGGER);
-    DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER);                                        
-    DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_STOP);
-    
-}
-
 void I2C_target_INST_IRQHandler(void) {
 
     //printf("I2C Interrupt Triggered to MCU (TARGET)!\n");
     static uint8_t receivedCommand= 0;
+    static uint8_t requestedSlot= 0;
     uint32_t status = DL_I2C_getPendingInterrupt(I2C_target_INST);
-    ADC_PARAMS params;
+    //ADC_PARAMS params;
     switch (status) {
 
         /* START condition detected */
@@ -336,27 +227,30 @@ void I2C_target_INST_IRQHandler(void) {
 
         /* TX FIFO trigger (Pi is reading data from MCU) */
         case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:
-            switch(receivedCommand){
-                case CMD_GET_BATTERY_STATUS:
-                    for(uint8_t slot=0; slot< NUM_SLOTS; slot++){
-                        Battery_StateUpdate(slot);
-                        uint8_t battery_status= batteries[slot].state;
-                        DL_I2C_fillTargetTXFIFO(I2C_target_INST, &battery_status, NUM_SLOTS);
-                        while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY); 
-                    }
-                break;
+            printf("Tx PI triggered!\n");
+            if (receivedCommand == CMD_GET_BATTERY_STATUS){
+                printf("Battery Status\n");
+                Battery_StateUpdate();
+                uint8_t battery_slots_status[NUM_SLOTS];
+                for(uint8_t slot= 0; slot< NUM_SLOTS; slot++){
+                    battery_slots_status[slot]= batteries[slot].state;
+                }
+                DL_I2C_fillTargetTXFIFO(I2C_target_INST, battery_slots_status, NUM_SLOTS);
+                while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY); 
 
-                case CMD_GET_BATTERY_DATA:
+            }
+            else if (receivedCommand == CMD_GET_BATTERY_DATA){
+                printf("Battery Data!\n");
                     piTxCount= 0;
                     piTxComplete= false;
-                    // Create a data message and transmit it
-                    for(uint8_t slot_id; slot_id<NUM_SLOTS; slot_id++){
-                        battery_data.slot_id= slot_id;
-                        battery_data.voltage= batteries[slot_id].voltage;
+                    if(requestedSlot < NUM_SLOTS){
+                        BatteryData battery_data;
+                        battery_data.slot_id= requestedSlot;
+                        battery_data.voltage= batteries[requestedSlot].voltage;
+                        // as of now set to 0 for testing
                         battery_data.current= 0;
                         battery_data.temperature=0;
                     }
-                    //printf("Sending Battery Data: Slot %d | Voltage %dmV| Current %d| Temperature %d.\n", slot_id, battery_data.voltage, battery_data.current, battery_data.temperature);
                     while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);
                     //Casting the struct pointer to byte array: (uint8_t*)
                     DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t*)&battery_data, sizeof(BatteryData));
@@ -368,11 +262,24 @@ void I2C_target_INST_IRQHandler(void) {
                         piTxCount = 0;  // Reset counter for next request
                         printf("Sent Full Battery Data\n");
                     }
-                    break;
             }
 
          /* TARGET_Rx FIFO trigger (Pi is writing data to MCU) */
         case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
+            if (!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)) {
+                if(receivedCommand == CMD_SET_BATTERY_LIMIT){
+                    BatteryLimitMsg battery_limits;
+                    requestedSlot= DL_I2C_receiveTargetData(I2C_target_INST);
+                    if(requestedSlot < NUM_SLOTS){
+                        batteries[requestedSlot].min_voltage= (DL_I2C_receiveTargetData(I2C_target_INST)<< 8)|DL_I2C_receiveTargetData(I2C_target_INST);
+                        batteries[requestedSlot].max_voltage= (DL_I2C_receiveTargetData(I2C_target_INST)<< 8)|DL_I2C_receiveTargetData(I2C_target_INST);
+                        batteries[requestedSlot].cut_off_current= (DL_I2C_receiveTargetData(I2C_target_INST)<< 8)|DL_I2C_receiveTargetData(I2C_target_INST);
+                        batteries[requestedSlot].capacitance= (DL_I2C_receiveTargetData(I2C_target_INST)<< 8)|DL_I2C_receiveTargetData(I2C_target_INST);
+                    }
+
+
+                }
+            }
             break;
 
         /* Arbitration lost or NACK */
@@ -410,12 +317,17 @@ int main(void)
 {
     // Initialize System and I2C
     SYSCFG_DL_init();
+
+    // Initialize battery array and default params
+    Battery_Init();
+    
     //Reset_I2C_Bus();
-    //NVIC_EnableIRQ(I2C_target_INST_INT_IRQN);
+    NVIC_EnableIRQ(I2C_target_INST_INT_IRQN);
     NVIC_EnableIRQ(I2C_controller_INST_INT_IRQN);
 
     printf("............System Configuration Enabled...............\n");
     
+    //Multiplexer
     Multiplexer_SelectChannel(I2C_CHANNEL);
     //I2C_scanBus();
     I2C_init(&gI2C);
@@ -428,14 +340,19 @@ int main(void)
         .gain= 1
 
     };
-    
     printf("Configuring ADC....\n");
     //**Set Configuration Register for ADC**
     ADC_SetConfigurationBytes(adc_params);
     uint16_t channel_a_value= 3300; // in mVolts
+    
+    
     while (1)
     {   
-         Battery_UpdateCurrentVoltage(adc_params);
+        
+        Battery_UpdateCurrentVoltage(adc_params);
+        for(uint8_t slot_id= 0; slot_id < NUM_SLOTS; slot++){
+            CC_CV_ControlCharging(slot_id);
+        }
         //delay_cycles(5000);
         //DAC_fastWrite(channel_a_value);
         delay_cycles(100000);

+ 9 - 21
i2c_target.c

@@ -29,7 +29,7 @@ uint32_t piRxLen, piRxCount;
 
 */
 
-void Battery_StateUpdate(uint8_t slot_id){
+void Battery_ReadState(uint8_t slot_id){
     
     uint16_t voltage_mv= batteries[slot_id].voltage;
     uint16_t min_voltage= batteries[slot_id].min_voltage;
@@ -55,33 +55,21 @@ void Battery_StateUpdate(uint8_t slot_id){
     }    
 }
 
+
+void Battery_StateUpdate(){
+    for(uint8_t slot=0; slot< NUM_SLOTS; slot++){
+        Battery_ReadState(slot);
+    }
+    while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY); 
+}
+
 void ProcessI2CCommand(uint8_t command, uint8_t slot_id, ADC_PARAMS params) {
     switch(command) {
         case CMD_GET_BATTERY_STATUS:
-            for(uint8_t slot=0; slot< NUM_SLOTS; slot++){
-                Battery_StateUpdate(slot);
-                DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER);
-                while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY); 
-            }
             break;
             
         case CMD_GET_BATTERY_DATA: 
 
-            piTxCount= 0;
-            piTxComplete= false;
-            // Create a data message and transmit it
-            Battery_UpdateCurrentVoltage(params);
-            battery_data.slot_id= slot_id;
-            battery_data.voltage= batteries[slot_id].voltage;
-            battery_data.current= 0;
-            battery_data.temperature=0;
-            printf("Sending Battery Data: Slot %d | Voltage %dmV| Current %d| Temperature %d.\n", slot_id, battery_data.voltage, battery_data.current, battery_data.temperature);
-            while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);
-            //Casting the struct pointer to byte array: (uint8_t*)
-            DL_I2C_enableInterrupt(I2C_target_INST, DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER);
-            DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t*)&battery_data, sizeof(BatteryData));
-            while(!piTxComplete);
-            while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY);      
             break;
         
         case CMD_SET_BATTERY_LIMIT: 

+ 1 - 1
i2c_target.h

@@ -43,5 +43,5 @@ typedef struct{
 
 //void I2C_Init();
 //void ProcessI2Ccommand();
-void Battery_StateUpdate(uint8_t slot_id);
+void Battery_StateUpdate();
 #endif