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 CUER

main.cpp

Committer:
lcockerton62
Date:
2017-01-16
Revision:
5:793afeef45dc
Parent:
4:9050c5d6925e
Child:
6:b567fcb604aa

File content as of revision 5:793afeef45dc:

#include "mbed.h"
#include "CANParserBMU.h"
#include "Data_Types_BMU.h"
#include "CAN_Data.h"
#include "CAN_IDs.h"
#include "EEPROM_I2C.h"
#include "Temperature.h"
#include "LTC2943_Read.h"

using namespace CAN_IDs;

// Function definitions
void transmit_data(BMU_data measurements,uint32_t status);
void read_temperature_sensors(BMU_data &measurements);
void update_SOC();
void init();
void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address);
uint16_t read_EEPROM_startup(BMU_data &measurements);
uint32_t check_measurements(BMU_data &measurements);
void take_measurements(BMU_data &measurements);

CAN can(CAN_READ_PIN, CAN_WRITE_PIN); //Create a CAN object to handle CAN comms
uint16_t eeprom_start_address; //the initial address where we store/read SoC values

Timeout loop_delay;
bool delay_finished = false;

void loop_delay_callback(void)
{
    delay_finished = true;
}

int main()
{
    BMU_data measurements;
    uint16_t current_EEPROM_address;
    uint32_t status;
    int c = 0;
    init();
    current_EEPROM_address = read_EEPROM_startup(measurements); // Read from the eeprom at startup to fill in the values of SoC
    ltc2943.accumulatedCharge(measurements.percentage_SOC); // Initialise the LTC2943 with the current state of charge
    
    while (true) {

        // Take measurements from the sensors
        take_measurements(measurements);
        // Dont want to read the temperature sensors during each iteration of the loop
        if (c == 0) {
            read_temperature_sensors(measurements);
        } else if(c >= 4) {
            c = -1;
        }
        c++;

        // Check data for errors
        status = check_measurements(measurements);

        // Update the SOC
        update_SOC();

        //Store data in the eeprom
        write_SOC_EEPROM(measurements, current_EEPROM_address);

        // CAN bus
        transmit_data(measurements,status);

        // Conserve power - enter a low powered mode
        delay_finished = false;
        loop_delay.attach(loop_delay_callback, LOOP_DELAY_S);
        while (!delay_finished) sleep();
    }
}

void transmit_data(BMU_data measurements, uint32_t status)
{
    /*
    Place all of the collected data onto the CAN bus
    */
    // Send cell voltages
    for(int i= 0; i < NO_CMUS; i++) {
        createVoltageTelemetry(i + 2 , measurements.cell_voltages[i].first_cell_voltages);
        createVoltageTelemetry(i + 3, measurements.cell_voltages[i].last_cell_voltages);
    }

    // Create SOC CAN message
    createPackSOC(measurements.SOC, measurements.percentage_SOC);

    // Min/max cell voltages
    createCellVoltageMAXMIN(measurements.max_cell_voltage, measurements.min_cell_voltage);

    // Min/Max cell temperature
    createCellTemperatureMAXMIN(measurements.min_cell_temp,measurements.max_cell_temp);

    // Battery voltage and current
    // @TODO add the voltage
    createBatteryVI(measurements.battery_voltage,measurements.battery_current);

    //Extended battery pack status
    createExtendedBatteryPackStatus(status);

}

