Cell voltages fork (SoC)

Dependencies:   CUER_CAN CUER_DS1820 LTC2943 LTC6804 mbed PowerControl

Committer:
maxv008
Date:
Thu Jul 13 20:05:16 2017 +0000
Revision:
31:888b2602aab2
Parent:
30:d90895e96226
Child:
32:5b82679b2e6f
All used CAN Packets from BMS in this code tested and working as expected (see comments in CANParserBMU.h

Who changed what in which revision?

UserRevisionLine numberNew contents of line
lcockerton62 0:0a5f554d2a16 1 #include "mbed.h"
lcockerton62 0:0a5f554d2a16 2 #include "CANParserBMU.h"
lcockerton62 0:0a5f554d2a16 3 #include "Data_Types_BMU.h"
lcockerton62 0:0a5f554d2a16 4 #include "CAN_Data.h"
lcockerton62 0:0a5f554d2a16 5 #include "CAN_IDs.h"
lcockerton62 1:51477fe4851b 6 #include "EEPROM_I2C.h"
lcockerton62 1:51477fe4851b 7 #include "Temperature.h"
DasSidG 4:9050c5d6925e 8 #include "LTC2943_Read.h"
maxv008 10:1079f8e52d65 9 #include "Cell_Voltage.h"
maxv008 7:d00f4433cea9 10 #include "SPI_I2C_Parser.h"
maxv008 25:1fe8a42f8a6d 11 #include "LTC2943.h"
lcockerton62 0:0a5f554d2a16 12
msharma97 9:82ba050a7e13 13
lcockerton62 0:0a5f554d2a16 14 using namespace CAN_IDs;
lcockerton62 0:0a5f554d2a16 15
lcockerton62 0:0a5f554d2a16 16 // Function definitions
lcockerton62 1:51477fe4851b 17 void transmit_data(BMU_data measurements,uint32_t status);
lcockerton62 1:51477fe4851b 18 void read_temperature_sensors(BMU_data &measurements);
lcockerton62 0:0a5f554d2a16 19 void update_SOC();
lcockerton62 0:0a5f554d2a16 20 void init();
maxv008 14:e0e88a009f4c 21 void interruptHandler();
maxv008 14:e0e88a009f4c 22 void CANDataSentCallback();
lcockerton62 1:51477fe4851b 23 void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address);
lcockerton62 1:51477fe4851b 24 uint16_t read_EEPROM_startup(BMU_data &measurements);
lcockerton62 1:51477fe4851b 25 uint32_t check_measurements(BMU_data &measurements);
maxv008 23:a1af4439c1fc 26 uint32_t take_measurements(BMU_data &measurements);
maxv008 14:e0e88a009f4c 27 void test_read_CAN_buffer();
DasSidG 12:fa9b1a459e47 28 bool test_read_voltage_CAN(uint16_t readings[], int can_ids[]);
maxv008 10:1079f8e52d65 29 void test_CAN_send();
maxv008 10:1079f8e52d65 30 void test_CAN_read();
lcockerton62 30:d90895e96226 31 bool check_EEPROM_PEC( uint16_t start_address, char start_address_array[], char SOC_out[]);
lcockerton62 0:0a5f554d2a16 32
lcockerton62 0:0a5f554d2a16 33 CAN can(CAN_READ_PIN, CAN_WRITE_PIN); //Create a CAN object to handle CAN comms
maxv008 14:e0e88a009f4c 34 CANMessage buffer[CAN_BUFFER_SIZE]; //CAN receive buffer
maxv008 14:e0e88a009f4c 35 bool safe_to_write[CAN_BUFFER_SIZE]; //Semaphore bit indicating that it's safe to write to the software buffer
maxv008 14:e0e88a009f4c 36 bool CAN_data_sent = false;
maxv008 14:e0e88a009f4c 37
maxv008 20:a1a1bfc938da 38 //Global array to store most recently obtained voltage and temp measurement:
maxv008 17:94dd9a0d3870 39 CMU_voltage voltage_readings[NO_CMUS];
maxv008 20:a1a1bfc938da 40 individual_temperature templist[NO_TEMPERATURE_SENSORS];
maxv008 28:f1f882bd1653 41 uint32_t status;
maxv008 28:f1f882bd1653 42 //LTC2943 ltc2943(i2c_sda, i2c_scl, alcc_pin, &dummyfunction, R_SENSE, BATTERY_CAPACITY);
maxv008 17:94dd9a0d3870 43
DasSidG 4:9050c5d6925e 44 uint16_t eeprom_start_address; //the initial address where we store/read SoC values
lcockerton62 0:0a5f554d2a16 45
lcockerton62 1:51477fe4851b 46 Timeout loop_delay;
lcockerton62 1:51477fe4851b 47 bool delay_finished = false;
lcockerton62 2:94716229ecc3 48
maxv008 28:f1f882bd1653 49 //The following is to initialize reading tests, can be removed when needed
maxv008 28:f1f882bd1653 50 float packSOC;
maxv008 28:f1f882bd1653 51 float packSOCPercentage;
maxv008 28:f1f882bd1653 52 pack_voltage_extremes minVolt;
maxv008 28:f1f882bd1653 53 pack_voltage_extremes maxVolt;
maxv008 28:f1f882bd1653 54 pack_temperature_extremes minTemp;
maxv008 28:f1f882bd1653 55 pack_temperature_extremes maxTemp;
maxv008 31:888b2602aab2 56 float batteryCurrent; uint32_t batteryVoltage;
maxv008 14:e0e88a009f4c 57
lcockerton62 2:94716229ecc3 58 void loop_delay_callback(void)
lcockerton62 2:94716229ecc3 59 {
lcockerton62 1:51477fe4851b 60 delay_finished = true;
lcockerton62 1:51477fe4851b 61 }
lcockerton62 1:51477fe4851b 62
lcockerton62 0:0a5f554d2a16 63 int main()
DasSidG 11:cf2db05cfa56 64 {
lcockerton62 1:51477fe4851b 65 BMU_data measurements;
lcockerton62 1:51477fe4851b 66 uint16_t current_EEPROM_address;
DasSidG 12:fa9b1a459e47 67 uint16_t volt_readings[36];
DasSidG 12:fa9b1a459e47 68 int can_ids[9];
maxv008 10:1079f8e52d65 69
lcockerton62 0:0a5f554d2a16 70 init();
maxv008 10:1079f8e52d65 71
DasSidG 11:cf2db05cfa56 72 //current_EEPROM_address = read_EEPROM_startup(measurements); // Read from the eeprom at startup to fill in the values of SoC
DasSidG 11:cf2db05cfa56 73 //ltc2943.accumulatedCharge(measurements.percentage_SOC); // Initialise the LTC2943 with the current state of charge
DasSidG 4:9050c5d6925e 74
lcockerton62 1:51477fe4851b 75 while (true) {
DasSidG 11:cf2db05cfa56 76
maxv008 31:888b2602aab2 77 status = take_measurements(measurements);
DasSidG 11:cf2db05cfa56 78 /*// Dont want to read the temperature sensors during each iteration of the loop
lcockerton62 0:0a5f554d2a16 79
lcockerton62 1:51477fe4851b 80 //Store data in the eeprom
lcockerton62 1:51477fe4851b 81 write_SOC_EEPROM(measurements, current_EEPROM_address);
DasSidG 11:cf2db05cfa56 82 */
lcockerton62 5:793afeef45dc 83 // CAN bus
maxv008 14:e0e88a009f4c 84 CAN_data_sent = false;//Currently does nothing, adding this line in more places then using
maxv008 14:e0e88a009f4c 85 //while(!CAN_data_sent); in order to ensure sending completes
maxv008 31:888b2602aab2 86 transmit_data(measurements,status);
maxv008 31:888b2602aab2 87 //test_read_CAN_buffer();
DasSidG 11:cf2db05cfa56 88
DasSidG 11:cf2db05cfa56 89 /*
lcockerton62 0:0a5f554d2a16 90 // Conserve power - enter a low powered mode
lcockerton62 2:94716229ecc3 91 delay_finished = false;
lcockerton62 1:51477fe4851b 92 loop_delay.attach(loop_delay_callback, LOOP_DELAY_S);
lcockerton62 1:51477fe4851b 93 while (!delay_finished) sleep();
DasSidG 11:cf2db05cfa56 94 */
DasSidG 11:cf2db05cfa56 95 wait(1);
maxv008 10:1079f8e52d65 96 }
lcockerton62 0:0a5f554d2a16 97 }
lcockerton62 0:0a5f554d2a16 98
lcockerton62 1:51477fe4851b 99 void transmit_data(BMU_data measurements, uint32_t status)
lcockerton62 0:0a5f554d2a16 100 {
msharma97 9:82ba050a7e13 101 CANMessage msg;
lcockerton62 0:0a5f554d2a16 102 /*
lcockerton62 0:0a5f554d2a16 103 Place all of the collected data onto the CAN bus
lcockerton62 0:0a5f554d2a16 104 */
lcockerton62 5:793afeef45dc 105 // Send cell voltages
maxv008 13:7b42af989cd1 106 //voltages sent in sets of 4 + one cmu data set
msharma97 9:82ba050a7e13 107 int repeating_unit_length = NO_READINGS_PER_CMU /4 + 1;
maxv008 10:1079f8e52d65 108 for(uint16_t i= 0; i < NO_CMUS; i++) {
msharma97 9:82ba050a7e13 109 //input id is offset, data structure is info, voltage, voltage, ......
maxv008 10:1079f8e52d65 110 //This is a slightly modified version of the Tritium BMS datasheet, to add an extra voltage reading set.
maxv008 10:1079f8e52d65 111 msg = createVoltageTelemetry(repeating_unit_length*i+2, measurements.cell_voltages[i].voltages);
msharma97 9:82ba050a7e13 112 can.write(msg);
maxv008 17:94dd9a0d3870 113 printf("Voltage Message id: %d \r\n", msg.id);
maxv008 17:94dd9a0d3870 114 //+4 - 4 cell voltages sent per measurement, simple pointer arithmetic
maxv008 10:1079f8e52d65 115 msg = createVoltageTelemetry(repeating_unit_length*i+3, measurements.cell_voltages[i].voltages + 4);
msharma97 9:82ba050a7e13 116 can.write(msg);
maxv008 17:94dd9a0d3870 117 printf("Voltage Message id: %d \r\n", msg.id);
maxv008 10:1079f8e52d65 118 msg = createVoltageTelemetry(repeating_unit_length*i+4, measurements.cell_voltages[i].voltages + 8);
msharma97 9:82ba050a7e13 119 can.write(msg);
maxv008 17:94dd9a0d3870 120 printf("Voltage Message id: %d \r\n", msg.id);
lcockerton62 1:51477fe4851b 121 }
maxv008 13:7b42af989cd1 122
maxv008 13:7b42af989cd1 123 //Transmitting all of the individual probes:
maxv008 17:94dd9a0d3870 124 for(uint8_t i = 0; i < devices_found; i++)
maxv008 13:7b42af989cd1 125 {
maxv008 14:e0e88a009f4c 126 individual_temperature tempreading = measurements.temperature_measurements[i];
maxv008 14:e0e88a009f4c 127 msg = createTemperatureTelemetry(i, &tempreading.ROMID[0], tempreading.measurement);
maxv008 17:94dd9a0d3870 128 individual_temperature testOut = decodeTemperatureTelemetry(msg);
maxv008 17:94dd9a0d3870 129 printf("Temperature reading sent (CAN ID = %d): (%f,%d) \r\n", msg.id, testOut.measurement, testOut.ID);
maxv008 20:a1a1bfc938da 130 if(can.write(msg));
maxv008 20:a1a1bfc938da 131 else
maxv008 20:a1a1bfc938da 132 printf("Sending Temperature Failed for some reason");
maxv008 13:7b42af989cd1 133 }
lcockerton62 1:51477fe4851b 134
lcockerton62 1:51477fe4851b 135 // Create SOC CAN message
maxv008 23:a1af4439c1fc 136 msg = createPackSOC(measurements.SOC, measurements.percentage_SOC);
maxv008 23:a1af4439c1fc 137 can.write(msg);
maxv008 28:f1f882bd1653 138 printf("SOC is %f and percentage SOC is %f and id is %d \r\n", measurements.SOC, measurements.percentage_SOC, msg.id);
maxv008 23:a1af4439c1fc 139
lcockerton62 1:51477fe4851b 140 // Min/max cell voltages
maxv008 23:a1af4439c1fc 141 msg = createCellVoltageMAXMIN(measurements.max_cell_voltage, measurements.min_cell_voltage);
maxv008 23:a1af4439c1fc 142 can.write(msg);
maxv008 23:a1af4439c1fc 143
maxv008 23:a1af4439c1fc 144 // Min/Max cell temperatures
maxv008 23:a1af4439c1fc 145 msg = createCellTemperatureMAXMIN(measurements.min_cell_temp, true);
maxv008 23:a1af4439c1fc 146 can.write(msg);
maxv008 23:a1af4439c1fc 147 msg = createCellTemperatureMAXMIN(measurements.max_cell_temp, false);
maxv008 23:a1af4439c1fc 148 can.write(msg);
maxv008 31:888b2602aab2 149 wait(0.1); //WAITS ABSOLUTELY NECESSARY! values may be changed. Limit to how fast msg can be sent
lcockerton62 2:94716229ecc3 150 // Battery voltage and current
lcockerton62 5:793afeef45dc 151 // @TODO add the voltage
maxv008 23:a1af4439c1fc 152 msg = createBatteryVI(measurements.battery_voltage,measurements.battery_current);
maxv008 31:888b2602aab2 153 can.write(msg);
maxv008 31:888b2602aab2 154 printf("Sent Battery voltage %d and current %f with id %d \r\n",decodeBatteryVoltage(msg),decodeBatteryCurrent(msg),msg.id);
maxv008 23:a1af4439c1fc 155
lcockerton62 1:51477fe4851b 156 //Extended battery pack status
maxv008 23:a1af4439c1fc 157 msg = createExtendedBatteryPackStatus(status);
maxv008 23:a1af4439c1fc 158 can.write(msg);
maxv008 31:888b2602aab2 159
maxv008 31:888b2602aab2 160 msg = createBMSHeartbeat(0, 0);
maxv008 31:888b2602aab2 161 can.write(msg);
lcockerton62 0:0a5f554d2a16 162 }
lcockerton62 0:0a5f554d2a16 163
maxv008 10:1079f8e52d65 164
lcockerton62 1:51477fe4851b 165 uint16_t read_EEPROM_startup(BMU_data &measurements)
lcockerton62 0:0a5f554d2a16 166 {
lcockerton62 1:51477fe4851b 167 /* The first page of the EEPROM, specifically the first 2 addresses store a
lcockerton62 1:51477fe4851b 168 pointer of the first memory location of measurement data. The EEPROM only has a finite number of
lcockerton62 1:51477fe4851b 169 read/write cycles which is why we aren't writing to the same location throughout
lcockerton62 1:51477fe4851b 170 */
lcockerton62 30:d90895e96226 171 uint16_t start_address1;
lcockerton62 30:d90895e96226 172 uint16_t start_address2;
lcockerton62 1:51477fe4851b 173 uint16_t start_address;
lcockerton62 30:d90895e96226 174 char start_address_array1[2];
lcockerton62 30:d90895e96226 175 char start_address_array2[2];
lcockerton62 22:2df45c818786 176 char SOC_out[10]; // 4 bytes for the 2 floats one is SOC and the other % charge
lcockerton62 1:51477fe4851b 177 float *fp1,*fp2; // temporary storage for float conversion
lcockerton62 30:d90895e96226 178 bool is_first_read_true = 0;
lcockerton62 30:d90895e96226 179 bool is_second_read_true = 0;
lcockerton62 30:d90895e96226 180
lcockerton62 30:d90895e96226 181 // Get a pointer to the start address for the data stored in the eeprom
lcockerton62 30:d90895e96226 182 i2c_page_read(0x0000,2,start_address_array1);
lcockerton62 30:d90895e96226 183 i2c_page_read(0x0002,2,start_address_array2);
lcockerton62 30:d90895e96226 184
lcockerton62 30:d90895e96226 185 is_first_read_true = check_EEPROM_PEC(start_address, start_address_array1, SOC_out);
lcockerton62 30:d90895e96226 186
lcockerton62 30:d90895e96226 187 if(is_first_read_true){
lcockerton62 30:d90895e96226 188 fp1 = (float*)(&SOC_out[0]);
lcockerton62 30:d90895e96226 189 fp2 = (float*)(&SOC_out[4]);
lcockerton62 30:d90895e96226 190 measurements.SOC = *fp1;
lcockerton62 30:d90895e96226 191 measurements.percentage_SOC = *fp2;
lcockerton62 30:d90895e96226 192 }
lcockerton62 30:d90895e96226 193 else{
lcockerton62 30:d90895e96226 194 is_second_read_true = check_EEPROM_PEC(start_address, start_address_array2, SOC_out);
lcockerton62 30:d90895e96226 195
lcockerton62 30:d90895e96226 196 if(is_second_read_true){
lcockerton62 30:d90895e96226 197 fp1 = (float*)(&SOC_out[0]);
lcockerton62 30:d90895e96226 198 fp2 = (float*)(&SOC_out[4]);
lcockerton62 30:d90895e96226 199 measurements.SOC = *fp1;
lcockerton62 30:d90895e96226 200 measurements.percentage_SOC = *fp2;
lcockerton62 30:d90895e96226 201 }
lcockerton62 30:d90895e96226 202 }
lcockerton62 30:d90895e96226 203
lcockerton62 30:d90895e96226 204 if(is_second_read_true || is_first_read_true){
lcockerton62 30:d90895e96226 205 // Select the next address to write to
lcockerton62 30:d90895e96226 206 start_address1 += 0x0040;
lcockerton62 30:d90895e96226 207 start_address2 += 0x0040;
lcockerton62 30:d90895e96226 208 if(start_address > MAX_WRITE_ADDRESS) {
lcockerton62 30:d90895e96226 209 start_address1 = START_WRITE_ADDRESS; // Loop to the start of the eeprom
lcockerton62 30:d90895e96226 210 start_address2 = START_WRITE_ADDRESS + SECOND_ADDRESS_OFFSET; // Write this data SECOND_ADDRESS_OFFSET memory locations later than the first set // (this was chosen since only 10 bytes are written to memory
lcockerton62 30:d90895e96226 211 }
lcockerton62 30:d90895e96226 212 start_address_array1[0] = start_address1 | 0x00FF;
lcockerton62 30:d90895e96226 213 start_address_array1[1] = start_address1 >> 8;
lcockerton62 30:d90895e96226 214 start_address_array2[0] = start_address2 | 0x00FF;
lcockerton62 30:d90895e96226 215 start_address_array2[1] = start_address2 >> 8;
lcockerton62 30:d90895e96226 216
lcockerton62 30:d90895e96226 217 // Write the new location of the address to memory
lcockerton62 30:d90895e96226 218 i2c_page_write(0x0000, 2, start_address_array1);
lcockerton62 30:d90895e96226 219 i2c_page_write(0x0002, 2, start_address_array2);
lcockerton62 30:d90895e96226 220
lcockerton62 30:d90895e96226 221 return start_address1;
lcockerton62 30:d90895e96226 222 }
lcockerton62 30:d90895e96226 223 else{
lcockerton62 30:d90895e96226 224 printf("PEC error"); //@TODO an error flag should be raised since both values have failed
lcockerton62 30:d90895e96226 225 }
lcockerton62 30:d90895e96226 226 }
lcockerton62 30:d90895e96226 227
lcockerton62 30:d90895e96226 228 bool check_EEPROM_PEC( uint16_t start_address, char start_address_array[], char SOC_out[]){
lcockerton62 30:d90895e96226 229 // Helper method to check the PEC, returns 0 if the pec is wrong and 1 if the pec is correct
lcockerton62 22:2df45c818786 230 uint16_t received_pec;
lcockerton62 22:2df45c818786 231 uint16_t data_pec;
lcockerton62 30:d90895e96226 232
lcockerton62 1:51477fe4851b 233 // Read the data from this address
lcockerton62 1:51477fe4851b 234 start_address = (start_address_array[1]<< 8) | start_address_array[0]; // mbed little endian follow this convention
lcockerton62 22:2df45c818786 235 i2c_page_read(start_address, 10,SOC_out); // Reading will aquire 2 floats and a PEC for the data
lcockerton62 0:0a5f554d2a16 236
lcockerton62 22:2df45c818786 237 // Convert the SOC_out values back into floats and deal with the pec
lcockerton62 22:2df45c818786 238 received_pec = (uint16_t)(SOC_out[8]<<8) + (uint16_t)SOC_out[9];
lcockerton62 22:2df45c818786 239 data_pec = pec15_calc(8, (uint8_t*)SOC_out);
lcockerton62 22:2df45c818786 240 if(received_pec != data_pec) {
lcockerton62 30:d90895e96226 241 return 0;
lcockerton62 22:2df45c818786 242 }
lcockerton62 30:d90895e96226 243 else
lcockerton62 30:d90895e96226 244 return 1;
lcockerton62 0:0a5f554d2a16 245 }
lcockerton62 0:0a5f554d2a16 246
lcockerton62 1:51477fe4851b 247 void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address)
lcockerton62 0:0a5f554d2a16 248 {
lcockerton62 22:2df45c818786 249 char data_out[10];
lcockerton62 1:51477fe4851b 250 float *fp1,*fp2;
lcockerton62 22:2df45c818786 251 uint16_t data_pec;
lcockerton62 1:51477fe4851b 252
lcockerton62 1:51477fe4851b 253 fp1 = (float*)(&measurements.SOC);
lcockerton62 1:51477fe4851b 254 fp2 = (float*)(&measurements.percentage_SOC);
lcockerton62 0:0a5f554d2a16 255
lcockerton62 1:51477fe4851b 256 for(int i = 0; i < 4; i++ ) {
lcockerton62 1:51477fe4851b 257 data_out[i] = *fp1;
lcockerton62 1:51477fe4851b 258 fp1++;
lcockerton62 1:51477fe4851b 259 }
lcockerton62 1:51477fe4851b 260 for(int j = 4; j < 7; j++ ) {
lcockerton62 1:51477fe4851b 261 data_out[j] = *fp2;
lcockerton62 1:51477fe4851b 262 fp2++;
lcockerton62 1:51477fe4851b 263 }
lcockerton62 22:2df45c818786 264 data_pec = pec15_calc(8, ((uint8_t*)data_out)); // Calculate the pec and then write it to memory
lcockerton62 22:2df45c818786 265 data_out[8] = (char)(data_pec >> 8);
lcockerton62 22:2df45c818786 266 data_out[9] = (char)(data_pec);
lcockerton62 30:d90895e96226 267 i2c_page_write(start_address, 10,data_out);
lcockerton62 30:d90895e96226 268 i2c_page_write((start_address+SECOND_ADDRESS_OFFSET), 10,data_out); // Write the data to the backup memory location, SECOND_ADDRESS_OFFSET memory locations later
lcockerton62 0:0a5f554d2a16 269 }
lcockerton62 0:0a5f554d2a16 270
lcockerton62 1:51477fe4851b 271 void read_temperature_sensors(BMU_data &measurements)
lcockerton62 0:0a5f554d2a16 272 {
lcockerton62 1:51477fe4851b 273 float min_temperature;
maxv008 23:a1af4439c1fc 274 char min_id[8];
lcockerton62 1:51477fe4851b 275 float max_temperature;
maxv008 23:a1af4439c1fc 276 char max_id[8];
DasSidG 21:d461d58e70fc 277 isotherm_12V_pin = 1;
lcockerton62 1:51477fe4851b 278 probe[0]->convert_temperature(DS1820::all_devices);
DasSidG 21:d461d58e70fc 279
lcockerton62 1:51477fe4851b 280 min_temperature = probe[0]->temperature('C');
maxv008 23:a1af4439c1fc 281 std::memcpy(min_id, probe[0]->ROM, sizeof(char)*8); //invalid shallow copy: min_id = probe[0]->ROM;
lcockerton62 1:51477fe4851b 282 max_temperature = min_temperature; // Initially set the max and min temperature equal
maxv008 23:a1af4439c1fc 283 std::memcpy(max_id, probe[0]->ROM, sizeof(char)*8);
DasSidG 16:b2ef68c9a4fd 284 for (int i=0; i<devices_found; i++) {
maxv008 14:e0e88a009f4c 285 for(int j = 0; j < 7; j++)
maxv008 14:e0e88a009f4c 286 measurements.temperature_measurements[i].ROMID[j] = probe[i]->ROM[j];
lcockerton62 1:51477fe4851b 287 measurements.temperature_measurements[i].measurement = probe[i] ->temperature('C');
maxv008 14:e0e88a009f4c 288
lcockerton62 1:51477fe4851b 289 if(measurements.temperature_measurements[i].measurement > max_temperature) {
lcockerton62 1:51477fe4851b 290 max_temperature = measurements.temperature_measurements[i].measurement;
maxv008 23:a1af4439c1fc 291 std::memcpy(max_id, measurements.temperature_measurements[i].ROMID, sizeof(char)*8);
lcockerton62 2:94716229ecc3 292 } else if (measurements.temperature_measurements[i].measurement < min_temperature) {
lcockerton62 1:51477fe4851b 293 min_temperature = measurements.temperature_measurements[i].measurement;
maxv008 23:a1af4439c1fc 294 std::memcpy(min_id, measurements.temperature_measurements[i].ROMID, sizeof(char)*8);
lcockerton62 1:51477fe4851b 295 }
DasSidG 12:fa9b1a459e47 296
maxv008 18:521ffdd724f3 297 //printf("Device %d temperature is %3.3f degrees Celcius.\r\n",i+1 ,probe[i]->temperature('C'));
lcockerton62 1:51477fe4851b 298 }
DasSidG 21:d461d58e70fc 299 isotherm_12V_pin = 0;
maxv008 13:7b42af989cd1 300 //There is also a CMU # component of this struct, currently unfilled, perhaps not needed at all.
lcockerton62 1:51477fe4851b 301 measurements.max_cell_temp.temperature = max_temperature;
maxv008 23:a1af4439c1fc 302 std::memcpy(measurements.max_cell_temp.ROMID, max_id, sizeof(char)*8);
lcockerton62 1:51477fe4851b 303 measurements.min_cell_temp.temperature = min_temperature;
maxv008 28:f1f882bd1653 304 std::memcpy(measurements.min_cell_temp.ROMID, min_id, sizeof(char)*8);
maxv008 28:f1f882bd1653 305 delete max_id;
maxv008 28:f1f882bd1653 306 delete min_id;
lcockerton62 0:0a5f554d2a16 307 }
lcockerton62 0:0a5f554d2a16 308
lcockerton62 0:0a5f554d2a16 309 void update_SOC()
lcockerton62 0:0a5f554d2a16 310 {
lcockerton62 1:51477fe4851b 311 // Update the SOC value
maxv008 25:1fe8a42f8a6d 312 ltc2943.readAll();
lcockerton62 0:0a5f554d2a16 313 }
lcockerton62 0:0a5f554d2a16 314
lcockerton62 0:0a5f554d2a16 315
lcockerton62 1:51477fe4851b 316 uint32_t check_measurements(BMU_data &measurements)
lcockerton62 1:51477fe4851b 317 {
lcockerton62 1:51477fe4851b 318 uint32_t status;
lcockerton62 2:94716229ecc3 319
lcockerton62 2:94716229ecc3 320 if(measurements.max_cell_voltage.voltage > MAX_CELL_VOLTAGE) {
lcockerton62 2:94716229ecc3 321 status = status | CELL_OVER_VOLTAGE;
lcockerton62 2:94716229ecc3 322 } else if (measurements.min_cell_voltage.voltage < MIN_CELL_VOLTAGE) {
lcockerton62 1:51477fe4851b 323 status = status | CELL_UNDER_VOLTAGE;
lcockerton62 2:94716229ecc3 324 } else if (measurements.max_cell_temp.temperature > MAX_CELL_TEMPERATURE) {
lcockerton62 1:51477fe4851b 325 status = status | CELL_OVER_TEMPERATURE;
lcockerton62 1:51477fe4851b 326 }
lcockerton62 2:94716229ecc3 327
lcockerton62 1:51477fe4851b 328 /*
lcockerton62 1:51477fe4851b 329 @TODO also include errors for:
lcockerton62 1:51477fe4851b 330 *untrusted measurement
lcockerton62 1:51477fe4851b 331 *CMU timeout
lcockerton62 1:51477fe4851b 332 *SOC not valid
lcockerton62 1:51477fe4851b 333 */
lcockerton62 1:51477fe4851b 334 return status;
lcockerton62 1:51477fe4851b 335 }
lcockerton62 1:51477fe4851b 336
maxv008 23:a1af4439c1fc 337 //Returns the status variable
maxv008 23:a1af4439c1fc 338 uint32_t take_measurements(BMU_data &measurements)
lcockerton62 1:51477fe4851b 339 {
maxv008 6:b567fcb604aa 340 uint16_t cellvoltages[NO_CMUS][12];
DasSidG 16:b2ef68c9a4fd 341 //Use LTC6804_acquireVoltage to fill this array, and then properly format
maxv008 6:b567fcb604aa 342 //it to be sent over CAN
maxv008 6:b567fcb604aa 343
DasSidG 16:b2ef68c9a4fd 344 LTC6804_acquireVoltage(cellvoltages);
maxv008 23:a1af4439c1fc 345 pack_voltage_extremes min_voltage;
maxv008 23:a1af4439c1fc 346 pack_voltage_extremes max_voltage; //TODO do minmax voltage stuff
maxv008 23:a1af4439c1fc 347 min_voltage.voltage = 65535; //largest 16 bit unsigned int
maxv008 23:a1af4439c1fc 348 max_voltage.voltage = 0;
maxv008 23:a1af4439c1fc 349
maxv008 23:a1af4439c1fc 350 //Sets voltage readings as well as max/min voltage values.
maxv008 10:1079f8e52d65 351 for(int i=0; i<NO_CMUS; i++){
maxv008 17:94dd9a0d3870 352 for(int j=0; j < NO_READINGS_PER_CMU; j++){
DasSidG 16:b2ef68c9a4fd 353 measurements.cell_voltages[i].voltages[j] = cellvoltages[i][j]/ 10; //To get units of mV
maxv008 17:94dd9a0d3870 354 measurements.cell_voltages[i].CMU_number = i;
maxv008 23:a1af4439c1fc 355 if(measurements.cell_voltages[i].voltages[j] < min_voltage.voltage)
maxv008 23:a1af4439c1fc 356 {
maxv008 23:a1af4439c1fc 357 min_voltage.voltage = measurements.cell_voltages[i].voltages[j];
maxv008 23:a1af4439c1fc 358 min_voltage.CMU_number = i;
maxv008 23:a1af4439c1fc 359 min_voltage.cell_number = j;
maxv008 23:a1af4439c1fc 360 }
maxv008 31:888b2602aab2 361 else if(measurements.cell_voltages[i].voltages[j] > max_voltage.voltage)
maxv008 23:a1af4439c1fc 362 {
maxv008 23:a1af4439c1fc 363 max_voltage.voltage = measurements.cell_voltages[i].voltages[j];
maxv008 23:a1af4439c1fc 364 max_voltage.CMU_number = i;
maxv008 23:a1af4439c1fc 365 max_voltage.cell_number = j;
maxv008 23:a1af4439c1fc 366 }
maxv008 10:1079f8e52d65 367 }
maxv008 23:a1af4439c1fc 368 }
maxv008 23:a1af4439c1fc 369 measurements.max_cell_voltage = max_voltage;
maxv008 31:888b2602aab2 370 printf("Max Voltage is %d \r\n", max_voltage.voltage);
maxv008 23:a1af4439c1fc 371 measurements.min_cell_voltage = min_voltage;
maxv008 31:888b2602aab2 372 printf("Min Voltage is %d \r\n", min_voltage.voltage);
DasSidG 4:9050c5d6925e 373
maxv008 13:7b42af989cd1 374 //Add code to take all temperature measurements and add it to measurements struct.
maxv008 13:7b42af989cd1 375 read_temperature_sensors(measurements);
maxv008 23:a1af4439c1fc 376
maxv008 23:a1af4439c1fc 377 // Update the SOC and take relevant measurements
maxv008 23:a1af4439c1fc 378 update_SOC();
maxv008 31:888b2602aab2 379 measurements.battery_voltage = 0;
maxv008 31:888b2602aab2 380 for(int i = 0; i < NO_CMUS; i++)
maxv008 31:888b2602aab2 381 {
maxv008 31:888b2602aab2 382 for(int j = 0; j < NO_READINGS_PER_CMU; j++)
maxv008 31:888b2602aab2 383 {
maxv008 31:888b2602aab2 384 measurements.battery_voltage += measurements.cell_voltages[i].voltages[j];
maxv008 31:888b2602aab2 385 }
maxv008 31:888b2602aab2 386 }
maxv008 31:888b2602aab2 387 measurements.battery_current =ltc2943.current() * 1000; //*1000 to convert to mA
DasSidG 4:9050c5d6925e 388 measurements.percentage_SOC = ltc2943.accumulatedCharge();
DasSidG 4:9050c5d6925e 389 measurements.SOC = (measurements.percentage_SOC /100) * BATTERY_CAPACITY;
maxv008 23:a1af4439c1fc 390
maxv008 23:a1af4439c1fc 391 // Check data for errors
maxv008 23:a1af4439c1fc 392 return check_measurements(measurements);
lcockerton62 1:51477fe4851b 393 }
lcockerton62 1:51477fe4851b 394
lcockerton62 0:0a5f554d2a16 395 void init()
lcockerton62 0:0a5f554d2a16 396 {
maxv008 18:521ffdd724f3 397 //Comment out measurement stuff with BCU testing
maxv008 31:888b2602aab2 398 temperature_init(); // Initialise the temperature sensors
DasSidG 4:9050c5d6925e 399 LTC2943_initialise(); //Initialises the fixed parameters of the LTC2943
DasSidG 15:e901aff1f5b3 400 LTC6804_init(MD_FAST, DCP_DISABLED, CELL_CH_ALL, AUX_CH_VREF2); //Initialises the LTC6804s
maxv008 31:888b2602aab2 401
maxv008 14:e0e88a009f4c 402 for(int i=0; i<CAN_BUFFER_SIZE; i++)
maxv008 14:e0e88a009f4c 403 {
maxv008 14:e0e88a009f4c 404 buffer[i].id = BLANK_ID;
maxv008 14:e0e88a009f4c 405 safe_to_write[i]= true;
maxv008 14:e0e88a009f4c 406 }
maxv008 14:e0e88a009f4c 407
maxv008 14:e0e88a009f4c 408 //Initialise CAN stuff, attach CAN interrupt handlers
maxv008 14:e0e88a009f4c 409 can.frequency(CAN_BIT_RATE); //set transmission rate to agreed bit rate (ELEC-006)
maxv008 14:e0e88a009f4c 410 can.reset(); // (FUNC-018)
maxv008 14:e0e88a009f4c 411 can.attach(&interruptHandler, CAN::RxIrq); //receive interrupt handler
maxv008 14:e0e88a009f4c 412 can.attach(&CANDataSentCallback, CAN::TxIrq); //send interrupt handler
maxv008 17:94dd9a0d3870 413
maxv008 17:94dd9a0d3870 414 //Initialize voltage array
maxv008 17:94dd9a0d3870 415 for(int i = 0; i < NO_CMUS; i++)
maxv008 17:94dd9a0d3870 416 {
maxv008 17:94dd9a0d3870 417 for(int j = 0; j < NO_READINGS_PER_CMU; j++)
maxv008 17:94dd9a0d3870 418 {
maxv008 17:94dd9a0d3870 419 voltage_readings[i].voltages[j] = 0;
maxv008 17:94dd9a0d3870 420 }
maxv008 17:94dd9a0d3870 421 }
maxv008 20:a1a1bfc938da 422 //Initialize Temperature Array
maxv008 20:a1a1bfc938da 423 for(int i = 0; i < NO_TEMPERATURE_SENSORS; i++)
maxv008 20:a1a1bfc938da 424 {
maxv008 28:f1f882bd1653 425 templist[i].measurement = INFINITY;
maxv008 20:a1a1bfc938da 426 templist[i].ID = 0;
maxv008 20:a1a1bfc938da 427 }
maxv008 28:f1f882bd1653 428 //initialize stuff used in reading test:
maxv008 28:f1f882bd1653 429 packSOC = INFINITY;
maxv008 28:f1f882bd1653 430 packSOCPercentage = INFINITY;
maxv008 28:f1f882bd1653 431
maxv008 28:f1f882bd1653 432 minVolt.voltage = 0;
maxv008 28:f1f882bd1653 433 maxVolt.voltage = 0;
maxv008 28:f1f882bd1653 434
maxv008 28:f1f882bd1653 435 minTemp.temperature = 0; minTemp.ID = 0;
maxv008 28:f1f882bd1653 436 maxTemp.temperature = 0; maxTemp.ID = 0;
maxv008 31:888b2602aab2 437
maxv008 31:888b2602aab2 438 batteryCurrent = INFINITY; batteryVoltage = 0;
maxv008 14:e0e88a009f4c 439 }
maxv008 14:e0e88a009f4c 440
maxv008 14:e0e88a009f4c 441 void CANDataSentCallback(void) {
maxv008 14:e0e88a009f4c 442 CAN_data_sent = true;
lcockerton62 0:0a5f554d2a16 443 }
lcockerton62 0:0a5f554d2a16 444
maxv008 14:e0e88a009f4c 445 void interruptHandler()
maxv008 14:e0e88a009f4c 446 {
maxv008 14:e0e88a009f4c 447 CANMessage msg;
DasSidG 16:b2ef68c9a4fd 448 can.read(msg);
maxv008 14:e0e88a009f4c 449 for(int i=0; i<CAN_BUFFER_SIZE; i++) {
maxv008 14:e0e88a009f4c 450 if((buffer[i].id == msg.id || buffer[i].id==BLANK_ID) && safe_to_write[i]) {
maxv008 14:e0e88a009f4c 451 //("id %d added to buffer \r\n", msg.id);
maxv008 14:e0e88a009f4c 452 buffer[i] = msg;
maxv008 14:e0e88a009f4c 453 //return required so that only first blank buffer entry is converted to incoming message ID each time new message ID is encountered
maxv008 14:e0e88a009f4c 454 return;
maxv008 14:e0e88a009f4c 455 }
maxv008 14:e0e88a009f4c 456 }
maxv008 14:e0e88a009f4c 457 }
maxv008 14:e0e88a009f4c 458
maxv008 14:e0e88a009f4c 459 void test_read_CAN_buffer()
maxv008 14:e0e88a009f4c 460 {
maxv008 14:e0e88a009f4c 461 //Import the data from the buffer into a non-volatile, more usable format
maxv008 14:e0e88a009f4c 462 CAN_Data can_data[CAN_BUFFER_SIZE]; //container for all of the raw data
maxv008 17:94dd9a0d3870 463 CANMessage msgArray[CAN_BUFFER_SIZE]; //Same as above but some functions take message as their parameter
maxv008 14:e0e88a009f4c 464 int received_CAN_IDs[CAN_BUFFER_SIZE]; //needed to keep track of which IDs we've received so far
maxv008 14:e0e88a009f4c 465 for (int i = 0; i<CAN_BUFFER_SIZE; ++i)
maxv008 14:e0e88a009f4c 466 {
maxv008 14:e0e88a009f4c 467 safe_to_write[i] = false;
maxv008 14:e0e88a009f4c 468 can_data[i].importCANData(buffer[i]);
maxv008 14:e0e88a009f4c 469 received_CAN_IDs[i] = buffer[i].id;
maxv008 17:94dd9a0d3870 470 msgArray[i] = buffer[i];
maxv008 14:e0e88a009f4c 471 safe_to_write[i] = true;
maxv008 31:888b2602aab2 472 //printf("Id recieved %d \r\n", buffer[i].id);
maxv008 14:e0e88a009f4c 473 }
maxv008 17:94dd9a0d3870 474
maxv008 23:a1af4439c1fc 475 //voltage and Temp and SOC readings:
maxv008 18:521ffdd724f3 476 for(int i = 0; i < CAN_BUFFER_SIZE; i++)
maxv008 18:521ffdd724f3 477 {
maxv008 18:521ffdd724f3 478 //voltage
maxv008 28:f1f882bd1653 479 if(decodeVoltageTelemetry(msgArray[i], voltage_readings))
ItsJustZi 29:44924d2b1293 480 continue;
maxv008 28:f1f882bd1653 481 //temperature
maxv008 20:a1a1bfc938da 482 if(msgArray[i].id >= 0x700)
maxv008 18:521ffdd724f3 483 {
maxv008 20:a1a1bfc938da 484 individual_temperature dataPoint = decodeTemperatureTelemetry(msgArray[i]);
maxv008 20:a1a1bfc938da 485 for(int j = 0; j < NO_TEMPERATURE_SENSORS; j++)
maxv008 20:a1a1bfc938da 486 {
maxv008 20:a1a1bfc938da 487 if(dataPoint.ID == templist[j].ID)
maxv008 20:a1a1bfc938da 488 {
maxv008 20:a1a1bfc938da 489 templist[j] = dataPoint;
maxv008 20:a1a1bfc938da 490 break;
maxv008 20:a1a1bfc938da 491 }
maxv008 20:a1a1bfc938da 492 else if(templist[j].ID == 0)
maxv008 20:a1a1bfc938da 493 {
maxv008 20:a1a1bfc938da 494 templist[j] = dataPoint;
maxv008 20:a1a1bfc938da 495 break;
maxv008 20:a1a1bfc938da 496 }
maxv008 20:a1a1bfc938da 497 }
maxv008 20:a1a1bfc938da 498
maxv008 23:a1af4439c1fc 499 }
maxv008 23:a1af4439c1fc 500 //SOC
maxv008 23:a1af4439c1fc 501 if(msgArray[i].id == 0x6F4)
maxv008 23:a1af4439c1fc 502 {
maxv008 23:a1af4439c1fc 503 packSOC = decodePackSOC(msgArray[i]);
maxv008 23:a1af4439c1fc 504 packSOCPercentage = decodePackSOCPercentage(msgArray[i]);
maxv008 28:f1f882bd1653 505 }
maxv008 23:a1af4439c1fc 506
maxv008 23:a1af4439c1fc 507 if(msgArray[i].id == BMS_BASE_ID + MIN_TEMPERATURE)
maxv008 23:a1af4439c1fc 508 minTemp = decodeCellTemperatureMAXMIN(msgArray[i]);
maxv008 23:a1af4439c1fc 509 if(msgArray[i].id == BMS_BASE_ID + MAX_TEMPERATURE)
maxv008 23:a1af4439c1fc 510 maxTemp = decodeCellTemperatureMAXMIN(msgArray[i]);
maxv008 28:f1f882bd1653 511
maxv008 23:a1af4439c1fc 512 if(msgArray[i].id == BMS_BASE_ID + MAX_MIN_VOLTAGE)
maxv008 23:a1af4439c1fc 513 {
maxv008 23:a1af4439c1fc 514 decodeCellVoltageMAXMIN(msgArray[i], minVolt, maxVolt);
maxv008 23:a1af4439c1fc 515 }
maxv008 23:a1af4439c1fc 516
maxv008 31:888b2602aab2 517 if(msgArray[i].id == BMS_BASE_ID + BATTERY_VI_ID)
maxv008 31:888b2602aab2 518 {
maxv008 31:888b2602aab2 519 batteryVoltage = decodeBatteryVoltage(msgArray[i]);
maxv008 31:888b2602aab2 520 batteryCurrent = decodeBatteryCurrent(msgArray[i]);
maxv008 31:888b2602aab2 521 }
maxv008 31:888b2602aab2 522
maxv008 23:a1af4439c1fc 523 if(msgArray[i].id == BMS_BASE_ID + BATTERY_STATUS_ID)
maxv008 28:f1f882bd1653 524 status = decodeExtendedBatteryPackStatus(msgArray[i]);
maxv008 31:888b2602aab2 525
maxv008 31:888b2602aab2 526 if(msgArray[i].id == BMS_BASE_ID)
maxv008 31:888b2602aab2 527 printf("BMS Heartbeat Recieved \r\n");
maxv008 28:f1f882bd1653 528 }
maxv008 18:521ffdd724f3 529 //Print obtained Readings:
maxv008 18:521ffdd724f3 530 for(int i = 0; i < NO_CMUS; i++)
maxv008 18:521ffdd724f3 531 for(int j = 0; j < 12; j++)
maxv008 18:521ffdd724f3 532 printf("Voltage number %d for CMU %d is %d \r\n", j, i, voltage_readings[i].voltages[j]);
maxv008 17:94dd9a0d3870 533
maxv008 18:521ffdd724f3 534 for(int i = 0; i < NO_TEMPERATURE_SENSORS; i++)
maxv008 23:a1af4439c1fc 535 printf("Temperature of Sensor with ID %d is %f \r\n", templist[i].ID, templist[i].measurement);
maxv008 23:a1af4439c1fc 536
maxv008 23:a1af4439c1fc 537 printf("SOC is %f and SOC Percentage is %f \r\n", packSOC, packSOCPercentage);
maxv008 23:a1af4439c1fc 538
maxv008 31:888b2602aab2 539 printf("Battery Current is %f and Battery Voltage is %d \r\n", batteryCurrent, batteryVoltage);
maxv008 31:888b2602aab2 540
maxv008 31:888b2602aab2 541 printf("Voltage (Max,Min),(Max_CMU,Max_num) = (%d,%d),(%d,%d) \r\n", maxVolt.voltage, minVolt.voltage, maxVolt.CMU_number, maxVolt.cell_number);
maxv008 23:a1af4439c1fc 542
maxv008 28:f1f882bd1653 543 printf("(Temperature, ID): Minimum = (%d,%d). Maximum = (%d,%d) \r\n",
maxv008 23:a1af4439c1fc 544 minTemp.temperature,minTemp.ID,maxTemp.temperature,maxTemp.ID);
maxv008 23:a1af4439c1fc 545
maxv008 23:a1af4439c1fc 546 printf("Status value is: %d \r\n", status);
maxv008 14:e0e88a009f4c 547 }
maxv008 23:a1af4439c1fc 548
DasSidG 12:fa9b1a459e47 549 bool test_read_voltage_CAN(uint16_t readings[], int can_ids[])
maxv008 10:1079f8e52d65 550 {
maxv008 10:1079f8e52d65 551 CANMessage msg;
maxv008 10:1079f8e52d65 552 int can_id;
maxv008 10:1079f8e52d65 553 int offset;
maxv008 10:1079f8e52d65 554 int first_index;
maxv008 10:1079f8e52d65 555 int second_index;
maxv008 10:1079f8e52d65 556
maxv008 10:1079f8e52d65 557 if(can.read(msg))
maxv008 10:1079f8e52d65 558 {
maxv008 10:1079f8e52d65 559 for(int i =0; i < 4; i++)
maxv008 10:1079f8e52d65 560 {
maxv008 10:1079f8e52d65 561 readings[i] = (msg.data[2 * i]) + (msg.data[2*i+1] << 8); //Since data is 8 8bit ints not 4 16 bit ones
maxv008 10:1079f8e52d65 562 }
DasSidG 12:fa9b1a459e47 563 can_id = msg.id;
DasSidG 12:fa9b1a459e47 564 can_ids[0] = msg.id;
DasSidG 12:fa9b1a459e47 565
DasSidG 11:cf2db05cfa56 566 offset = can_id - 1536; //1536 = 0x600
maxv008 10:1079f8e52d65 567 first_index = (offset - 1)/4; //offset of 2,3,4 is CMU 1; 6,7,8, is CMU 2; etc.
DasSidG 11:cf2db05cfa56 568 second_index = ((offset - 1) % 4) - 1; //Makes it so 0,1,2 represent each voltage set //SID: subtracted 1 to make it work
DasSidG 12:fa9b1a459e47 569
DasSidG 12:fa9b1a459e47 570 return true;
maxv008 10:1079f8e52d65 571 }
maxv008 10:1079f8e52d65 572 else
DasSidG 12:fa9b1a459e47 573 return false;
maxv008 10:1079f8e52d65 574 }
maxv008 10:1079f8e52d65 575
maxv008 10:1079f8e52d65 576 void test_CAN_send()
maxv008 10:1079f8e52d65 577 {
maxv008 10:1079f8e52d65 578 CANMessage msg;
DasSidG 11:cf2db05cfa56 579 char value = 142;
maxv008 10:1079f8e52d65 580 msg = CANMessage(1, &value,1);
maxv008 10:1079f8e52d65 581 if(can.write(msg))
maxv008 10:1079f8e52d65 582 printf("Succesfully sent %d \r\n", value);
maxv008 10:1079f8e52d65 583 else
maxv008 10:1079f8e52d65 584 printf("Sending Failed \r\n");
maxv008 10:1079f8e52d65 585 }
maxv008 10:1079f8e52d65 586
maxv008 10:1079f8e52d65 587 void test_CAN_read()
maxv008 10:1079f8e52d65 588 {
maxv008 10:1079f8e52d65 589 CANMessage msg;
maxv008 10:1079f8e52d65 590 if(can.read(msg))
maxv008 10:1079f8e52d65 591 printf("Successfully recieved %d \r\n", msg.data[0]);
maxv008 10:1079f8e52d65 592 else
maxv008 10:1079f8e52d65 593 printf("Reading Failed \r\n");
maxv008 10:1079f8e52d65 594 }