/* Main Source File */ #include "adc.h" #include "battery.h" #include "cc_cv_charging.h" #include "dac.h" #include "i2c_target.h" #include "multiplexer.h" #include "ti/comm_modules/i2c/controller/i2c_comm_controller.h" #include "ti/devices/msp/peripherals/hw_dac12.h" #include "ti/driverlib/dl_adc12.h" #include "ti/driverlib/dl_gpio.h" #include "ti/driverlib/dl_i2c.h" #include "ti/driverlib/m0p/dl_core.h" #include "ti_msp_dl_config.h" #include #include #include #include I2C_Instance gI2C; I2C_ResponseInfo gResponse; BatteryData battery_data; /*Interrupt for MCU -> ADC * CASE: DL_I2C_IIDX_CONTROLLER_RX_DONE: ADC Reception Complete - ADC has finished sending data and it's fully received. - gI2C.rxMsg.len = gI2C.rxMsg.ptr: - Stores the received data length in the response buffer. - I2C_decodeResponse(): - Decodes the received response. - gI2C.status = I2C_STATUS_RX_COMPLETE: - Marks reception is complete. * CASE: DL_I2C_IIDX_CONTROLLER_TX_DONE: Data Transmit to ADC complete - DL_I2C_disableInterrupt(..): Disables the TXFIFO interrupt since data is now sent * CASE: DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER: Receive Data in FIFO - The I2C Receive FIFO has data ready to be read. - while (DL_I2C_isControllerRXFIFOEmpty(...) != true): Loops until the RX FIFOis empty (READ all available bytes) - Inside the while loop: - If buffer has SPACE, store the received byte - Prints each received byte in HEXADECIMAL format for debugging - IF BUFFER is FULL, avoids OVERFLOW by discarding extra byte. * CASE: DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER: Transmit Data in FIFO - If there is still data to send: gI2C.txMsg.ptr += DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &gI2C.txMsg.buffer[gI2C.txMsg.ptr], gI2C.txMsg.len - gI2C.txMsg.ptr); */ void I2C_controller_INST_IRQHandler(void) { // printf("I2C Interrupt Triggered to ADC!\n"); switch (DL_I2C_getPendingInterrupt(I2C_controller_INST)) { /*START Condition*/ case DL_I2C_IIDX_CONTROLLER_START: // gTxADCcount= 0; gRxADCcount = 0; DL_I2C_flushControllerTXFIFO(I2C_controller_INST); break; case DL_I2C_IIDX_CONTROLLER_RXFIFO_TRIGGER: gI2C.status = I2C_STATUS_RX_INPROGRESS; /* Store bytes received from target in Rx Msg Buffer */ while (DL_I2C_isControllerRXFIFOEmpty(I2C_controller_INST) != true) { if (gRxADCcount < gRxADClen) { gRxPacket[gRxADCcount] = DL_I2C_receiveControllerData(I2C_controller_INST); printf("Received Byte[%d]: 0x%02X\n", gRxADCcount, gRxPacket[gRxADCcount]); // Debug print gRxADCcount++; } else { // printf("ERROR: RX Buffer Overflow! ptr=%d MAX_BUFFER_SIZE=%d\n", // gI2C.rxMsg.ptr, MAX_BUFFER_SIZE); /* Ignore and remove from FIFO if the buffer is full */ DL_I2C_receiveControllerData(I2C_controller_INST); } } if (gRxADCcount >= gRxADClen) { // printf("ADC Bytes Received!\n"); gRxComplete = true; DL_I2C_enableInterrupt(I2C_controller_INST, DL_I2C_INTERRUPT_CONTROLLER_STOP); } break; /*TRANSMIT data to ADC*/ case DL_I2C_IIDX_CONTROLLER_TXFIFO_TRIGGER: // printf("TX FIFO with data!\n"); gI2C.status = I2C_STATUS_TX_INPROGRESS; if (gTxADCcount < gTxADClen) { gTxADCcount += DL_I2C_fillControllerTXFIFO(I2C_controller_INST, &gTxPacket[gTxADCcount], (gTxADClen - gTxADCcount)); } else { /*Prevent overflow and just ignore data*/ DL_I2C_fillTargetTXFIFO(I2C_controller_INST, (uint8_t[]){0x00}, 1); gTxComplete = true; } // DL_I2C_flushControllerTXFIFO(I2C_controller_INST); break; /*STOP condition*/ case DL_I2C_IIDX_CONTROLLER_STOP: gTxComplete = true; gRxComplete = true; // printf("I2C Stop Detected- RX Complete"); break; case DL_I2C_IIDX_CONTROLLER_ARBITRATION_LOST: // printf("Interrupt index for I2C controller Arbitration Lost!\n"); break; case DL_I2C_IIDX_CONTROLLER_NACK: // printf("I2C NACK Received\n"); if ((gI2C.status == I2C_STATUS_RX_STARTED) || (gI2C.status = I2C_STATUS_TX_STARTED)) { gI2C.status = I2C_STATUS_ERROR; } break; default: break; } } /**** Interrupt for Pi to MCU ****/ void I2C_target_INST_IRQHandler(void) { uint8_t receivedCommand = 0; uint8_t battery_state[8] = {0x00}; uint32_t status = DL_I2C_getPendingInterrupt(I2C_target_INST); printf("status: %d\n", status); switch (status) { case DL_I2C_IIDX_TARGET_START: /*Initialize Tx or RX after Start condition is recieved*/ piTxCount = 0; piRxCount = 0; piTxComplete = false; DL_I2C_flushTargetTXFIFO(I2C_target_INST); break; case DL_I2C_IIDX_TARGET_STOP: piTxComplete = true; piRxComplete = true; DL_I2C_flushTargetTXFIFO(I2C_target_INST); DL_I2C_flushTargetRXFIFO(I2C_target_INST); break; case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER: printf("Rx Interrupt Triggered \n"); if (DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)) { return; } receivedCommand = DL_I2C_receiveTargetData(I2C_target_INST); if (receivedCommand == CMD_GET_BATTERY_STATUS) { printf("Received Command: 0x%02X\n", receivedCommand); for (uint8_t slot = 0; slot < NUM_SLOTS; slot++) { battery_state[slot] = batteries[slot].state; } DL_I2C_fillTargetTXFIFO(I2C_target_INST, battery_state, 8); while (DL_I2C_transmitTargetDataCheck(I2C_target_INST, 0x00) != false) ; printf("Sent Data\n"); } /* To receive the Battery Mesaurements from MCU, bit masking is applied where: - command type is upper 4 bits: 0010 (for CMD_GET_BATTERY_DATA)-> consistent - slot_id is lower 3 bits, since NUM_SLOTS are 8 so it ranges from 000 till 111 - bit mask for command is 0xF0: 11110000 - bit mask for requested slot is 0x07: 00000111 receivedCommand now ranges from 0x20 till 0x27 */ else if ((receivedCommand & 0xF0) == 0x20) { //printf("Received Command: 0x%02X\n", receivedCommand); uint8_t requestedSlot = (receivedCommand & 0x07); //printf("Requested slot:%d\n", requestedSlot); // piTxCount = 0; piTxLen = sizeof(BatteryData); BatteryData battery_data; if (requestedSlot >= NUM_SLOTS) { //printf("Requested Slot is not valid.\n"); DL_I2C_flushTargetTXFIFO(I2C_target_INST); return; } Battery *battery = &batteries[requestedSlot]; battery_data.slot_id = battery->slot_id; // !TODO: recheck if necessary //printf("slot_id:%u\n", battery_data.slot_id); battery_data.voltage = battery->voltage; //printf("voltage:%u\n", battery_data.voltage); battery_data.current = battery->current; //printf("current:%u\n", battery_data.current); battery_data.temperature = battery->temperature; //printf("temperature:%u\n", battery_data.temperature); DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t *)&battery_data, piTxLen); /*piTxComplete= true; if(piTxCount >= piTxLen){ piTxComplete= true; piTxCount= 0; }*/ printf("Battery Measurement Sent. \n"); DL_I2C_flushTargetTXFIFO(I2C_target_INST); } else if (receivedCommand == CMD_SET_BATTERY_LIMIT) { uint8_t rx_buffer[sizeof(BatteryLimitMsg)]; uint8_t index = 0; while (!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)) { if (index < sizeof(BatteryLimitMsg)) { rx_buffer[index] = DL_I2C_receiveTargetData(I2C_target_INST); index++; } else { DL_I2C_receiveTargetData(I2C_target_INST); } } if (index == sizeof(BatteryLimitMsg)) { BatteryLimitMsg battery_limits; memcpy(&battery_limits, rx_buffer, sizeof(BatteryLimitMsg)); if (battery_limits.slot_id < NUM_SLOTS) { Battery *battery = &batteries[battery_limits.slot_id]; battery->min_voltage = battery_limits.min_voltage; battery->max_voltage = battery_limits.max_voltage; battery->cut_off_current = battery_limits.cut_off_current; battery->capacitance = battery_limits.capacitance; battery->charge_fraction = battery_limits.charge_fraction; } } } break; case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER: break; case DL_I2C_IIDX_TARGET_ARBITRATION_LOST: break; default: break; } } /********MAIN function*************/ 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_controller_INST_INT_IRQN); printf("............System Configuration Enabled...............\n"); // Multiplexer Multiplexer_SelectChannel(I2C_CHANNEL); // I2C_scanBus(); I2C_init(&gI2C); // ADC_SetConfigurationBytes(adc_voltage_params); // delay_cycles(50000); // ADC_SetConfigurationBytes(adc_current_params); // delay_cycles(50000); // DAC_ReadCurrentAddress(); while (1) { // Looping through the ADC Channels for (uint8_t slot_id = 0; slot_id < NUM_SLOTS; slot_id++) { for (uint8_t adc_channel = 0; adc_channel < ADC_CHANNEL_NUM; adc_channel++) { Battery_UpdateADCReading(slot_id, adc_channel); } Battery_ReadState(slot_id); } printf("Battery Details: Slot: %u, Voltage:%u, Current: %u \n, State:%u\n:", batteries[0].slot_id, batteries[0].voltage, batteries[0].current, batteries[0].state); // CC-CV Cycle: maximum cycles is not yet implemented // for(uint8_t slot_id= 0; slot_id < NUM_SLOTS; slot_id++){ // CC_CV_ControlCharging(slot_id); // } // DAC_fastWrite(CHANNEL_A_VALUE); } }