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

Files at this revision

API Documentation at this revision

Comitter:
maxv008
Date:
Sat Jan 28 14:41:19 2017 +0000
Parent:
5:793afeef45dc
Child:
7:d00f4433cea9
Commit message:
Added Library to acquire cell voltages and balance cells, still need to implement storing them for CAN use.

Changed in this revision

Data_Types_BMU.h Show annotated file Show diff for this revision Revisions of this file
LTC6804/SPI_I2C_Parser.cpp Show annotated file Show diff for this revision Revisions of this file
LTC6804/SPI_I2C_Parser.h Show annotated file Show diff for this revision Revisions of this file
LTC6804/State_Of_Charge.cpp Show annotated file Show diff for this revision Revisions of this file
LTC6804/State_Of_Charge.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/Data_Types_BMU.h	Mon Jan 16 14:39:30 2017 +0000
+++ b/Data_Types_BMU.h	Sat Jan 28 14:41:19 2017 +0000
@@ -51,7 +51,7 @@
     uint8_t ID; // CMU serial number
     uint8_t CMU_number; // Number CMU's from 0-(N-1) (N is number of CMU's) it will aid CAN communications the ID and CMU number may be the same not sure yet
     uint16_t first_cell_voltages[4]; // Split the cell voltages up easier to send over CAN