uint16_t read_EEPROM_startup(BMU_data &measurements)
{
    /* The first page of the EEPROM, specifically the first 2 addresses store a
    pointer of the first memory location of measurement data. The EEPROM only has a finite number of
    read/write cycles which is why we aren't writing to the same location throughout
    */
    
    uint16_t start_address;
    char start_address_array[2];
    char SOC_out[8]; // 4 bytes for the 2 floats one is SOC and the other % charge
    float *fp1,*fp2; // temporary storage for float conversion

    // Get a pointer to the start address for the data stored in the eeprom
    i2c_page_read(0x0000,2,start_address_array);

    // Read the data from this address
    start_address = (start_address_array[1]<< 8) | start_address_array[0]; // mbed little endian follow this convention
    i2c_page_read(start_address, 8,SOC_out);

    // Convert the SOC_out values back into floats
    fp1 = (float*)(&SOC_out[0]);
    fp2 = (float*)(&SOC_out[4]);
    measurements.SOC = *fp1;
    measurements.percentage_SOC = *fp2;

    // Select the next address to write to
    start_address += 0x0040;
    if(start_address > MAX_WRITE_ADDRESS) {
        start_address = START_WRITE_ADDRESS; // Loop to the start of the eeprom
    }

    /*@TODO need to include a CRC check for the address pointer for the scenario 
    when power is removed and we are writing to the eeprom*/
    // write the new address to location 0x0000
    start_address_array[0] = start_address | 0x00FF;
    start_address_array[1] = start_address >> 8;
    i2c_page_write(0x0000, 2, start_address_array);

    return start_address;
}

void write_SOC_EEPROM(BMU_data &measurements,uint16_t start_address)
{
    char data_out[8];
    float *fp1,*fp2;

    fp1 = (float*)(&measurements.SOC);
    fp2 = (float*)(&measurements.percentage_SOC);

    for(int i = 0; i < 4; i++ ) {
        data_out[i] = *fp1;
        fp1++;
    }
    for(int j = 4; j < 7; j++ ) {
        data_out[j] = *fp2;
        fp2++;
    }
    i2c_page_write(start_address, 8,data_out);
}

void read_temperature_sensors(BMU_data &measurements)
{
    float min_temperature;
    float max_temperature;

    probe[0]->convert_temperature(DS1820::all_devices);
    min_temperature = probe[0]->temperature('C');
    max_temperature = min_temperature; // Initially set the max and min temperature equal
    for (int i=1; i<devices_found; i++) {

        measurements.temperature_measurements[i].ID = i;
        measurements.temperature_measurements[i].measurement = probe[i] ->temperature('C');

        if(measurements.temperature_measurements[i].measurement > max_temperature) {
            max_temperature = measurements.temperature_measurements[i].measurement;
        } else if (measurements.temperature_measurements[i].measurement < min_temperature) {
            min_temperature = measurements.temperature_measurements[i].measurement;
        }
    }
    measurements.max_cell_temp.temperature = max_temperature;
    measurements.min_cell_temp.temperature = min_temperature;
}

void update_SOC()
{
    // Update the SOC value
}


uint32_t check_measurements(BMU_data &measurements)
{
    uint32_t status;

    if(measurements.max_cell_voltage.voltage > MAX_CELL_VOLTAGE) {
        status = status | CELL_OVER_VOLTAGE;
    } else if (measurements.min_cell_voltage.voltage < MIN_CELL_VOLTAGE) {
        status = status | CELL_UNDER_VOLTAGE;
    } else if (measurements.max_cell_temp.temperature > MAX_CELL_TEMPERATURE) {
        status = status | CELL_OVER_TEMPERATURE;
    }

    /*
    @TODO also include errors for:
    *untrusted measurement
    *CMU timeout
    *SOC not valid
    */
    return status;
}

void take_measurements(BMU_data &measurements)
{
    // Here collect all measured data from the sensors
    /*
    * TODO Cell voltages
    */
    
    //Current, SoC
    measurements.battery_current = (uint32_t) ltc2943.current()*1000; //*1000 to converet to mA
    measurements.percentage_SOC = ltc2943.accumulatedCharge();
    measurements.SOC = (measurements.percentage_SOC /100) * BATTERY_CAPACITY;
    
}

void init()
{
    temperature_init(); // Initialise the temperature sensors
    LTC2943_initialise(); //Initialises the fixed parameters of the LTC2943
}