req

Dependents:   BMS_BMUCore_Max_DummyData BMS_BMUCore_Max

Fork of LTC6804 by Max Vigdorchik

Revision:
5:324a19dcfdec
Child:
6:47ffbe9ee110
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPI_Parser.cpp	Sun Jul 23 10:33:23 2017 +0000
@@ -0,0 +1,428 @@
+#include "SPI_Parser.h"
+
+//Define SPI and I2C I/O pins
+SPI spi(p5, p6, p7); // mosi, miso, sclk
+DigitalOut chipSelect(p8);
+
+uint8_t ADCV[2];
+uint8_t ADAX[2];
+
+//I2C i2c(p9, p10); This line gives conflicting definition errors
+
+
+void wake_LTC6804()
+{
+    spi.format(8,3);//All data transfer on LTC6804 occur in byte groups. LTC6820 set up such that POL=1 and PHA=3, this corresponds to mode 3 in mbed library. spi.frequency(spiBitrate);
+    spi.frequency(spiBitrate);
+    chipSelect=0;
+    wait_us(70);
+    spi.write(0x00); //Ensures isoSPI is in ready mode
+    wait_us(30);
+    chipSelect=1;
+}
+
+void wake_SPI()
+{
+    chipSelect=0;
+    wait(0.000025);
+    chipSelect=1;
+}
+
+void LTC6804_init(uint8_t mode, uint8_t balancingEn, uint8_t cellCh, uint8_t gpioCh)
+{
+    uint8_t bitSetter;
+
+    bitSetter = (mode & 0x02) >> 1;
+    ADCV[0] = bitSetter + 0x02;
+    bitSetter = (mode & 0x01) << 7;
+    ADCV[1] =  bitSetter + 0x60 + (balancingEn<<4) + cellCh;
+
+    bitSetter = (mode & 0x02) >> 1;
+    ADAX[0] = bitSetter + 0x04;
+    bitSetter = (mode & 0x01) << 7;
+    ADAX[1] = bitSetter + 0x60 + gpioCh;
+}
+
+void LTC6804_acquireVoltageTx()
+{
+    uint8_t broadcastCmd[4];
+    uint16_t pec;
+
+    broadcastCmd[0]=ADCV[0];
+    broadcastCmd[1]=ADCV[1];
+
+    pec=pec15_calc(2, ADCV);
+    broadcastCmd[2] = (uint8_t)(pec>>8);
+    broadcastCmd[3] = (uint8_t)(pec);
+
+    wake_SPI();
+    //chipSelect=1;
+    chipSelect=0; //select LTC6820 by driving pin low
+    spi_write_array(4, broadcastCmd);
+    chipSelect=1; //de-select LTC6820 by driving pin high
+}
+
+uint8_t LTC6804_acquireAllVoltageRegRx(uint8_t reg, uint8_t cmuCount, uint16_t cell_codes[][12])
+{
+    //rdcv
+    const uint8_t NUM_RX_BYT = 8;
+    const uint8_t BYT_IN_REG = 6;
+    const uint8_t CELL_IN_REG = 3;
+
+    uint8_t *cell_data;
+    int8_t pec_error = 0;
+    uint16_t parsed_cell;
+    uint16_t received_pec;
+    uint16_t data_pec;
+    uint8_t data_counter = 0;
+    cell_data = (uint8_t *)malloc((NUM_RX_BYT*cmuCount) * sizeof(uint8_t));
+
+    if (reg == 0) {
+        for (uint8_t cell_reg = 1; cell_reg < 5; cell_reg++) {
+            data_counter = 0;
+            LTC6804_acquireSingleVoltageRegRx(cell_reg, cmuCount, cell_data);
+            for (uint8_t current_cmu = 0; current_cmu < cmuCount; current_cmu++) {
+                for (uint8_t current_cell = 0; current_cell < CELL_IN_REG; current_cell++) {
+                    parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);
+                    cell_codes[current_cmu][current_cell + ((cell_reg - 1)*CELL_IN_REG)] = parsed_cell;
+                    data_counter = data_counter + 2;
+                }
+                received_pec = (cell_data[data_counter] << 8) + cell_data[data_counter + 1];
+                data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_cmu*NUM_RX_BYT]);
+                if (received_pec != data_pec) {
+                    cout << " PEC ERROR " << endl;
+                    pec_error--;//pec_error=-1;
+                }
+                data_counter = data_counter + 2;
+            }
+        }
+    }
+
+    else {
+        LTC6804_acquireSingleVoltageRegRx(reg, cmuCount, cell_data);
+        for (uint8_t current_cmu = 0; current_cmu < cmuCount; current_cmu++) {
+            for (uint8_t current_cell = 0; current_cell < CELL_IN_REG; current_cell++) {
+                parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);
+                cell_codes[current_cmu][current_cell + ((reg - 1)*CELL_IN_REG)] = 0X0000FFFF & parsed_cell;
+                data_counter = data_counter + 2;
+            }
+            received_pec = (cell_data[data_counter] << 8) + cell_data[data_counter + 1];
+            data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_cmu*NUM_RX_BYT*(reg - 1)]);
+            if (received_pec != data_pec) {
+                cout << " PEC ERROR " << endl;
+                pec_error--;//pec+error=-1;
+            }
+        }
+    }
+    free(cell_data);
+    return(pec_error);
+}
+
+void LTC6804_acquireSingleVoltageRegRx(uint8_t reg, uint8_t cmuCount, uint8_t *data)
+{
+    //rdcv_reg
+    uint8_t cmd[4];
+    uint16_t temporary_pec;
+
+    if (reg == 1) {
+        cmd[1] = 0x04;
+        cmd[0] = 0x00;
+    } else if (reg == 2) {
+        cmd[1] = 0x06;
+        cmd[0] = 0x00;
+    } else if (reg == 3) {
+        cmd[1] = 0x08;
+        cmd[0] = 0x00;
+    } else if (reg == 4) {
+        cmd[1] = 0x0A;
+        cmd[0] = 0x00;
+    }
+
+    wake_SPI();
+
+    for (int current_cmu = 0; current_cmu < cmuCount; current_cmu++) {
+        cmd[0] = 0x80 + (current_cmu << 3);//setting address
+        temporary_pec = pec15_calc(2, cmd);
+        cmd[2] = (uint8_t)(temporary_pec >> 8);
+        cmd[3] = (uint8_t)(temporary_pec);
+        chipSelect = 0;
+        spi_write_read(cmd,4,&data[current_cmu*8],8);
+        chipSelect = 1;
+    }
+}
+
+void LTC6804_setConfigReg(uint8_t cmuCount, uint8_t config[][6])
+{
+    const uint8_t BYTES_IN_REG = 6;
+    const uint8_t CMD_LEN = 4 + (8 * cmuCount);
+    uint8_t *cmd;
+    uint16_t temporary_pec;
+    uint8_t cmd_index;
+
+    cmd = (uint8_t *)malloc(CMD_LEN * sizeof(uint8_t));
+
+    cmd[0] = 0x00;
+    cmd[1] = 0x01;
+    cmd[2] = 0x3d;
+    cmd[3] = 0x6e;
+
+    cmd_index = 4;
+    for (int8_t current_cmu = cmuCount; current_cmu > 0; current_cmu--) {
+        for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
+            cmd[cmd_index] = config[current_cmu - 1][current_byte];
+            cmd_index = cmd_index + 1;
+        }
+        temporary_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &config[current_cmu - 1][0]);
+        cmd[cmd_index] = (uint8_t)(temporary_pec >> 8);
+        cmd[cmd_index + 1] = (uint8_t)temporary_pec;
+        cmd_index = cmd_index + 2;
+    }
+
+    //wake_SPI();
+    for (int current_cmu = 0; current_cmu < cmuCount; current_cmu++) {
+        cmd[0] = 0x80 + (current_cmu << 3);
+        temporary_pec = pec15_calc(2, cmd);
+        cmd[2] = (uint8_t)(temporary_pec >> 8);
+        cmd[3] = (uint8_t)(temporary_pec);
+        chipSelect = 0;
+        wait_us(350);
+        spi_write_array(4, cmd);
+        spi_write_array(8,&cmd[4+(8*current_cmu)]);
+        chipSelect=1;
+    }
+    free(cmd);
+}
+
+
+uint16_t pec15_calc(uint8_t len, uint8_t *data)
+{
+    uint16_t remainder,addr;
+
+    remainder = 16;//initialize the PEC
+    for(uint8_t i = 0; i<len; i++) { // loops for each byte in data array
+        addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
+        remainder = (remainder<<8)^crc15Table[addr];
+    }
+    return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
+}
+
+
+void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
+                     uint8_t data[] //Array of bytes to be written on the SPI port
+                    )
+{
+    wait_us(70);
+    spi.format(8,3); //All data transfer on LTC6804 occur in byte groups. LTC6820 set up such that POL=1 and PHA=3, this corresponds to mode 3 in mbed library. spi.frequency(spiBitrate);
+    spi.frequency(spiBitrate);
+    for (uint8_t i = 0; i < len; i++) {
+        spi.write((char)data[i]);
+        wait_us(110);
+    }
+}
+
+
+void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
+                    uint8_t tx_len, //length of the tx data arry
+                    uint8_t *rx_data,//Input: array that will store the data read by the SPI port
+                    uint8_t rx_len //Option: number of bytes to be read from the SPI port
+                   )
+{
+    //cout<<" SPI Write Read Called" << endl;
+    spi.format(8,3);//All data transfer on LTC6804 occur in byte groups. LTC6820 set up such that POL=1 and PHA=3, this corresponds to mode 3 in mbed library. spi.frequency(spiBitrate);
+    spi.frequency(spiBitrate);
+    //printf("\r\n");
+    //uint8_t ret;
+
+    chipSelect=0;
+    wait_us(70);
+    for (uint8_t i = 0; i < tx_len; i++) {
+        //printf("index is %d: %d \r\n",i,tx_Data[i]);
+        //cout << (int)tx_Data[i] << " , " << endl;
+        spi.write(tx_Data[i]);
+        wait_us(110);
+        //printf("writing has returned %d \r\n", ret);
+    }
+    for (uint8_t i = 0; i < rx_len; i++) {
+        rx_data[i] = (uint8_t)spi.write(0x00);
+        wait_us(110);
+        //ret = rx_data[i];
+        //printf("reading has returned %d \r\n", ret);
+    }
+    chipSelect=1;
+
+    for (uint8_t i = 0; i < tx_len; i++) {
+        //printf("index is %d: %d \r\n",i,tx_Data[i]);
+        break;
+        cout << "Transmit Data " ;
+        cout << (int)tx_Data[i] << " , " ;
+        cout << endl;
+    }
+
+}
+
+
+
+int8_t LTC6804_rdcfg(uint8_t total_ic, uint8_t r_config[][8])
+{
+    //cout<<"Read Config function called" << endl;
+    const uint8_t BYTES_IN_REG = 8;
+
+    uint8_t cmd[4];
+    uint8_t *rx_data;
+    int8_t pec_error = 0;
+    uint16_t data_pec;
+    uint16_t received_pec;
+    rx_data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t));
+    //1
+    cmd[0] = 0x00;
+    cmd[1] = 0x02;
+    cmd[2] = 0x2b;
+    cmd[3] = 0x0A;
+
+    //2
+    //wake_SPI(); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
+    //3
+    for(int current_ic = 0; current_ic<total_ic; current_ic++) {
+        cmd[0] = 0x80 + (current_ic<<3); //Setting address
+        data_pec = pec15_calc(2, cmd);
+        cmd[2] = (uint8_t)(data_pec >> 8);
+        cmd[3] = (uint8_t)(data_pec);
+        //ut << "RdConf cmd:" << (int)cmd[0] << endl;
+        spi_write_read(cmd,4,&rx_data[current_ic*8],8);
+    }
+    //for (int i=0; i<8; i++) {
+    //cout << (int)rx_data[i] << " , ";
+    //}
+    //cout << endl;
+
+    for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) { //executes for each LTC6804 in the stack
+        //4.a
+        for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
+            r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
+        }
+        //4.b
+        received_pec = (r_config[current_ic][6]<<8) + r_config[current_ic][7];
+        //cout << "Rxpec " << received_pec << endl;
+        data_pec = pec15_calc(6, &r_config[current_ic][0]);
+        //cout << "Datpec" << data_pec << endl;
+        if(received_pec != data_pec) {
+            pec_error = -1;
+            cout << "PEC error!!!" << endl;
+        }
+    }
+    free(rx_data);
+    //5
+    //cout << r_config << endl;
+    return(pec_error);
+}
+/*
+    1. Load cmd array with the write configuration command and PEC
+    2. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
+    3. read configuration of each LTC6804 on the stack
+    4. For each LTC6804 in the stack
+      a. load configuration data into r_config array
+      b. calculate PEC of received data and compare against calculated PEC
+    5. Return PEC Error
+
+*/
+
+
+int8_t LTC6804_rdstat(uint8_t total_ic, uint8_t r_config[][8])
+{
+    cout<<"Read Config function called" << endl;
+    const uint8_t BYTES_IN_REG = 8;
+
+    uint8_t cmd[4];
+    uint8_t *rx_data;
+    int8_t pec_error = 0;
+    uint16_t data_pec;
+    uint16_t received_pec;
+    rx_data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t));
+    //1
+    cmd[0] = 0x00;
+    cmd[1] = 0x12;
+
+    //2
+    //wake_SPI(); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
+    //3
+    for(int current_ic = 0; current_ic<total_ic; current_ic++) {
+        cmd[0] = 0x80 + (15<<3); //Setting address
+        data_pec = pec15_calc(2, cmd);
+        cmd[2] = (uint8_t)(data_pec >> 8);
+        cmd[3] = (uint8_t)(data_pec);
+        //ut << "RdConf cmd:" << (int)cmd[0] << endl;
+        spi_write_read(cmd,4,&rx_data[current_ic*8],8);
+    }
+    //for (int i=0; i<8; i++) {
+    //cout << (int)rx_data[i] << " , ";
+    //}
+    //cout << endl;
+
+    for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) { //executes for each LTC6804 in the stack
+        //4.a
+        for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
+            r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
+        }
+        //4.b
+        received_pec = (r_config[current_ic][6]<<8) + r_config[current_ic][7];
+        //cout << "Rxpec " << received_pec << endl;
+        data_pec = pec15_calc(6, &r_config[current_ic][0]);
+        //cout << "Datpec" << data_pec << endl;
+        if(received_pec != data_pec) {
+            pec_error = -1;
+            //cout << "PEC error!!!" << endl;
+        }
+    }
+    free(rx_data);
+    //5
+    //cout << r_config << endl;
+    return(pec_error);
+}
+
+
+void LTC6804_wrcfg(uint8_t total_ic,uint8_t config[][6])
+{
+    const uint8_t BYTES_IN_REG = 6;
+    const uint8_t CMD_LEN = 4+(8*total_ic);
+    uint8_t *cmd;
+    uint16_t temp_pec;
+    uint8_t cmd_index; //command counter
+
+    cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
+    //1
+    cmd[0] = 0x00;
+    cmd[1] = 0x01;
+    cmd[2] = 0x3d;
+    cmd[3] = 0x6e;
+
+    //2
+    cmd_index = 4;
+    for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--) {     // executes for each LTC6804 in stack,
+        for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) { // executes for each byte in the CFGR register
+            // i is the byte counter
+
+            cmd[cmd_index] = config[current_ic-1][current_byte];    //adding the config data to the array to be sent
+            cmd_index = cmd_index + 1;
+        }
+        //3
+        temp_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &config[current_ic-1][0]);// calculating the PEC for each board
+        cmd[cmd_index] = (uint8_t)(temp_pec >> 8);
+        cmd[cmd_index + 1] = (uint8_t)temp_pec;
+        cmd_index = cmd_index + 2;
+    }
+
+    //4                               //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
+    //5
+    for (int current_ic = 0; current_ic<total_ic; current_ic++) {
+        cmd[0] = 0x80 + (current_ic<<3); //Setting address
+        temp_pec = pec15_calc(2, cmd);
+        cmd[2] = (uint8_t)(temp_pec >> 8);
+        cmd[3] = (uint8_t)(temp_pec);
+        chipSelect=0;
+        wait_us(350);
+        spi_write_array(4,cmd);
+        spi_write_array(8,&cmd[4+(8*current_ic)]);
+        chipSelect=1;
+    }
+    free(cmd);
+}
\ No newline at end of file