Has base BMU code but sends dummy temperature and voltage readings to test CAN
Dependencies: CUER_CAN DS1820 LTC2943 LTC6804 mbed
Fork of BMS_BMUCore_Max by
main.cpp@14:e0e88a009f4c, 2017-07-02 (annotated)
- Committer:
- maxv008
- Date:
- Sun Jul 02 01:45:39 2017 +0000
- Revision:
- 14:e0e88a009f4c
- Parent:
- 13:7b42af989cd1
- Child:
- 15:e901aff1f5b3
Added a proper unique identification to the temperature CAN. Implemented an interrupt based CAN read setup, currently configured with Dummy data and test code that will be cleaned up in a future commit
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 | 7:d00f4433cea9 | 10 | #include "SPI_I2C_Parser.h" |
lcockerton62 | 0:0a5f554d2a16 | 11 | |
msharma97 | 9:82ba050a7e13 | 12 | |
lcockerton62 | 0:0a5f554d2a16 | 13 | using namespace CAN_IDs; |
lcockerton62 | 0:0a5f554d2a16 | 14 | |
lcockerton62 | 0:0a5f554d2a16 | 15 | // Function definitions |
lcockerton62 | 1:51477fe4851b | 16 | void transmit_data(BMU_data measurements,uint32_t status); |
lcockerton62 | 1:51477fe4851b | 17 | void read_temperature_sensors(BMU_data &measurements); |
lcockerton62 | 0:0a5f554d2a16 | 18 | void update_SOC(); |
lcockerton62 | 0:0a5f554d2a16 | 19 | void init(); |
maxv008 | 14:e0e88a009f4c | 20 | void interruptHandler(); |
maxv008 | 14:e0e88a009f4c | 21 | void CANDataSentCallback(); |
lcockerton62 | 1:51477fe4851b | 22 | void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address); |
lcockerton62 | 1:51477fe4851b | 23 | uint16_t read_EEPROM_startup(BMU_data &measurements); |
lcockerton62 | 1:51477fe4851b | 24 | uint32_t check_measurements(BMU_data &measurements); |
lcockerton62 | 1:51477fe4851b | 25 | void take_measurements(BMU_data &measurements); |
maxv008 | 14:e0e88a009f4c | 26 | void test_read_CAN_buffer(); |
DasSidG | 12:fa9b1a459e47 | 27 | bool test_read_voltage_CAN(uint16_t readings[], int can_ids[]); |
maxv008 | 10:1079f8e52d65 | 28 | void test_CAN_send(); |
maxv008 | 10:1079f8e52d65 | 29 | void test_CAN_read(); |
lcockerton62 | 0:0a5f554d2a16 | 30 | |
lcockerton62 | 0:0a5f554d2a16 | 31 | CAN can(CAN_READ_PIN, CAN_WRITE_PIN); //Create a CAN object to handle CAN comms |
maxv008 | 14:e0e88a009f4c | 32 | CANMessage buffer[CAN_BUFFER_SIZE]; //CAN receive buffer |
maxv008 | 14:e0e88a009f4c | 33 | bool safe_to_write[CAN_BUFFER_SIZE]; //Semaphore bit indicating that it's safe to write to the software buffer |
maxv008 | 14:e0e88a009f4c | 34 | bool CAN_data_sent = false; |
maxv008 | 14:e0e88a009f4c | 35 | |
DasSidG | 4:9050c5d6925e | 36 | uint16_t eeprom_start_address; //the initial address where we store/read SoC values |
lcockerton62 | 0:0a5f554d2a16 | 37 | |
lcockerton62 | 1:51477fe4851b | 38 | Timeout loop_delay; |
lcockerton62 | 1:51477fe4851b | 39 | bool delay_finished = false; |
lcockerton62 | 2:94716229ecc3 | 40 | |
maxv008 | 14:e0e88a009f4c | 41 | |
lcockerton62 | 2:94716229ecc3 | 42 | void loop_delay_callback(void) |
lcockerton62 | 2:94716229ecc3 | 43 | { |
lcockerton62 | 1:51477fe4851b | 44 | delay_finished = true; |
lcockerton62 | 1:51477fe4851b | 45 | } |
lcockerton62 | 1:51477fe4851b | 46 | |
lcockerton62 | 0:0a5f554d2a16 | 47 | int main() |
DasSidG | 11:cf2db05cfa56 | 48 | { |
lcockerton62 | 1:51477fe4851b | 49 | BMU_data measurements; |
lcockerton62 | 1:51477fe4851b | 50 | uint16_t current_EEPROM_address; |
lcockerton62 | 1:51477fe4851b | 51 | uint32_t status; |
DasSidG | 12:fa9b1a459e47 | 52 | uint16_t volt_readings[36]; |
DasSidG | 12:fa9b1a459e47 | 53 | int can_ids[9]; |
maxv008 | 10:1079f8e52d65 | 54 | |
DasSidG | 12:fa9b1a459e47 | 55 | |
maxv008 | 14:e0e88a009f4c | 56 | /**while(true) |
maxv008 | 10:1079f8e52d65 | 57 | { |
DasSidG | 12:fa9b1a459e47 | 58 | for (int i = 0; i < 9; ++i) { |
DasSidG | 12:fa9b1a459e47 | 59 | while(!test_read_voltage_CAN(&volt_readings[(i*4)], &can_ids[i])); |
DasSidG | 12:fa9b1a459e47 | 60 | } |
DasSidG | 12:fa9b1a459e47 | 61 | |
DasSidG | 12:fa9b1a459e47 | 62 | for (int i = 0; i < 36; ++i) { |
DasSidG | 12:fa9b1a459e47 | 63 | printf("Cellvoltage %d = %d, CAN ID is %d \r\n", i, volt_readings[i], can_ids[i/4]); |
DasSidG | 12:fa9b1a459e47 | 64 | volt_readings[i] = -1; |
DasSidG | 12:fa9b1a459e47 | 65 | can_ids[i/4] = 0; |
DasSidG | 12:fa9b1a459e47 | 66 | } |
DasSidG | 12:fa9b1a459e47 | 67 | printf("\r\n"); |
DasSidG | 12:fa9b1a459e47 | 68 | |
maxv008 | 14:e0e88a009f4c | 69 | } */ |
lcockerton62 | 0:0a5f554d2a16 | 70 | init(); |
maxv008 | 10:1079f8e52d65 | 71 | |
DasSidG | 11:cf2db05cfa56 | 72 | |
DasSidG | 11:cf2db05cfa56 | 73 | |
DasSidG | 11:cf2db05cfa56 | 74 | //current_EEPROM_address = read_EEPROM_startup(measurements); // Read from the eeprom at startup to fill in the values of SoC |
DasSidG | 11:cf2db05cfa56 | 75 | //ltc2943.accumulatedCharge(measurements.percentage_SOC); // Initialise the LTC2943 with the current state of charge |
DasSidG | 4:9050c5d6925e | 76 | |
lcockerton62 | 1:51477fe4851b | 77 | while (true) { |
DasSidG | 11:cf2db05cfa56 | 78 | |
lcockerton62 | 1:51477fe4851b | 79 | // Take measurements from the sensors |
lcockerton62 | 1:51477fe4851b | 80 | take_measurements(measurements); |
DasSidG | 11:cf2db05cfa56 | 81 | /*// Dont want to read the temperature sensors during each iteration of the loop |
lcockerton62 | 1:51477fe4851b | 82 | if (c == 0) { |
lcockerton62 | 1:51477fe4851b | 83 | read_temperature_sensors(measurements); |
lcockerton62 | 1:51477fe4851b | 84 | } else if(c >= 4) { |
lcockerton62 | 0:0a5f554d2a16 | 85 | c = -1; |
lcockerton62 | 0:0a5f554d2a16 | 86 | } |
lcockerton62 | 0:0a5f554d2a16 | 87 | c++; |
lcockerton62 | 0:0a5f554d2a16 | 88 | |
lcockerton62 | 1:51477fe4851b | 89 | // Check data for errors |
lcockerton62 | 1:51477fe4851b | 90 | status = check_measurements(measurements); |
lcockerton62 | 1:51477fe4851b | 91 | |
lcockerton62 | 0:0a5f554d2a16 | 92 | // Update the SOC |
lcockerton62 | 0:0a5f554d2a16 | 93 | update_SOC(); |
lcockerton62 | 0:0a5f554d2a16 | 94 | |
lcockerton62 | 1:51477fe4851b | 95 | //Store data in the eeprom |
lcockerton62 | 1:51477fe4851b | 96 | write_SOC_EEPROM(measurements, current_EEPROM_address); |
DasSidG | 11:cf2db05cfa56 | 97 | */ |
lcockerton62 | 0:0a5f554d2a16 | 98 | |
lcockerton62 | 5:793afeef45dc | 99 | // CAN bus |
maxv008 | 14:e0e88a009f4c | 100 | CAN_data_sent = false;//Currently does nothing, adding this line in more places then using |
maxv008 | 14:e0e88a009f4c | 101 | //while(!CAN_data_sent); in order to ensure sending completes |
maxv008 | 14:e0e88a009f4c | 102 | //transmit_data(measurements,status); |
maxv008 | 14:e0e88a009f4c | 103 | test_read_CAN_buffer(); |
DasSidG | 11:cf2db05cfa56 | 104 | |
DasSidG | 11:cf2db05cfa56 | 105 | /* |
lcockerton62 | 0:0a5f554d2a16 | 106 | // Conserve power - enter a low powered mode |
lcockerton62 | 2:94716229ecc3 | 107 | delay_finished = false; |
lcockerton62 | 1:51477fe4851b | 108 | loop_delay.attach(loop_delay_callback, LOOP_DELAY_S); |
lcockerton62 | 1:51477fe4851b | 109 | while (!delay_finished) sleep(); |
DasSidG | 11:cf2db05cfa56 | 110 | */ |
DasSidG | 11:cf2db05cfa56 | 111 | |
DasSidG | 11:cf2db05cfa56 | 112 | //test_CAN_send(); |
DasSidG | 11:cf2db05cfa56 | 113 | //test_CAN_read(); |
DasSidG | 11:cf2db05cfa56 | 114 | wait(1); |
maxv008 | 10:1079f8e52d65 | 115 | } |
lcockerton62 | 0:0a5f554d2a16 | 116 | } |
lcockerton62 | 0:0a5f554d2a16 | 117 | |
lcockerton62 | 1:51477fe4851b | 118 | void transmit_data(BMU_data measurements, uint32_t status) |
lcockerton62 | 0:0a5f554d2a16 | 119 | { |
msharma97 | 9:82ba050a7e13 | 120 | CANMessage msg; |
lcockerton62 | 0:0a5f554d2a16 | 121 | /* |
lcockerton62 | 0:0a5f554d2a16 | 122 | Place all of the collected data onto the CAN bus |
lcockerton62 | 0:0a5f554d2a16 | 123 | */ |
lcockerton62 | 5:793afeef45dc | 124 | // Send cell voltages |
maxv008 | 13:7b42af989cd1 | 125 | //voltages sent in sets of 4 + one cmu data set |
msharma97 | 9:82ba050a7e13 | 126 | int repeating_unit_length = NO_READINGS_PER_CMU /4 + 1; |
maxv008 | 10:1079f8e52d65 | 127 | for(uint16_t i= 0; i < NO_CMUS; i++) { |
msharma97 | 9:82ba050a7e13 | 128 | //input id is offset, data structure is info, voltage, voltage, ...... |
maxv008 | 10:1079f8e52d65 | 129 | //This is a slightly modified version of the Tritium BMS datasheet, to add an extra voltage reading set. |
maxv008 | 10:1079f8e52d65 | 130 | msg = createVoltageTelemetry(repeating_unit_length*i+2, measurements.cell_voltages[i].voltages); |
msharma97 | 9:82ba050a7e13 | 131 | can.write(msg); |
DasSidG | 11:cf2db05cfa56 | 132 | wait(0.1); |
maxv008 | 10:1079f8e52d65 | 133 | //CONSIDER WAITS JUST IN CASE |
msharma97 | 9:82ba050a7e13 | 134 | //+4 - 4 cell voltages sent per measurement |
maxv008 | 10:1079f8e52d65 | 135 | msg = createVoltageTelemetry(repeating_unit_length*i+3, measurements.cell_voltages[i].voltages + 4); |
msharma97 | 9:82ba050a7e13 | 136 | can.write(msg); |
DasSidG | 11:cf2db05cfa56 | 137 | wait(0.1); |
maxv008 | 10:1079f8e52d65 | 138 | msg = createVoltageTelemetry(repeating_unit_length*i+4, measurements.cell_voltages[i].voltages + 8); |
msharma97 | 9:82ba050a7e13 | 139 | can.write(msg); |
DasSidG | 11:cf2db05cfa56 | 140 | wait(0.1); |
DasSidG | 11:cf2db05cfa56 | 141 | //printf("Message id: %d \r\n", msg.id); |
lcockerton62 | 1:51477fe4851b | 142 | } |
maxv008 | 13:7b42af989cd1 | 143 | |
maxv008 | 13:7b42af989cd1 | 144 | //Transmitting all of the individual probes: |
maxv008 | 14:e0e88a009f4c | 145 | //for(uint8_t i = 0; i < devices_found; i++) REPLACED BY DUMMY LOOP |
maxv008 | 14:e0e88a009f4c | 146 | for(uint8_t i = 0; i < 10; i++) |
maxv008 | 13:7b42af989cd1 | 147 | { |
maxv008 | 14:e0e88a009f4c | 148 | individual_temperature tempreading = measurements.temperature_measurements[i]; |
maxv008 | 14:e0e88a009f4c | 149 | msg = createTemperatureTelemetry(i, &tempreading.ROMID[0], tempreading.measurement); |
maxv008 | 14:e0e88a009f4c | 150 | if(can.write(msg)) |
maxv008 | 14:e0e88a009f4c | 151 | printf("Message sent succesfully \r\n"); |
maxv008 | 14:e0e88a009f4c | 152 | else |
maxv008 | 14:e0e88a009f4c | 153 | printf("message failed to send \r\n"); |
maxv008 | 14:e0e88a009f4c | 154 | individual_temperature testOut = decodeTemperatureTelemetry(msg); |
maxv008 | 14:e0e88a009f4c | 155 | printf("ID[6] is %d and temp is %f \r\n",testOut.ROMID[6],testOut.measurement); |
maxv008 | 13:7b42af989cd1 | 156 | wait(0.1); |
maxv008 | 13:7b42af989cd1 | 157 | } |
lcockerton62 | 1:51477fe4851b | 158 | |
lcockerton62 | 1:51477fe4851b | 159 | // Create SOC CAN message |
lcockerton62 | 1:51477fe4851b | 160 | createPackSOC(measurements.SOC, measurements.percentage_SOC); |
lcockerton62 | 0:0a5f554d2a16 | 161 | |
lcockerton62 | 1:51477fe4851b | 162 | // Min/max cell voltages |
lcockerton62 | 1:51477fe4851b | 163 | createCellVoltageMAXMIN(measurements.max_cell_voltage, measurements.min_cell_voltage); |
lcockerton62 | 2:94716229ecc3 | 164 | |
maxv008 | 13:7b42af989cd1 | 165 | // Min/Max cell temperature, Currently the meaning of temp max/min is a ambiguous |
maxv008 | 13:7b42af989cd1 | 166 | // due to changes to Temperature reading (namely the CMU ID portion of it), @TODO change MAXMIN |
lcockerton62 | 1:51477fe4851b | 167 | createCellTemperatureMAXMIN(measurements.min_cell_temp,measurements.max_cell_temp); |
lcockerton62 | 2:94716229ecc3 | 168 | |
lcockerton62 | 2:94716229ecc3 | 169 | // Battery voltage and current |
lcockerton62 | 5:793afeef45dc | 170 | // @TODO add the voltage |
lcockerton62 | 1:51477fe4851b | 171 | createBatteryVI(measurements.battery_voltage,measurements.battery_current); |
lcockerton62 | 2:94716229ecc3 | 172 | |
lcockerton62 | 1:51477fe4851b | 173 | //Extended battery pack status |
lcockerton62 | 1:51477fe4851b | 174 | createExtendedBatteryPackStatus(status); |
lcockerton62 | 2:94716229ecc3 | 175 | |
lcockerton62 | 0:0a5f554d2a16 | 176 | } |
lcockerton62 | 0:0a5f554d2a16 | 177 | |
maxv008 | 10:1079f8e52d65 | 178 | |
lcockerton62 | 1:51477fe4851b | 179 | uint16_t read_EEPROM_startup(BMU_data &measurements) |
lcockerton62 | 0:0a5f554d2a16 | 180 | { |
lcockerton62 | 1:51477fe4851b | 181 | /* The first page of the EEPROM, specifically the first 2 addresses store a |
lcockerton62 | 1:51477fe4851b | 182 | pointer of the first memory location of measurement data. The EEPROM only has a finite number of |
lcockerton62 | 1:51477fe4851b | 183 | read/write cycles which is why we aren't writing to the same location throughout |
lcockerton62 | 1:51477fe4851b | 184 | */ |
lcockerton62 | 5:793afeef45dc | 185 | |
lcockerton62 | 1:51477fe4851b | 186 | uint16_t start_address; |
lcockerton62 | 1:51477fe4851b | 187 | char start_address_array[2]; |
lcockerton62 | 1:51477fe4851b | 188 | char SOC_out[8]; // 4 bytes for the 2 floats one is SOC and the other % charge |
lcockerton62 | 1:51477fe4851b | 189 | float *fp1,*fp2; // temporary storage for float conversion |
lcockerton62 | 1:51477fe4851b | 190 | |
lcockerton62 | 1:51477fe4851b | 191 | // Get a pointer to the start address for the data stored in the eeprom |
lcockerton62 | 1:51477fe4851b | 192 | i2c_page_read(0x0000,2,start_address_array); |
lcockerton62 | 1:51477fe4851b | 193 | |
lcockerton62 | 1:51477fe4851b | 194 | // Read the data from this address |
lcockerton62 | 1:51477fe4851b | 195 | start_address = (start_address_array[1]<< 8) | start_address_array[0]; // mbed little endian follow this convention |
lcockerton62 | 1:51477fe4851b | 196 | i2c_page_read(start_address, 8,SOC_out); |
lcockerton62 | 0:0a5f554d2a16 | 197 | |
lcockerton62 | 1:51477fe4851b | 198 | // Convert the SOC_out values back into floats |
lcockerton62 | 1:51477fe4851b | 199 | fp1 = (float*)(&SOC_out[0]); |
lcockerton62 | 1:51477fe4851b | 200 | fp2 = (float*)(&SOC_out[4]); |
lcockerton62 | 1:51477fe4851b | 201 | measurements.SOC = *fp1; |
lcockerton62 | 1:51477fe4851b | 202 | measurements.percentage_SOC = *fp2; |
lcockerton62 | 1:51477fe4851b | 203 | |
lcockerton62 | 1:51477fe4851b | 204 | // Select the next address to write to |
lcockerton62 | 1:51477fe4851b | 205 | start_address += 0x0040; |
lcockerton62 | 1:51477fe4851b | 206 | if(start_address > MAX_WRITE_ADDRESS) { |
lcockerton62 | 5:793afeef45dc | 207 | start_address = START_WRITE_ADDRESS; // Loop to the start of the eeprom |
lcockerton62 | 1:51477fe4851b | 208 | } |
lcockerton62 | 1:51477fe4851b | 209 | |
lcockerton62 | 5:793afeef45dc | 210 | /*@TODO need to include a CRC check for the address pointer for the scenario |
lcockerton62 | 5:793afeef45dc | 211 | when power is removed and we are writing to the eeprom*/ |
lcockerton62 | 1:51477fe4851b | 212 | // write the new address to location 0x0000 |
lcockerton62 | 1:51477fe4851b | 213 | start_address_array[0] = start_address | 0x00FF; |
lcockerton62 | 1:51477fe4851b | 214 | start_address_array[1] = start_address >> 8; |
lcockerton62 | 1:51477fe4851b | 215 | i2c_page_write(0x0000, 2, start_address_array); |
lcockerton62 | 1:51477fe4851b | 216 | |
lcockerton62 | 1:51477fe4851b | 217 | return start_address; |
lcockerton62 | 0:0a5f554d2a16 | 218 | } |
lcockerton62 | 0:0a5f554d2a16 | 219 | |
lcockerton62 | 1:51477fe4851b | 220 | void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address) |
lcockerton62 | 0:0a5f554d2a16 | 221 | { |
lcockerton62 | 1:51477fe4851b | 222 | char data_out[8]; |
lcockerton62 | 1:51477fe4851b | 223 | float *fp1,*fp2; |
lcockerton62 | 1:51477fe4851b | 224 | |
lcockerton62 | 1:51477fe4851b | 225 | fp1 = (float*)(&measurements.SOC); |
lcockerton62 | 1:51477fe4851b | 226 | fp2 = (float*)(&measurements.percentage_SOC); |
lcockerton62 | 0:0a5f554d2a16 | 227 | |
lcockerton62 | 1:51477fe4851b | 228 | for(int i = 0; i < 4; i++ ) { |
lcockerton62 | 1:51477fe4851b | 229 | data_out[i] = *fp1; |
lcockerton62 | 1:51477fe4851b | 230 | fp1++; |
lcockerton62 | 1:51477fe4851b | 231 | } |
lcockerton62 | 1:51477fe4851b | 232 | for(int j = 4; j < 7; j++ ) { |
lcockerton62 | 1:51477fe4851b | 233 | data_out[j] = *fp2; |
lcockerton62 | 1:51477fe4851b | 234 | fp2++; |
lcockerton62 | 1:51477fe4851b | 235 | } |
lcockerton62 | 1:51477fe4851b | 236 | i2c_page_write(start_address, 8,data_out); |
lcockerton62 | 0:0a5f554d2a16 | 237 | } |
lcockerton62 | 0:0a5f554d2a16 | 238 | |
lcockerton62 | 1:51477fe4851b | 239 | void read_temperature_sensors(BMU_data &measurements) |
lcockerton62 | 0:0a5f554d2a16 | 240 | { |
lcockerton62 | 1:51477fe4851b | 241 | float min_temperature; |
lcockerton62 | 1:51477fe4851b | 242 | float max_temperature; |
DasSidG | 12:fa9b1a459e47 | 243 | DigitalOut isotherm_12V_pin(ISOTHERM_12V_PIN); |
DasSidG | 12:fa9b1a459e47 | 244 | isotherm_12V_pin = 1; |
lcockerton62 | 1:51477fe4851b | 245 | probe[0]->convert_temperature(DS1820::all_devices); |
DasSidG | 12:fa9b1a459e47 | 246 | isotherm_12V_pin = 0; |
lcockerton62 | 1:51477fe4851b | 247 | min_temperature = probe[0]->temperature('C'); |
lcockerton62 | 1:51477fe4851b | 248 | max_temperature = min_temperature; // Initially set the max and min temperature equal |
maxv008 | 14:e0e88a009f4c | 249 | /**for (int i=0; i<devices_found; i++) { |
maxv008 | 14:e0e88a009f4c | 250 | for(int j = 0; j < 7; j++) |
maxv008 | 14:e0e88a009f4c | 251 | measurements.temperature_measurements[i].ROMID[j] = probe[i]->ROM[j]; |
lcockerton62 | 1:51477fe4851b | 252 | measurements.temperature_measurements[i].measurement = probe[i] ->temperature('C'); |
maxv008 | 14:e0e88a009f4c | 253 | |
maxv008 | 14:e0e88a009f4c | 254 | |
maxv008 | 14:e0e88a009f4c | 255 | |
lcockerton62 | 1:51477fe4851b | 256 | if(measurements.temperature_measurements[i].measurement > max_temperature) { |
lcockerton62 | 1:51477fe4851b | 257 | max_temperature = measurements.temperature_measurements[i].measurement; |
lcockerton62 | 2:94716229ecc3 | 258 | } else if (measurements.temperature_measurements[i].measurement < min_temperature) { |
lcockerton62 | 1:51477fe4851b | 259 | min_temperature = measurements.temperature_measurements[i].measurement; |
lcockerton62 | 1:51477fe4851b | 260 | } |
DasSidG | 12:fa9b1a459e47 | 261 | |
DasSidG | 12:fa9b1a459e47 | 262 | printf("Device %d temperature is %3.3f degrees Celcius.\r\n",i+1 ,probe[i]->temperature('C')); |
maxv008 | 14:e0e88a009f4c | 263 | }ABOVE BLOCK REPLACED BY DUMMY MEASUREMENTS */ |
maxv008 | 14:e0e88a009f4c | 264 | //Dummy data goes here |
maxv008 | 14:e0e88a009f4c | 265 | for(int i = 0; i < 10; i++) |
maxv008 | 14:e0e88a009f4c | 266 | { |
maxv008 | 14:e0e88a009f4c | 267 | for(int j = 0; j < 7; j++) |
maxv008 | 14:e0e88a009f4c | 268 | measurements.temperature_measurements[i].ROMID[j] = j; |
maxv008 | 14:e0e88a009f4c | 269 | |
maxv008 | 14:e0e88a009f4c | 270 | measurements.temperature_measurements[i].measurement = 22.7 + (float) i; |
maxv008 | 14:e0e88a009f4c | 271 | |
maxv008 | 14:e0e88a009f4c | 272 | if(measurements.temperature_measurements[i].measurement > max_temperature) { |
maxv008 | 14:e0e88a009f4c | 273 | max_temperature = measurements.temperature_measurements[i].measurement; |
maxv008 | 14:e0e88a009f4c | 274 | } else if (measurements.temperature_measurements[i].measurement < min_temperature) { |
maxv008 | 14:e0e88a009f4c | 275 | min_temperature = measurements.temperature_measurements[i].measurement; |
maxv008 | 14:e0e88a009f4c | 276 | } |
lcockerton62 | 1:51477fe4851b | 277 | } |
maxv008 | 14:e0e88a009f4c | 278 | |
maxv008 | 13:7b42af989cd1 | 279 | //There is also a CMU # component of this struct, currently unfilled, perhaps not needed at all. |
lcockerton62 | 1:51477fe4851b | 280 | measurements.max_cell_temp.temperature = max_temperature; |
lcockerton62 | 1:51477fe4851b | 281 | measurements.min_cell_temp.temperature = min_temperature; |
lcockerton62 | 0:0a5f554d2a16 | 282 | } |
lcockerton62 | 0:0a5f554d2a16 | 283 | |
lcockerton62 | 0:0a5f554d2a16 | 284 | void update_SOC() |
lcockerton62 | 0:0a5f554d2a16 | 285 | { |
lcockerton62 | 1:51477fe4851b | 286 | // Update the SOC value |
lcockerton62 | 0:0a5f554d2a16 | 287 | } |
lcockerton62 | 0:0a5f554d2a16 | 288 | |
lcockerton62 | 0:0a5f554d2a16 | 289 | |
lcockerton62 | 1:51477fe4851b | 290 | uint32_t check_measurements(BMU_data &measurements) |
lcockerton62 | 1:51477fe4851b | 291 | { |
lcockerton62 | 1:51477fe4851b | 292 | uint32_t status; |
lcockerton62 | 2:94716229ecc3 | 293 | |
lcockerton62 | 2:94716229ecc3 | 294 | if(measurements.max_cell_voltage.voltage > MAX_CELL_VOLTAGE) { |
lcockerton62 | 2:94716229ecc3 | 295 | status = status | CELL_OVER_VOLTAGE; |
lcockerton62 | 2:94716229ecc3 | 296 | } else if (measurements.min_cell_voltage.voltage < MIN_CELL_VOLTAGE) { |
lcockerton62 | 1:51477fe4851b | 297 | status = status | CELL_UNDER_VOLTAGE; |
lcockerton62 | 2:94716229ecc3 | 298 | } else if (measurements.max_cell_temp.temperature > MAX_CELL_TEMPERATURE) { |
lcockerton62 | 1:51477fe4851b | 299 | status = status | CELL_OVER_TEMPERATURE; |
lcockerton62 | 1:51477fe4851b | 300 | } |
lcockerton62 | 2:94716229ecc3 | 301 | |
lcockerton62 | 1:51477fe4851b | 302 | /* |
lcockerton62 | 1:51477fe4851b | 303 | @TODO also include errors for: |
lcockerton62 | 1:51477fe4851b | 304 | *untrusted measurement |
lcockerton62 | 1:51477fe4851b | 305 | *CMU timeout |
lcockerton62 | 1:51477fe4851b | 306 | *SOC not valid |
lcockerton62 | 1:51477fe4851b | 307 | */ |
lcockerton62 | 1:51477fe4851b | 308 | return status; |
lcockerton62 | 1:51477fe4851b | 309 | } |
lcockerton62 | 1:51477fe4851b | 310 | |
lcockerton62 | 1:51477fe4851b | 311 | void take_measurements(BMU_data &measurements) |
lcockerton62 | 1:51477fe4851b | 312 | { |
maxv008 | 6:b567fcb604aa | 313 | uint16_t cellvoltages[NO_CMUS][12]; |
maxv008 | 6:b567fcb604aa | 314 | //TODO Use LTC6804_acquireVoltage to fill this array, and then properly format |
maxv008 | 6:b567fcb604aa | 315 | //it to be sent over CAN |
maxv008 | 6:b567fcb604aa | 316 | |
maxv008 | 14:e0e88a009f4c | 317 | //LTC6804_acquireVoltage(cellvoltages); REPLACED BY DUMMY DATA |
maxv008 | 14:e0e88a009f4c | 318 | for(int i = 0; i < NO_CMUS; i++) |
maxv008 | 14:e0e88a009f4c | 319 | { |
maxv008 | 14:e0e88a009f4c | 320 | for(int j = 0; j < 12; j++) |
maxv008 | 14:e0e88a009f4c | 321 | cellvoltages[i][j] = i*j; //Just to have some data variation |
maxv008 | 14:e0e88a009f4c | 322 | } |
maxv008 | 10:1079f8e52d65 | 323 | for(int i=0; i<NO_CMUS; i++){ |
maxv008 | 10:1079f8e52d65 | 324 | for(int j=0; j<12; j++){ |
maxv008 | 14:e0e88a009f4c | 325 | measurements.cell_voltages[i].voltages[j] = cellvoltages[i][j]; // / 10; REMOVED FOR DUMMY DATA |
maxv008 | 14:e0e88a009f4c | 326 | //printf("Cellvoltage[%d][%d] = %d \r\n",i,j,cellvoltages[i][j]); // SAME AS ABOVE /10); |
maxv008 | 10:1079f8e52d65 | 327 | } |
maxv008 | 14:e0e88a009f4c | 328 | } |
DasSidG | 4:9050c5d6925e | 329 | |
maxv008 | 13:7b42af989cd1 | 330 | //Add code to take all temperature measurements and add it to measurements struct. |
maxv008 | 13:7b42af989cd1 | 331 | read_temperature_sensors(measurements); |
maxv008 | 13:7b42af989cd1 | 332 | |
DasSidG | 4:9050c5d6925e | 333 | //Current, SoC |
maxv008 | 13:7b42af989cd1 | 334 | measurements.battery_current = (uint32_t) ltc2943.current()*1000; //*1000 to convert to mA |
DasSidG | 4:9050c5d6925e | 335 | measurements.percentage_SOC = ltc2943.accumulatedCharge(); |
DasSidG | 4:9050c5d6925e | 336 | measurements.SOC = (measurements.percentage_SOC /100) * BATTERY_CAPACITY; |
lcockerton62 | 1:51477fe4851b | 337 | } |
lcockerton62 | 1:51477fe4851b | 338 | |
lcockerton62 | 0:0a5f554d2a16 | 339 | void init() |
lcockerton62 | 0:0a5f554d2a16 | 340 | { |
lcockerton62 | 1:51477fe4851b | 341 | temperature_init(); // Initialise the temperature sensors |
DasSidG | 4:9050c5d6925e | 342 | LTC2943_initialise(); //Initialises the fixed parameters of the LTC2943 |
maxv008 | 14:e0e88a009f4c | 343 | |
maxv008 | 14:e0e88a009f4c | 344 | for(int i=0; i<CAN_BUFFER_SIZE; i++) |
maxv008 | 14:e0e88a009f4c | 345 | { |
maxv008 | 14:e0e88a009f4c | 346 | buffer[i].id = BLANK_ID; |
maxv008 | 14:e0e88a009f4c | 347 | //("%d",buffer[i].id); |
maxv008 | 14:e0e88a009f4c | 348 | safe_to_write[i]= true; |
maxv008 | 14:e0e88a009f4c | 349 | } |
maxv008 | 14:e0e88a009f4c | 350 | |
maxv008 | 14:e0e88a009f4c | 351 | //Initialise CAN stuff, attach CAN interrupt handlers |
maxv008 | 14:e0e88a009f4c | 352 | can.frequency(CAN_BIT_RATE); //set transmission rate to agreed bit rate (ELEC-006) |
maxv008 | 14:e0e88a009f4c | 353 | can.reset(); // (FUNC-018) |
maxv008 | 14:e0e88a009f4c | 354 | can.attach(&interruptHandler, CAN::RxIrq); //receive interrupt handler |
maxv008 | 14:e0e88a009f4c | 355 | can.attach(&CANDataSentCallback, CAN::TxIrq); //send interrupt handler |
maxv008 | 14:e0e88a009f4c | 356 | |
maxv008 | 14:e0e88a009f4c | 357 | } |
maxv008 | 14:e0e88a009f4c | 358 | |
maxv008 | 14:e0e88a009f4c | 359 | void CANDataSentCallback(void) { |
maxv008 | 14:e0e88a009f4c | 360 | CAN_data_sent = true; |
maxv008 | 14:e0e88a009f4c | 361 | printf("Some CAN was sent \r\n"); |
lcockerton62 | 0:0a5f554d2a16 | 362 | } |
lcockerton62 | 0:0a5f554d2a16 | 363 | |
maxv008 | 14:e0e88a009f4c | 364 | void interruptHandler() |
maxv008 | 14:e0e88a009f4c | 365 | { |
maxv008 | 14:e0e88a009f4c | 366 | CANMessage msg; |
maxv008 | 14:e0e88a009f4c | 367 | if(can.read(msg)) |
maxv008 | 14:e0e88a009f4c | 368 | printf("interrupt reached with id %d \r\n",msg.id); |
maxv008 | 14:e0e88a009f4c | 369 | else |
maxv008 | 14:e0e88a009f4c | 370 | printf("reading failed \r\n"); |
maxv008 | 14:e0e88a009f4c | 371 | for(int i=0; i<CAN_BUFFER_SIZE; i++) { |
maxv008 | 14:e0e88a009f4c | 372 | if((buffer[i].id == msg.id || buffer[i].id==BLANK_ID) && safe_to_write[i]) { |
maxv008 | 14:e0e88a009f4c | 373 | //("id %d added to buffer \r\n", msg.id); |
maxv008 | 14:e0e88a009f4c | 374 | buffer[i] = msg; |
maxv008 | 14:e0e88a009f4c | 375 | //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 | 376 | return; |
maxv008 | 14:e0e88a009f4c | 377 | } |
maxv008 | 14:e0e88a009f4c | 378 | } |
maxv008 | 14:e0e88a009f4c | 379 | } |
maxv008 | 14:e0e88a009f4c | 380 | |
maxv008 | 14:e0e88a009f4c | 381 | void test_read_CAN_buffer() |
maxv008 | 14:e0e88a009f4c | 382 | { |
maxv008 | 14:e0e88a009f4c | 383 | //Import the data from the buffer into a non-volatile, more usable format |
maxv008 | 14:e0e88a009f4c | 384 | CAN_Data can_data[CAN_BUFFER_SIZE]; //container for all of the raw data |
maxv008 | 14:e0e88a009f4c | 385 | int received_CAN_IDs[CAN_BUFFER_SIZE]; //needed to keep track of which IDs we've received so far |
maxv008 | 14:e0e88a009f4c | 386 | for (int i = 0; i<CAN_BUFFER_SIZE; ++i) |
maxv008 | 14:e0e88a009f4c | 387 | { |
maxv008 | 14:e0e88a009f4c | 388 | safe_to_write[i] = false; |
maxv008 | 14:e0e88a009f4c | 389 | can_data[i].importCANData(buffer[i]); |
maxv008 | 14:e0e88a009f4c | 390 | received_CAN_IDs[i] = buffer[i].id; |
maxv008 | 14:e0e88a009f4c | 391 | safe_to_write[i] = true; |
maxv008 | 14:e0e88a009f4c | 392 | } |
maxv008 | 14:e0e88a009f4c | 393 | |
maxv008 | 14:e0e88a009f4c | 394 | for(int i = 0; i < CAN_BUFFER_SIZE; i++) |
maxv008 | 14:e0e88a009f4c | 395 | { |
maxv008 | 14:e0e88a009f4c | 396 | individual_temperature testpoint; |
maxv008 | 14:e0e88a009f4c | 397 | if(!(buffer[i].id == BLANK_ID) && buffer[i].id < 10) |
maxv008 | 14:e0e88a009f4c | 398 | { |
maxv008 | 14:e0e88a009f4c | 399 | testpoint = decodeTemperatureTelemetry(buffer[i]); |
maxv008 | 14:e0e88a009f4c | 400 | printf("Temperature is %f and ID[5] is %d \r\n", testpoint.measurement, testpoint.ROMID[5]); |
maxv008 | 14:e0e88a009f4c | 401 | }else if(buffer[i].id == 1538) |
maxv008 | 14:e0e88a009f4c | 402 | printf("id 1538 was recieved\r\n"); |
maxv008 | 14:e0e88a009f4c | 403 | } |
maxv008 | 14:e0e88a009f4c | 404 | } |
DasSidG | 12:fa9b1a459e47 | 405 | bool test_read_voltage_CAN(uint16_t readings[], int can_ids[]) |
maxv008 | 10:1079f8e52d65 | 406 | { |
maxv008 | 10:1079f8e52d65 | 407 | CANMessage msg; |
maxv008 | 10:1079f8e52d65 | 408 | int can_id; |
maxv008 | 10:1079f8e52d65 | 409 | int offset; |
maxv008 | 10:1079f8e52d65 | 410 | int first_index; |
maxv008 | 10:1079f8e52d65 | 411 | int second_index; |
maxv008 | 10:1079f8e52d65 | 412 | |
maxv008 | 10:1079f8e52d65 | 413 | if(can.read(msg)) |
maxv008 | 10:1079f8e52d65 | 414 | { |
maxv008 | 10:1079f8e52d65 | 415 | for(int i =0; i < 4; i++) |
maxv008 | 10:1079f8e52d65 | 416 | { |
maxv008 | 10:1079f8e52d65 | 417 | readings[i] = (msg.data[2 * i]) + (msg.data[2*i+1] << 8); //Since data is 8 8bit ints not 4 16 bit ones |
maxv008 | 10:1079f8e52d65 | 418 | } |
DasSidG | 12:fa9b1a459e47 | 419 | can_id = msg.id; |
DasSidG | 12:fa9b1a459e47 | 420 | can_ids[0] = msg.id; |
DasSidG | 12:fa9b1a459e47 | 421 | |
DasSidG | 11:cf2db05cfa56 | 422 | offset = can_id - 1536; //1536 = 0x600 |
maxv008 | 10:1079f8e52d65 | 423 | first_index = (offset - 1)/4; //offset of 2,3,4 is CMU 1; 6,7,8, is CMU 2; etc. |
DasSidG | 11:cf2db05cfa56 | 424 | second_index = ((offset - 1) % 4) - 1; //Makes it so 0,1,2 represent each voltage set //SID: subtracted 1 to make it work |
DasSidG | 12:fa9b1a459e47 | 425 | |
DasSidG | 12:fa9b1a459e47 | 426 | return true; |
maxv008 | 10:1079f8e52d65 | 427 | } |
maxv008 | 10:1079f8e52d65 | 428 | else |
DasSidG | 12:fa9b1a459e47 | 429 | return false; |
maxv008 | 10:1079f8e52d65 | 430 | } |
maxv008 | 10:1079f8e52d65 | 431 | |
maxv008 | 10:1079f8e52d65 | 432 | void test_CAN_send() |
maxv008 | 10:1079f8e52d65 | 433 | { |
maxv008 | 10:1079f8e52d65 | 434 | CANMessage msg; |
DasSidG | 11:cf2db05cfa56 | 435 | char value = 142; |
maxv008 | 10:1079f8e52d65 | 436 | msg = CANMessage(1, &value,1); |
maxv008 | 10:1079f8e52d65 | 437 | if(can.write(msg)) |
maxv008 | 10:1079f8e52d65 | 438 | printf("Succesfully sent %d \r\n", value); |
maxv008 | 10:1079f8e52d65 | 439 | else |
maxv008 | 10:1079f8e52d65 | 440 | printf("Sending Failed \r\n"); |
maxv008 | 10:1079f8e52d65 | 441 | } |
maxv008 | 10:1079f8e52d65 | 442 | |
maxv008 | 10:1079f8e52d65 | 443 | void test_CAN_read() |
maxv008 | 10:1079f8e52d65 | 444 | { |
maxv008 | 10:1079f8e52d65 | 445 | CANMessage msg; |
maxv008 | 10:1079f8e52d65 | 446 | if(can.read(msg)) |
maxv008 | 10:1079f8e52d65 | 447 | printf("Successfully recieved %d \r\n", msg.data[0]); |
maxv008 | 10:1079f8e52d65 | 448 | else |
maxv008 | 10:1079f8e52d65 | 449 | printf("Reading Failed \r\n"); |
maxv008 | 10:1079f8e52d65 | 450 | } |