KIT Solar Car Project / Mbed 2 deprecated BMS_6804_pb

Dependencies:   mbed INA226

main.cpp

Committer:
takuma1
Date:
2019-10-26
Revision:
2:f6f76dde7e1d
Parent:
0:f06ed53310a3
Child:
3:a1368cd4b0a9

File content as of revision 2:f6f76dde7e1d:


#include "mbed.h"
#include "bms.h"
#include "LTC681x.h"
#include "LTC6811.h"

#define UI_BUFFER_SIZE 64
#define SERIAL_TERMINATOR '\n'

#define ENABLED 1
#define DISABLED 0

#define DATALOG_ENABLED 1
#define DATALOG_DISABLED 0

Ticker ticker;
DigitalOut led1(LED1);
Serial pc(USBTX, USBRX);
CAN BMS_CAN(p9,p10);


void run_command(uint32_t cmd);
void measurement_loop(uint8_t datalog_en);
//void print_menu();
void print_cells(uint8_t datalog_en);
void print_open();
void print_aux(uint8_t datalog_en);
void print_stat();
void print_config();
void print_rxconfig();
void print_pec(void);
void serial_print_hex(uint8_t data);
void check_error(int error);
void wakeup();
void cell_read();
void spi_error();

//char get_char();
//void read_config_data(uint8_t cfg_data[][6], uint8_t nIC);

/**********************************************************
  Setup Variables
  The following variables can be modified to
  configure the software.

***********************************************************/
const uint8_t TOTAL_IC = 1;//!<number of ICs in the daisy chain
char ui_buffer[UI_BUFFER_SIZE];


//ADC Command Configurations
//const uint8_t ADC_OPT = ADC_OPT_DISABLED; // See LTC6811_daisy.h for Options
const uint8_t ADC_CONVERSION_MODE = MD_7KHZ_3KHZ;//MD_7KHZ_3KHZ; //MD_26HZ_2KHZ;//MD_7KHZ_3KHZ; // See LTC6811_daisy.h for Options
const uint8_t ADC_DCP = DCP_DISABLED; // See LTC6811_daisy.h for Options
const uint8_t CELL_CH_TO_CONVERT = CELL_CH_ALL; // See LTC6811_daisy.h for Options
const uint8_t AUX_CH_TO_CONVERT = AUX_CH_ALL; // See LTC6811_daisy.h for Options
const uint8_t STAT_CH_TO_CONVERT = STAT_CH_ALL; // See LTC6811_daisy.h for Options

const uint16_t MEASUREMENT_LOOP_TIME = 500;//milliseconds(mS)

//Under Voltage and Over Voltage Thresholds
const uint16_t OV_THRESHOLD = 41000; //
const uint16_t UV_THRESHOLD = 30000; // 

//Loop Measurement Setup These Variables are ENABLED or DISABLED Remember ALL CAPS
const uint8_t WRITE_CONFIG = DISABLED; // This is ENABLED or DISABLED
const uint8_t READ_CONFIG = DISABLED; // This is ENABLED or DISABLED
const uint8_t MEASURE_CELL = ENABLED; // This is ENABLED or DISABLED
const uint8_t MEASURE_AUX = DISABLED; // This is ENABLED or DISABLED
const uint8_t MEASURE_STAT = DISABLED; //This is ENABLED or DISABLED
const uint8_t PRINT_PEC = DISABLED; //This is ENABLED or DISABLED


// Read data from the serial interface into the ui_buffer buffer
uint8_t read_data();

// Read a float value from the serial interface
float read_float();

// Read an integer from the serial interface.
// The routine can recognize Hex, Decimal, Octal, or Binary
// Example:
// Hex:     0x11 (0x prefix)
// Decimal: 17
// Octal:   O21 (leading letter O prefix)
// Binary:  B10001 (leading letter B prefix)
int32_t read_int();
int kaisuu;
// Read a string from the serial interface.  Returns a pointer to the ui_buffer.
char *read_string();

// Read a character from the serial interface
int8_t read_char();

