|
@@ -0,0 +1,121 @@
|
|
|
|
|
+/*
|
|
|
|
|
+References: https://stackoverflow.com/questions/246127/why-is-volatile-needed-in-c
|
|
|
|
|
+
|
|
|
|
|
+*/
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#include "battery.h"
|
|
|
|
|
+#include "dac.h"
|
|
|
|
|
+#include "src/interfaces/mcu_slave_interface.h"
|
|
|
|
|
+#include "ti/driverlib/dl_i2c.h"
|
|
|
|
|
+#include "ti_msp_dl_config.h"
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
+#include <string.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[10] = {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[10] = {0};
|
|
|
|
|
+ /*Handling GET commands with bitmasking*/
|
|
|
|
|
+ // GET command for ADC(Battery Measurement): Voltage, Current, Temperature
|
|
|
|
|
+ if ((receivedCommand & 0xF0) == 0x60) {
|
|
|
|
|
+ uint8_t slot = receivedCommand & 0x0F;
|
|
|
|
|
+ if (slot > NUM_SLOTS) {
|
|
|
|
|
+ DL_I2C_flushTargetTXFIFO(i2c);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // Struct for voltage, current and temperature
|
|
|
|
|
+ BatteryMeasurementData battery_measure;
|
|
|
|
|
+ // Pointer pointing to the address of the requested battery slot:
|
|
|
|
|
+ Battery *battery = &batteries[slot];
|
|
|
|
|
+ // take the updated battery measurement from the battery struct and store it
|
|
|
|
|
+ // in the battery_measure struct
|
|
|
|
|
+ battery_measure.voltage = battery->voltage;
|
|
|
|
|
+ battery_measure.current = battery->current;
|
|
|
|
|
+ battery_measure.temperature = battery->temperature;
|
|
|
|
|
+ // Copying the memory block from battery_measure struct to tx_buffer:
|
|
|
|
|
+ memcpy(tx_buffer, &battery_measure, sizeof(battery_measure));
|
|
|
|
|
+ DL_I2C_fillTargetTXFIFO(i2c, tx_buffer, sizeof(BatteryMeasurementData));
|
|
|
|
|
+ printf("Battery Measurement Sent to MCU. \n");
|
|
|
|
|
+ DL_I2C_flushTargetTXFIFO(i2c);
|
|
|
|
|
+ }
|
|
|
|
|
+ // GET command for Battery Discharge State: 0x00, 0x01, 0x02, 0x03
|
|
|
|
|
+ else if ((receivedCommand & 0xF0) == 0x70) {
|
|
|
|
|
+ uint8_t slot = receivedCommand & 0x0F;
|
|
|
|
|
+ if (slot > NUM_SLOTS) {
|
|
|
|
|
+ DL_I2C_flushTargetTXFIFO(i2c);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Battery *battery = &batteries[slot];
|
|
|
|
|
+ uint8_t discharge_state = battery->condition;
|
|
|
|
|
+ DL_I2C_fillTargetTXFIFO(i2c, &discharge_state, 1);
|
|
|
|
|
+ while (DL_I2C_transmitTargetDataCheck(i2c, 0x00) != false)
|
|
|
|
|
+ ;
|
|
|
|
|
+
|
|
|
|
|
+ } else if (receivedCommand == CMD_SET_CURRENT) {
|
|
|
|
|
+ SetChargeDischargeCurrent set_current;
|
|
|
|
|
+ // Read incoming bytes from the Controller:
|
|
|
|
|
+ uint8_t rx_index = 0;
|
|
|
|
|
+ while (rx_index < sizeof(SetChargeDischargeCurrent)) {
|
|
|
|
|
+ //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);
|
|
|
|
|
+ //printf("Received Bytes[%d]: 0x%02X\n", rx_index, rx_buffer[rx_index]);
|
|
|
|
|
+ rx_index++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // printf("index:%d\n", rx_index);
|
|
|
|
|
+ // Byte array received from the Controller will be typecasted to (const
|
|
|
|
|
+ // uint8_t *), treats the rx_buffer as an array of READ ONLY bytes because
|
|
|
|
|
+ // of the const
|
|
|
|
|
+ if (rx_index != sizeof(SetChargeDischargeCurrent)) {
|
|
|
|
|
+ printf("ERROR: Incomplete I2C Rx: received %d%zu bytes\n", rx_index,
|
|
|
|
|
+ sizeof(SetChargeDischargeCurrent));
|
|
|
|
|
+ DL_I2C_flushTargetRXFIFO(i2c);
|
|
|
|
|
+ rx_index = 0;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ memcpy(&set_current, (const uint8_t *)rx_buffer,
|
|
|
|
|
+ sizeof(SetChargeDischargeCurrent));
|
|
|
|
|
+ if (set_current.slot_id < NUM_SLOTS) {
|
|
|
|
|
+ Battery *battery = &batteries[set_current.slot_id];
|
|
|
|
|
+ battery->charge_discharge_current = set_current.current;
|
|
|
|
|
+ // printf("Charge Current:%u\n", battery->charge_discharge_current);
|
|
|
|
|
+ }
|
|
|
|
|
+ uint8_t slot = set_current.slot_id;
|
|
|
|
|
+ int16_t current = set_current.current;
|
|
|
|
|
+
|
|
|
|
|
+ printf("Slot id: %d, Current: %d\n", slot, current);
|
|
|
|
|
+ if (current > 0) {
|
|
|
|
|
+ // Calibrate charge current for DAC, different slots will have different
|
|
|
|
|
+ // channels, how to handle that?-> ans: with slot_id, since each slots
|
|
|
|
|
+ // will be connected to each channels of the same DAC, address is same
|
|
|
|
|
+ // channels change
|
|
|
|
|
+ DL_GPIO_setPins(GPIO_Battery_Charging_PORT,
|
|
|
|
|
+ GPIO_Battery_Charging_PIN_PB4_PIN);
|
|
|
|
|
+ DAC_SingleWrite(current);
|
|
|
|
|
+ } else if (current < 0) {
|
|
|
|
|
+ // Calibrate discharge current for PWM
|
|
|
|
|
+ // TODO: PWM function develop
|
|
|
|
|
+ printf("PWM Discharge");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // do nothing, charge or discharge
|
|
|
|
|
+ printf("state is idle");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else if (receivedCommand == CMD_SET_HOV_CLEAR) {
|
|
|
|
|
+ uint8_t slot = DL_I2C_receiveTargetDataBlocking(i2c);
|
|
|
|
|
+ /*if (slot >= NUM_SLOTS) {
|
|
|
|
|
+ }*/
|
|
|
|
|
+ Battery *battery = &batteries[slot];
|
|
|
|
|
+ // clear hov state flag to false:
|
|
|
|
|
+ battery->pwm_hov_state = false;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|