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@1:51477fe4851b, 2016-12-30 (annotated)
- Committer:
- lcockerton62
- Date:
- Fri Dec 30 16:01:59 2016 +0000
- Revision:
- 1:51477fe4851b
- Parent:
- 0:0a5f554d2a16
- Child:
- 2:94716229ecc3
Storing SOC in EEPROM, added temperature sensors code, changed some of the data structures, added to CAN messages, added basic error status
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
lcockerton62 | 1:51477fe4851b | 1 | /* |
lcockerton62 | 0:0a5f554d2a16 | 2 | Should also consider the different errors that need to be sent |
lcockerton62 | 0:0a5f554d2a16 | 3 | */ |
lcockerton62 | 0:0a5f554d2a16 | 4 | #include "mbed.h" |
lcockerton62 | 0:0a5f554d2a16 | 5 | #include "CANParserBMU.h" |
lcockerton62 | 0:0a5f554d2a16 | 6 | #include "Data_Types_BMU.h" |
lcockerton62 | 0:0a5f554d2a16 | 7 | #include "CAN_Data.h" |
lcockerton62 | 0:0a5f554d2a16 | 8 | #include "CAN_IDs.h" |
lcockerton62 | 1:51477fe4851b | 9 | #include "EEPROM_I2C.h" |
lcockerton62 | 1:51477fe4851b | 10 | #include "Temperature.h" |
lcockerton62 | 0:0a5f554d2a16 | 11 | |
lcockerton62 | 0:0a5f554d2a16 | 12 | using namespace CAN_IDs; |
lcockerton62 | 0:0a5f554d2a16 | 13 | |
lcockerton62 | 0:0a5f554d2a16 | 14 | // Function definitions |
lcockerton62 | 1:51477fe4851b | 15 | void transmit_data(BMU_data measurements,uint32_t status); |
lcockerton62 | 1:51477fe4851b | 16 | void read_temperature_sensors(BMU_data &measurements); |
lcockerton62 | 0:0a5f554d2a16 | 17 | void update_SOC(); |
lcockerton62 | 0:0a5f554d2a16 | 18 | void init(); |
lcockerton62 | 1:51477fe4851b | 19 | void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address); |
lcockerton62 | 1:51477fe4851b | 20 | uint16_t read_EEPROM_startup(BMU_data &measurements); |
lcockerton62 | 1:51477fe4851b | 21 | uint32_t check_measurements(BMU_data &measurements); |
lcockerton62 | 1:51477fe4851b | 22 | void take_measurements(BMU_data &measurements); |
lcockerton62 | 0:0a5f554d2a16 | 23 | |
lcockerton62 | 0:0a5f554d2a16 | 24 | CAN can(CAN_READ_PIN, CAN_WRITE_PIN); //Create a CAN object to handle CAN comms |
lcockerton62 | 0:0a5f554d2a16 | 25 | |
lcockerton62 | 1:51477fe4851b | 26 | Timeout loop_delay; |
lcockerton62 | 1:51477fe4851b | 27 | bool delay_finished = false; |
lcockerton62 | 1:51477fe4851b | 28 | |
lcockerton62 | 1:51477fe4851b | 29 | void loop_delay_callback(void) { |
lcockerton62 | 1:51477fe4851b | 30 | delay_finished = true; |
lcockerton62 | 1:51477fe4851b | 31 | } |
lcockerton62 | 1:51477fe4851b | 32 | |
lcockerton62 | 0:0a5f554d2a16 | 33 | int main() |
lcockerton62 | 0:0a5f554d2a16 | 34 | { |
lcockerton62 | 1:51477fe4851b | 35 | BMU_data measurements; |
lcockerton62 | 1:51477fe4851b | 36 | uint16_t current_EEPROM_address; |
lcockerton62 | 1:51477fe4851b | 37 | uint32_t status; |
lcockerton62 | 0:0a5f554d2a16 | 38 | int c = 0; |
lcockerton62 | 0:0a5f554d2a16 | 39 | init(); |
lcockerton62 | 1:51477fe4851b | 40 | current_EEPROM_address = read_EEPROM_startup(measurements); |
lcockerton62 | 0:0a5f554d2a16 | 41 | // Read from the eeprom at startup to fill in the values |
lcockerton62 | 1:51477fe4851b | 42 | while (true) { |
lcockerton62 | 1:51477fe4851b | 43 | |
lcockerton62 | 1:51477fe4851b | 44 | // Take measurements from the sensors |
lcockerton62 | 1:51477fe4851b | 45 | take_measurements(measurements); |
lcockerton62 | 0:0a5f554d2a16 | 46 | // Dont want to read the temperature sensors during each iteration of the loop |
lcockerton62 | 1:51477fe4851b | 47 | if (c == 0) { |
lcockerton62 | 1:51477fe4851b | 48 | read_temperature_sensors(measurements); |
lcockerton62 | 1:51477fe4851b | 49 | } else if(c >= 4) { |
lcockerton62 | 0:0a5f554d2a16 | 50 | c = -1; |
lcockerton62 | 0:0a5f554d2a16 | 51 | } |
lcockerton62 | 0:0a5f554d2a16 | 52 | c++; |
lcockerton62 | 0:0a5f554d2a16 | 53 | |
lcockerton62 | 1:51477fe4851b | 54 | // Check data for errors |
lcockerton62 | 1:51477fe4851b | 55 | status = check_measurements(measurements); |
lcockerton62 | 1:51477fe4851b | 56 | |
lcockerton62 | 0:0a5f554d2a16 | 57 | // Update the SOC |
lcockerton62 | 0:0a5f554d2a16 | 58 | update_SOC(); |
lcockerton62 | 0:0a5f554d2a16 | 59 | |
lcockerton62 | 1:51477fe4851b | 60 | //Store data in the eeprom |
lcockerton62 | 1:51477fe4851b | 61 | write_SOC_EEPROM(measurements, current_EEPROM_address); |
lcockerton62 | 0:0a5f554d2a16 | 62 | |
lcockerton62 | 0:0a5f554d2a16 | 63 | // CAN bus transactions |
lcockerton62 | 1:51477fe4851b | 64 | transmit_data(measurements,status); |
lcockerton62 | 0:0a5f554d2a16 | 65 | |
lcockerton62 | 0:0a5f554d2a16 | 66 | // Conserve power - enter a low powered mode |
lcockerton62 | 1:51477fe4851b | 67 | delay_finished = false; |
lcockerton62 | 1:51477fe4851b | 68 | loop_delay.attach(loop_delay_callback, LOOP_DELAY_S); |
lcockerton62 | 1:51477fe4851b | 69 | while (!delay_finished) sleep(); |
lcockerton62 | 0:0a5f554d2a16 | 70 | } |
lcockerton62 | 0:0a5f554d2a16 | 71 | } |
lcockerton62 | 0:0a5f554d2a16 | 72 | |
lcockerton62 | 1:51477fe4851b | 73 | void transmit_data(BMU_data measurements, uint32_t status) |
lcockerton62 | 0:0a5f554d2a16 | 74 | { |
lcockerton62 | 0:0a5f554d2a16 | 75 | /* |
lcockerton62 | 0:0a5f554d2a16 | 76 | Place all of the collected data onto the CAN bus |
lcockerton62 | 0:0a5f554d2a16 | 77 | */ |
lcockerton62 | 1:51477fe4851b | 78 | // Send cell voltaages voltages |
lcockerton62 | 1:51477fe4851b | 79 | for(int i= 0; i < NO_CMUS; i++) { |
lcockerton62 | 1:51477fe4851b | 80 | createVoltageTelemetry(i + 2 , measurements.cell_voltages[i].first_cell_voltages); |
lcockerton62 | 1:51477fe4851b | 81 | createVoltageTelemetry(i + 3, measurements.cell_voltages[i].last_cell_voltages); |
lcockerton62 | 1:51477fe4851b | 82 | } |
lcockerton62 | 1:51477fe4851b | 83 | |
lcockerton62 | 1:51477fe4851b | 84 | // Create SOC CAN message |
lcockerton62 | 1:51477fe4851b | 85 | createPackSOC(measurements.SOC, measurements.percentage_SOC); |
lcockerton62 | 0:0a5f554d2a16 | 86 | |
lcockerton62 | 1:51477fe4851b | 87 | // Min/max cell voltages |
lcockerton62 | 1:51477fe4851b | 88 | createCellVoltageMAXMIN(measurements.max_cell_voltage, measurements.min_cell_voltage); |
lcockerton62 | 1:51477fe4851b | 89 | |
lcockerton62 | 1:51477fe4851b | 90 | // Min/Max cell temperature |
lcockerton62 | 1:51477fe4851b | 91 | createCellTemperatureMAXMIN(measurements.min_cell_temp,measurements.max_cell_temp); |
lcockerton62 | 1:51477fe4851b | 92 | |
lcockerton62 | 1:51477fe4851b | 93 | // Battery voltage and current |
lcockerton62 | 1:51477fe4851b | 94 | // @TODO make add the voltage and current |
lcockerton62 | 1:51477fe4851b | 95 | createBatteryVI(measurements.battery_voltage,measurements.battery_current); |
lcockerton62 | 1:51477fe4851b | 96 | |
lcockerton62 | 1:51477fe4851b | 97 | //Extended battery pack status |
lcockerton62 | 1:51477fe4851b | 98 | createExtendedBatteryPackStatus(status); |
lcockerton62 | 0:0a5f554d2a16 | 99 | |
lcockerton62 | 0:0a5f554d2a16 | 100 | } |
lcockerton62 | 0:0a5f554d2a16 | 101 | |
lcockerton62 | 1:51477fe4851b | 102 | uint16_t read_EEPROM_startup(BMU_data &measurements) |
lcockerton62 | 0:0a5f554d2a16 | 103 | { |
lcockerton62 | 1:51477fe4851b | 104 | /* The first page of the EEPROM, specifically the first 2 addresses store a |
lcockerton62 | 1:51477fe4851b | 105 | pointer of the first memory location of measurement data. The EEPROM only has a finite number of |
lcockerton62 | 1:51477fe4851b | 106 | read/write cycles which is why we aren't writing to the same location throughout |
lcockerton62 | 1:51477fe4851b | 107 | */ |
lcockerton62 | 1:51477fe4851b | 108 | uint16_t start_address; |
lcockerton62 | 1:51477fe4851b | 109 | char start_address_array[2]; |
lcockerton62 | 1:51477fe4851b | 110 | char SOC_out[8]; // 4 bytes for the 2 floats one is SOC and the other % charge |
lcockerton62 | 1:51477fe4851b | 111 | float *fp1,*fp2; // temporary storage for float conversion |
lcockerton62 | 1:51477fe4851b | 112 | |
lcockerton62 | 1:51477fe4851b | 113 | // Get a pointer to the start address for the data stored in the eeprom |
lcockerton62 | 1:51477fe4851b | 114 | i2c_page_read(0x0000,2,start_address_array); |
lcockerton62 | 1:51477fe4851b | 115 | |
lcockerton62 | 1:51477fe4851b | 116 | // Read the data from this address |
lcockerton62 | 1:51477fe4851b | 117 | start_address = (start_address_array[1]<< 8) | start_address_array[0]; // mbed little endian follow this convention |
lcockerton62 | 1:51477fe4851b | 118 | i2c_page_read(start_address, 8,SOC_out); |
lcockerton62 | 0:0a5f554d2a16 | 119 | |
lcockerton62 | 1:51477fe4851b | 120 | // Convert the SOC_out values back into floats |
lcockerton62 | 1:51477fe4851b | 121 | fp1 = (float*)(&SOC_out[0]); |
lcockerton62 | 1:51477fe4851b | 122 | fp2 = (float*)(&SOC_out[4]); |
lcockerton62 | 1:51477fe4851b | 123 | measurements.SOC = *fp1; |
lcockerton62 | 1:51477fe4851b | 124 | measurements.percentage_SOC = *fp2; |
lcockerton62 | 1:51477fe4851b | 125 | |
lcockerton62 | 1:51477fe4851b | 126 | // Select the next address to write to |
lcockerton62 | 1:51477fe4851b | 127 | start_address += 0x0040; |
lcockerton62 | 1:51477fe4851b | 128 | if(start_address > MAX_WRITE_ADDRESS) { |
lcockerton62 | 1:51477fe4851b | 129 | start_address = START_WRITE_ADDRESS; // Loop round to the start of the eeprom |
lcockerton62 | 1:51477fe4851b | 130 | } |
lcockerton62 | 1:51477fe4851b | 131 | |
lcockerton62 | 1:51477fe4851b | 132 | // write the new address to location 0x0000 |
lcockerton62 | 1:51477fe4851b | 133 | start_address_array[0] = start_address | 0x00FF; |
lcockerton62 | 1:51477fe4851b | 134 | start_address_array[1] = start_address >> 8; |
lcockerton62 | 1:51477fe4851b | 135 | i2c_page_write(0x0000, 2, start_address_array); |
lcockerton62 | 1:51477fe4851b | 136 | |
lcockerton62 | 1:51477fe4851b | 137 | return start_address; |
lcockerton62 | 0:0a5f554d2a16 | 138 | } |
lcockerton62 | 0:0a5f554d2a16 | 139 | |
lcockerton62 | 1:51477fe4851b | 140 | void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address) |
lcockerton62 | 0:0a5f554d2a16 | 141 | { |
lcockerton62 | 1:51477fe4851b | 142 | char data_out[8]; |
lcockerton62 | 1:51477fe4851b | 143 | float *fp1,*fp2; |
lcockerton62 | 1:51477fe4851b | 144 | |
lcockerton62 | 1:51477fe4851b | 145 | fp1 = (float*)(&measurements.SOC); |
lcockerton62 | 1:51477fe4851b | 146 | fp2 = (float*)(&measurements.percentage_SOC); |
lcockerton62 | 0:0a5f554d2a16 | 147 | |
lcockerton62 | 1:51477fe4851b | 148 | for(int i = 0; i < 4; i++ ) { |
lcockerton62 | 1:51477fe4851b | 149 | data_out[i] = *fp1; |
lcockerton62 | 1:51477fe4851b | 150 | fp1++; |
lcockerton62 | 1:51477fe4851b | 151 | } |
lcockerton62 | 1:51477fe4851b | 152 | for(int j = 4; j < 7; j++ ) { |
lcockerton62 | 1:51477fe4851b | 153 | data_out[j] = *fp2; |
lcockerton62 | 1:51477fe4851b | 154 | fp2++; |
lcockerton62 | 1:51477fe4851b | 155 | } |
lcockerton62 | 1:51477fe4851b | 156 | i2c_page_write(start_address, 8,data_out); |
lcockerton62 | 0:0a5f554d2a16 | 157 | } |
lcockerton62 | 0:0a5f554d2a16 | 158 | |
lcockerton62 | 1:51477fe4851b | 159 | void read_temperature_sensors(BMU_data &measurements) |
lcockerton62 | 0:0a5f554d2a16 | 160 | { |
lcockerton62 | 1:51477fe4851b | 161 | float min_temperature; |
lcockerton62 | 1:51477fe4851b | 162 | float max_temperature; |
lcockerton62 | 1:51477fe4851b | 163 | |
lcockerton62 | 1:51477fe4851b | 164 | probe[0]->convert_temperature(DS1820::all_devices); |
lcockerton62 | 1:51477fe4851b | 165 | min_temperature = probe[0]->temperature('C'); |
lcockerton62 | 1:51477fe4851b | 166 | max_temperature = min_temperature; // Initially set the max and min temperature equal |
lcockerton62 | 1:51477fe4851b | 167 | for (int i=1; i<devices_found; i++) { |
lcockerton62 | 1:51477fe4851b | 168 | |
lcockerton62 | 1:51477fe4851b | 169 | measurements.temperature_measurements[i].ID = i; |
lcockerton62 | 1:51477fe4851b | 170 | measurements.temperature_measurements[i].measurement = probe[i] ->temperature('C'); |
lcockerton62 | 1:51477fe4851b | 171 | |
lcockerton62 | 1:51477fe4851b | 172 | if(measurements.temperature_measurements[i].measurement > max_temperature) { |
lcockerton62 | 1:51477fe4851b | 173 | max_temperature = measurements.temperature_measurements[i].measurement; |
lcockerton62 | 1:51477fe4851b | 174 | } |
lcockerton62 | 1:51477fe4851b | 175 | else if (measurements.temperature_measurements[i].measurement < min_temperature) { |
lcockerton62 | 1:51477fe4851b | 176 | min_temperature = measurements.temperature_measurements[i].measurement; |
lcockerton62 | 1:51477fe4851b | 177 | } |
lcockerton62 | 1:51477fe4851b | 178 | } |
lcockerton62 | 1:51477fe4851b | 179 | measurements.max_cell_temp.temperature = max_temperature; |
lcockerton62 | 1:51477fe4851b | 180 | measurements.min_cell_temp.temperature = min_temperature; |
lcockerton62 | 0:0a5f554d2a16 | 181 | } |
lcockerton62 | 0:0a5f554d2a16 | 182 | |
lcockerton62 | 0:0a5f554d2a16 | 183 | void update_SOC() |
lcockerton62 | 0:0a5f554d2a16 | 184 | { |
lcockerton62 | 1:51477fe4851b | 185 | // Update the SOC value |
lcockerton62 | 0:0a5f554d2a16 | 186 | } |
lcockerton62 | 0:0a5f554d2a16 | 187 | |
lcockerton62 | 0:0a5f554d2a16 | 188 | |
lcockerton62 | 1:51477fe4851b | 189 | uint32_t check_measurements(BMU_data &measurements) |
lcockerton62 | 1:51477fe4851b | 190 | { |
lcockerton62 | 1:51477fe4851b | 191 | uint32_t status; |
lcockerton62 | 1:51477fe4851b | 192 | |
lcockerton62 | 1:51477fe4851b | 193 | if(measurements.max_cell_voltage.voltage > MAX_CELL_VOLTAGE) |
lcockerton62 | 1:51477fe4851b | 194 | { |
lcockerton62 | 1:51477fe4851b | 195 | status = status | CELL_OVER_VOLTAGE; |
lcockerton62 | 1:51477fe4851b | 196 | } |
lcockerton62 | 1:51477fe4851b | 197 | else if (measurements.min_cell_voltage.voltage < MIN_CELL_VOLTAGE) |
lcockerton62 | 1:51477fe4851b | 198 | { |
lcockerton62 | 1:51477fe4851b | 199 | status = status | CELL_UNDER_VOLTAGE; |
lcockerton62 | 1:51477fe4851b | 200 | } |
lcockerton62 | 1:51477fe4851b | 201 | else if (measurements.max_cell_temp.temperature > MAX_CELL_TEMPERATURE) |
lcockerton62 | 1:51477fe4851b | 202 | { |
lcockerton62 | 1:51477fe4851b | 203 | status = status | CELL_OVER_TEMPERATURE; |
lcockerton62 | 1:51477fe4851b | 204 | } |
lcockerton62 | 1:51477fe4851b | 205 | |
lcockerton62 | 1:51477fe4851b | 206 | /* |
lcockerton62 | 1:51477fe4851b | 207 | @TODO also include errors for: |
lcockerton62 | 1:51477fe4851b | 208 | *untrusted measurement |
lcockerton62 | 1:51477fe4851b | 209 | *CMU timeout |
lcockerton62 | 1:51477fe4851b | 210 | *SOC not valid |
lcockerton62 | 1:51477fe4851b | 211 | */ |
lcockerton62 | 1:51477fe4851b | 212 | return status; |
lcockerton62 | 1:51477fe4851b | 213 | } |
lcockerton62 | 1:51477fe4851b | 214 | |
lcockerton62 | 1:51477fe4851b | 215 | void take_measurements(BMU_data &measurements) |
lcockerton62 | 1:51477fe4851b | 216 | { |
lcockerton62 | 1:51477fe4851b | 217 | // Here collect all measured data from the sensors |
lcockerton62 | 1:51477fe4851b | 218 | /* |
lcockerton62 | 1:51477fe4851b | 219 | TODO SOC and cell voltages |
lcockerton62 | 1:51477fe4851b | 220 | */ |
lcockerton62 | 1:51477fe4851b | 221 | } |
lcockerton62 | 1:51477fe4851b | 222 | |
lcockerton62 | 0:0a5f554d2a16 | 223 | void init() |
lcockerton62 | 0:0a5f554d2a16 | 224 | { |
lcockerton62 | 1:51477fe4851b | 225 | temperature_init(); // Initialise the temperature sensors |
lcockerton62 | 0:0a5f554d2a16 | 226 | } |
lcockerton62 | 0:0a5f554d2a16 | 227 |