-    uint16_t last_cell_voltages[4]; // 
+    uint16_t last_cell_voltages[4]; 
 };
 
 struct pack_voltage_extremes{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC6804/SPI_I2C_Parser.cpp	Sat Jan 28 14:41:19 2017 +0000
@@ -0,0 +1,428 @@
+#include "SPI_I2C_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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC6804/SPI_I2C_Parser.h	Sat Jan 28 14:41:19 2017 +0000
@@ -0,0 +1,129 @@
+#ifndef SPI_I2C_Parser
+#define SPI_I2C_Parser
+
+#include "mbed.h"
+#include "CAN_Data.h"
+#include "CAN_IDs.h"
+#include <stdlib.h>
+#include "mbed.h"
+#include <iostream>
+
+const int socAddress = 0x64 << 1; //refer to slave address for LTC2943 on pg 16 of datasheet. mbed API uses 8 bit addresses, therefore left shift by 1 needed before passing.
+
+
+const int spiBitrate=250000;
+const int i2cBitrate=400000;
+
+/*! 
+ 
+  |MD| Dec  | ADC Conversion Model|
+  |--|------|---------------------|
+  |01| 1    | Fast                |
+  |10| 2    | Normal              |
+  |11| 3    | Filtered            |
+*/
+#define MD_FAST 1
+#define MD_NORMAL 2
+#define MD_FILTERED 3
+
+
+ /*! 
+ |CH | Dec  | Channels to convert |
+ |---|------|---------------------|
+ |000| 0    | All Cells           |
+ |001| 1    | Cell 1 and Cell 7   |
+ |010| 2    | Cell 2 and Cell 8   |
+ |011| 3    | Cell 3 and Cell 9   |
+ |100| 4    | Cell 4 and Cell 10  |
+ |101| 5    | Cell 5 and Cell 11  |
+ |110| 6    | Cell 6 and Cell 12  |
+*/
+
+#define CELL_CH_ALL 0
+#define CELL_CH_1and7 1
+#define CELL_CH_2and8 2
+#define CELL_CH_3and9 3
+#define CELL_CH_4and10 4
+#define CELL_CH_5and11 5
+#define CELL_CH_6and12 6
+
+
+/*!
+
+  |CHG | Dec  |Channels to convert   | 
+  |----|------|----------------------|
+  |000 | 0    | All GPIOS and 2nd Ref| 
+  |001 | 1    | GPIO 1               |
+  |010 | 2    | GPIO 2               |
+  |011 | 3    | GPIO 3               |
+  |100 | 4    | GPIO 4               |
+  |101 | 5    | GPIO 5               |
+  |110 | 6    | Vref2                |
+*/
+
+#define AUX_CH_ALL 0
+#define AUX_CH_GPIO1 1
+#define AUX_CH_GPIO2 2
+#define AUX_CH_GPIO3 3
+#define AUX_CH_GPIO4 4
+#define AUX_CH_GPIO5 5
+#define AUX_CH_VREF2 6
+
+//uint8_t CHG = 0; //!< aux channels to be converted
+ /*!****************************************************
+  \brief Controls if Discharging transitors are enabled
+  or disabled during Cell conversions.
+  
+ |DCP | Discharge Permitted During conversion |
+ |----|----------------------------------------|
+ |0   | No - discharge is not permitted         |
+ |1   | Yes - discharge is permitted           |
+ 
+********************************************************/
+#define DCP_DISABLED 0
+#define DCP_ENABLED 1
+
+
+
+
+static const unsigned int crc15Table[256] = {0x0,0xc599, 0xceab, 0xb32, 0xd8cf, 0x1d56, 0x1664, 0xd3fd, 0xf407, 0x319e, 0x3aac,  //!<precomputed CRC15 Table
+0xff35, 0x2cc8, 0xe951, 0xe263, 0x27fa, 0xad97, 0x680e, 0x633c, 0xa6a5, 0x7558, 0xb0c1, 
+0xbbf3, 0x7e6a, 0x5990, 0x9c09, 0x973b, 0x52a2, 0x815f, 0x44c6, 0x4ff4, 0x8a6d, 0x5b2e,
+0x9eb7, 0x9585, 0x501c, 0x83e1, 0x4678, 0x4d4a, 0x88d3, 0xaf29, 0x6ab0, 0x6182, 0xa41b,
+0x77e6, 0xb27f, 0xb94d, 0x7cd4, 0xf6b9, 0x3320, 0x3812, 0xfd8b, 0x2e76, 0xebef, 0xe0dd, 
+0x2544, 0x2be, 0xc727, 0xcc15, 0x98c, 0xda71, 0x1fe8, 0x14da, 0xd143, 0xf3c5, 0x365c, 
+0x3d6e, 0xf8f7,0x2b0a, 0xee93, 0xe5a1, 0x2038, 0x7c2, 0xc25b, 0xc969, 0xcf0, 0xdf0d, 
+0x1a94, 0x11a6, 0xd43f, 0x5e52, 0x9bcb, 0x90f9, 0x5560, 0x869d, 0x4304, 0x4836, 0x8daf,
+0xaa55, 0x6fcc, 0x64fe, 0xa167, 0x729a, 0xb703, 0xbc31, 0x79a8, 0xa8eb, 0x6d72, 0x6640,
+0xa3d9, 0x7024, 0xb5bd, 0xbe8f, 0x7b16, 0x5cec, 0x9975, 0x9247, 0x57de, 0x8423, 0x41ba,
+0x4a88, 0x8f11, 0x57c, 0xc0e5, 0xcbd7, 0xe4e, 0xddb3, 0x182a, 0x1318, 0xd681, 0xf17b, 
+0x34e2, 0x3fd0, 0xfa49, 0x29b4, 0xec2d, 0xe71f, 0x2286, 0xa213, 0x678a, 0x6cb8, 0xa921, 
+0x7adc, 0xbf45, 0xb477, 0x71ee, 0x5614, 0x938d, 0x98bf, 0x5d26, 0x8edb, 0x4b42, 0x4070, 
+0x85e9, 0xf84, 0xca1d, 0xc12f, 0x4b6, 0xd74b, 0x12d2, 0x19e0, 0xdc79, 0xfb83, 0x3e1a, 0x3528, 
+0xf0b1, 0x234c, 0xe6d5, 0xede7, 0x287e, 0xf93d, 0x3ca4, 0x3796, 0xf20f, 0x21f2, 0xe46b, 0xef59, 
+0x2ac0, 0xd3a, 0xc8a3, 0xc391, 0x608, 0xd5f5, 0x106c, 0x1b5e, 0xdec7, 0x54aa, 0x9133, 0x9a01, 
+0x5f98, 0x8c65, 0x49fc, 0x42ce, 0x8757, 0xa0ad, 0x6534, 0x6e06, 0xab9f, 0x7862, 0xbdfb, 0xb6c9, 
+0x7350, 0x51d6, 0x944f, 0x9f7d, 0x5ae4, 0x8919, 0x4c80, 0x47b2, 0x822b, 0xa5d1, 0x6048, 0x6b7a, 
+0xaee3, 0x7d1e, 0xb887, 0xb3b5, 0x762c, 0xfc41, 0x39d8, 0x32ea, 0xf773, 0x248e, 0xe117, 0xea25, 
+0x2fbc, 0x846, 0xcddf, 0xc6ed, 0x374, 0xd089, 0x1510, 0x1e22, 0xdbbb, 0xaf8, 0xcf61, 0xc453, 
+0x1ca, 0xd237, 0x17ae, 0x1c9c, 0xd905, 0xfeff, 0x3b66, 0x3054, 0xf5cd, 0x2630, 0xe3a9, 0xe89b, 
+0x2d02, 0xa76f, 0x62f6, 0x69c4, 0xac5d, 0x7fa0, 0xba39, 0xb10b, 0x7492, 0x5368, 0x96f1, 0x9dc3, 
+0x585a, 0x8ba7, 0x4e3e, 0x450c, 0x8095}; 
+
+
+void wake_LTC6804();
+void wake_SPI();
+void LTC6804_init(uint8_t mode, uint8_t balancingEn, uint8_t cellCh, uint8_t gpioCh);
+void LTC6804_acquireVoltageTx();
+uint8_t LTC6804_acquireAllVoltageRegRx(uint8_t reg, uint8_t cmuCount, uint16_t cell_codes[][12]);
+void LTC6804_acquireSingleVoltageRegRx(uint8_t reg, uint8_t cmuCount, uint8_t *data);
+void LTC6804_setConfigReg(uint8_t cmuCount, uint8_t config[][6]);
+uint16_t pec15_calc(uint8_t len, uint8_t *data);
+void spi_write_array(uint8_t len, uint8_t data[]);
+void spi_write_read(uint8_t tx_Data[], uint8_t tx_len, uint8_t *rx_data, uint8_t rx_len);
+int8_t LTC6804_rdcfg(uint8_t total_ic, uint8_t r_config[][8]);
+int8_t LTC6804_rdstat(uint8_t total_ic, uint8_t r_config[][8]);
+void LTC6804_wrcfg(uint8_t total_ic,uint8_t config[][6]);
+void LTC6804_balance(uint8_t total_ic, uint8_t ic, uint8_t states[12]);
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC6804/State_Of_Charge.cpp	Sat Jan 28 14:41:19 2017 +0000
@@ -0,0 +1,114 @@
+#include "SPI_I2C_Parser.h"
+#include "mbed.h"
+#include "CAN_Data.h"
+#include "CAN_IDs.h"
+#include <stdlib.h>
+#include "State_Of_Charge.h"
+
+//Define SoC ALCC digital in pins might be necessary as a setup, testing needed
+//DigitalIn alcc(p20);
+//Timer t;
+
+/**
+* Sets the values of the cellvoltage array wiht units 100 uV from all of the CMUs
+* Uses the NO_CMUS parameter for the first dimension of cellcodes
+* @param cellcodes[NO_CMUS][12] Will hold the voltage values for every cell in uV.
+*/
+void LTC6804_acquireVoltage(uint16_t cellcodes [][12])
+{
+    //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);
+     wake_LTC6804();//ensures CMU's are in ready state and wakes it up from low power mode
+     wait_us(330);
+     wake_LTC6804(); //This might need to be removed
+     LTC6804_acquireVoltageTx();
+     wait_us(930);
+     LTC6804_acquireAllVoltageRegRx(0, NO_CMUS, cellcodes);   
+}
+
+/**
+Sets the balancing transistors by adjusting the configuration states of the 
+LTC6804. This version of the function writes all 12 states for a chosen 
+transistor. If other forms end up being more useful I will add other overloaded
+versions.
+ 
+@param uint8_t ic The specific IC to write to (can be changed in favor of a 
+states array of size 12*total_ic if preferred)
+ 
+@param uint8_t states[12] For Sn in S1-S12 set states[n-1] to 1 to enable 
+balancing and 0 to disable balancing.
+*/
+void LTC6804_balance(uint8_t ic, uint8_t states[12])
+{
+        uint8_t total_ic = NO_CMUS;
+        //Consider using this to define the configs: (uint8_t *)malloc(total_ic*sizeof(uint8_t));
+        uint8_t r_config[total_ic][8];
+        uint8_t w_config[total_ic][6];//Size is smaller because there aren't PEC codes
+        wake_LTC6804();
+        wait_us(330);
+        LTC6804_rdcfg(total_ic, r_config); 
+        
+        /*for (int i=0; i<8; i++) {
+            printf("TEST %d config \r\n", (uint8_t)r_config[0][i]); 
+        } */
+        
+        uint8_t cfgr4 = 0; //This entire configuration is DCC states
+        uint8_t cfgr5 = r_config[ic][5];
+        
+        for(int i = 0; i < 8; i++)
+        {
+               //Note: This disgusting thing is written by someone who has not used c++ in a long time
+               cfgr4 = states[i] ? cfgr4 | (1u << i) : cfgr4 & ~(1u << i);
+        }
+        
+        for(int i = 8; i < 12; i++)
+        {
+               cfgr5 = states[i] ? cfgr5 | (1u << (i-8)) : cfgr5 & ~(1u << (i-8));
+        }
+        
+        //printf("cfgr4 %d \r\n", (uint8_t)cfgr4);
+        //printf("cfgr5 %d \r\n", (uint8_t)cfgr5);
+        for(int i =0 ; i < total_ic; i++)
+        {
+           for(int j = 0; j < 6; j++)
+            {
+                w_config[i][j] = r_config[i][j];   
+            }   
+        }
+        w_config[ic][4] = cfgr4;
+        w_config[ic][5] = cfgr5;
+        
+        wake_LTC6804();
+        wait_us(330);
+        LTC6804_wrcfg(total_ic,w_config); //Make sure this is written in the write order
+}
+/**
+Takes a set of voltages corresponding to cell voltage measurements and a voltage
+limit (presumably 4200 mV) and then drains all cells as needed. If current state
+of balancing is needed outside of this function, it can be modified.
+
+Current implementation of this function just uses the hard limit, so it might end
+up constantly enabling and disabling balancing as it hits the limit then goes under.
+That behavior can be improved upon if needed. One idea is to use derivative of
+voltage with time to predict when it will hit maxVoltage so there is no risk of 
+going over, or allow them to drain such that all of the cells are at the same voltage.
+
+@param uint16_t voltages[][12] Measured voltages to be used for deciding what to
+balance. The dimensions must be [total_ic][12].
+
+@param uint16_t maxVoltage voltage limit for the cells 
+*/
+void LTC6804_balanceVoltage(uint16_t voltages[][12], uint16_t maxVoltage)
+{
+        uint8_t total_ic = NO_CMUS;
+        //Consider making states a parameter as a pointer so it can be referenced outside of the function easier.
+        uint8_t states[total_ic][12];
+        for(int i = 0; i < total_ic; i++)
+        {
+            for(int j = 0; j < 12; j++)
+            {
+                states[i][j] = voltages[i][j] >= maxVoltage ? 1 : 0; //Not sure if ternary operator is needed in C.    
+            }
+            LTC6804_balance(i, states[i]);    
+        }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LTC6804/State_Of_Charge.h	Sat Jan 28 14:41:19 2017 +0000
@@ -0,0 +1,16 @@
+#ifndef State_Of_Charge
+#define State_Of_Charge
+
+#include "SPI_I2C_Parser.h"
+#include "mbed.h"
+#include "CAN_Data.h"
+#include "CAN_IDs.h"
+#include <stdlib.h>
+#include "Data_Types_BMU.h"
+
+void LTC6804_acquireVoltage(uint16_t cellcodes [][12]);
+void LTC6804_balance(uint8_t ic, uint8_t states[12]);
+void LTC6804_balanceVoltage(uint16_t voltages[][12], uint16_t maxVoltage);
+
+
+#endif
\ No newline at end of file
--- a/main.cpp	Mon Jan 16 14:39:30 2017 +0000
+++ b/main.cpp	Sat Jan 28 14:41:19 2017 +0000
@@ -212,6 +212,10 @@
 
 void take_measurements(BMU_data &measurements)
 {
+    uint16_t cellvoltages[NO_CMUS][12];
+    //TODO Use LTC6804_acquireVoltage to fill this array, and then properly format
+    //it to be sent over CAN
+    
     // Here collect all measured data from the sensors
     /*
     * TODO Cell voltages