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