/************************************
  END SETUP
*************************************/

/******************************************************
 *** Global Battery Variables received from 681x commands
 These variables store the results from the LTC6811
 register reads and the array lengths must be based
 on the number of ICs on the stack
 ******************************************************/

cell_asic bms_ic[TOTAL_IC];

/*!*********************************************************************
  \brief main loop
***********************************************************************/
int main(void)
{
    uint32_t user_command;
    
    pc.baud(115200);
    spi_enable();
    LTC681x_init_cfg(TOTAL_IC, bms_ic);
    LTC6811_reset_crc_count(TOTAL_IC,bms_ic);
    LTC6811_init_reg_limits(TOTAL_IC,bms_ic);
    wakeup();
    //print_menu();
   

    while(1) {
      
        spi_error();
        //pc.printf("check 00\n");
        //while(!pc.readable()) {
        wait(0.3);
        //    pc.printf("check 001\n");
        //}         // Check for user input
        //pc.printf("check 01\n");
        user_command = read_int();     
        run_command(user_command);
        
    }
}

void wakeup(){
    int countup;
    int8_t error = 0;
    uint32_t conv_time = 0;
    
    
    wakeup_sleep(TOTAL_IC);
            LTC6811_wrcfg(TOTAL_IC,bms_ic);
            print_config();
                 
                 wait(0.05);
                 
     wakeup_sleep(TOTAL_IC);
            error = LTC6811_rdcfg(TOTAL_IC,bms_ic);
            check_error(error);
            print_rxconfig(); 
                 wait(0.05);
                 
     wakeup_sleep(TOTAL_IC);
            LTC6811_adcv(ADC_CONVERSION_MODE,ADC_DCP,CELL_CH_TO_CONVERT);
            conv_time = LTC6811_pollAdc();
            pc.printf("cell conversion completed in:");
            pc.printf("%.1f",((float)conv_time/1000));
            pc.printf("mS\n"); 
            
            
    }
    
    
void spi_error(){
            
            int8_t error = 0;
            int countup;
            
            if(error = -1 ){
            for(countup = 0; countup <= 100; countup++){
             wakeup();
             if(error = 1){
                 break;
                           }
                                                        }                                       
                          }
             if(error = 1){
             cell_read();
                          }
             
                 }
    
/*!*****************************************
  \brief executes the user command
*******************************************/

