/* Main Source File */ #include "i2c_target.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 "ti/comm_modules/i2c/controller/i2c_comm_controller.h" #include #include #include #include "multiplexer.h" #include "adc.h" #include "dac.h" #include "battery.h" #include "i2c_target.h" #include "cc_cv_charging.h" #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 slot_id; battery_data.voltage= battery-> voltage; battery_data.current= battery-> current; battery_data.temperature= battery-> temperature; while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY); DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t *)&battery_data, sizeof(BatteryData)); //piTxCount += DL_I2C_fillTargetTXFIFO(I2C_target_INST, (uint8_t*)&battery_data, piTxLen); piTxComplete= true; while (DL_I2C_getTargetStatus(I2C_target_INST) & DL_I2C_TARGET_STATUS_BUS_BUSY); if(piTxCount >= piTxLen){ piTxComplete= true; piTxCount=0; } } else{ printf("Invalid Slot ID: %d\n.", requestedSlot); } } } break; /* TARGET_Rx FIFO trigger (Pi is writing data to MCU) */ /*Pi SET battery data limits for each slot, where: - RXFIFO buffer is filled if the command from Pi is 0x03 - Creating a temporary buffer named ´rxbuffer´ - sizeof(BatteryLimitMsg): 11 bytes (1 byte: slot_id, 2 bytes: min_voltage; max_voltage; cut_off_current; capacitance; charge_fraction) - rx_buffer stores the data from Pi. - if all the expected bytes are received from Pi then, - memcpy() to copy the block of address from the temporary buffer to the BatteryLimitMsg structure - Why?, A: It copies the specified number of bytes from one memory location to another regardless of the type of the data stored. - verify if the received slot_id is less than NUM_SLOTS, where slot_id count starts from 0 then: - create a pointer variable for 'Battery' - battery_limits.slot_id: index of the battery slot to be updated - &batteries[battery_limits.slot_id]: gets the memory address of the battery in that slot - Accessing the structure members of Battery using -> operator. This allows efficient access to the structure's members without directly using the structure variable. */ case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER: printf("Pi SET Battery limit to MCU.....\n"); if(!DL_I2C_isTargetRXFIFOEmpty(I2C_target_INST)){ receivedCommand= DL_I2C_receiveTargetData(I2C_target_INST); printf("Received Command: 0x%02X\n", receivedCommand); 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); printf("Received Byte[%d]: 0x%02X\n", index, rx_buffer[index]); index++; } else{ DL_I2C_receiveTargetData(I2C_target_INST); } } printf("Total Bytes Received: %d (Expected: %d)\n", index, sizeof(BatteryLimitMsg)); if(index == sizeof(BatteryLimitMsg)){ printf("Received Battery Limits.\n"); 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; printf("\n Received Battery Limits for slot %d: \n", battery_limits.slot_id); printf(" Min Voltage: %d mV (0x%04X)\n", battery_limits.min_voltage, battery_limits.min_voltage); printf(" Max Voltage: %d mV (0x%04X)\n", battery_limits.max_voltage, battery_limits.max_voltage); printf(" Cutoff Current: %d mA (0x%04X)\n", battery_limits.cut_off_current, battery_limits.cut_off_current); printf(" Capacitance: %d µF (0x%04X)\n", battery_limits.capacitance, battery_limits.capacitance); printf(" Charge Fraction: %d%% (0x%02X)\n", battery_limits.charge_fraction, battery_limits.charge_fraction); } } } } break; /* Arbitration lost or NACK */ case DL_I2C_IIDX_TARGET_ARBITRATION_LOST: printf("Arbitration Lost.\n"); break; default: printf("Unknown Interrupt.\n"); 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); // *Configure ADC for voltage: Channel 1 and Channel 2* /*ADC_PARAMS adc_voltage_params={ .channel= 1, .resolution= 12, .continuous= 1, .gain= 1 }; ADC_PARAMS adc_current_params={ .channel= 2, .resolution= 12, .continuous= 1, .gain= 1 };*/ //ADC_SetConfigurationBytes(adc_voltage_params); //delay_cycles(50000); //ADC_SetConfigurationBytes(adc_current_params); //delay_cycles(50000); while (1) { //Looping through the ADC Channels Battery_UpdateADCReading(); delay_cycles(100000); //Battery_UpdateCurrent(adc_current_params); //delay_cycles(50000); //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); } }