Cell voltages fork (SoC)

Dependencies:   CUER_CAN CUER_DS1820 LTC2943 LTC6804 mbed PowerControl

Committer:
lcockerton62
Date:
Mon Jul 10 19:45:31 2017 +0000
Revision:
30:d90895e96226
Parent:
29:44924d2b1293
Child:
31:888b2602aab2
Software now writes and reads from 2 memory locations

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