void run_command(uint32_t cmd)
{
    int8_t error = 0;
    uint32_t conv_time = 0;
//    uint32_t user_command;
    int8_t readIC=0;
    char input = 0;
    
    cell_read();
   
    
    switch (cmd) {


        case 3: // Start GPIO ADC Measurement
            wakeup_sleep(TOTAL_IC);
            LTC6811_adax(ADC_CONVERSION_MODE , AUX_CH_TO_CONVERT);
            LTC6811_pollAdc();
            pc.printf("aux conversion completed\n");
            pc.printf("\n");
            break;

        case 4: // Read AUX Voltage Registers
            wakeup_sleep(TOTAL_IC);
            error = LTC6811_rdaux(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
            check_error(error);
            print_aux(DATALOG_DISABLED);
            break;

        case 5: // Start Status ADC Measurement
            wakeup_sleep(TOTAL_IC);
            LTC6811_adstat(ADC_CONVERSION_MODE, STAT_CH_TO_CONVERT);
            LTC6811_pollAdc();
            pc.printf("stat conversion completed\n");
            pc.printf("\n");
            break;

        case 6: // Read Status registers
            wakeup_sleep(TOTAL_IC);
            error = LTC6811_rdstat(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
            check_error(error);
            print_stat();
            break;

        case 7: // Loop Measurements
            pc.printf("transmit 'm' to quit\n");
            wakeup_sleep(TOTAL_IC);
            LTC6811_wrcfg(TOTAL_IC,bms_ic);
            while (input != 'm') {
                //if (pc.readable()) {
                    input = read_char();
                //}

                measurement_loop(DATALOG_DISABLED);

                wait_ms(MEASUREMENT_LOOP_TIME);
            }
            //print_menu();
            break;

        case 8: // Run open wire self test
            print_pec();

            break;

        case 9: // Read in raw configuration data
            LTC6811_reset_crc_count(TOTAL_IC,bms_ic);
            break;

        case 10:  // Run the ADC/Memory Self Test
            wakeup_sleep(TOTAL_IC);
            error = LTC6811_run_cell_adc_st(CELL,ADC_CONVERSION_MODE,bms_ic);
            pc.printf("%d", error);
            pc.printf(" : errors detected in Digital Filter and CELL Memory\n");

            wakeup_sleep(TOTAL_IC);
            error = LTC6811_run_cell_adc_st(AUX,ADC_CONVERSION_MODE, bms_ic);
            pc.printf("%d",error);
            pc.printf(" : errors detected in Digital Filter and AUX Memory\n");

            wakeup_sleep(TOTAL_IC);
            error = LTC6811_run_cell_adc_st(STAT,ADC_CONVERSION_MODE, bms_ic);
            pc.printf("%d",error);
            pc.printf(" : errors detected in Digital Filter and STAT Memory\n");
            //print_menu();
            break;

        case 11: // Enable a discharge transistor
            pc.printf("Please enter the Spin number\n");
            readIC = (int8_t)read_int();
            LTC6811_set_discharge(readIC,TOTAL_IC,bms_ic);
            wakeup_sleep(TOTAL_IC);
            LTC6811_wrcfg(TOTAL_IC,bms_ic);
            print_config();
            break;

        case 12: // Clear all discharge transistors
            clear_discharge(TOTAL_IC,bms_ic);
            wakeup_sleep(TOTAL_IC);
            LTC6811_wrcfg(TOTAL_IC,bms_ic);
            print_config();
            break;

        case 13: // Clear all ADC measurement registers
            wakeup_sleep(TOTAL_IC);
            LTC6811_clrcell();
            LTC6811_clraux();
            LTC6811_clrstat();
            pc.printf("All Registers Cleared\n");
            break;

        case 14: // Run the Mux Decoder Self Test
            wakeup_sleep(TOTAL_IC);
            LTC6811_diagn();
            wait_ms(5);
            error = LTC6811_rdstat(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
            check_error(error);
            error = 0;
            for (int ic = 0;
                    ic<TOTAL_IC;
                    ic++) {
                if (bms_ic[ic].stat.mux_fail[0] != 0) error++;
            }
            if (error==0) pc.printf("Mux Test: PASS\n");
            else pc.printf("Mux Test: FAIL\n");

            break;

        case 15: // Run ADC Overlap self test
            wakeup_sleep(TOTAL_IC);
            error = (int8_t)LTC6811_run_adc_overlap(TOTAL_IC,bms_ic);
            if (error==0) pc.printf("Overlap Test: PASS\n");
            else pc.printf("Overlap Test: FAIL\n");
            break;

        case 16: // Run ADC Redundancy self test
            wakeup_sleep(TOTAL_IC);
            error = LTC6811_run_adc_redundancy_st(ADC_CONVERSION_MODE,AUX,TOTAL_IC, bms_ic);
            pc.printf("%d",error);
            pc.printf(" : errors detected in AUX Measurement\n");

            wakeup_sleep(TOTAL_IC);
            error = LTC6811_run_adc_redundancy_st(ADC_CONVERSION_MODE,STAT,TOTAL_IC, bms_ic);
            pc.printf("%d",error);
            pc.printf(" : errors detected in STAT Measurement\n");
            break;

        case 17:
            LTC6811_run_openwire(TOTAL_IC, bms_ic);
            print_open();
            break;

        case 18: //Datalog print option Loop Measurements
            pc.printf("transmit 'm' to quit\n");
            wakeup_sleep(TOTAL_IC);
            LTC6811_wrcfg(TOTAL_IC,bms_ic);
            while (input != 'm') {
                //if (pc.readable()) {
                    input = read_char();
                //}

                measurement_loop(DATALOG_ENABLED);

                wait_ms(MEASUREMENT_LOOP_TIME);
            }
            //print_menu();
            break;

        case 'm': //prints menu
            //print_menu();
            break;

        default:
            pc.printf("Incorrect Option\n");
            break;
            }
    }
void cell_read(){
    
    int8_t error = 0;
    uint32_t conv_time = 0;

    int8_t readIC=0;
         wakeup_sleep(TOTAL_IC);
            error = LTC6811_rdcv(0, TOTAL_IC,bms_ic); // Set to read back all cell voltage registers
            check_error(error);
            print_cells(DATALOG_DISABLED);
        
        }


void measurement_loop(uint8_t datalog_en)
{
    int8_t error = 0;
    if (WRITE_CONFIG == ENABLED) {
        wakeup_sleep(TOTAL_IC);
        LTC6811_wrcfg(TOTAL_IC,bms_ic);
        print_config();
    }

    if (READ_CONFIG == ENABLED) {
        wakeup_sleep(TOTAL_IC);
        error = LTC6811_rdcfg(TOTAL_IC,bms_ic);
        check_error(error);
        print_rxconfig();
    }

    if (MEASURE_CELL == ENABLED) {
        wakeup_idle(TOTAL_IC);
        LTC6811_adcv(ADC_CONVERSION_MODE,ADC_DCP,CELL_CH_TO_CONVERT);
        LTC6811_pollAdc();
        wakeup_idle(TOTAL_IC);
        error = LTC6811_rdcv(0, TOTAL_IC,bms_ic);
        check_error(error);
        print_cells(datalog_en);

    }

    if (MEASURE_AUX == ENABLED) {
        wakeup_idle(TOTAL_IC);
        LTC6811_adax(ADC_CONVERSION_MODE , AUX_CH_ALL);
        LTC6811_pollAdc();
        wakeup_idle(TOTAL_IC);
        error = LTC6811_rdaux(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
        check_error(error);
        print_aux(datalog_en);
    }

    if (MEASURE_STAT == ENABLED) {
        wakeup_idle(TOTAL_IC);
        LTC6811_adstat(ADC_CONVERSION_MODE, STAT_CH_ALL);
        LTC6811_pollAdc();
        wakeup_idle(TOTAL_IC);
        error = LTC6811_rdstat(0,TOTAL_IC,bms_ic); // Set to read back all aux registers
        check_error(error);
        print_stat();
    }

    if (PRINT_PEC == ENABLED) {
        print_pec();
    }

}


/*!*********************************
  \brief Prints the main menu
***********************************/
/*
void print_menu()
{
    pc.printf("Please enter LTC6811 Command\n");
    pc.printf("Write Configuration: 1            | Reset PEC Counter: 11\n");
    pc.printf("Read Configuration: 2             | Run ADC Self Test: 12\n");
    pc.printf("Start Cell Voltage Conversion: 3  | Set Discharge: 13\n");
    pc.printf("Read Cell Voltages: 4             | Clear Discharge: 14\n");
    pc.printf("Start Aux Voltage Conversion: 5   | Clear Registers: 15\n");
    pc.printf("Read Aux Voltages: 6              | Run Mux Self Test: 16\n");
    pc.printf("Start Stat Voltage Conversion: 7  | Run ADC overlap Test: 17\n");
    pc.printf("Read Stat Voltages: 8             | Run Digital Redundancy Test: 18\n");
    pc.printf("loop Measurements: 9              | Run Open Wire Test: 19\n");
    pc.printf("Read PEC Errors: 10               |  Loop measurements with datalog output: 20\n");
    pc.printf("\n");
    pc.printf("Please enter command:\n");
    pc.printf("\n");
}
*/
/*!************************************************************
  \brief Prints cell voltage codes to the serial port
 *************************************************************/
void print_cells(uint8_t datalog_en)
{
    for (int current_ic = 0 ; current_ic < TOTAL_IC; current_ic++) {

        if (datalog_en == 0) {
            pc.printf("IC%d, ", current_ic+1);
            for (int i=0; i<bms_ic[0].ic_reg.cell_channels; i++) {
                pc.printf("C%d:", i+1);
                pc.printf("%.4f, ", bms_ic[current_ic].cells.c_codes[i]*0.0001);
            }
            pc.printf("\n");
        } else {
            pc.printf("Cells, ");
            for (int i=0; i<bms_ic[0].ic_reg.cell_channels; i++) {
                pc.printf("%.4f, ",bms_ic[current_ic].cells.c_codes[i]*0.0001);
            }
        }

    }
    pc.printf("\n");
}

/*!****************************************************************************
  \brief Prints Open wire test results to the serial port
 *****************************************************************************/
void print_open()
{
    for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++) {
        if (bms_ic[current_ic].system_open_wire == 0) {
            pc.printf("No Opens Detected on IC%d\n", current_ic+1);
        } else {
            for (int cell=0; cell<bms_ic[0].ic_reg.cell_channels+1; cell++) {
                if ((bms_ic[current_ic].system_open_wire &(1<<cell))>0) {
                    pc.printf("There is an open wire on IC%d Channel: %d\n", current_ic + 1, cell);
                }
            }
        }
    }
}

/*!****************************************************************************
  \brief Prints GPIO voltage codes and Vref2 voltage code onto the serial port
 *****************************************************************************/
void print_aux(uint8_t datalog_en)
{

    for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++) {
        if (datalog_en == 0) {
            pc.printf(" IC%d", current_ic+1);
            for (int i=0; i < 5; i++) {
                pc.printf(" GPIO-%d:%.4f,", i+1, bms_ic[current_ic].aux.a_codes[i]*0.0001);
            }
            pc.printf("Vref2:%.4f\n", bms_ic[current_ic].aux.a_codes[5]*0.0001);
        } else {
            pc.printf("AUX, ");
            for (int i=0; i < 6; i++) {
                pc.printf("%.4f,", bms_ic[current_ic].aux.a_codes[i]*0.0001);
            }
        }
    }
    pc.printf("\n");
}

/*!****************************************************************************
  \brief Prints Status voltage codes and Vref2 voltage code onto the serial port
 *****************************************************************************/
void print_stat()
{

    for (int current_ic =0 ; current_ic < TOTAL_IC; current_ic++) {
        pc.printf("IC%d", current_ic+1);
        pc.printf(" SOC:%.4f,", bms_ic[current_ic].stat.stat_codes[0]*0.0001*20);
        pc.printf(" Itemp:%.4f,", bms_ic[current_ic].stat.stat_codes[1]*0.0001);
        pc.printf(" VregA:%.4f,", bms_ic[current_ic].stat.stat_codes[2]*0.0001);
        pc.printf(" VregD:%.4f\n", bms_ic[current_ic].stat.stat_codes[3]*0.0001);
    }

    pc.printf("\n");
}

/*!******************************************************************************
 \brief Prints the configuration data that is going to be written to the LTC6811
 to the serial port.
 ********************************************************************************/
void print_config()
{
    int cfg_pec;

    pc.printf("Written Configuration: \n");
    for (int current_ic = 0; current_ic<TOTAL_IC; current_ic++) {
        pc.printf(" IC ");
        pc.printf("%d", current_ic+1);
        pc.printf(": ");
        pc.printf("0x");
        serial_print_hex(bms_ic[current_ic].config.tx_data[0]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.tx_data[1]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.tx_data[2]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.tx_data[3]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.tx_data[4]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.tx_data[5]);
        pc.printf(", Calculated PEC: 0x");
        cfg_pec = pec15_calc(6,&bms_ic[current_ic].config.tx_data[0]);
        serial_print_hex((uint8_t)(cfg_pec>>8));
        pc.printf(", 0x");
        serial_print_hex((uint8_t)(cfg_pec));
        pc.printf("\n");
    }
    pc.printf("\n");
}

/*!*****************************************************************
 \brief Prints the configuration data that was read back from the
 LTC6811 to the serial port.
 *******************************************************************/
void print_rxconfig()
{
    pc.printf("Received Configuration ");
    for (int current_ic=0; current_ic<TOTAL_IC; current_ic++) {
        pc.printf(" IC ");
        pc.printf("%d", current_ic+1);
        pc.printf(": 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[0]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[1]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[2]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[3]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[4]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[5]);
        pc.printf(", Received PEC: 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[6]);
        pc.printf(", 0x");
        serial_print_hex(bms_ic[current_ic].config.rx_data[7]);
        pc.printf("\n");
    }
    pc.printf("\n");
}

void print_pec()
{
    for (int current_ic=0; current_ic<TOTAL_IC; current_ic++) {
        pc.printf("\n%d", bms_ic[current_ic].crc_count.pec_count);
        pc.printf(" : PEC Errors Detected on IC");
        pc.printf("%d\n", current_ic+1);
    }
}


void serial_print_hex(uint8_t data)
{
    if (data < 16) {
        pc.printf("0x0%X", data);
    } else
        pc.printf("0x%X", data);
}

//Function to check error flag and print PEC error message
void check_error(int error)
{
    if (error == -1) {
        pc.printf("A PEC error was detected in the received data");
    }
}


// hex conversion constants
char hex_digits[16]= {
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

// global variables

char hex_to_byte_buffer[5]= {
    '0', 'x', '0', '0', '\0'
};               // buffer for ASCII hex to byte conversion
char byte_to_hex_buffer[3]= {
    '\0','\0','\0'
};

// シリアル インターフェイスから ui_バッファへのデータの読み取り
uint8_t read_data()
{
    uint8_t index = 0; // 内の現在の場所を保持するインデックス
    int c; // 着信キーストロークの格納に使用される単一の文字
    //pc.printf("check 1\n");
    while (index < UI_BUFFER_SIZE-1) {
        //pc.printf("check 2\n");
        c = pc.getc(); //read one character
        //return c;
        //pc.printf("check 3\n");
        
        if (((char) c == '\r') || ((char) c == '\n')) break; // キャリッジ リターンまたはラインフィードの場合は、データを停止して返します。
        if ( ((char) c == '\x7F') || ((char) c == '\x08') ) { // remove previous character (decrement index) if Backspace/Delete key pressed      index--;
            if (index > 0) index--;
        } else if (c >= 0) {
            ui_buffer[index++]=(char) c; // put character into ui_buffer
        }
        //pc.printf("check 4\n");
        
    }
    ui_buffer[index]='\0';  // terminate string with NULL

    if ((char) c == '\r') {  // if the "last" character was a carriage return, also clear linefeed if it is next character
        wait_ms(1);
        //pc.printf("check 5\n");
        
        if (pc.readable()==1) {
            //pc.printf("check 6\n");
            pc.getc(); // if linefeed appears, read it and throw it away
        }
        //pc.printf("check 7\n");
        
    }
    //pc.printf("check 8\n");
        
    return index; // return number of characters, not including null terminator
}

// Read a float value from the serial interface
float read_float()
{
    float data;
    read_data();
    data = atof(ui_buffer);
    return(data);
}

// Read an integer from the serial interface.
// The routine can recognize Hex, Decimal, Octal, or Binary
// Example:
// Hex:     0x11 (0x prefix)
// Decimal: 17
// Octal:   021 (leading zero prefix)
// Binary:  B10001 (leading B prefix)
int32_t read_int()
{
    int32_t data;
    read_data();
    if (ui_buffer[0] == 'm')
        return('m');
    if ((ui_buffer[0] == 'B') || (ui_buffer[0] == 'b')) {
        data = strtol(ui_buffer+1, NULL, 2);
    } else
        data = strtol(ui_buffer, NULL, 0);
    return(data);
}

// Read a string from the serial interface.  Returns a pointer to the ui_buffer.
char *read_string()
{
    read_data();
    return(ui_buffer);
}

// Read a character from the serial interface
int8_t read_char()
{
    read_data();
    return(ui_buffer[0]);
}