diff --git a/BMS/CMakeLists.txt b/BMS/CMakeLists.txt index 13b9437d8..2bb501df3 100644 --- a/BMS/CMakeLists.txt +++ b/BMS/CMakeLists.txt @@ -39,8 +39,8 @@ add_executable(BMS src/main.cpp src/EnergusTempSensor.cpp src/EnergusTempSensor.h src/Event.h - src/LTC6811.h - src/LTC6811.cpp + src/LTC6810.h + src/LTC6810.cpp src/StateOfCharge.cpp src/DS18B20.cpp ) diff --git a/BMS/src/BmsThread.cpp b/BMS/src/BmsThread.cpp index b4d04933c..1f984a985 100644 --- a/BMS/src/BmsThread.cpp +++ b/BMS/src/BmsThread.cpp @@ -9,10 +9,12 @@ #include "EnergusTempSensor.h" +#include "LTC6810.h" + BMSThread::BMSThread(LTC681xBus &bus, unsigned int frequency, BmsEventMailbox* bmsEventMailbox, MainToBMSMailbox* mainToBMSMailbox) : m_bus(bus), bmsEventMailbox(bmsEventMailbox), mainToBMSMailbox(mainToBMSMailbox) { for (int i = 0; i < BMS_BANK_COUNT; i++) { - m_chips.push_back(LTC6811(bus, i)); + m_chips.push_back(LTC6810(bus, i)); } for (int i = 0; i < BMS_BANK_COUNT; i++) { // m_chips[i].getConfig().gpio5 = LTC6811::GPIOOutputState::kLow; @@ -119,6 +121,13 @@ void BMSThread::threadWorker() { charging = mainToBMSEvent->charging;// assign charging to mainToBMSEvent // that is assigned the value held by charging // printf("Balance Allowed: %x\nCharging: %x\n", balanceAllowed, charging); + if (mainToBMSEvent->readI2CTemp) { + // Read temperature from I2C sensor on each bank + for (int i = 0; i < BMS_BANK_COUNT; i++) { + float temp = m_chips[i].readTemperatureTMP1075(); + printf("Bank %d I2C Temperature: %.2f°C\n", i, temp); + } + } delete mainToBMSEvent; // deallocate memory that was previously allocated dynamically to mainToBMSEvent } @@ -130,14 +139,14 @@ void BMSThread::threadWorker() { // TODO: This should be in some sort of config class for (int i = 0; i < BMS_BANK_COUNT; i++) { - LTC6811::Configuration &config = m_chips[i].getConfig(); - config.gpio5 = LTC6811::GPIOOutputState::kLow; + LTC6810::Configuration &config = m_chips[i].getConfig(); + config.gpio5 = LTC6810::GPIOOutputState::kLow; m_chips[i].updateConfig(); } // turn off cell balancing for voltage reading for (int i = 0; i < BMS_BANK_COUNT; i++) { - LTC6811::Configuration &config = m_chips[i].getConfig(); + LTC6810::Configuration &config = m_chips[i].getConfig(); config.dischargeState.value = 0x0000; @@ -207,14 +216,14 @@ void BMSThread::threadWorker() { for (uint8_t j = 0; j < BMS_BANK_CELL_COUNT; j++) { for (int i = 0; i < BMS_BANK_COUNT; i++) { // set the GPIOs for the segment we are looking at to the cell # we are getting temperature for - LTC6811::Configuration &config = m_chips[i].getConfig(); - config.gpio1 = (j & 0b001) ? LTC6811::GPIOOutputState::kHigh - : LTC6811::GPIOOutputState::kLow; - config.gpio2 = ((j & 0b010) >> 1) ? LTC6811::GPIOOutputState::kHigh - : LTC6811::GPIOOutputState::kLow; - config.gpio3 = ((j & 0b100) >> 2) ? LTC6811::GPIOOutputState::kHigh - : LTC6811::GPIOOutputState::kLow; - config.gpio4 = LTC6811::GPIOOutputState::kPassive; + LTC6810::Configuration &config = m_chips[i].getConfig(); + config.gpio1 = (j & 0b001) ? LTC6810::GPIOOutputState::kHigh + : LTC6810::GPIOOutputState::kLow; + config.gpio2 = ((j & 0b010) >> 1) ? LTC6810::GPIOOutputState::kHigh + : LTC6810::GPIOOutputState::kLow; + config.gpio3 = ((j & 0b100) >> 2) ? LTC6810::GPIOOutputState::kHigh + : LTC6810::GPIOOutputState::kLow; + config.gpio4 = LTC6810::GPIOOutputState::kPassive; m_chips[i].updateConfig(); @@ -337,7 +346,7 @@ void BMSThread::threadWorker() { if (bmsState == BMSThreadState::BMSIdle && balanceAllowed) { for (int i = 0; i < BMS_BANK_COUNT; i++) { - LTC6811::Configuration &config = m_chips[i].getConfig(); + LTC6810::Configuration &config = m_chips[i].getConfig(); uint16_t dischargeValue = 0x0000; @@ -364,15 +373,15 @@ void BMSThread::threadWorker() { } else { for (int i = 0; i < BMS_BANK_COUNT; i++) { - LTC6811::Configuration &config = m_chips[i].getConfig(); + LTC6810::Configuration &config = m_chips[i].getConfig(); config.dischargeState.value = 0x0000; m_chips[i].updateConfig(); } } for (int i = 0; i < BMS_BANK_COUNT; i++) { - LTC6811::Configuration &config = m_chips[i].getConfig(); - config.gpio5 = LTC6811::GPIOOutputState::kLow; + LTC6810::Configuration &config = m_chips[i].getConfig(); + config.gpio5 = LTC6810::GPIOOutputState::kLow; m_chips[i].updateConfig(); } diff --git a/BMS/src/BmsThread.h b/BMS/src/BmsThread.h index 46d7f5626..2184e8005 100644 --- a/BMS/src/BmsThread.h +++ b/BMS/src/BmsThread.h @@ -15,7 +15,7 @@ //#include "Can.h" #include "EnergusTempSensor.h" -#include "LTC6811.h" +#include "LTC6810.h" #include "LTC681xBus.h" #include "Event.h" @@ -32,8 +32,9 @@ class BMSThread { private: bool balanceAllowed = false; bool charging = false; + bool readI2CTemp; LTC681xBus& m_bus; - std::vector m_chips; + std::vector m_chips; BmsEventMailbox* bmsEventMailbox; MainToBMSMailbox* mainToBMSMailbox; diff --git a/BMS/src/Event.h b/BMS/src/Event.h index dc6d2d7a6..046f679f7 100644 --- a/BMS/src/Event.h +++ b/BMS/src/Event.h @@ -34,6 +34,7 @@ class MainToBMSEvent { public: bool balanceAllowed = false; bool charging = false; + bool readI2CTemp; }; static constexpr auto mailboxSize = 4; diff --git a/BMS/src/LTC6811.cpp b/BMS/src/LTC6810.cpp similarity index 58% rename from BMS/src/LTC6811.cpp rename to BMS/src/LTC6810.cpp index 032436a1d..4bd88db5b 100644 --- a/BMS/src/LTC6811.cpp +++ b/BMS/src/LTC6810.cpp @@ -1,16 +1,19 @@ -#include "LTC6811.h" +#include "LTC6810.h" #include "mbed.h" #include "rtos.h" #include "LTC681xParallelBus.h" -LTC6811::LTC6811(LTC681xBus &bus, uint8_t id) : m_bus(bus), m_id(id) { +#define TMP1075_I2C_ADDR 0x48 +#define TMP1075_TEMP_REG 0x00 + +LTC6810::LTC6810(LTC681xBus &bus, uint8_t id) : m_bus(bus), m_id(id) { m_config = Configuration{.gpio5 = GPIOOutputState::kPassive, - .gpio4 = GPIOOutputState::kPassive, - .gpio3 = GPIOOutputState::kPassive, - .gpio2 = GPIOOutputState::kPassive, + .gpio4 = GPIOOutputState::kHigh, + .gpio3 = GPIOOutputState::kHigh, + .gpio2 = GPIOOutputState::kHigh, .gpio1 = GPIOOutputState::kPassive, .referencePowerOff = ReferencePowerOff::kAfterConversions, .dischargeTimerEnabled = DischargeTimerEnable::kDisabled, @@ -21,7 +24,7 @@ LTC6811::LTC6811(LTC681xBus &bus, uint8_t id) : m_bus(bus), m_id(id) { .dischargeTimeout = DischargeTimeoutValue::kDisabled}; } -void LTC6811::updateConfig() { +void LTC6810::updateConfig() { // Create configuration data to write uint8_t config[6]; config[0] = (uint8_t) m_config.gpio5 << 7 @@ -45,9 +48,9 @@ void LTC6811::updateConfig() { m_bus.SendDataCommand(cmd, config); } -LTC6811::Configuration <C6811::getConfig() { return m_config; } +LTC6810::Configuration <C6810::getConfig() { return m_config; } -uint16_t *LTC6811::getVoltages() { +uint16_t *LTC6810::getVoltages() { auto cmd = StartCellVoltageADC(AdcMode::k7k, false, CellSelection::kAll); m_bus.SendCommand(LTC681xBus::BuildAddressedBusCommand(cmd, m_id)); @@ -55,15 +58,14 @@ uint16_t *LTC6811::getVoltages() { ThisThread::sleep_for(2ms); // TODO: Change // 4 * (Register of 6 Bytes + PEC) - uint8_t rxbuf[8 * 4]; + uint8_t rxbuf[8 * 2]; m_bus.SendReadCommand(LTC681xBus::BuildAddressedBusCommand(ReadCellVoltageGroupA(), m_id), rxbuf); m_bus.SendReadCommand(LTC681xBus::BuildAddressedBusCommand(ReadCellVoltageGroupB(), m_id), rxbuf + 8); - m_bus.SendReadCommand(LTC681xBus::BuildAddressedBusCommand(ReadCellVoltageGroupC(), m_id), rxbuf + 16); - m_bus.SendReadCommand(LTC681xBus::BuildAddressedBusCommand(ReadCellVoltageGroupD(), m_id), rxbuf + 24); + // Voltage = val • 100μV - uint16_t *voltages = new uint16_t[12]; + uint16_t *voltages = new uint16_t[6]; for (unsigned int i = 0; i < sizeof(rxbuf); i++) { // Skip over PEC if (i % 8 == 6 || i % 8 == 7) continue; @@ -78,7 +80,7 @@ uint16_t *LTC6811::getVoltages() { return voltages; } -uint16_t *LTC6811::getGpio() { +uint16_t *LTC6810::getGpio() { auto cmd = StartGpioADC(AdcMode::k7k, GpioSelection::kAll); m_bus.SendCommand(LTC681xBus::BuildAddressedBusCommand(cmd, m_id)); @@ -106,7 +108,7 @@ uint16_t *LTC6811::getGpio() { return voltages; } -uint16_t *LTC6811::getGpioPin(GpioSelection pin) { +uint16_t *LTC6810::getGpioPin(GpioSelection pin) { auto cmd = StartGpioADC(AdcMode::k7k, pin); m_bus.SendCommand(LTC681xBus::BuildAddressedBusCommand(cmd, m_id)); @@ -132,4 +134,81 @@ uint16_t *LTC6811::getGpioPin(GpioSelection pin) { } return voltages; -} \ No newline at end of file +} + +void LTC6810::buildCOMMBytes(uint8_t icom, uint8_t fcom, uint8_t data, uint8_t *commBytes) { + // COMMn (even byte): Upper 4 bits = ICOM, Lower 4 bits = upper half of data + commBytes[0] = (icom << 4) | ((data >> 4) & 0x0F); + + // COMMn+1 (odd byte): Upper 4 bits = lower half of data, Lower 4 bits = FCOM + commBytes[1] = ((data & 0x0F) << 4) | fcom; +} + +float LTC6810::readTemperatureTMP1075() { + uint8_t commData[6]; + uint8_t rxData[8]; + uint8_t tempBytes[2]; + + buildCOMMBytes(0x6, 0x0, (TMP1075_I2C_ADDR << 1) | 0x00, tempBytes); + commData[0] = tempBytes[0]; // COMM0 + commData[1] = tempBytes[1]; // COMM1 + + buildCOMMBytes(0x0, 0x0, TMP1075_TEMP_REG, tempBytes); + commData[2] = tempBytes[0]; // COMM2 + commData[3] = tempBytes[1]; // COMM3 + + buildCOMMBytes(0x1, 0x0, 0x00, tempBytes); + commData[4] = tempBytes[0]; // COMM4 + commData[5] = tempBytes[1]; // COMM5 + + auto wrCmd = LTC681xBus::BuildAddressedBusCommand(WriteCommGroup(), m_id); + m_bus.SendDataCommand(wrCmd, commData); + + auto stCmd = LTC681xBus::BuildAddressedBusCommand(StartComm(), m_id); + m_bus.SendCommand(stCmd); + + ThisThread::sleep_for(3ms); + + buildCOMMBytes(0x6, 0x0, (TMP1075_I2C_ADDR << 1) | 0x01, tempBytes); + commData[0] = tempBytes[0]; // COMM0 + commData[1] = tempBytes[1]; // COMM1 + + + buildCOMMBytes(0x0, 0x0, 0xFF, tempBytes); + commData[2] = tempBytes[0]; // COMM2 + commData[3] = tempBytes[1]; // COMM3 + + buildCOMMBytes(0x0, 0x9, 0xFF, tempBytes); + commData[4] = tempBytes[0]; // COMM4 + commData[5] = tempBytes[1]; // COMM5 + + m_bus.SendDataCommand(wrCmd, commData); + m_bus.SendCommand(stCmd); + + ThisThread::sleep_for(3ms); + + auto rdCmd = LTC681xBus::BuildAddressedBusCommand(ReadCommGroup(), m_id); + m_bus.SendReadCommand(rdCmd, rxData); + + uint8_t tempMSB = ((rxData[2] & 0x0F) << 4) | ((rxData[3] >> 4) & 0x0F); + + uint8_t tempLSB = ((rxData[4] & 0x0F) << 4) | ((rxData[5] >> 4) & 0x0F); + + int16_t rawTemp = (tempMSB << 8) | tempLSB; + + float temperature = (rawTemp >> 4) * 0.0625f; + + return temperature; +} + +bool LTC6810::verifyI2CStatus(uint8_t *rxData) { + uint8_t data1 = ((rxData[2] & 0x0F) << 4) | ((rxData[3] >> 4) & 0x0F); + uint8_t data2 = ((rxData[4] & 0x0F) << 4) | ((rxData[5] >> 4) & 0x0F); + + if (data1 == 0xFF && data2 == 0xFF) { + return false; // No response from sensor + } + + return true; +} + diff --git a/BMS/src/LTC6811.h b/BMS/src/LTC6810.h similarity index 85% rename from BMS/src/LTC6811.h rename to BMS/src/LTC6810.h index 38e0fcf9c..0c091e914 100644 --- a/BMS/src/LTC6811.h +++ b/BMS/src/LTC6810.h @@ -2,7 +2,7 @@ #include -class LTC6811 { +class LTC6810 { public: enum class GPIOOutputState : uint8_t { // States with pull up resistor @@ -20,8 +20,7 @@ class LTC6811 { enum class AdcModeOption : uint8_t { kDefault = 0, kLowSpeed = 1 }; union DischargeState { struct { - uint8_t cell12 : 1, cell11 : 1, cell10 : 1, cell9 : 1, cell8 : 1, - cell7 : 1, cell6 : 1, cell5 : 1, cell4 : 1, cell3 : 1, cell2 : 1, + uint8_t cell6 : 1, cell5 : 1, cell4 : 1, cell3 : 1, cell2 : 1, cell1 : 1; }; uint16_t value; @@ -63,13 +62,16 @@ class LTC6811 { DischargeTimeoutValue dischargeTimeout; }; - LTC6811(LTC681xBus &bus, uint8_t id); + LTC6810(LTC681xBus &bus, uint8_t id); Configuration &getConfig(); void updateConfig(); uint16_t *getVoltages(); uint16_t *getGpio(); uint16_t *getGpioPin(GpioSelection pin); + void buildCOMMBytes(uint8_t icom, uint8_t fcom, uint8_t data, uint8_t *commBytes); + float readTemperatureTMP1075(); + bool verifyI2CStatus(uint8_t *rxData); private: LTC681xBus &m_bus; diff --git a/BMS/src/main.cpp b/BMS/src/main.cpp index 6ca5ec185..edcbd2e02 100644 --- a/BMS/src/main.cpp +++ b/BMS/src/main.cpp @@ -118,6 +118,9 @@ int main() { Timer soc_timer; t.start(); // start timer soc_timer.start(); + + uint32_t last_i2c_temp_read = 0; + int32_t capacityDischarged = -1; while (true) { // infinite loop @@ -125,6 +128,20 @@ int main() { status_message.glv_voltage = glvVoltage; // printf("GLV voltage: %d mV\n", glvVoltage * 100); // capacity initialization using the voltage lookup table + + uint32_t current_time = t.read_ms(); + // read I2C temperature + if (current_time - last_i2c_temp_read >= 1000) { // Every 1 second + if (!mainToBMSMailbox->full()) { + MainToBMSEvent* tempEvent = new MainToBMSEvent(); + tempEvent->balanceAllowed = shutdown_measure_pin; + tempEvent->charging = isCharging; + tempEvent->readI2CTemp = true; // Request temperature reading + mainToBMSMailbox->put(tempEvent); + } + last_i2c_temp_read = current_time; + } + while (!bmsMailbox->empty()) { // while the bmsMailbox is not empty BmsEvent* bmsEvent; // create bms event pointer