#include "src/controller/controller.h" //#include "src/i2c_comm/i2c_hal.h" #include "ti/driverlib/dl_i2c.h" #include "ti/driverlib/m0p/dl_core.h" #include "ti_msp_dl_config.h" #include //#include /* * Generic Function to send data to the target controller using I2C: Format: command + ((slot_id) + data (optional)) */ //Send command to set charge and discharge current to the target void controller_SetCurrent(uint8_t const TARGET_ADDRESS, uint8_t slot_id, int16_t current_mA){ //Bitmasked: Slot id + Command txPacket.txBuffer[0]= (slot_id<<4) | (CMD_SET_CURRENT & 0x0F); //Filling the buffer with current value *((int16_t*)(&txPacket.txBuffer[1])) = current_mA; /*I2C Communication for transmitting Charging/Discharging current for the slots*/ //Length is calculated as 1 byte for the bitmasked slot and command+ 2 bytes of current + 1 byte of padding txPacket.txLen= 4; DL_I2C_enableInterrupt(I2C_1_INST, DL_I2C_INTERRUPT_CONTROLLER_TXFIFO_TRIGGER); DL_I2C_startControllerTransfer(I2C_1_INST, TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_TX, txPacket.txLen); printf("Packet Sent:: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X \n", TARGET_ADDRESS, txPacket.txBuffer[0], txPacket.txBuffer[1],txPacket.txBuffer[2], txPacket.txBuffer[3]); DL_I2C_fillControllerTXFIFO(I2C_1_INST, txPacket.txBuffer, txPacket.txLen); // Wait for the bus to become not busy WITH a timeout uint32_t timeout = 10000; while ((DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS) && timeout > 0) { timeout--; } printf("STATUS ***SetCurrent successful for slot %d with current %d mA***\n", slot_id, current_mA); // Clean up and exit DL_I2C_flushControllerTXFIFO(I2C_1_INST); } //Get battery measurement: Voltage, Current, Temperature including slot state: bool controller_GetBatteryMeasurement(uint8_t slot_id){ uint8_t target_address= TARGET_BASE_ADDRESS + ((slot_id & 0b00000100) >> 2); printf("Target Address 0x%02X \n", target_address); //Initializing BatteryMeasurement structure from battery.h of size 8 BatteryMeasurement measurement; //Flush the TX FIFO and make the buffer ready to transmit data: DL_I2C_flushControllerTXFIFO(I2C_1_INST); DL_I2C_flushControllerRXFIFO(I2C_1_INST); //Write Command to the target //Set the command in the tx buffer in bit masked format to the target: Upper Nibble-> Slot and Lower Nibble -> Command txPacket.txBuffer[0]= (slot_id << 4)|(CMD_GET_MEASUREMENT & 0x0F); //shift slot_id to the left by 4 bits txPacket.txLen= 1; txPacket.txCount= 0; txPacket.txComplete= false; DL_I2C_fillControllerTXFIFO(I2C_1_INST, &txPacket.txBuffer[0], txPacket.txLen); // Wait for the bus to be idle uint32_t timeout = 10000; while (!(DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_IDLE) && timeout--); if(timeout == 0){ printf("Error in reading from I2C Bus: Bus is not getting ready before transmit start\n"); DL_I2C_resetControllerTransfer(I2C_1_INST); return false; } //Send command bytes to the target DL_I2C_startControllerTransferAdvanced(I2C_1_INST, target_address, DL_I2C_CONTROLLER_DIRECTION_TX, txPacket.txLen, DL_I2C_CONTROLLER_START_ENABLE, DL_I2C_CONTROLLER_STOP_DISABLE, DL_I2C_CONTROLLER_ACK_ENABLE); printf("[I2C] TX Packet Sent:: 0x%02X\n", txPacket.txBuffer[0]); //If I2C Bus is stuck then reset the controller: if(DL_I2C_getControllerStatus(I2C_1_INST)&(DL_I2C_CONTROLLER_STATUS_ERROR)){ printf("ERROR ***I2C Write Error: Bus is stuck***\n"); DL_I2C_resetControllerTransfer(I2C_1_INST); return false; } // Wait until TX FIFO is empty (TX complete) timeout = 10000; while ((DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS) && timeout--); if (timeout == 0) { printf("Bus stuck during TX.\n"); DL_I2C_resetControllerTransfer(I2C_1_INST); return false; } //delay_cycles(1000); //Re-initializing te timeout value for Rx: timeout= 10000; rxPacket.rxLen= sizeof(BatteryMeasurement); rxPacket.rxCount= 0; rxPacket.rxComplete= false; DL_I2C_enableInterrupt(I2C_1_INST, DL_I2C_INTERRUPT_CONTROLLER_RXFIFO_TRIGGER); //BatteryMeasurement size is 8 similar to the target side //DL_I2C_startControllerTransferAdvanced(I2C_1_INST, TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_RX, rxPacket.rxLen, DL_I2C_CONTROLLER_START_ENABLE, DL_I2C_CONTROLLER_STOP_ENABLE, DL_I2C_CONTROLLER_ACK_DISABLE); DL_I2C_startControllerTransfer(I2C_1_INST, target_address, DL_I2C_CONTROLLER_DIRECTION_RX, rxPacket.rxLen); while((DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS) && timeout--); if(timeout == 0 || (DL_I2C_getSCLStatus(I2C_1_INST)== DL_I2C_CONTROLLER_SCL_LOW)){ printf("Bus stuck during Rx transmit or SCL held LOW.\n"); DL_I2C_resetControllerTransfer(I2C_1_INST); return false; } //DEBUG //printf("Rx Count: %d\n", rxPacket.rxCount); printf("Total Received Bytes out of total length of [0x%02X]: 0x%02X\n", rxPacket.rxLen, sizeof(rxPacket.rxBuffer[rxPacket.rxCount])); printf("Rx Complete: %d\n", rxPacket.rxComplete); //Check if all the data is received then store the battery limits in BatteryInfo struct: if(rxPacket.rxCount== (sizeof(BatteryMeasurement))){ measurement.voltage= rxPacket.rxBuffer[0] | (rxPacket.rxBuffer[1] << 8); measurement.current= rxPacket.rxBuffer[2]|(rxPacket.rxBuffer[3] << 8); measurement.temperature = rxPacket.rxBuffer[4] | (rxPacket.rxBuffer[5] << 8); measurement.slot_state = (SlotState)(rxPacket.rxBuffer[6]); battery_data[slot_id].battery_measurement= measurement; //DEBUG printf("[I2C] Successfully read %d bytes from target 0x%02X\n", rxPacket.rxCount, target_address); printf("Voltage: %u\n", battery_data[slot_id].battery_measurement.voltage); printf("Current: %d\n", battery_data[slot_id].battery_measurement.current); printf("Temp: %u\n", battery_data[slot_id].battery_measurement.temperature); printf("Slot state: %u\n", battery_data[slot_id].battery_measurement.slot_state); return true; } return false; } //Clear error flag to the target to change it back to SLOT_STATE_OK //Format: command + ((slot_id) + data (optional)) void controller_ClearError(uint8_t const TARGET_ADDRESS, uint8_t slot_id){ uint8_t command= CMD_CLEAR_ERR| (slot_id<<4); //shift slot_id to the left by 4 bits printf("[MCU] Clear Error Bitmasked Command:: 0x%02X\n", command); txPacket.txBuffer[0]= command; txPacket.txBuffer[1]= slot_id; txPacket.txLen= sizeof(txPacket.txBuffer); while (DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS); DL_I2C_startControllerTransfer(I2C_1_INST, TARGET_ADDRESS, DL_I2C_CONTROLLER_DIRECTION_TX, txPacket.txLen); DL_I2C_fillControllerTXFIFO(I2C_1_INST, txPacket.txBuffer, txPacket.txLen); while (DL_I2C_getControllerStatus(I2C_1_INST) & DL_I2C_CONTROLLER_STATUS_BUSY_BUS); DL_I2C_flushControllerTXFIFO(I2C_1_INST); } //Logic to handle Power Burning PWM on the controller side: Problem of power flow back to the device which was breaking the board has been resolved void controller_EvaluateBatterySlotState(uint8_t slot_id, BatteryMeasurement *measurement){ static bool slot_sov_hov_state= false; if((measurement->slot_state== SLOT_ERR_HOV) || (measurement->slot_state == SLOT_STATE_SOV)){ slot_sov_hov_state= true; if(battery_data[slot_id].pwm_value < (PWM_MAX_VALUE - PWM_INCREMENT_VALUE)){ battery_data[slot_id].pwm_value+= PWM_INCREMENT_VALUE; printf("[Power Burning PWM] SOV/HOV state: Increased power burn PWM to %d\n", battery_data[slot_id].pwm_value); DL_TimerG_setCaptureCompareValue(PWM_0_INST, battery_data[slot_id].pwm_value, DL_TIMER_CC_0_INDEX); } }else if(measurement->slot_state== SLOT_STATE_OK && slot_sov_hov_state== true){ if(battery_data[slot_id].pwm_value >= (INITIAL_PWM_VALUE + PWM_DECREMENT_VALUE)){ battery_data[slot_id].pwm_value-= PWM_DECREMENT_VALUE; printf("[Power Burning PWM] OK state: Decreased power burn PWM to %d\n", battery_data[slot_id].pwm_value); DL_TimerG_setCaptureCompareValue(PWM_0_INST, battery_data[slot_id].pwm_value, DL_TIMER_CC_0_INDEX); } }else{ printf("[Power Burning PWM] initial state: %d\n", battery_data[slot_id].pwm_value); DL_TimerG_setCaptureCompareValue(PWM_0_INST, battery_data[slot_id].pwm_value, DL_TIMER_CC_0_INDEX); } }