|
|
@@ -0,0 +1,87 @@
|
|
|
+/*
|
|
|
+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 <stdio.h>
|
|
|
+#include <string.h>
|
|
|
+#include "src/peripherals/dac/dac.h"
|
|
|
+#include <inttypes.h>
|
|
|
+
|
|
|
+/*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
|
|
|
+
|
|
|
+void mcu_i2c_handle(I2C_Regs *i2c) {
|
|
|
+ printf("MCU interrupt triggered\n");
|
|
|
+ uint8_t receivedCommand = DL_I2C_receiveTargetData(i2c);
|
|
|
+ printf("[SLAVE] Received Command: 0x%02X\n", receivedCommand);
|
|
|
+ uint8_t tx_buffer[8] = {0};
|
|
|
+ // changed to volatile variable, so that the compiler cannot optimize the
|
|
|
+ // variable out and is forced to do as told by the code
|
|
|
+ volatile uint8_t rx_buffer[8] = {0};
|
|
|
+ /*Handling GET commands with bitmasking*/
|
|
|
+ // GET command for ADC(Battery Measurement): Voltage, Current, Temperature
|
|
|
+ if ((receivedCommand & 0x0F) == CMD_GET_MEASUREMENT) {
|
|
|
+ uint8_t slot = receivedCommand & 0xF0;
|
|
|
+ if (slot > NUM_SLOTS) {
|
|
|
+ DL_I2C_flushTargetTXFIFO(i2c);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Copying the memory block from battery_measure struct to tx_buffer:
|
|
|
+ // @todo check if this memcpy is even needed, probably
|
|
|
+ // &battery_slots[slot].measurement can be directly used as buffer for DL_I2C_fillTargetTXFIFO
|
|
|
+ memcpy(tx_buffer, &battery_slots[slot].measurement, sizeof(BatteryMeasurement));
|
|
|
+ DL_I2C_fillTargetTXFIFO(i2c, tx_buffer, sizeof(BatteryMeasurement));
|
|
|
+ printf("Battery Measurement Sent to MCU. \n");
|
|
|
+ DL_I2C_flushTargetTXFIFO(i2c);
|
|
|
+
|
|
|
+ } else if (receivedCommand == CMD_SET_CURRENT) {
|
|
|
+ // Read incoming bytes from the Controller:
|
|
|
+ uint8_t rx_index = 0;
|
|
|
+ while (rx_index < 4) {
|
|
|
+ // 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++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // we expect 4 bytes:
|
|
|
+ // 1. command
|
|
|
+ // 2. slot_id
|
|
|
+ // 3 + 4. current (int16)
|
|
|
+ if (rx_index != 4) {
|
|
|
+ printf("ERROR: Incomplete I2C Rx: received %d%zu bytes\n", rx_index, 4);
|
|
|
+ DL_I2C_flushTargetRXFIFO(i2c);
|
|
|
+ rx_index = 0;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ uint8_t slot = rx_buffer[1]; // first byte is the slot id (0..3)
|
|
|
+ battery_slots[slot].set_current = *((rx_buffer)+2); // byte 3+4 is the current
|
|
|
+ printf("Slot id: %d, Current: %" SCNd16 "\n", slot, battery_slots[slot].set_current);
|
|
|
+ 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_startCounter(PWM_0_INST);
|
|
|
+ DL_TimerG_setCaptureCompareValue(PWM_0_INST, -1*battery_slots[slot].set_current, DL_TIMER_CC_0_INDEX); // update ccr0 value
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // do nothing, charge or discharge
|
|
|
+ printf("state is idle");
|
|
|
+ }
|
|
|
+ } else if (receivedCommand == CMD_CELAR_ERR) {
|
|
|
+ uint8_t slot = receivedCommand & 0xF0;
|
|
|
+ if (slot > NUM_SLOTS) {
|
|
|
+ DL_I2C_flushTargetTXFIFO(i2c);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ *battery_slots[slot].state = SLOT_STATE_OK;
|
|
|
+ }
|
|
|
+}
|