/* References: https://stackoverflow.com/questions/246127/why-is-volatile-needed-in-c */ #include "i2c_target.h" #include "src/battery_data/battery.h" #include "ti/driverlib/dl_i2c.h" #include #include #include "src/peripherals/dac/dac.h" #include #include "src/config.h" #include "ti_msp_dl_config.h" #include "src/peripherals/temp/tmp1075.h" /** * Dynamic addressing function * 1. set resistor to pullup * 2. measure gpio: * is it up, set the address +0, else set it +1 * 3. disable the pullup again, so there is no current wasted */ void initialize_target_address() { uint8_t add = 0; if (DL_GPIO_readPins(GPIOS_PORT, GPIOS_ADDR_PIN)) { add = 1; addr_offset = 4; } DL_I2C_setTargetOwnAddress(I2C_target_INST, I2C_TARGET_BASE_ADDRESS+add); DL_I2C_enableTargetOwnAddress(I2C_target_INST); } /*Function to Rx and Tx data from Target to Controller*/ // The code has multiple i2c instances (multiple MCUs connected) from which we // need to select the right one, passing a pointer as an argument int8_t mcu_i2c_handle(I2C_Regs *i2c) { if (DL_I2C_isTargetRXFIFOEmpty(i2c)) { return -1; } uint8_t receivedByte = DL_I2C_receiveTargetData(i2c); uint8_t receivedCommand = (receivedByte & 0x0F); uint8_t slot = ((receivedByte & 0xF0) >> 4); if (receivedCommand == CMD_GET_MEASUREMENT) { DL_I2C_flushTargetTXFIFO(i2c); DL_I2C_fillTargetTXFIFO(i2c, (uint8_t *)&battery_slots[slot].measurement, 8); } else if (receivedCommand == CMD_SET_CURRENT) { return slot; } else if (receivedCommand == CMD_CLEAR_ERR) { if (slot > NUM_SLOTS) { DL_I2C_flushTargetTXFIFO(i2c); return -1; } *battery_slots[slot].state = SLOT_STATE_OK; } DL_I2C_flushTargetRXFIFO(i2c); return -1; } void mcu_i2c_handle_read(I2C_Regs *i2c, uint8_t slot) { // Read incoming bytes from the Controller: uint8_t rx_index = 0; uint8_t rx_buffer[2] = {0x00, 0x00}; while (rx_index < 2) { // TODO: Need to have a workaround, currently the code is getting stuck on // the first trigger and provides result on the second trigger if (!DL_I2C_isTargetRXFIFOEmpty(i2c)) { rx_buffer[rx_index] = DL_I2C_receiveTargetData(i2c); rx_index++; } } if (rx_index != 2) { #ifdef DEBUG_TARGET printf("ERROR: Incomplete I2C Rx: received %d bytes\n", rx_index); #endif DL_I2C_flushTargetRXFIFO(i2c); rx_index = 0; return; } battery_slots[slot].set_current = *((int16_t*)(&rx_buffer[0])); #ifdef DEBUG_TARGET printf("Slot id: %d, Current: %d mA (Bytes 0x%02X 0x%02X)\n", slot, battery_slots[slot].set_current, rx_buffer[0], rx_buffer[1]); #endif /* // This code is for debugging: // you can shoot directly code to the DAC / PWM for debugging if (battery_slots[slot].set_current >= 0) { DAC_SingleWrite(slot, battery_slots[slot].set_current); } else if (battery_slots[slot].set_current < 0) { DL_TimerG_setCaptureCompareValue(PWM_0_INST, -1*battery_slots[slot].set_current, DL_TIMER_CC_1_INDEX); } else { // do nothing, charge or discharge #ifdef DEBUG_TARGET printf("state is idle"); #else ; #endif } */ }