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