Cell voltages fork (SoC)

Dependencies:   CUER_CAN CUER_DS1820 LTC2943 LTC6804 mbed PowerControl

Committer:
maxv008
Date:
Mon Jul 24 15:00:53 2017 +0000
Revision:
48:5c3f42c44036
Parent:
47:62ba8c071a0f
Child:
50:89f54b7a4c1b
Added code in interrupt to reset EEPROM whenever the correct ID CAN Message is recieved. Contents of msg determine initital values. Currently it is inside the interrupt which should be fine as it should only happen very rarely.

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 25:1fe8a42f8a6d 10 #include "LTC2943.h"
DasSidG 41:9183c5616281 11 #include "PowerControl/PowerControl.h"
DasSidG 41:9183c5616281 12 #include "PowerControl/EthernetPowerControl.h"
lcockerton62 0:0a5f554d2a16 13
DasSidG 47:62ba8c071a0f 14 #define DEBUG 0
maxv008 45:c288d7cbdb4a 15 #define ACTIVE 0
maxv008 45:c288d7cbdb4a 16 #define INACTIVE 1
maxv008 45:c288d7cbdb4a 17 #define TRANSMIT_MODE 1 //Useful to allow testing CAN read on BCU. Leave as 1 for BMS (and CAN write) 0 for BCU read-mode
msharma97 9:82ba050a7e13 18
lcockerton62 0:0a5f554d2a16 19 using namespace CAN_IDs;
lcockerton62 0:0a5f554d2a16 20
lcockerton62 0:0a5f554d2a16 21 // Function definitions
lcockerton62 1:51477fe4851b 22 void transmit_data(BMU_data measurements,uint32_t status);
lcockerton62 1:51477fe4851b 23 void read_temperature_sensors(BMU_data &measurements);
lcockerton62 0:0a5f554d2a16 24 void update_SOC();
lcockerton62 0:0a5f554d2a16 25 void init();
maxv008 14:e0e88a009f4c 26 void interruptHandler();
maxv008 14:e0e88a009f4c 27 void CANDataSentCallback();
lcockerton62 1:51477fe4851b 28 void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address);
lcockerton62 1:51477fe4851b 29 uint16_t read_EEPROM_startup(BMU_data &measurements);
maxv008 32:5b82679b2e6f 30 void reset_EEPROM(float init_SOC, float init_SOC_Percent);
lcockerton62 1:51477fe4851b 31 uint32_t check_measurements(BMU_data &measurements);
maxv008 23:a1af4439c1fc 32 uint32_t take_measurements(BMU_data &measurements);
maxv008 14:e0e88a009f4c 33 void test_read_CAN_buffer();
DasSidG 12:fa9b1a459e47 34 bool test_read_voltage_CAN(uint16_t readings[], int can_ids[]);
maxv008 10:1079f8e52d65 35 void test_CAN_send();
maxv008 10:1079f8e52d65 36 void test_CAN_read();
maxv008 35:be07fef5db72 37 bool check_EEPROM_PEC(char start_address_array[], char SOC_out[]);
maxv008 45:c288d7cbdb4a 38 int ivta_init(void);
maxv008 45:c288d7cbdb4a 39 int ivta_transfer(int * txrx);
maxv008 45:c288d7cbdb4a 40 int ivta_get_current(int measurements[]);
maxv008 45:c288d7cbdb4a 41 //IVTA stuff (sorry for the mess)
maxv008 45:c288d7cbdb4a 42 DigitalOut IVTA_SS(p11);
maxv008 45:c288d7cbdb4a 43 Serial pc(USBTX, USBRX);
maxv008 45:c288d7cbdb4a 44 SPI spi_ivta(p5, p6, p7); // mosi, miso, sclk
lcockerton62 0:0a5f554d2a16 45
lcockerton62 0:0a5f554d2a16 46 CAN can(CAN_READ_PIN, CAN_WRITE_PIN); //Create a CAN object to handle CAN comms
maxv008 14:e0e88a009f4c 47 CANMessage buffer[CAN_BUFFER_SIZE]; //CAN receive buffer
maxv008 14:e0e88a009f4c 48 bool safe_to_write[CAN_BUFFER_SIZE]; //Semaphore bit indicating that it's safe to write to the software buffer
maxv008 14:e0e88a009f4c 49 bool CAN_data_sent = false;
maxv008 14:e0e88a009f4c 50
maxv008 20:a1a1bfc938da 51 //Global array to store most recently obtained voltage and temp measurement:
maxv008 17:94dd9a0d3870 52 CMU_voltage voltage_readings[NO_CMUS];
maxv008 20:a1a1bfc938da 53 individual_temperature templist[NO_TEMPERATURE_SENSORS];
maxv008 28:f1f882bd1653 54 uint32_t status;
DasSidG 38:b1f5bfe38d70 55 int temperature_counter = TEMPERATURE_MEASUREMENT_FREQ;
DasSidG 38:b1f5bfe38d70 56
maxv008 17:94dd9a0d3870 57
maxv008 48:5c3f42c44036 58 uint16_t eeprom_start_address; //the current address where we store/read SoC values
lcockerton62 0:0a5f554d2a16 59
lcockerton62 1:51477fe4851b 60 Timeout loop_delay;
lcockerton62 1:51477fe4851b 61 bool delay_finished = false;
lcockerton62 2:94716229ecc3 62
DasSidG 39:34be1b8f46be 63 void loop_delay_callback(void) {
DasSidG 39:34be1b8f46be 64 delay_finished = true;
DasSidG 39:34be1b8f46be 65 }
DasSidG 39:34be1b8f46be 66
maxv008 28:f1f882bd1653 67 //The following is to initialize reading tests, can be removed when needed
maxv008 28:f1f882bd1653 68 float packSOC;
maxv008 28:f1f882bd1653 69 float packSOCPercentage;
maxv008 28:f1f882bd1653 70 pack_voltage_extremes minVolt;
maxv008 28:f1f882bd1653 71 pack_voltage_extremes maxVolt;
maxv008 28:f1f882bd1653 72 pack_temperature_extremes minTemp;
maxv008 28:f1f882bd1653 73 pack_temperature_extremes maxTemp;
maxv008 31:888b2602aab2 74 float batteryCurrent; uint32_t batteryVoltage;
maxv008 14:e0e88a009f4c 75
maxv008 48:5c3f42c44036 76 BMU_data measurements; //Put as global variable so interrupt can see it, otherwise treated like it is local to main
lcockerton62 0:0a5f554d2a16 77 int main()
maxv008 48:5c3f42c44036 78 {
DasSidG 46:ac7065d52d6e 79 //uint16_t volt_readings[36];
DasSidG 46:ac7065d52d6e 80 //int can_ids[9];
maxv008 10:1079f8e52d65 81
lcockerton62 0:0a5f554d2a16 82 init();
maxv008 10:1079f8e52d65 83
maxv008 48:5c3f42c44036 84 //eeprom_start_address = 0x0040; //reset has no way of setting the current address for rest of code.
maxv008 35:be07fef5db72 85 //reset_EEPROM(1,100); //Used to completely initialize EEPROM as if it has never been touched
maxv008 48:5c3f42c44036 86 eeprom_start_address = read_EEPROM_startup(measurements); // Read from the eeprom at startup to fill in the values of SoC
maxv008 48:5c3f42c44036 87 if (DEBUG) printf("Current EEPROM Address %d \r\n", eeprom_start_address);
DasSidG 36:1b23c0692f54 88 if (DEBUG) printf("SOC is %f and SOC Percentage is %f \r\n", measurements.SOC, measurements.percentage_SOC);
maxv008 35:be07fef5db72 89 ltc2943.accumulatedCharge(measurements.percentage_SOC); // Initialise the LTC2943 with the current state of charge
DasSidG 4:9050c5d6925e 90
lcockerton62 1:51477fe4851b 91 while (true) {
DasSidG 11:cf2db05cfa56 92
maxv008 35:be07fef5db72 93 Timer t;
maxv008 35:be07fef5db72 94 t.start();
maxv008 35:be07fef5db72 95
maxv008 45:c288d7cbdb4a 96 if(TRANSMIT_MODE) status = take_measurements(measurements);
maxv008 35:be07fef5db72 97 // Dont want to read the temperature sensors during each iteration of the loop
lcockerton62 0:0a5f554d2a16 98
lcockerton62 1:51477fe4851b 99 //Store data in the eeprom
maxv008 48:5c3f42c44036 100 if(TRANSMIT_MODE) write_SOC_EEPROM(measurements, eeprom_start_address);
maxv008 35:be07fef5db72 101
lcockerton62 5:793afeef45dc 102 // CAN bus
maxv008 14:e0e88a009f4c 103 CAN_data_sent = false;//Currently does nothing, adding this line in more places then using
maxv008 14:e0e88a009f4c 104 //while(!CAN_data_sent); in order to ensure sending completes
maxv008 45:c288d7cbdb4a 105 if(TRANSMIT_MODE)
maxv008 45:c288d7cbdb4a 106 transmit_data(measurements,status);
maxv008 45:c288d7cbdb4a 107 else
maxv008 45:c288d7cbdb4a 108 test_read_CAN_buffer();
DasSidG 11:cf2db05cfa56 109
DasSidG 39:34be1b8f46be 110
lcockerton62 0:0a5f554d2a16 111 // Conserve power - enter a low powered mode
lcockerton62 2:94716229ecc3 112 delay_finished = false;
lcockerton62 1:51477fe4851b 113 loop_delay.attach(loop_delay_callback, LOOP_DELAY_S);
DasSidG 40:0753cbb8bc6a 114 //while (!delay_finished) sleep();
DasSidG 39:34be1b8f46be 115
DasSidG 40:0753cbb8bc6a 116 wait(1);
DasSidG 46:ac7065d52d6e 117 if (DEBUG) printf("Loop time is %d \r\n", t.read_ms());
maxv008 10:1079f8e52d65 118 }
lcockerton62 0:0a5f554d2a16 119 }
lcockerton62 0:0a5f554d2a16 120
lcockerton62 1:51477fe4851b 121 void transmit_data(BMU_data measurements, uint32_t status)
lcockerton62 0:0a5f554d2a16 122 {
msharma97 9:82ba050a7e13 123 CANMessage msg;
lcockerton62 0:0a5f554d2a16 124 /*
lcockerton62 0:0a5f554d2a16 125 Place all of the collected data onto the CAN bus
lcockerton62 0:0a5f554d2a16 126 */
maxv008 48:5c3f42c44036 127 //Send cell voltages
maxv008 13:7b42af989cd1 128 //voltages sent in sets of 4 + one cmu data set
msharma97 9:82ba050a7e13 129 int repeating_unit_length = NO_READINGS_PER_CMU /4 + 1;
maxv008 10:1079f8e52d65 130 for(uint16_t i= 0; i < NO_CMUS; i++) {
msharma97 9:82ba050a7e13 131 //input id is offset, data structure is info, voltage, voltage, ......
maxv008 10:1079f8e52d65 132 //This is a slightly modified version of the Tritium BMS datasheet, to add an extra voltage reading set.
maxv008 10:1079f8e52d65 133 msg = createVoltageTelemetry(repeating_unit_length*i+2, measurements.cell_voltages[i].voltages);
msharma97 9:82ba050a7e13 134 can.write(msg);
DasSidG 36:1b23c0692f54 135 if (DEBUG) printf("Voltage Message id: %d \r\n", msg.id);
maxv008 17:94dd9a0d3870 136 //+4 - 4 cell voltages sent per measurement, simple pointer arithmetic
maxv008 10:1079f8e52d65 137 msg = createVoltageTelemetry(repeating_unit_length*i+3, measurements.cell_voltages[i].voltages + 4);
msharma97 9:82ba050a7e13 138 can.write(msg);
DasSidG 36:1b23c0692f54 139 if (DEBUG) printf("Voltage Message id: %d \r\n", msg.id);
maxv008 10:1079f8e52d65 140 msg = createVoltageTelemetry(repeating_unit_length*i+4, measurements.cell_voltages[i].voltages + 8);
msharma97 9:82ba050a7e13 141 can.write(msg);
DasSidG 36:1b23c0692f54 142 if (DEBUG) printf("Voltage Message id: %d \r\n", msg.id);
lcockerton62 1:51477fe4851b 143 }
maxv008 13:7b42af989cd1 144
maxv008 13:7b42af989cd1 145 //Transmitting all of the individual probes:
DasSidG 38:b1f5bfe38d70 146
DasSidG 38:b1f5bfe38d70 147 if (temperature_counter == TEMPERATURE_MEASUREMENT_FREQ) {
DasSidG 38:b1f5bfe38d70 148 for(uint8_t i = 0; i < devices_found; i++)
DasSidG 38:b1f5bfe38d70 149 {
DasSidG 38:b1f5bfe38d70 150 individual_temperature tempreading = measurements.temperature_measurements[i];
DasSidG 38:b1f5bfe38d70 151 msg = createTemperatureTelemetry(i, &tempreading.ROMID[0], tempreading.measurement);
DasSidG 38:b1f5bfe38d70 152 if(can.write(msg));
DasSidG 38:b1f5bfe38d70 153 else
DasSidG 38:b1f5bfe38d70 154 if (DEBUG) printf("Sending Temperature Failed for some reason \r\n");
DasSidG 38:b1f5bfe38d70 155 }
maxv008 13:7b42af989cd1 156 }
lcockerton62 1:51477fe4851b 157
lcockerton62 1:51477fe4851b 158 // Create SOC CAN message
maxv008 23:a1af4439c1fc 159 msg = createPackSOC(measurements.SOC, measurements.percentage_SOC);
maxv008 23:a1af4439c1fc 160 can.write(msg);
DasSidG 36:1b23c0692f54 161 if (DEBUG) 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 162
lcockerton62 1:51477fe4851b 163 // Min/max cell voltages
maxv008 23:a1af4439c1fc 164 msg = createCellVoltageMAXMIN(measurements.max_cell_voltage, measurements.min_cell_voltage);
maxv008 23:a1af4439c1fc 165 can.write(msg);
maxv008 23:a1af4439c1fc 166
maxv008 23:a1af4439c1fc 167 // Min/Max cell temperatures
maxv008 23:a1af4439c1fc 168 msg = createCellTemperatureMAXMIN(measurements.min_cell_temp, true);
maxv008 23:a1af4439c1fc 169 can.write(msg);
maxv008 23:a1af4439c1fc 170 msg = createCellTemperatureMAXMIN(measurements.max_cell_temp, false);
maxv008 23:a1af4439c1fc 171 can.write(msg);
maxv008 31:888b2602aab2 172 wait(0.1); //WAITS ABSOLUTELY NECESSARY! values may be changed. Limit to how fast msg can be sent
lcockerton62 2:94716229ecc3 173 // Battery voltage and current
maxv008 23:a1af4439c1fc 174 msg = createBatteryVI(measurements.battery_voltage,measurements.battery_current);
maxv008 31:888b2602aab2 175 can.write(msg);
DasSidG 36:1b23c0692f54 176 if (DEBUG) printf("Sent Battery voltage %d and current %f with id %d \r\n",decodeBatteryVoltage(msg),decodeBatteryCurrent(msg),msg.id);
maxv008 23:a1af4439c1fc 177
lcockerton62 1:51477fe4851b 178 //Extended battery pack status
maxv008 23:a1af4439c1fc 179 msg = createExtendedBatteryPackStatus(status);
maxv008 23:a1af4439c1fc 180 can.write(msg);
maxv008 31:888b2602aab2 181
DasSidG 36:1b23c0692f54 182 if (DEBUG) printf("Sent battery pack status with value %d \r\n", status);
DasSidG 36:1b23c0692f54 183
maxv008 31:888b2602aab2 184 msg = createBMSHeartbeat(0, 0);
maxv008 31:888b2602aab2 185 can.write(msg);
maxv008 45:c288d7cbdb4a 186
maxv008 45:c288d7cbdb4a 187 msg = createIVTACurrent(measurements.ivta_current);
maxv008 45:c288d7cbdb4a 188 can.write(msg);
lcockerton62 0:0a5f554d2a16 189 }
lcockerton62 0:0a5f554d2a16 190
maxv008 10:1079f8e52d65 191
lcockerton62 1:51477fe4851b 192 uint16_t read_EEPROM_startup(BMU_data &measurements)
lcockerton62 0:0a5f554d2a16 193 {
lcockerton62 1:51477fe4851b 194 /* The first page of the EEPROM, specifically the first 2 addresses store a
lcockerton62 1:51477fe4851b 195 pointer of the first memory location of measurement data. The EEPROM only has a finite number of
lcockerton62 1:51477fe4851b 196 read/write cycles which is why we aren't writing to the same location throughout
lcockerton62 1:51477fe4851b 197 */
lcockerton62 30:d90895e96226 198 uint16_t start_address1;
lcockerton62 30:d90895e96226 199 uint16_t start_address2;
maxv008 35:be07fef5db72 200 char start_address_array1[4];
maxv008 35:be07fef5db72 201 char start_address_array2[4];
lcockerton62 22:2df45c818786 202 char SOC_out[10]; // 4 bytes for the 2 floats one is SOC and the other % charge
lcockerton62 30:d90895e96226 203 bool is_first_read_true = 0;
lcockerton62 30:d90895e96226 204 bool is_second_read_true = 0;
maxv008 35:be07fef5db72 205
maxv008 35:be07fef5db72 206 union float2bytes { float f; char b[sizeof(float)]; };
maxv008 35:be07fef5db72 207 float2bytes SOC_union;
maxv008 35:be07fef5db72 208 float2bytes SOC_Percent_union;
lcockerton62 30:d90895e96226 209
lcockerton62 30:d90895e96226 210 // Get a pointer to the start address for the data stored in the eeprom
maxv008 35:be07fef5db72 211 i2c_page_read(0x0000, 4, start_address_array1);
DasSidG 36:1b23c0692f54 212 if (DEBUG) printf("\r\n\ Start address (%d,%d) \r\n \r\n", start_address_array1[0], start_address_array1[1]);
maxv008 35:be07fef5db72 213 i2c_page_read(0x0004, 4, start_address_array2);
lcockerton62 30:d90895e96226 214
maxv008 35:be07fef5db72 215 is_first_read_true = check_EEPROM_PEC(start_address_array1, SOC_out);
lcockerton62 30:d90895e96226 216
lcockerton62 30:d90895e96226 217 if(is_first_read_true){
maxv008 35:be07fef5db72 218 for ( int i=0; i < sizeof(float); i++ ) {
maxv008 35:be07fef5db72 219 SOC_union.b[i] = SOC_out[i];
maxv008 35:be07fef5db72 220 }
maxv008 35:be07fef5db72 221
maxv008 35:be07fef5db72 222 for ( int i=0; i < sizeof(float); i++ ) {
maxv008 35:be07fef5db72 223 SOC_Percent_union.b[i] = SOC_out[i + sizeof(float)];
maxv008 35:be07fef5db72 224 }
maxv008 35:be07fef5db72 225 measurements.SOC = SOC_union.f;
maxv008 35:be07fef5db72 226 measurements.percentage_SOC = SOC_Percent_union.f;
lcockerton62 30:d90895e96226 227 }
lcockerton62 30:d90895e96226 228 else{
maxv008 35:be07fef5db72 229 is_second_read_true = check_EEPROM_PEC(start_address_array2, SOC_out);
lcockerton62 30:d90895e96226 230
lcockerton62 30:d90895e96226 231 if(is_second_read_true){
maxv008 35:be07fef5db72 232 for ( int i=0; i < sizeof(float); i++ ) {
maxv008 35:be07fef5db72 233 SOC_union.b[i] = SOC_out[i];
maxv008 35:be07fef5db72 234 }
maxv008 35:be07fef5db72 235
maxv008 35:be07fef5db72 236 for ( int i=0; i < sizeof(float); i++ ) {
maxv008 35:be07fef5db72 237 SOC_Percent_union.b[i] = SOC_out[i + sizeof(float)];
maxv008 35:be07fef5db72 238 }
maxv008 35:be07fef5db72 239 measurements.SOC = SOC_union.f;
maxv008 35:be07fef5db72 240 measurements.percentage_SOC = SOC_Percent_union.f;
lcockerton62 30:d90895e96226 241 }
lcockerton62 30:d90895e96226 242 }
lcockerton62 30:d90895e96226 243
lcockerton62 30:d90895e96226 244 if(is_second_read_true || is_first_read_true){
lcockerton62 30:d90895e96226 245 // Select the next address to write to
maxv008 35:be07fef5db72 246 start_address1 = (start_address_array1[1] << 8) | (start_address_array1[0]);
maxv008 35:be07fef5db72 247 start_address2 = (start_address_array2[1] << 8) | (start_address_array2[0]);
maxv008 35:be07fef5db72 248 start_address1 += 0x0040;
maxv008 32:5b82679b2e6f 249 start_address2 += 0x0040; //Also each SOC is taking 0xA space, so 0x15 should be sufficient offset
maxv008 35:be07fef5db72 250 if(start_address2 > MAX_WRITE_ADDRESS) { //Check second start address since it is the larger value.
DasSidG 36:1b23c0692f54 251 if (DEBUG) printf("Resetting start_address \r\n");
lcockerton62 30:d90895e96226 252 start_address1 = START_WRITE_ADDRESS; // Loop to the start of the eeprom
lcockerton62 30:d90895e96226 253 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 254 }
maxv008 35:be07fef5db72 255 start_address_array1[0] = start_address1 & 0x00FF;
maxv008 35:be07fef5db72 256 start_address_array1[1] = start_address1 >> 8;
maxv008 35:be07fef5db72 257 start_address_array2[0] = start_address2 & 0x00FF;
maxv008 32:5b82679b2e6f 258 start_address_array2[1] = start_address2 >> 8;
maxv008 35:be07fef5db72 259 //PEC for new address
maxv008 35:be07fef5db72 260 uint16_t pec_address1 = pec15_calc(2, (uint8_t*)start_address_array1);
maxv008 35:be07fef5db72 261 uint16_t pec_address2 = pec15_calc(2, (uint8_t*)start_address_array2);
maxv008 35:be07fef5db72 262 start_address_array1[2] = (char) (pec_address1 >> 8);
maxv008 35:be07fef5db72 263 start_address_array1[3] = (char) (pec_address1);
maxv008 35:be07fef5db72 264 start_address_array2[2] = (char) (pec_address2 >> 8);
maxv008 35:be07fef5db72 265 start_address_array2[3] = (char) (pec_address2);
lcockerton62 30:d90895e96226 266
lcockerton62 30:d90895e96226 267 // Write the new location of the address to memory
maxv008 35:be07fef5db72 268 wait_ms(10);
maxv008 35:be07fef5db72 269 i2c_page_write(0x0000, 4, start_address_array1);
maxv008 33:44b241c7b2c1 270 wait_ms(10);
maxv008 35:be07fef5db72 271 i2c_page_write(0x0004, 4, start_address_array2);
lcockerton62 30:d90895e96226 272
maxv008 35:be07fef5db72 273 write_SOC_EEPROM(measurements, start_address1); //Initializes new memory location to avoid PEC if reset without taking measurements.
lcockerton62 30:d90895e96226 274 return start_address1;
lcockerton62 30:d90895e96226 275 }
lcockerton62 30:d90895e96226 276 else{
DasSidG 46:ac7065d52d6e 277 if (DEBUG) printf("EEPROM PEC error \r\n"); //@TODO an error flag should be raised since both values have failed
maxv008 32:5b82679b2e6f 278
lcockerton62 30:d90895e96226 279 }
maxv008 32:5b82679b2e6f 280 return -1; //Will end up as maximum integer, just indicating an error.
maxv008 32:5b82679b2e6f 281 }
maxv008 32:5b82679b2e6f 282
maxv008 32:5b82679b2e6f 283 void reset_EEPROM(float init_SOC, float init_SOC_Percent)
maxv008 32:5b82679b2e6f 284 {
maxv008 32:5b82679b2e6f 285 char start_address_array1[2]; //Purely for testing
DasSidG 34:65fd6a72106f 286 char start_address_array2[2]; //Purely for testing
maxv008 33:44b241c7b2c1 287 char test_float_array[10];
maxv008 32:5b82679b2e6f 288 //Very first addresses to use
maxv008 35:be07fef5db72 289 char first_address[4] = {0x40,0,0,0}; //Address 0x0040, PEC section left blank to start
maxv008 35:be07fef5db72 290 char second_address[4] = {first_address[0] + SECOND_ADDRESS_OFFSET,0,0,0};
maxv008 32:5b82679b2e6f 291 uint16_t address1 = (first_address[1] << 8) | first_address[0];
maxv008 32:5b82679b2e6f 292 uint16_t address2 = (second_address[1] << 8) | second_address[0];
maxv008 35:be07fef5db72 293
maxv008 35:be07fef5db72 294 //PEC stuff for the addresses
maxv008 35:be07fef5db72 295 uint16_t pec_address1 = pec15_calc(2, (uint8_t*)first_address);
maxv008 35:be07fef5db72 296 uint16_t pec_address2 = pec15_calc(2, (uint8_t*)second_address);
maxv008 35:be07fef5db72 297 first_address[2] = (char) (pec_address1 >> 8);
maxv008 35:be07fef5db72 298 first_address[3] = (char) (pec_address1);
maxv008 35:be07fef5db72 299 second_address[2] = (char) (pec_address2 >> 8);
maxv008 35:be07fef5db72 300 second_address[3] = (char) (pec_address2);
maxv008 32:5b82679b2e6f 301
maxv008 48:5c3f42c44036 302 wait_ms(10);
maxv008 35:be07fef5db72 303 i2c_page_write(0x0000, 4, first_address);
maxv008 33:44b241c7b2c1 304 wait_ms(10);
maxv008 35:be07fef5db72 305 i2c_page_write(0x0004, 4, second_address); //This initializes addresses
maxv008 32:5b82679b2e6f 306 //Next segment is for putting initial SOC in:
maxv008 33:44b241c7b2c1 307 wait_ms(10);
maxv008 32:5b82679b2e6f 308
maxv008 32:5b82679b2e6f 309 char data_out[10];
maxv008 32:5b82679b2e6f 310 uint16_t data_pec;
DasSidG 34:65fd6a72106f 311
DasSidG 34:65fd6a72106f 312 union float2bytes { float f; char b[sizeof(float)]; };
DasSidG 34:65fd6a72106f 313
DasSidG 34:65fd6a72106f 314 float2bytes init_SOC_union;
DasSidG 34:65fd6a72106f 315 float2bytes init_SOC_Percent_union;
DasSidG 34:65fd6a72106f 316
DasSidG 34:65fd6a72106f 317 init_SOC_union.f = init_SOC;
DasSidG 34:65fd6a72106f 318 for ( int i=0; i < sizeof(float); i++ ) {
DasSidG 34:65fd6a72106f 319 data_out[i] = init_SOC_union.b[i];
DasSidG 34:65fd6a72106f 320 }
DasSidG 34:65fd6a72106f 321
DasSidG 34:65fd6a72106f 322 init_SOC_Percent_union.f = init_SOC_Percent;
DasSidG 34:65fd6a72106f 323 for ( int i=0; i < sizeof(float); i++ ) {
DasSidG 34:65fd6a72106f 324 data_out[i+sizeof(float)] = init_SOC_Percent_union.b[i];
DasSidG 34:65fd6a72106f 325 }
maxv008 32:5b82679b2e6f 326
maxv008 32:5b82679b2e6f 327 data_pec = pec15_calc(8, ((uint8_t*)data_out)); // Calculate the pec and then write it to memory
maxv008 32:5b82679b2e6f 328 data_out[8] = (char)(data_pec >> 8);
maxv008 32:5b82679b2e6f 329 data_out[9] = (char)(data_pec);
DasSidG 34:65fd6a72106f 330
maxv008 32:5b82679b2e6f 331 i2c_page_write(address1, 10,data_out);
maxv008 33:44b241c7b2c1 332 wait_ms(10);
maxv008 32:5b82679b2e6f 333 i2c_page_write(address2, 10,data_out);
DasSidG 34:65fd6a72106f 334 wait_ms(10);
maxv008 35:be07fef5db72 335 i2c_page_read(0x0000,4,start_address_array1);
DasSidG 34:65fd6a72106f 336 wait_ms(10);
maxv008 35:be07fef5db72 337 i2c_page_read(0x0004,4,start_address_array2);
DasSidG 36:1b23c0692f54 338 if (DEBUG) printf("Start address 1 is (%x,%x) \r\n \r\n", start_address_array1[0], start_address_array1[1]);
DasSidG 36:1b23c0692f54 339 if (DEBUG) printf("Start address 2 is (%x,%x) \r\n \r\n", start_address_array2[0], start_address_array2[1]);
maxv008 33:44b241c7b2c1 340 wait_ms(10);
maxv008 48:5c3f42c44036 341 //TODO: Figure out of this can be removed, unecessary reading for testing purposes. (Hide behind if(DEBUG)?)
DasSidG 34:65fd6a72106f 342 i2c_page_read(address1,10,test_float_array);
maxv008 35:be07fef5db72 343 /*for (int i = 0; i < 10; ++i) {
DasSidG 34:65fd6a72106f 344 printf("test_float array %d is %d \r\n", i, test_float_array[i]);
maxv008 35:be07fef5db72 345 }*/
DasSidG 34:65fd6a72106f 346
DasSidG 34:65fd6a72106f 347 float2bytes rec_init_SOC_union;
DasSidG 34:65fd6a72106f 348 float2bytes rec_init_SOC_Percentage_union;
DasSidG 34:65fd6a72106f 349
DasSidG 34:65fd6a72106f 350
DasSidG 34:65fd6a72106f 351 for ( int i=0; i < sizeof(float); i++ ) {
DasSidG 34:65fd6a72106f 352 rec_init_SOC_union.b[i] = test_float_array[i];
DasSidG 34:65fd6a72106f 353 }
DasSidG 34:65fd6a72106f 354 float rec_init_SOC = rec_init_SOC_union.f;
DasSidG 34:65fd6a72106f 355
DasSidG 34:65fd6a72106f 356 for ( int i=0; i < sizeof(float); i++ ) {
DasSidG 34:65fd6a72106f 357 rec_init_SOC_Percentage_union.b[i] = test_float_array[i+4];
DasSidG 34:65fd6a72106f 358 }
DasSidG 34:65fd6a72106f 359 float rec_init_SOC_Percentage = rec_init_SOC_Percentage_union.f;
DasSidG 34:65fd6a72106f 360
DasSidG 36:1b23c0692f54 361 if (DEBUG) printf("init SOC %f \r\n \r\n", rec_init_SOC);
DasSidG 36:1b23c0692f54 362 if (DEBUG) printf("percentage SOC %f \r\n \r\n", rec_init_SOC_Percentage);
lcockerton62 30:d90895e96226 363 }
lcockerton62 30:d90895e96226 364
maxv008 35:be07fef5db72 365 bool check_EEPROM_PEC(char start_address_array[], char SOC_out[]){
lcockerton62 30:d90895e96226 366 // Helper method to check the PEC, returns 0 if the pec is wrong and 1 if the pec is correct
maxv008 35:be07fef5db72 367 uint16_t adr_recieved_pec;
maxv008 35:be07fef5db72 368 uint16_t adr_data_pec;
lcockerton62 22:2df45c818786 369 uint16_t received_pec;
lcockerton62 22:2df45c818786 370 uint16_t data_pec;
lcockerton62 30:d90895e96226 371
maxv008 35:be07fef5db72 372 //Check the PEC of the address itself
maxv008 35:be07fef5db72 373 adr_recieved_pec = (uint16_t)(start_address_array[2] << 8) + (uint16_t)start_address_array[3];
maxv008 35:be07fef5db72 374 adr_data_pec = pec15_calc(2, (uint8_t*)start_address_array);
maxv008 35:be07fef5db72 375 if(adr_recieved_pec != adr_data_pec){
DasSidG 36:1b23c0692f54 376 if (DEBUG) printf("PEC Error in address \r\n");
maxv008 35:be07fef5db72 377 return 0; //If they are equal, continue on to checking the data
maxv008 35:be07fef5db72 378 }
maxv008 35:be07fef5db72 379
lcockerton62 1:51477fe4851b 380 // Read the data from this address
maxv008 35:be07fef5db72 381 uint16_t start_address = (start_address_array[1]<< 8) | start_address_array[0]; // mbed little endian follow this convention
lcockerton62 22:2df45c818786 382 i2c_page_read(start_address, 10,SOC_out); // Reading will aquire 2 floats and a PEC for the data
lcockerton62 0:0a5f554d2a16 383
lcockerton62 22:2df45c818786 384 // Convert the SOC_out values back into floats and deal with the pec
lcockerton62 22:2df45c818786 385 received_pec = (uint16_t)(SOC_out[8]<<8) + (uint16_t)SOC_out[9];
lcockerton62 22:2df45c818786 386 data_pec = pec15_calc(8, (uint8_t*)SOC_out);
lcockerton62 22:2df45c818786 387 if(received_pec != data_pec) {
lcockerton62 30:d90895e96226 388 return 0;
lcockerton62 22:2df45c818786 389 }
lcockerton62 30:d90895e96226 390 else
lcockerton62 30:d90895e96226 391 return 1;
lcockerton62 0:0a5f554d2a16 392 }
lcockerton62 0:0a5f554d2a16 393
maxv008 35:be07fef5db72 394 //Note, this function does not check PEC of address, assumes correctness!
lcockerton62 1:51477fe4851b 395 void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address)
lcockerton62 0:0a5f554d2a16 396 {
lcockerton62 22:2df45c818786 397 char data_out[10];
maxv008 35:be07fef5db72 398 //float *fp1,*fp2;
lcockerton62 22:2df45c818786 399 uint16_t data_pec;
maxv008 35:be07fef5db72 400 union float2bytes { float f; char b[sizeof(float)]; };
maxv008 35:be07fef5db72 401 float2bytes SOC_union;
maxv008 35:be07fef5db72 402 float2bytes SOC_Percent_union;
lcockerton62 0:0a5f554d2a16 403
maxv008 35:be07fef5db72 404
maxv008 35:be07fef5db72 405 SOC_union.f = measurements.SOC;
maxv008 35:be07fef5db72 406 for ( int i=0; i < sizeof(float); i++ ) {
maxv008 35:be07fef5db72 407 data_out[i] = SOC_union.b[i];
lcockerton62 1:51477fe4851b 408 }
maxv008 35:be07fef5db72 409
maxv008 35:be07fef5db72 410 SOC_Percent_union.f = measurements.percentage_SOC;
maxv008 35:be07fef5db72 411 for ( int i=0; i < sizeof(float); i++ ) {
maxv008 35:be07fef5db72 412 data_out[i+sizeof(float)] = SOC_Percent_union.b[i];
lcockerton62 1:51477fe4851b 413 }
maxv008 35:be07fef5db72 414
lcockerton62 22:2df45c818786 415 data_pec = pec15_calc(8, ((uint8_t*)data_out)); // Calculate the pec and then write it to memory
lcockerton62 22:2df45c818786 416 data_out[8] = (char)(data_pec >> 8);
lcockerton62 22:2df45c818786 417 data_out[9] = (char)(data_pec);
maxv008 35:be07fef5db72 418 wait_ms(10); //Just in case function calling it doesnt put a wait before hand
lcockerton62 30:d90895e96226 419 i2c_page_write(start_address, 10,data_out);
maxv008 35:be07fef5db72 420 wait_ms(10);
lcockerton62 30:d90895e96226 421 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 422 }
lcockerton62 0:0a5f554d2a16 423
maxv008 45:c288d7cbdb4a 424 int ivta_transfer(int * txrx)
maxv008 45:c288d7cbdb4a 425 {
maxv008 45:c288d7cbdb4a 426 char i;// j;
maxv008 45:c288d7cbdb4a 427 uint16_t crc;
maxv008 45:c288d7cbdb4a 428
maxv008 45:c288d7cbdb4a 429 //pc.printf("*** Into a transfer*** \r \n");
maxv008 45:c288d7cbdb4a 430
maxv008 45:c288d7cbdb4a 431 // Activate IVT-A and send packet.
maxv008 45:c288d7cbdb4a 432 IVTA_SS = ACTIVE;
maxv008 45:c288d7cbdb4a 433 //pc.printf("Data sent");
maxv008 45:c288d7cbdb4a 434 wait_us(3);
maxv008 45:c288d7cbdb4a 435 for(i = 0; i < 9; i++)
maxv008 45:c288d7cbdb4a 436 {
maxv008 45:c288d7cbdb4a 437 spi_ivta.write(txrx[i]);
maxv008 45:c288d7cbdb4a 438 wait_us(3);
maxv008 45:c288d7cbdb4a 439 }
maxv008 45:c288d7cbdb4a 440 wait_us(3);
maxv008 45:c288d7cbdb4a 441 IVTA_SS = INACTIVE;
maxv008 45:c288d7cbdb4a 442 /*
maxv008 45:c288d7cbdb4a 443 Note: we ignore the packet sent by the IVT-A
maxv008 45:c288d7cbdb4a 444 during this communication phase. Similarly,
maxv008 45:c288d7cbdb4a 445 we only receive data in the next phase. Essentially
maxv008 45:c288d7cbdb4a 446 we run the IVT-A in half-duplex mode.
maxv008 45:c288d7cbdb4a 447 */
maxv008 45:c288d7cbdb4a 448
maxv008 45:c288d7cbdb4a 449 wait_us(500); // Wait between packets
maxv008 45:c288d7cbdb4a 450 IVTA_SS = ACTIVE; // Activate IVT-A and receive packet.
maxv008 45:c288d7cbdb4a 451 wait_us(3);
maxv008 45:c288d7cbdb4a 452 for(i = 0; i < 9; i++)
maxv008 45:c288d7cbdb4a 453 {
maxv008 45:c288d7cbdb4a 454 txrx[i] = spi_ivta.write(0x00); // Write some dummy data(half duplex)
maxv008 45:c288d7cbdb4a 455 wait_us(3);
maxv008 45:c288d7cbdb4a 456 }
maxv008 45:c288d7cbdb4a 457 wait_us(3);
maxv008 45:c288d7cbdb4a 458 IVTA_SS = INACTIVE;
maxv008 45:c288d7cbdb4a 459
maxv008 45:c288d7cbdb4a 460 return 0;
maxv008 45:c288d7cbdb4a 461 }
maxv008 45:c288d7cbdb4a 462
maxv008 45:c288d7cbdb4a 463 /*
maxv008 45:c288d7cbdb4a 464 Initialise IVT-A.
maxv008 45:c288d7cbdb4a 465 Write configuration:
maxv008 45:c288d7cbdb4a 466 + Current in 300A range measured on channel A.
maxv008 45:c288d7cbdb4a 467 + Temperature measured on channel B (currently unused).
maxv008 45:c288d7cbdb4a 468 + Average data over 10 samples.
maxv008 45:c288d7cbdb4a 469 */
maxv008 45:c288d7cbdb4a 470 int ivta_init(void)
maxv008 45:c288d7cbdb4a 471 {
maxv008 45:c288d7cbdb4a 472 spi_ivta.format(8,0); // The format works for 0 or 1, most of testing done with 0
maxv008 45:c288d7cbdb4a 473 spi_ivta.frequency(500000);
maxv008 45:c288d7cbdb4a 474 /* The last 2 bytes of the package are the CRC check, upper 4 bits in the
maxv008 45:c288d7cbdb4a 475 command are the command code */
maxv008 45:c288d7cbdb4a 476 int transfer;
maxv008 45:c288d7cbdb4a 477 int packet[9] = {0x90,1,5,200,0,0,0,0x78,0xB8};
maxv008 45:c288d7cbdb4a 478 transfer = ivta_transfer(packet);
maxv008 45:c288d7cbdb4a 479 return transfer;
maxv008 45:c288d7cbdb4a 480 }
maxv008 45:c288d7cbdb4a 481
maxv008 45:c288d7cbdb4a 482 /*
maxv008 45:c288d7cbdb4a 483 Fetch current from IVT-A. Return error codes
maxv008 45:c288d7cbdb4a 484 as defined in ivta.h. Supplied current pointer
maxv008 45:c288d7cbdb4a 485 must point to 3 chars.
maxv008 45:c288d7cbdb4a 486 */
maxv008 45:c288d7cbdb4a 487 int ivta_get_current(int measurements[])
maxv008 45:c288d7cbdb4a 488 {
maxv008 45:c288d7cbdb4a 489 //printf("In get current \r \n");
maxv008 45:c288d7cbdb4a 490 //int r_val;
maxv008 45:c288d7cbdb4a 491 int packet[9] = {0x10,1,0,0,0,0,0,0x0B,0x10}; // Command code 1.
maxv008 45:c288d7cbdb4a 492 //printf("In get current \r \n");
maxv008 45:c288d7cbdb4a 493 int r_val = ivta_transfer(packet);
maxv008 45:c288d7cbdb4a 494
maxv008 45:c288d7cbdb4a 495 /* printf("Packet1 : %d \r", packet[1]);
maxv008 45:c288d7cbdb4a 496 printf("Packet1 : %d \r", packet[2]);
maxv008 45:c288d7cbdb4a 497 printf("Packet1 : %d \r", packet[3]);
maxv008 45:c288d7cbdb4a 498 printf("Packet1 : %d \r", packet[4]);*/
maxv008 45:c288d7cbdb4a 499
maxv008 45:c288d7cbdb4a 500 measurements[0] = packet[1]; // Must shift the index of the packet
maxv008 45:c288d7cbdb4a 501 measurements[1] = packet[2];
maxv008 45:c288d7cbdb4a 502 measurements[2] = packet[3];
maxv008 45:c288d7cbdb4a 503 measurements[3] = packet[4];
maxv008 45:c288d7cbdb4a 504 measurements[4] = packet[5];
maxv008 45:c288d7cbdb4a 505 measurements[5] = packet[6];
maxv008 45:c288d7cbdb4a 506
maxv008 45:c288d7cbdb4a 507 return 0;
maxv008 45:c288d7cbdb4a 508 }
maxv008 45:c288d7cbdb4a 509
maxv008 45:c288d7cbdb4a 510
lcockerton62 1:51477fe4851b 511 void read_temperature_sensors(BMU_data &measurements)
lcockerton62 0:0a5f554d2a16 512 {
lcockerton62 1:51477fe4851b 513 float min_temperature;
maxv008 23:a1af4439c1fc 514 char min_id[8];
lcockerton62 1:51477fe4851b 515 float max_temperature;
maxv008 23:a1af4439c1fc 516 char max_id[8];
DasSidG 21:d461d58e70fc 517 isotherm_12V_pin = 1;
lcockerton62 1:51477fe4851b 518 probe[0]->convert_temperature(DS1820::all_devices);
DasSidG 21:d461d58e70fc 519
lcockerton62 1:51477fe4851b 520 min_temperature = probe[0]->temperature('C');
maxv008 23:a1af4439c1fc 521 std::memcpy(min_id, probe[0]->ROM, sizeof(char)*8); //invalid shallow copy: min_id = probe[0]->ROM;
lcockerton62 1:51477fe4851b 522 max_temperature = min_temperature; // Initially set the max and min temperature equal
maxv008 23:a1af4439c1fc 523 std::memcpy(max_id, probe[0]->ROM, sizeof(char)*8);
DasSidG 16:b2ef68c9a4fd 524 for (int i=0; i<devices_found; i++) {
maxv008 14:e0e88a009f4c 525 for(int j = 0; j < 7; j++)
maxv008 14:e0e88a009f4c 526 measurements.temperature_measurements[i].ROMID[j] = probe[i]->ROM[j];
lcockerton62 1:51477fe4851b 527 measurements.temperature_measurements[i].measurement = probe[i] ->temperature('C');
maxv008 14:e0e88a009f4c 528
lcockerton62 1:51477fe4851b 529 if(measurements.temperature_measurements[i].measurement > max_temperature) {
lcockerton62 1:51477fe4851b 530 max_temperature = measurements.temperature_measurements[i].measurement;
maxv008 23:a1af4439c1fc 531 std::memcpy(max_id, measurements.temperature_measurements[i].ROMID, sizeof(char)*8);
lcockerton62 2:94716229ecc3 532 } else if (measurements.temperature_measurements[i].measurement < min_temperature) {
lcockerton62 1:51477fe4851b 533 min_temperature = measurements.temperature_measurements[i].measurement;
maxv008 23:a1af4439c1fc 534 std::memcpy(min_id, measurements.temperature_measurements[i].ROMID, sizeof(char)*8);
lcockerton62 1:51477fe4851b 535 }
DasSidG 12:fa9b1a459e47 536
maxv008 18:521ffdd724f3 537 //printf("Device %d temperature is %3.3f degrees Celcius.\r\n",i+1 ,probe[i]->temperature('C'));
lcockerton62 1:51477fe4851b 538 }
DasSidG 21:d461d58e70fc 539 isotherm_12V_pin = 0;
maxv008 13:7b42af989cd1 540 //There is also a CMU # component of this struct, currently unfilled, perhaps not needed at all.
lcockerton62 1:51477fe4851b 541 measurements.max_cell_temp.temperature = max_temperature;
maxv008 23:a1af4439c1fc 542 std::memcpy(measurements.max_cell_temp.ROMID, max_id, sizeof(char)*8);
lcockerton62 1:51477fe4851b 543 measurements.min_cell_temp.temperature = min_temperature;
maxv008 28:f1f882bd1653 544 std::memcpy(measurements.min_cell_temp.ROMID, min_id, sizeof(char)*8);
maxv008 28:f1f882bd1653 545 delete max_id;
maxv008 28:f1f882bd1653 546 delete min_id;
lcockerton62 0:0a5f554d2a16 547 }
lcockerton62 0:0a5f554d2a16 548
lcockerton62 0:0a5f554d2a16 549 void update_SOC()
lcockerton62 0:0a5f554d2a16 550 {
lcockerton62 1:51477fe4851b 551 // Update the SOC value
maxv008 25:1fe8a42f8a6d 552 ltc2943.readAll();
lcockerton62 0:0a5f554d2a16 553 }
lcockerton62 0:0a5f554d2a16 554
lcockerton62 0:0a5f554d2a16 555
lcockerton62 1:51477fe4851b 556 uint32_t check_measurements(BMU_data &measurements)
lcockerton62 1:51477fe4851b 557 {
DasSidG 46:ac7065d52d6e 558 uint32_t status = 0;
lcockerton62 2:94716229ecc3 559
lcockerton62 2:94716229ecc3 560 if(measurements.max_cell_voltage.voltage > MAX_CELL_VOLTAGE) {
lcockerton62 2:94716229ecc3 561 status = status | CELL_OVER_VOLTAGE;
lcockerton62 2:94716229ecc3 562 } else if (measurements.min_cell_voltage.voltage < MIN_CELL_VOLTAGE) {
lcockerton62 1:51477fe4851b 563 status = status | CELL_UNDER_VOLTAGE;
lcockerton62 2:94716229ecc3 564 } else if (measurements.max_cell_temp.temperature > MAX_CELL_TEMPERATURE) {
lcockerton62 1:51477fe4851b 565 status = status | CELL_OVER_TEMPERATURE;
lcockerton62 1:51477fe4851b 566 }
lcockerton62 2:94716229ecc3 567
lcockerton62 1:51477fe4851b 568 /*
lcockerton62 1:51477fe4851b 569 @TODO also include errors for:
lcockerton62 1:51477fe4851b 570 *untrusted measurement
lcockerton62 1:51477fe4851b 571 *CMU timeout
lcockerton62 1:51477fe4851b 572 *SOC not valid
lcockerton62 1:51477fe4851b 573 */
lcockerton62 1:51477fe4851b 574 return status;
lcockerton62 1:51477fe4851b 575 }
lcockerton62 1:51477fe4851b 576
maxv008 23:a1af4439c1fc 577 //Returns the status variable
maxv008 23:a1af4439c1fc 578 uint32_t take_measurements(BMU_data &measurements)
lcockerton62 1:51477fe4851b 579 {
maxv008 6:b567fcb604aa 580 uint16_t cellvoltages[NO_CMUS][12];
DasSidG 16:b2ef68c9a4fd 581 //Use LTC6804_acquireVoltage to fill this array, and then properly format
maxv008 6:b567fcb604aa 582 //it to be sent over CAN
maxv008 6:b567fcb604aa 583
DasSidG 46:ac7065d52d6e 584 LTC6804_acquireVoltage(cellvoltages);
maxv008 23:a1af4439c1fc 585 pack_voltage_extremes min_voltage;
DasSidG 37:fae62a2773a1 586 pack_voltage_extremes max_voltage;
maxv008 23:a1af4439c1fc 587 min_voltage.voltage = 65535; //largest 16 bit unsigned int
maxv008 23:a1af4439c1fc 588 max_voltage.voltage = 0;
maxv008 23:a1af4439c1fc 589
DasSidG 37:fae62a2773a1 590 bool last_CMU = false;
maxv008 23:a1af4439c1fc 591 //Sets voltage readings as well as max/min voltage values.
maxv008 10:1079f8e52d65 592 for(int i=0; i<NO_CMUS; i++){
DasSidG 37:fae62a2773a1 593 if (i == (NO_CMUS - 1)) last_CMU = true;
maxv008 17:94dd9a0d3870 594 for(int j=0; j < NO_READINGS_PER_CMU; j++){
DasSidG 16:b2ef68c9a4fd 595 measurements.cell_voltages[i].voltages[j] = cellvoltages[i][j]/ 10; //To get units of mV
maxv008 17:94dd9a0d3870 596 measurements.cell_voltages[i].CMU_number = i;
DasSidG 37:fae62a2773a1 597
DasSidG 37:fae62a2773a1 598 if(!(last_CMU && j >(NO_READINGS_PER_CMU - (NUM_MISSING_CELLS + 1))))
DasSidG 37:fae62a2773a1 599 //the condition above is to account for the missing cells (not a complete set of 12) on the top CMU
maxv008 23:a1af4439c1fc 600 {
DasSidG 37:fae62a2773a1 601 if(measurements.cell_voltages[i].voltages[j] < min_voltage.voltage)
DasSidG 37:fae62a2773a1 602 {
DasSidG 37:fae62a2773a1 603 min_voltage.voltage = measurements.cell_voltages[i].voltages[j];
DasSidG 37:fae62a2773a1 604 min_voltage.CMU_number = i;
DasSidG 37:fae62a2773a1 605 min_voltage.cell_number = j;
DasSidG 37:fae62a2773a1 606 }
DasSidG 37:fae62a2773a1 607 else if(measurements.cell_voltages[i].voltages[j] > max_voltage.voltage)
DasSidG 37:fae62a2773a1 608 {
DasSidG 37:fae62a2773a1 609 max_voltage.voltage = measurements.cell_voltages[i].voltages[j];
DasSidG 37:fae62a2773a1 610 max_voltage.CMU_number = i;
DasSidG 37:fae62a2773a1 611 max_voltage.cell_number = j;
DasSidG 37:fae62a2773a1 612 }
DasSidG 37:fae62a2773a1 613 }
maxv008 10:1079f8e52d65 614 }
maxv008 23:a1af4439c1fc 615 }
maxv008 23:a1af4439c1fc 616 measurements.max_cell_voltage = max_voltage;
DasSidG 36:1b23c0692f54 617 if (DEBUG) printf("Max Voltage is %d \r\n", max_voltage.voltage);
maxv008 23:a1af4439c1fc 618 measurements.min_cell_voltage = min_voltage;
DasSidG 36:1b23c0692f54 619 if (DEBUG) printf("Min Voltage is %d \r\n", min_voltage.voltage);
DasSidG 4:9050c5d6925e 620
DasSidG 38:b1f5bfe38d70 621 //Code to take all temperature measurements and add it to measurements struct.
DasSidG 38:b1f5bfe38d70 622 //Don't need to take temperature measurements every loop though
DasSidG 38:b1f5bfe38d70 623
DasSidG 38:b1f5bfe38d70 624 if (temperature_counter ==TEMPERATURE_MEASUREMENT_FREQ) {
DasSidG 38:b1f5bfe38d70 625 read_temperature_sensors(measurements);
DasSidG 38:b1f5bfe38d70 626 temperature_counter = 0;
DasSidG 38:b1f5bfe38d70 627 }
DasSidG 38:b1f5bfe38d70 628 temperature_counter++;
DasSidG 38:b1f5bfe38d70 629
maxv008 23:a1af4439c1fc 630 // Update the SOC and take relevant measurements
maxv008 23:a1af4439c1fc 631 update_SOC();
maxv008 31:888b2602aab2 632 measurements.battery_voltage = 0;
maxv008 31:888b2602aab2 633 for(int i = 0; i < NO_CMUS; i++)
maxv008 31:888b2602aab2 634 {
maxv008 31:888b2602aab2 635 for(int j = 0; j < NO_READINGS_PER_CMU; j++)
maxv008 31:888b2602aab2 636 {
maxv008 31:888b2602aab2 637 measurements.battery_voltage += measurements.cell_voltages[i].voltages[j];
maxv008 31:888b2602aab2 638 }
maxv008 31:888b2602aab2 639 }
maxv008 31:888b2602aab2 640 measurements.battery_current =ltc2943.current() * 1000; //*1000 to convert to mA
DasSidG 4:9050c5d6925e 641 measurements.percentage_SOC = ltc2943.accumulatedCharge();
DasSidG 4:9050c5d6925e 642 measurements.SOC = (measurements.percentage_SOC /100) * BATTERY_CAPACITY;
maxv008 23:a1af4439c1fc 643
maxv008 45:c288d7cbdb4a 644 //The following takes IVT-A measurement
maxv008 45:c288d7cbdb4a 645 IVTA_SS = 1;
maxv008 45:c288d7cbdb4a 646 int ivta_measurements[6];
maxv008 45:c288d7cbdb4a 647 uint32_t unsigned_current;
maxv008 45:c288d7cbdb4a 648 ivta_init();
maxv008 45:c288d7cbdb4a 649
maxv008 45:c288d7cbdb4a 650 ivta_get_current(ivta_measurements);
maxv008 45:c288d7cbdb4a 651 unsigned_current = ((uint32_t)ivta_measurements[0]);
maxv008 45:c288d7cbdb4a 652 unsigned_current = unsigned_current | (((uint32_t)ivta_measurements[1]<<8));
maxv008 45:c288d7cbdb4a 653 unsigned_current = unsigned_current | (((uint32_t)ivta_measurements[2]<<16));
maxv008 45:c288d7cbdb4a 654
maxv008 45:c288d7cbdb4a 655 if(ivta_measurements[2] & 0x80){ //For some reason converting using 2's complement ¯\_(ツ)_/¯
maxv008 45:c288d7cbdb4a 656 uint32_t convertedData = ((~unsigned_current) + 1) & 0x00FFFFFF;
maxv008 45:c288d7cbdb4a 657 int32_t convertedData2 = (~convertedData)+1;
maxv008 45:c288d7cbdb4a 658 measurements.ivta_current = convertedData2;
maxv008 45:c288d7cbdb4a 659 if(DEBUG) printf("*** Current measurement value: %d *** \r \n",convertedData2);
maxv008 45:c288d7cbdb4a 660 }
maxv008 45:c288d7cbdb4a 661 else{
maxv008 45:c288d7cbdb4a 662 measurements.ivta_current = unsigned_current;
maxv008 45:c288d7cbdb4a 663 if(DEBUG) pc.printf("*** Current measurement value: %d *** \r \n", (int32_t)unsigned_current);
maxv008 45:c288d7cbdb4a 664 }
maxv008 23:a1af4439c1fc 665 // Check data for errors
maxv008 23:a1af4439c1fc 666 return check_measurements(measurements);
lcockerton62 1:51477fe4851b 667 }
lcockerton62 1:51477fe4851b 668
lcockerton62 0:0a5f554d2a16 669 void init()
lcockerton62 0:0a5f554d2a16 670 {
DasSidG 41:9183c5616281 671 PHY_PowerDown();
DasSidG 41:9183c5616281 672
maxv008 45:c288d7cbdb4a 673 if(TRANSMIT_MODE)
maxv008 45:c288d7cbdb4a 674 {
maxv008 45:c288d7cbdb4a 675 temperature_init(); // Initialise the temperature sensors
maxv008 45:c288d7cbdb4a 676 LTC2943_initialise(); //Initialises the fixed parameters of the LTC2943
maxv008 45:c288d7cbdb4a 677 LTC6804_init(MD_FAST, DCP_DISABLED, CELL_CH_ALL, AUX_CH_VREF2); //Initialises the LTC6804s
maxv008 31:888b2602aab2 678
maxv008 45:c288d7cbdb4a 679 ivta_init();
maxv008 45:c288d7cbdb4a 680 }
maxv008 14:e0e88a009f4c 681 for(int i=0; i<CAN_BUFFER_SIZE; i++)
maxv008 14:e0e88a009f4c 682 {
maxv008 14:e0e88a009f4c 683 buffer[i].id = BLANK_ID;
maxv008 14:e0e88a009f4c 684 safe_to_write[i]= true;
maxv008 14:e0e88a009f4c 685 }
maxv008 14:e0e88a009f4c 686
maxv008 14:e0e88a009f4c 687 //Initialise CAN stuff, attach CAN interrupt handlers
maxv008 14:e0e88a009f4c 688 can.frequency(CAN_BIT_RATE); //set transmission rate to agreed bit rate (ELEC-006)
maxv008 14:e0e88a009f4c 689 can.reset(); // (FUNC-018)
maxv008 14:e0e88a009f4c 690 can.attach(&interruptHandler, CAN::RxIrq); //receive interrupt handler
maxv008 14:e0e88a009f4c 691 can.attach(&CANDataSentCallback, CAN::TxIrq); //send interrupt handler
maxv008 17:94dd9a0d3870 692
maxv008 17:94dd9a0d3870 693 //Initialize voltage array
maxv008 17:94dd9a0d3870 694 for(int i = 0; i < NO_CMUS; i++)
maxv008 17:94dd9a0d3870 695 {
maxv008 17:94dd9a0d3870 696 for(int j = 0; j < NO_READINGS_PER_CMU; j++)
maxv008 17:94dd9a0d3870 697 {
maxv008 17:94dd9a0d3870 698 voltage_readings[i].voltages[j] = 0;
maxv008 17:94dd9a0d3870 699 }
maxv008 17:94dd9a0d3870 700 }
maxv008 20:a1a1bfc938da 701 //Initialize Temperature Array
maxv008 20:a1a1bfc938da 702 for(int i = 0; i < NO_TEMPERATURE_SENSORS; i++)
maxv008 20:a1a1bfc938da 703 {
maxv008 28:f1f882bd1653 704 templist[i].measurement = INFINITY;
maxv008 20:a1a1bfc938da 705 templist[i].ID = 0;
maxv008 20:a1a1bfc938da 706 }
maxv008 28:f1f882bd1653 707 //initialize stuff used in reading test:
maxv008 28:f1f882bd1653 708 packSOC = INFINITY;
maxv008 28:f1f882bd1653 709 packSOCPercentage = INFINITY;
maxv008 28:f1f882bd1653 710
maxv008 28:f1f882bd1653 711 minVolt.voltage = 0;
maxv008 28:f1f882bd1653 712 maxVolt.voltage = 0;
maxv008 28:f1f882bd1653 713
maxv008 28:f1f882bd1653 714 minTemp.temperature = 0; minTemp.ID = 0;
maxv008 28:f1f882bd1653 715 maxTemp.temperature = 0; maxTemp.ID = 0;
maxv008 31:888b2602aab2 716
maxv008 31:888b2602aab2 717 batteryCurrent = INFINITY; batteryVoltage = 0;
maxv008 14:e0e88a009f4c 718 }
maxv008 14:e0e88a009f4c 719
maxv008 14:e0e88a009f4c 720 void CANDataSentCallback(void) {
maxv008 14:e0e88a009f4c 721 CAN_data_sent = true;
lcockerton62 0:0a5f554d2a16 722 }
lcockerton62 0:0a5f554d2a16 723
maxv008 14:e0e88a009f4c 724 void interruptHandler()
maxv008 14:e0e88a009f4c 725 {
maxv008 14:e0e88a009f4c 726 CANMessage msg;
DasSidG 16:b2ef68c9a4fd 727 can.read(msg);
maxv008 14:e0e88a009f4c 728 for(int i=0; i<CAN_BUFFER_SIZE; i++) {
maxv008 14:e0e88a009f4c 729 if((buffer[i].id == msg.id || buffer[i].id==BLANK_ID) && safe_to_write[i]) {
maxv008 14:e0e88a009f4c 730 //("id %d added to buffer \r\n", msg.id);
maxv008 14:e0e88a009f4c 731 buffer[i] = msg;
maxv008 14:e0e88a009f4c 732 //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 733 return;
maxv008 14:e0e88a009f4c 734 }
maxv008 14:e0e88a009f4c 735 }
maxv008 48:5c3f42c44036 736 if(TRANSMIT_MODE) //It may be better to do this outside of an interrupt, it is fairly long. Requires a global variable
maxv008 48:5c3f42c44036 737 {
maxv008 48:5c3f42c44036 738 if(msg.id == BMS_BASE_ID + EEPROM_RESET_ID)
maxv008 48:5c3f42c44036 739 {
maxv008 48:5c3f42c44036 740 reset_EEPROM(decodeEEPROMSOC(msg), decodeEEPROMSOCPercentage(msg));
maxv008 48:5c3f42c44036 741 eeprom_start_address = read_EEPROM_startup(measurements); // Read newly written data back from EEPROM (can be done faster but this is more safe)
maxv008 48:5c3f42c44036 742 ltc2943.accumulatedCharge(measurements.percentage_SOC); // Initialise the LTC2943 with the current state of charge
maxv008 48:5c3f42c44036 743 }
maxv008 48:5c3f42c44036 744 }
maxv008 14:e0e88a009f4c 745 }
maxv008 14:e0e88a009f4c 746
maxv008 14:e0e88a009f4c 747 void test_read_CAN_buffer()
maxv008 14:e0e88a009f4c 748 {
maxv008 14:e0e88a009f4c 749 //Import the data from the buffer into a non-volatile, more usable format
maxv008 14:e0e88a009f4c 750 CAN_Data can_data[CAN_BUFFER_SIZE]; //container for all of the raw data
maxv008 17:94dd9a0d3870 751 CANMessage msgArray[CAN_BUFFER_SIZE]; //Same as above but some functions take message as their parameter
maxv008 14:e0e88a009f4c 752 int received_CAN_IDs[CAN_BUFFER_SIZE]; //needed to keep track of which IDs we've received so far
maxv008 14:e0e88a009f4c 753 for (int i = 0; i<CAN_BUFFER_SIZE; ++i)
maxv008 14:e0e88a009f4c 754 {
maxv008 14:e0e88a009f4c 755 safe_to_write[i] = false;
maxv008 14:e0e88a009f4c 756 can_data[i].importCANData(buffer[i]);
maxv008 14:e0e88a009f4c 757 received_CAN_IDs[i] = buffer[i].id;
maxv008 17:94dd9a0d3870 758 msgArray[i] = buffer[i];
maxv008 14:e0e88a009f4c 759 safe_to_write[i] = true;
maxv008 31:888b2602aab2 760 //printf("Id recieved %d \r\n", buffer[i].id);
maxv008 14:e0e88a009f4c 761 }
maxv008 17:94dd9a0d3870 762
maxv008 23:a1af4439c1fc 763 //voltage and Temp and SOC readings:
maxv008 18:521ffdd724f3 764 for(int i = 0; i < CAN_BUFFER_SIZE; i++)
maxv008 18:521ffdd724f3 765 {
maxv008 18:521ffdd724f3 766 //voltage
maxv008 28:f1f882bd1653 767 if(decodeVoltageTelemetry(msgArray[i], voltage_readings))
ItsJustZi 29:44924d2b1293 768 continue;
maxv008 28:f1f882bd1653 769 //temperature
maxv008 20:a1a1bfc938da 770 if(msgArray[i].id >= 0x700)
maxv008 18:521ffdd724f3 771 {
maxv008 20:a1a1bfc938da 772 individual_temperature dataPoint = decodeTemperatureTelemetry(msgArray[i]);
maxv008 20:a1a1bfc938da 773 for(int j = 0; j < NO_TEMPERATURE_SENSORS; j++)
maxv008 20:a1a1bfc938da 774 {
maxv008 20:a1a1bfc938da 775 if(dataPoint.ID == templist[j].ID)
maxv008 20:a1a1bfc938da 776 {
maxv008 20:a1a1bfc938da 777 templist[j] = dataPoint;
maxv008 20:a1a1bfc938da 778 break;
maxv008 20:a1a1bfc938da 779 }
maxv008 20:a1a1bfc938da 780 else if(templist[j].ID == 0)
maxv008 20:a1a1bfc938da 781 {
maxv008 20:a1a1bfc938da 782 templist[j] = dataPoint;
maxv008 20:a1a1bfc938da 783 break;
maxv008 20:a1a1bfc938da 784 }
maxv008 20:a1a1bfc938da 785 }
maxv008 20:a1a1bfc938da 786
maxv008 23:a1af4439c1fc 787 }
maxv008 23:a1af4439c1fc 788 //SOC
maxv008 23:a1af4439c1fc 789 if(msgArray[i].id == 0x6F4)
maxv008 23:a1af4439c1fc 790 {
maxv008 23:a1af4439c1fc 791 packSOC = decodePackSOC(msgArray[i]);
maxv008 23:a1af4439c1fc 792 packSOCPercentage = decodePackSOCPercentage(msgArray[i]);
maxv008 28:f1f882bd1653 793 }
maxv008 23:a1af4439c1fc 794
maxv008 23:a1af4439c1fc 795 if(msgArray[i].id == BMS_BASE_ID + MIN_TEMPERATURE)
maxv008 23:a1af4439c1fc 796 minTemp = decodeCellTemperatureMAXMIN(msgArray[i]);
maxv008 23:a1af4439c1fc 797 if(msgArray[i].id == BMS_BASE_ID + MAX_TEMPERATURE)
maxv008 23:a1af4439c1fc 798 maxTemp = decodeCellTemperatureMAXMIN(msgArray[i]);
maxv008 28:f1f882bd1653 799
maxv008 23:a1af4439c1fc 800 if(msgArray[i].id == BMS_BASE_ID + MAX_MIN_VOLTAGE)
maxv008 23:a1af4439c1fc 801 {
maxv008 23:a1af4439c1fc 802 decodeCellVoltageMAXMIN(msgArray[i], minVolt, maxVolt);
maxv008 23:a1af4439c1fc 803 }
maxv008 23:a1af4439c1fc 804
maxv008 31:888b2602aab2 805 if(msgArray[i].id == BMS_BASE_ID + BATTERY_VI_ID)
maxv008 31:888b2602aab2 806 {
maxv008 31:888b2602aab2 807 batteryVoltage = decodeBatteryVoltage(msgArray[i]);
maxv008 31:888b2602aab2 808 batteryCurrent = decodeBatteryCurrent(msgArray[i]);
maxv008 31:888b2602aab2 809 }
maxv008 31:888b2602aab2 810
maxv008 23:a1af4439c1fc 811 if(msgArray[i].id == BMS_BASE_ID + BATTERY_STATUS_ID)
maxv008 28:f1f882bd1653 812 status = decodeExtendedBatteryPackStatus(msgArray[i]);
maxv008 31:888b2602aab2 813
maxv008 31:888b2602aab2 814 if(msgArray[i].id == BMS_BASE_ID)
DasSidG 36:1b23c0692f54 815 if (DEBUG) printf("BMS Heartbeat Recieved \r\n");
maxv008 45:c288d7cbdb4a 816
maxv008 45:c288d7cbdb4a 817 if(msgArray[i].id == BMS_BASE_ID + IVTA_ID)
maxv008 45:c288d7cbdb4a 818 if (DEBUG) printf("IVTA Current is %d \r\n", decodeIVTACurrent(msgArray[i]));
maxv008 28:f1f882bd1653 819 }
maxv008 18:521ffdd724f3 820 //Print obtained Readings:
maxv008 18:521ffdd724f3 821 for(int i = 0; i < NO_CMUS; i++)
maxv008 18:521ffdd724f3 822 for(int j = 0; j < 12; j++)
DasSidG 36:1b23c0692f54 823 if (DEBUG) printf("Voltage number %d for CMU %d is %d \r\n", j, i, voltage_readings[i].voltages[j]);
maxv008 17:94dd9a0d3870 824
maxv008 18:521ffdd724f3 825 for(int i = 0; i < NO_TEMPERATURE_SENSORS; i++)
DasSidG 36:1b23c0692f54 826 if (DEBUG) printf("Temperature of Sensor with ID %d is %f \r\n", templist[i].ID, templist[i].measurement);
maxv008 23:a1af4439c1fc 827
DasSidG 36:1b23c0692f54 828 if (DEBUG) printf("SOC is %f and SOC Percentage is %f \r\n", packSOC, packSOCPercentage);
maxv008 23:a1af4439c1fc 829
DasSidG 36:1b23c0692f54 830 if (DEBUG) printf("Battery Current is %f and Battery Voltage is %d \r\n", batteryCurrent, batteryVoltage);
maxv008 31:888b2602aab2 831
DasSidG 36:1b23c0692f54 832 if (DEBUG) 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 833
DasSidG 36:1b23c0692f54 834 if (DEBUG) printf("(Temperature, ID): Minimum = (%d,%d). Maximum = (%d,%d) \r\n",
maxv008 23:a1af4439c1fc 835 minTemp.temperature,minTemp.ID,maxTemp.temperature,maxTemp.ID);
maxv008 23:a1af4439c1fc 836
DasSidG 36:1b23c0692f54 837 if (DEBUG) printf("Status value is: %d \r\n", status);
maxv008 14:e0e88a009f4c 838 }
maxv008 23:a1af4439c1fc 839
maxv008 10:1079f8e52d65 840 void test_CAN_send()
maxv008 10:1079f8e52d65 841 {
maxv008 10:1079f8e52d65 842 CANMessage msg;
DasSidG 11:cf2db05cfa56 843 char value = 142;
maxv008 10:1079f8e52d65 844 msg = CANMessage(1, &value,1);
maxv008 10:1079f8e52d65 845 if(can.write(msg))
DasSidG 36:1b23c0692f54 846 if (DEBUG) printf("Succesfully sent %d \r\n", value);
maxv008 10:1079f8e52d65 847 else
DasSidG 36:1b23c0692f54 848 if (DEBUG) printf("Sending Failed \r\n");
maxv008 10:1079f8e52d65 849 }
maxv008 10:1079f8e52d65 850
maxv008 10:1079f8e52d65 851 void test_CAN_read()
maxv008 10:1079f8e52d65 852 {
maxv008 10:1079f8e52d65 853 CANMessage msg;
maxv008 10:1079f8e52d65 854 if(can.read(msg))
DasSidG 36:1b23c0692f54 855 if (DEBUG) printf("Successfully recieved %d \r\n", msg.data[0]);
maxv008 10:1079f8e52d65 856 else
DasSidG 36:1b23c0692f54 857 if (DEBUG) printf("Reading Failed \r\n");
maxv008 10:1079f8e52d65 858 }