LTC6811 Battery Management System with ADuCM3029.

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LTC681x.cpp Source File

LTC681x.cpp

00001 /*
00002     General BMS Library
00003     LTC681x.cpp
00004 */
00005 
00006 #include "mbed.h"
00007 
00008 #include "LTC681x.h"
00009 #include "bms.h"
00010 //#include "LT_SPI.h"
00011 
00012 
00013 void wakeup_idle(uint8_t total_ic)
00014 {
00015     for (int i =0; i<total_ic; i++) {
00016         cs_low();
00017         wait_ms(2); //Guarantees the isoSPI will be in ready mode
00018         spi_read_byte(0xff);
00019         cs_high();
00020     }
00021 }
00022 
00023 //Generic wakeup commannd to wake the LTC6813 from sleep
00024 void wakeup_sleep(uint8_t total_ic)
00025 {
00026     for (int i =0; i<total_ic; i++) {
00027         cs_low();
00028         delay_u(300); // Guarantees the LTC6813 will be in standby
00029         cs_high();
00030         delay_u(10);
00031     }
00032 }
00033 
00034 //Generic function to write 68xx commands. Function calculated PEC for tx_cmd data
00035 void cmd_68(uint8_t tx_cmd[2])
00036 {
00037     uint8_t cmd[4];
00038     uint16_t cmd_pec;
00039 //    uint8_t md_bits;
00040 
00041     cmd[0] = tx_cmd[0];
00042     cmd[1] =  tx_cmd[1];
00043     cmd_pec = pec15_calc(2, cmd);
00044     cmd[2] = (uint8_t)(cmd_pec >> 8);
00045     cmd[3] = (uint8_t)(cmd_pec);
00046     cs_low();
00047     spi_write_array(4,cmd);
00048     cs_high();
00049 }
00050 
00051 //Generic function to write 68xx commands and write payload data. Function calculated PEC for tx_cmd data
00052 void write_68(uint8_t total_ic , uint8_t tx_cmd[2], uint8_t data[])
00053 {
00054     const uint8_t BYTES_IN_REG = 6;
00055     const uint8_t CMD_LEN = 4+(8*total_ic);
00056     uint8_t *cmd;
00057     uint16_t data_pec;
00058     uint16_t cmd_pec;
00059     uint8_t cmd_index;
00060 
00061     cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
00062     cmd[0] = tx_cmd[0];
00063     cmd[1] = tx_cmd[1];
00064     cmd_pec = pec15_calc(2, cmd);
00065     cmd[2] = (uint8_t)(cmd_pec >> 8);
00066     cmd[3] = (uint8_t)(cmd_pec);
00067     cmd_index = 4;
00068     for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--) {     // executes for each LTC681x in daisy chain, this loops starts with
00069         // the last IC on the stack. The first configuration written is
00070         // received by the last IC in the daisy chain
00071 
00072         for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
00073             cmd[cmd_index] = data[((current_ic-1)*6)+current_byte];
00074             cmd_index = cmd_index + 1;
00075         }
00076 
00077         data_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &data[(current_ic-1)*6]);    // calculating the PEC for each Iss configuration register data
00078         cmd[cmd_index] = (uint8_t)(data_pec >> 8);
00079         cmd[cmd_index + 1] = (uint8_t)data_pec;
00080         cmd_index = cmd_index + 2;
00081     }
00082 
00083 
00084     cs_low();
00085     spi_write_array(CMD_LEN, cmd);
00086     cs_high();
00087     free(cmd);
00088 }
00089 
00090 //Generic function to write 68xx commands and read data. Function calculated PEC for tx_cmd data
00091 int8_t read_68( uint8_t total_ic, uint8_t tx_cmd[2], uint8_t *rx_data)
00092 {
00093     const uint8_t BYTES_IN_REG = 8;
00094     uint8_t cmd[4];
00095     uint8_t data[256];
00096     int8_t pec_error = 0;
00097     uint16_t cmd_pec;
00098     uint16_t data_pec;
00099     uint16_t received_pec;
00100 
00101     // data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t)); // This is a problem because it can fail
00102 
00103     cmd[0] = tx_cmd[0];
00104     cmd[1] = tx_cmd[1];
00105     cmd_pec = pec15_calc(2, cmd);
00106     cmd[2] = (uint8_t)(cmd_pec >> 8);
00107     cmd[3] = (uint8_t)(cmd_pec);
00108 
00109 
00110     cs_low();
00111     spi_write_read(cmd, 4, data, (BYTES_IN_REG*total_ic));         //Read the configuration data of all ICs on the daisy chain into
00112     cs_high();                         //rx_data[] array
00113 
00114     for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) {     //executes for each LTC681x in the daisy chain and packs the data
00115         //into the r_comm array as well as check the received Config data
00116         //for any bit errors
00117         for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
00118             rx_data[(current_ic*8)+current_byte] = data[current_byte + (current_ic*BYTES_IN_REG)];
00119         }
00120         received_pec = (rx_data[(current_ic*8)+6]<<8) + rx_data[(current_ic*8)+7];
00121         data_pec = pec15_calc(6, &rx_data[current_ic*8]);
00122         if (received_pec != data_pec) {
00123             pec_error = -1;
00124         }
00125     }
00126 
00127 
00128     return(pec_error);
00129 }
00130 
00131 
00132 /*
00133   Calculates  and returns the CRC15
00134   */
00135 uint16_t pec15_calc(uint8_t len, //Number of bytes that will be used to calculate a PEC
00136                     uint8_t *data //Array of data that will be used to calculate  a PEC
00137                    )
00138 {
00139     uint16_t remainder,addr;
00140 
00141     remainder = 16;//initialize the PEC
00142     for (uint8_t i = 0; i<len; i++) { // loops for each byte in data array
00143         addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
00144 //#ifdef MBED
00145         remainder = (remainder<<8)^crc15Table[addr];
00146 //#else
00147 //        remainder = (remainder<<8)^pgm_read_word_near(crc15Table+addr);
00148 //#endif
00149     }
00150     return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
00151 }
00152 
00153 //Starts cell voltage conversion
00154 void LTC681x_adcv(
00155     uint8_t MD, //ADC Mode
00156     uint8_t DCP, //Discharge Permit
00157     uint8_t CH //Cell Channels to be measured
00158 )
00159 {
00160     uint8_t cmd[4];
00161     uint8_t md_bits;
00162 
00163     md_bits = (MD & 0x02) >> 1;
00164     cmd[0] = md_bits + 0x02;
00165     md_bits = (MD & 0x01) << 7;
00166     cmd[1] =  md_bits + 0x60 + (DCP<<4) + CH;
00167     cmd_68(cmd);
00168 }
00169 
00170 
00171 //Starts cell voltage and SOC conversion
00172 void LTC681x_adcvsc(
00173     uint8_t MD, //ADC Mode
00174     uint8_t DCP //Discharge Permit
00175 )
00176 {
00177     uint8_t cmd[4];
00178     uint8_t md_bits;
00179     md_bits = (MD & 0x02) >> 1;
00180     cmd[0] = md_bits | 0x04;
00181     md_bits = (MD & 0x01) << 7;
00182     cmd[1] =  md_bits | 0x60 | (DCP<<4) | 0x07;
00183     cmd_68(cmd);
00184 
00185 }
00186 
00187 // Starts cell voltage  and GPIO 1&2 conversion
00188 void LTC681x_adcvax(
00189     uint8_t MD, //ADC Mode
00190     uint8_t DCP //Discharge Permit
00191 )
00192 {
00193     uint8_t cmd[4];
00194     uint8_t md_bits;
00195     md_bits = (MD & 0x02) >> 1;
00196     cmd[0] = md_bits | 0x04;
00197     md_bits = (MD & 0x01) << 7;
00198     cmd[1] =  md_bits | ((DCP&0x01)<<4) + 0x6F;
00199     cmd_68(cmd);
00200 }
00201 
00202 //Starts cell voltage overlap conversion
00203 void LTC681x_adol(
00204     uint8_t MD, //ADC Mode
00205     uint8_t DCP //Discharge Permit
00206 )
00207 {
00208     uint8_t cmd[4];
00209     uint8_t md_bits;
00210     md_bits = (MD & 0x02) >> 1;
00211     cmd[0] = md_bits + 0x02;
00212     md_bits = (MD & 0x01) << 7;
00213     cmd[1] =  md_bits + (DCP<<4) +0x01;
00214     cmd_68(cmd);
00215 }
00216 
00217 //Starts cell voltage self test conversion
00218 void LTC681x_cvst(
00219     uint8_t MD, //ADC Mode
00220     uint8_t ST //Self Test
00221 )
00222 {
00223     uint8_t cmd[2];
00224     uint8_t md_bits;
00225 
00226     md_bits = (MD & 0x02) >> 1;
00227     cmd[0] = md_bits + 0x02;
00228     md_bits = (MD & 0x01) << 7;
00229     cmd[1] =  md_bits + ((ST)<<5) +0x07;
00230     cmd_68(cmd);
00231 
00232 }
00233 
00234 //Start an Auxiliary Register Self Test Conversion
00235 void LTC681x_axst(
00236     uint8_t MD, //ADC Mode
00237     uint8_t ST //Self Test
00238 )
00239 {
00240     uint8_t cmd[4];
00241     uint8_t md_bits;
00242 
00243     md_bits = (MD & 0x02) >> 1;
00244     cmd[0] = md_bits + 0x04;
00245     md_bits = (MD & 0x01) << 7;
00246     cmd[1] =  md_bits + ((ST&0x03)<<5) +0x07;
00247     cmd_68(cmd);
00248 
00249 }
00250 
00251 //Start a Status Register Self Test Conversion
00252 void LTC681x_statst(
00253     uint8_t MD, //ADC Mode
00254     uint8_t ST //Self Test
00255 )
00256 {
00257     uint8_t cmd[2];
00258     uint8_t md_bits;
00259 
00260     md_bits = (MD & 0x02) >> 1;
00261     cmd[0] = md_bits + 0x04;
00262     md_bits = (MD & 0x01) << 7;
00263     cmd[1] =  md_bits + ((ST&0x03)<<5) +0x0F;
00264     cmd_68(cmd);
00265 
00266 }
00267 
00268 //Sends the poll adc command
00269 uint8_t LTC681x_pladc()
00270 {
00271     uint8_t cmd[4];
00272     uint8_t adc_state = 0xFF;
00273     uint16_t cmd_pec;
00274 
00275     cmd[0] = 0x07;
00276     cmd[1] = 0x14;
00277     cmd_pec = pec15_calc(2, cmd);
00278     cmd[2] = (uint8_t)(cmd_pec >> 8);
00279     cmd[3] = (uint8_t)(cmd_pec);
00280 
00281 
00282     cs_low();
00283     spi_write_array(4,cmd);
00284 // adc_state = spi_read_byte(0xFF);
00285     cs_high();
00286     return(adc_state);
00287 }
00288 
00289 //This function will block operation until the ADC has finished it's conversion
00290 uint32_t LTC681x_pollAdc()
00291 {
00292     uint32_t counter = 0;
00293     uint8_t finished = 0;
00294     uint8_t current_time = 0;
00295     uint8_t cmd[4];
00296     uint16_t cmd_pec;
00297 
00298 
00299     cmd[0] = 0x07;
00300     cmd[1] = 0x14;
00301     cmd_pec = pec15_calc(2, cmd);
00302     cmd[2] = (uint8_t)(cmd_pec >> 8);
00303     cmd[3] = (uint8_t)(cmd_pec);
00304 
00305     cs_low();
00306     spi_write_array(4,cmd);
00307 
00308     while ((counter<200000)&&(finished == 0)) {
00309         current_time = spi_read_byte(0xff);
00310         if (current_time>0) {
00311             finished = 1;
00312         } else {
00313             counter = counter + 10;
00314         }
00315     }
00316     cs_high();
00317     
00318 
00319     return(counter);
00320 }
00321 
00322 //Start a GPIO and Vref2 Conversion
00323 void LTC681x_adax(
00324     uint8_t MD, //ADC Mode
00325     uint8_t CHG //GPIO Channels to be measured)
00326 )
00327 {
00328     uint8_t cmd[4];
00329     uint8_t md_bits;
00330 
00331     md_bits = (MD & 0x02) >> 1;
00332     cmd[0] = md_bits + 0x04;
00333     md_bits = (MD & 0x01) << 7;
00334     cmd[1] = md_bits + 0x60 + CHG ;
00335     cmd_68(cmd);
00336 
00337 }
00338 
00339 //Start an GPIO Redundancy test
00340 void LTC681x_adaxd(
00341     uint8_t MD, //ADC Mode
00342     uint8_t CHG //GPIO Channels to be measured)
00343 )
00344 {
00345     uint8_t cmd[4];
00346     uint8_t md_bits;
00347 
00348     md_bits = (MD & 0x02) >> 1;
00349     cmd[0] = md_bits + 0x04;
00350     md_bits = (MD & 0x01) << 7;
00351     cmd[1] = md_bits + CHG ;
00352     cmd_68(cmd);
00353 }
00354 
00355 //Start a Status ADC Conversion
00356 void LTC681x_adstat(
00357     uint8_t MD, //ADC Mode
00358     uint8_t CHST //GPIO Channels to be measured
00359 )
00360 {
00361     uint8_t cmd[4];
00362     uint8_t md_bits;
00363 
00364     md_bits = (MD & 0x02) >> 1;
00365     cmd[0] = md_bits + 0x04;
00366     md_bits = (MD & 0x01) << 7;
00367     cmd[1] = md_bits + 0x68 + CHST ;
00368     cmd_68(cmd);
00369 }
00370 
00371 // Start a Status register redundancy test Conversion
00372 void LTC681x_adstatd(
00373     uint8_t MD, //ADC Mode
00374     uint8_t CHST //GPIO Channels to be measured
00375 )
00376 {
00377     uint8_t cmd[2];
00378     uint8_t md_bits;
00379 
00380     md_bits = (MD & 0x02) >> 1;
00381     cmd[0] = md_bits + 0x04;
00382     md_bits = (MD & 0x01) << 7;
00383     cmd[1] = md_bits + 0x08 + CHST ;
00384     cmd_68(cmd);
00385 
00386 }
00387 
00388 
00389 // Start an open wire Conversion
00390 void LTC681x_adow(
00391     uint8_t MD, //ADC Mode
00392     uint8_t PUP //Discharge Permit
00393 )
00394 {
00395     uint8_t cmd[2];
00396     uint8_t md_bits;
00397     md_bits = (MD & 0x02) >> 1;
00398     cmd[0] = md_bits + 0x02;
00399     md_bits = (MD & 0x01) << 7;
00400     cmd[1] =  md_bits + 0x28 + (PUP<<6) ;//+ CH;
00401     cmd_68(cmd);
00402 }
00403 
00404 // Reads the raw cell voltage register data
00405 void LTC681x_rdcv_reg(uint8_t reg, //Determines which cell voltage register is read back
00406                       uint8_t total_ic, //the number of ICs in the
00407                       uint8_t *data //An array of the unparsed cell codes
00408                      )
00409 {
00410     const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
00411     uint8_t cmd[4];
00412     uint16_t cmd_pec;
00413 
00414     if (reg == 1) {   //1: RDCVA
00415         cmd[1] = 0x04;
00416         cmd[0] = 0x00;
00417     } else if (reg == 2) { //2: RDCVB
00418         cmd[1] = 0x06;
00419         cmd[0] = 0x00;
00420     } else if (reg == 3) { //3: RDCVC
00421         cmd[1] = 0x08;
00422         cmd[0] = 0x00;
00423     } else if (reg == 4) { //4: RDCVD
00424         cmd[1] = 0x0A;
00425         cmd[0] = 0x00;
00426     } else if (reg == 5) { //4: RDCVE
00427         cmd[1] = 0x09;
00428         cmd[0] = 0x00;
00429     } else if (reg == 6) { //4: RDCVF
00430         cmd[1] = 0x0B;
00431         cmd[0] = 0x00;
00432     }
00433 
00434 
00435     cmd_pec = pec15_calc(2, cmd);
00436     cmd[2] = (uint8_t)(cmd_pec >> 8);
00437     cmd[3] = (uint8_t)(cmd_pec);
00438 
00439     cs_low();
00440     spi_write_read(cmd,4,data,(REG_LEN*total_ic));
00441     cs_high();
00442 
00443 }
00444 
00445 //helper function that parses voltage measurement registers
00446 int8_t parse_cells(uint8_t current_ic, uint8_t cell_reg, uint8_t cell_data[], uint16_t *cell_codes, uint8_t *ic_pec)
00447 {
00448 
00449     const uint8_t BYT_IN_REG = 6;
00450     const uint8_t CELL_IN_REG = 3;
00451     int8_t pec_error = 0;
00452     uint16_t parsed_cell;
00453     uint16_t received_pec;
00454     uint16_t data_pec;
00455     uint8_t data_counter = current_ic*NUM_RX_BYT; //data counter
00456 
00457 
00458     for (uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) { // This loop parses the read back data into cell voltages, it
00459         // loops once for each of the 3 cell voltage codes in the register
00460 
00461         parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);//Each cell code is received as two bytes and is combined to
00462         // create the parsed cell voltage code
00463         cell_codes[current_cell  + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
00464         data_counter = data_counter + 2;                       //Because cell voltage codes are two bytes the data counter
00465         //must increment by two for each parsed cell code
00466     }
00467 
00468     received_pec = (cell_data[data_counter] << 8) | cell_data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
00469     //after the 6 cell voltage data bytes
00470     data_pec = pec15_calc(BYT_IN_REG, &cell_data[(current_ic) * NUM_RX_BYT]);
00471 
00472     if (received_pec != data_pec) {
00473         pec_error = 1;                             //The pec_error variable is simply set negative if any PEC errors
00474         ic_pec[cell_reg-1]=1;
00475     } else {
00476         ic_pec[cell_reg-1]=0;
00477     }
00478     data_counter=data_counter+2;
00479     return(pec_error);
00480 }
00481 
00482 /*
00483 The function reads a single GPIO voltage register and stores thre read data
00484 in the *data point as a byte array. This function is rarely used outside of
00485 the LTC6811_rdaux() command.
00486 */
00487 void LTC681x_rdaux_reg(uint8_t reg, //Determines which GPIO voltage register is read back
00488                        uint8_t total_ic, //The number of ICs in the system
00489                        uint8_t *data //Array of the unparsed auxiliary codes
00490                       )
00491 {
00492     const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
00493     uint8_t cmd[4];
00494     uint16_t cmd_pec;
00495 
00496 
00497     if (reg == 1) {   //Read back auxiliary group A
00498         cmd[1] = 0x0C;
00499         cmd[0] = 0x00;
00500     } else if (reg == 2) { //Read back auxiliary group B
00501         cmd[1] = 0x0e;
00502         cmd[0] = 0x00;
00503     } else if (reg == 3) { //Read back auxiliary group C
00504         cmd[1] = 0x0D;
00505         cmd[0] = 0x00;
00506     } else if (reg == 4) { //Read back auxiliary group D
00507         cmd[1] = 0x0F;
00508         cmd[0] = 0x00;
00509     } else {      //Read back auxiliary group A
00510         cmd[1] = 0x0C;
00511         cmd[0] = 0x00;
00512     }
00513 
00514     cmd_pec = pec15_calc(2, cmd);
00515     cmd[2] = (uint8_t)(cmd_pec >> 8);
00516     cmd[3] = (uint8_t)(cmd_pec);
00517 
00518     cs_low();
00519     spi_write_read(cmd,4,data,(REG_LEN*total_ic));
00520     cs_high();
00521 
00522 }
00523 
00524 /*
00525 The function reads a single stat  register and stores the read data
00526 in the *data point as a byte array. This function is rarely used outside of
00527 the LTC6811_rdstat() command.
00528 */
00529 void LTC681x_rdstat_reg(uint8_t reg, //Determines which stat register is read back
00530                         uint8_t total_ic, //The number of ICs in the system
00531                         uint8_t *data //Array of the unparsed stat codes
00532                        )
00533 {
00534     const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
00535     uint8_t cmd[4];
00536     uint16_t cmd_pec;
00537 
00538 
00539     if (reg == 1) {   //Read back statiliary group A
00540         cmd[1] = 0x10;
00541         cmd[0] = 0x00;
00542     } else if (reg == 2) { //Read back statiliary group B
00543         cmd[1] = 0x12;
00544         cmd[0] = 0x00;
00545     }
00546 
00547     else {        //Read back statiliary group A
00548         cmd[1] = 0x10;
00549         cmd[0] = 0x00;
00550     }
00551 
00552     cmd_pec = pec15_calc(2, cmd);
00553     cmd[2] = (uint8_t)(cmd_pec >> 8);
00554     cmd[3] = (uint8_t)(cmd_pec);
00555 
00556     cs_low();
00557     spi_write_read(cmd,4,data,(REG_LEN*total_ic));
00558     cs_high();
00559 
00560 }
00561 
00562 /*
00563 The command clears the cell voltage registers and intiallizes
00564 all values to 1. The register will read back hexadecimal 0xFF
00565 after the command is sent.
00566 */
00567 void LTC681x_clrcell()
00568 {
00569     uint8_t cmd[2]= {0x07 , 0x11};
00570     cmd_68(cmd);
00571 }
00572 
00573 
00574 /*
00575 The command clears the Auxiliary registers and initializes
00576 all values to 1. The register will read back hexadecimal 0xFF
00577 after the command is sent.
00578 */
00579 void LTC681x_clraux()
00580 {
00581     uint8_t cmd[2]= {0x07 , 0x12};
00582     cmd_68(cmd);
00583 }
00584 
00585 
00586 /*
00587 The command clears the Stat registers and intiallizes
00588 all values to 1. The register will read back hexadecimal 0xFF
00589 after the command is sent.
00590 
00591 */
00592 void LTC681x_clrstat()
00593 {
00594     uint8_t cmd[2]= {0x07 , 0x13};
00595     cmd_68(cmd);
00596 }
00597 /*
00598 The command clears the Sctrl registers and initializes
00599 all values to 0. The register will read back hexadecimal 0x00
00600 after the command is sent.
00601 */
00602 void LTC681x_clrsctrl()
00603 {
00604     uint8_t cmd[2]= {0x00 , 0x18};
00605     cmd_68(cmd);
00606 }
00607 //Starts the Mux Decoder diagnostic self test
00608 void LTC681x_diagn()
00609 {
00610     uint8_t cmd[2] = {0x07 , 0x15};
00611     cmd_68(cmd);
00612 }
00613 
00614 //Reads and parses the LTC681x cell voltage registers.
00615 uint8_t LTC681x_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
00616                      uint8_t total_ic, // the number of ICs in the system
00617                      cell_asic ic[] // Array of the parsed cell codes
00618                     )
00619 {
00620     int8_t pec_error = 0;
00621     uint8_t *cell_data;
00622     uint8_t c_ic = 0;
00623     cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
00624 
00625     if (reg == 0) {
00626         for (uint8_t cell_reg = 1; cell_reg<ic[0].ic_reg.num_cv_reg+1; cell_reg++) {                 //executes once for each of the LTC6811 cell voltage registers
00627             LTC681x_rdcv_reg(cell_reg, total_ic,cell_data );
00628             for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00629                 if (ic->isospi_reverse == false) {
00630                     c_ic = current_ic;
00631                 } else {
00632                     c_ic = total_ic - current_ic - 1;
00633                 }
00634                 pec_error = pec_error + parse_cells(current_ic,cell_reg, cell_data,
00635                                                     &ic[c_ic].cells.c_codes[0],
00636                                                     &ic[c_ic].cells.pec_match[0]);
00637             }
00638         }
00639     }
00640 
00641     else {
00642         LTC681x_rdcv_reg(reg, total_ic,cell_data);
00643 
00644         for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00645             if (ic->isospi_reverse == false) {
00646                 c_ic = current_ic;
00647             } else {
00648                 c_ic = total_ic - current_ic - 1;
00649             }
00650             pec_error = pec_error + parse_cells(current_ic,reg, &cell_data[8*c_ic],
00651                                                 &ic[c_ic].cells.c_codes[0],
00652                                                 &ic[c_ic].cells.pec_match[0]);
00653         }
00654     }
00655     LTC681x_check_pec(total_ic,CELL,ic);
00656     free(cell_data);
00657     return(pec_error);
00658 }
00659 
00660 
00661 
00662 /*
00663 The function is used
00664 to read the  parsed GPIO codes of the LTC6811. This function will send the requested
00665 read commands parse the data and store the gpio voltages in aux_codes variable
00666 */
00667 int8_t LTC681x_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
00668                      uint8_t total_ic,//the number of ICs in the system
00669                      cell_asic ic[]//A two dimensional array of the gpio voltage codes.
00670                     )
00671 {
00672     uint8_t *data;
00673     int8_t pec_error = 0;
00674     uint8_t c_ic =0;
00675     data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
00676 
00677     if (reg == 0) {
00678         for (uint8_t gpio_reg = 1; gpio_reg<ic[0].ic_reg.num_gpio_reg+1; gpio_reg++) {               //executes once for each of the LTC6811 aux voltage registers
00679             LTC681x_rdaux_reg(gpio_reg, total_ic,data);                 //Reads the raw auxiliary register data into the data[] array
00680             for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00681                 if (ic->isospi_reverse == false) {
00682                     c_ic = current_ic;
00683                 } else {
00684                     c_ic = total_ic - current_ic - 1;
00685                 }
00686                 pec_error = parse_cells(current_ic,gpio_reg, data,
00687                                         &ic[c_ic].aux.a_codes[0],
00688                                         &ic[c_ic].aux.pec_match[0]);
00689 
00690             }
00691         }
00692     } else {
00693         LTC681x_rdaux_reg(reg, total_ic, data);
00694 
00695         for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00696             if (ic->isospi_reverse == false) {
00697                 c_ic = current_ic;
00698             } else {
00699                 c_ic = total_ic - current_ic - 1;
00700             }
00701             pec_error = parse_cells(current_ic,reg, data,
00702                                     &ic[c_ic].aux.a_codes[0],
00703                                     &ic[c_ic].aux.pec_match[0]);
00704         }
00705 
00706     }
00707     LTC681x_check_pec(total_ic,AUX,ic);
00708     free(data);
00709     return (pec_error);
00710 }
00711 
00712 // Reads and parses the LTC681x stat registers.
00713 int8_t LTC681x_rdstat(uint8_t reg, //Determines which Stat  register is read back.
00714                       uint8_t total_ic,//the number of ICs in the system
00715                       cell_asic ic[]
00716                      )
00717 
00718 {
00719 
00720     const uint8_t BYT_IN_REG = 6;
00721     const uint8_t GPIO_IN_REG = 3;
00722 
00723     uint8_t *data;
00724     uint8_t data_counter = 0;
00725     int8_t pec_error = 0;
00726     uint16_t parsed_stat;
00727     uint16_t received_pec;
00728     uint16_t data_pec;
00729     uint8_t c_ic = 0;
00730     data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
00731 
00732     if (reg == 0) {
00733 
00734         for (uint8_t stat_reg = 1; stat_reg< 3; stat_reg++) {                    //executes once for each of the LTC6811 stat voltage registers
00735             data_counter = 0;
00736             LTC681x_rdstat_reg(stat_reg, total_ic,data);                            //Reads the raw statiliary register data into the data[] array
00737 
00738             for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) {    // executes for every LTC6811 in the daisy chain
00739                 if (ic->isospi_reverse == false) {
00740                     c_ic = current_ic;
00741                 } else {
00742                     c_ic = total_ic - current_ic - 1;
00743                 }
00744                 // current_ic is used as the IC counter
00745                 if (stat_reg ==1) {
00746                     for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
00747                         // loops once for each of the 3 gpio voltage codes in the register
00748 
00749                         parsed_stat = data[data_counter] + (data[data_counter+1]<<8);              //Each gpio codes is received as two bytes and is combined to
00750                         ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
00751                         data_counter=data_counter+2;                                               //Because gpio voltage codes are two bytes the data counter
00752 
00753                     }
00754                 } else if (stat_reg == 2) {
00755                     parsed_stat = data[data_counter] + (data[data_counter+1]<<8);              //Each gpio codes is received as two bytes and is combined to
00756                     data_counter = data_counter +2;
00757                     ic[c_ic].stat.stat_codes[3] = parsed_stat;
00758                     ic[c_ic].stat.flags[0] = data[data_counter++];
00759                     ic[c_ic].stat.flags[1] = data[data_counter++];
00760                     ic[c_ic].stat.flags[2] = data[data_counter++];
00761                     ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
00762                     ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
00763                 }
00764 
00765                 received_pec = (data[data_counter]<<8)+ data[data_counter+1];          //The received PEC for the current_ic is transmitted as the 7th and 8th
00766                 //after the 6 gpio voltage data bytes
00767                 data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
00768 
00769                 if (received_pec != data_pec) {
00770                     pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
00771                     ic[c_ic].stat.pec_match[stat_reg-1]=1;
00772                     //are detected in the received serial data
00773                 } else {
00774                     ic[c_ic].stat.pec_match[stat_reg-1]=0;
00775                 }
00776 
00777                 data_counter=data_counter+2;                        //Because the transmitted PEC code is 2 bytes long the data_counter
00778                 //must be incremented by 2 bytes to point to the next ICs gpio voltage data
00779             }
00780 
00781 
00782         }
00783 
00784     } else {
00785 
00786         LTC681x_rdstat_reg(reg, total_ic, data);
00787         for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {          // executes for every LTC6811 in the daisy chain
00788             // current_ic is used as an IC counter
00789             if (ic->isospi_reverse == false) {
00790                 c_ic = current_ic;
00791             } else {
00792                 c_ic = total_ic - current_ic - 1;
00793             }
00794             if (reg ==1) {
00795                 for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
00796                     // loops once for each of the 3 gpio voltage codes in the register
00797                     parsed_stat = data[data_counter] + (data[data_counter+1]<<8);              //Each gpio codes is received as two bytes and is combined to
00798                     // create the parsed gpio voltage code
00799 
00800                     ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
00801                     data_counter=data_counter+2;                        //Because gpio voltage codes are two bytes the data counter
00802                     //must increment by two for each parsed gpio voltage code
00803 
00804                 }
00805             } else if (reg == 2) {
00806                 parsed_stat = data[data_counter++] + (data[data_counter++]<<8);              //Each gpio codes is received as two bytes and is combined to
00807                 ic[c_ic].stat.stat_codes[3] = parsed_stat;
00808                 ic[c_ic].stat.flags[0] = data[data_counter++];
00809                 ic[c_ic].stat.flags[1] = data[data_counter++];
00810                 ic[c_ic].stat.flags[2] = data[data_counter++];
00811                 ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
00812                 ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
00813             }
00814 
00815 
00816             received_pec = (data[data_counter]<<8)+ data[data_counter+1];          //The received PEC for the current_ic is transmitted as the 7th and 8th
00817             //after the 6 gpio voltage data bytes
00818             data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
00819             if (received_pec != data_pec) {
00820                 pec_error = -1;                             //The pec_error variable is simply set negative if any PEC errors
00821                 ic[c_ic].stat.pec_match[reg-1]=1;
00822 
00823             }
00824 
00825             data_counter=data_counter+2;
00826         }
00827     }
00828     LTC681x_check_pec(total_ic,STAT,ic);
00829     free(data);
00830     return (pec_error);
00831 }
00832 
00833 //Write the LTC681x CFGRA
00834 void LTC681x_wrcfg(uint8_t total_ic, //The number of ICs being written to
00835                    cell_asic ic[]
00836                   )
00837 {
00838     uint8_t cmd[2] = {0x00 , 0x01} ;
00839     uint8_t write_buffer[256];
00840     uint8_t write_count = 0;
00841     uint8_t c_ic = 0;
00842     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00843         if (ic->isospi_reverse == true) {
00844             c_ic = current_ic;
00845         } else {
00846             c_ic = total_ic - current_ic - 1;
00847         }
00848 
00849         for (uint8_t data = 0; data<6; data++) {
00850             write_buffer[write_count] = ic[c_ic].config.tx_data[data];
00851             write_count++;
00852         }
00853     }
00854     write_68(total_ic, cmd, write_buffer);
00855 }
00856 
00857 //Write the LTC681x CFGRB
00858 void LTC681x_wrcfgb(uint8_t total_ic, //The number of ICs being written to
00859                     cell_asic ic[]
00860                    )
00861 {
00862     uint8_t cmd[2] = {0x00 , 0x24} ;
00863     uint8_t write_buffer[256];
00864     uint8_t write_count = 0;
00865     uint8_t c_ic = 0;
00866     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00867         if (ic->isospi_reverse == true) {
00868             c_ic = current_ic;
00869         } else {
00870             c_ic = total_ic - current_ic - 1;
00871         }
00872 
00873         for (uint8_t data = 0; data<6; data++) {
00874             write_buffer[write_count] = ic[c_ic].configb.tx_data[data];
00875             write_count++;
00876         }
00877     }
00878     write_68(total_ic, cmd, write_buffer);
00879 }
00880 
00881 //Read CFGA
00882 int8_t LTC681x_rdcfg(uint8_t total_ic, //Number of ICs in the system
00883                      cell_asic ic[]
00884                     )
00885 {
00886     uint8_t cmd[2]= {0x00 , 0x02};
00887     uint8_t read_buffer[256];
00888     int8_t pec_error = 0;
00889     uint16_t data_pec;
00890     uint16_t calc_pec;
00891     uint8_t c_ic = 0;
00892     pec_error = read_68(total_ic, cmd, read_buffer);
00893     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00894         if (ic->isospi_reverse == false) {
00895             c_ic = current_ic;
00896         } else {
00897             c_ic = total_ic - current_ic - 1;
00898         }
00899 
00900         for (int byte=0; byte<8; byte++) {
00901             ic[c_ic].config.rx_data[byte] = read_buffer[byte+(8*current_ic)];
00902         }
00903         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
00904         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
00905         if (calc_pec != data_pec ) {
00906             ic[c_ic].config.rx_pec_match = 1;
00907         } else ic[c_ic].config.rx_pec_match = 0;
00908     }
00909     LTC681x_check_pec(total_ic,CFGR,ic);
00910     return(pec_error);
00911 }
00912 
00913 //Reads CFGB
00914 int8_t LTC681x_rdcfgb(uint8_t total_ic, //Number of ICs in the system
00915                       cell_asic ic[]
00916                      )
00917 {
00918     uint8_t cmd[2]= {0x00 , 0x26};
00919     uint8_t read_buffer[256];
00920     int8_t pec_error = 0;
00921     uint16_t data_pec;
00922     uint16_t calc_pec;
00923     uint8_t c_ic = 0;
00924     pec_error = read_68(total_ic, cmd, read_buffer);
00925     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00926         if (ic->isospi_reverse == false) {
00927             c_ic = current_ic;
00928         } else {
00929             c_ic = total_ic - current_ic - 1;
00930         }
00931 
00932         for (int byte=0; byte<8; byte++) {
00933             ic[c_ic].configb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
00934         }
00935         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
00936         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
00937         if (calc_pec != data_pec ) {
00938             ic[c_ic].configb.rx_pec_match = 1;
00939         } else ic[c_ic].configb.rx_pec_match = 0;
00940     }
00941     LTC681x_check_pec(total_ic,CFGRB,ic);
00942     return(pec_error);
00943 }
00944 
00945 //Looks up the result pattern for digital filter self test
00946 uint16_t LTC681x_st_lookup(
00947     uint8_t MD, //ADC Mode
00948     uint8_t ST //Self Test
00949 )
00950 {
00951     uint16_t test_pattern = 0;
00952     if (MD == 1) {
00953         if (ST == 1) {
00954             test_pattern = 0x9565;
00955         } else {
00956             test_pattern = 0x6A9A;
00957         }
00958     } else {
00959         if (ST == 1) {
00960             test_pattern = 0x9555;
00961         } else {
00962             test_pattern = 0x6AAA;
00963         }
00964     }
00965     return(test_pattern);
00966 }
00967 
00968 //Clears all of the DCC bits in the configuration registers
00969 void clear_discharge(uint8_t total_ic, cell_asic ic[])
00970 {
00971     for (int i=0; i<total_ic; i++) {
00972         ic[i].config.tx_data[4] = 0;
00973         ic[i].config.tx_data[5] = 0;
00974     }
00975 }
00976 
00977 // Runs the Digital Filter Self Test
00978 int16_t LTC681x_run_cell_adc_st(uint8_t adc_reg,uint8_t total_ic, cell_asic ic[])
00979 {
00980     int16_t error = 0;
00981     uint16_t expected_result = 0;
00982     for (int self_test = 1; self_test<3; self_test++) {
00983 
00984         expected_result = LTC681x_st_lookup(2,self_test);
00985         wakeup_idle(total_ic);
00986         switch (adc_reg) {
00987             case CELL:
00988                 wakeup_idle(total_ic);
00989                 LTC681x_clrcell();
00990                 LTC681x_cvst(2,self_test);
00991                 LTC681x_pollAdc();//this isn't working
00992                 wakeup_idle(total_ic);
00993                 error = LTC681x_rdcv(0, total_ic,ic);
00994                 for (int cic = 0; cic < total_ic; cic++) {
00995                     for (int channel=0; channel< ic[cic].ic_reg.cell_channels; channel++) {
00996                         if (ic[cic].cells.c_codes[channel] != expected_result) {
00997                             error = error+1;
00998                         }
00999                     }
01000                 }
01001                 break;
01002             case AUX:
01003                 error = 0;
01004                 wakeup_idle(total_ic);
01005                 LTC681x_clraux();
01006                 LTC681x_axst(2,self_test);
01007                 LTC681x_pollAdc();
01008                 delay_m(10);
01009                 wakeup_idle(total_ic);
01010                 LTC681x_rdaux(0, total_ic,ic);
01011                 for (int cic = 0; cic < total_ic; cic++) {
01012                     for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
01013                         if (ic[cic].aux.a_codes[channel] != expected_result) {
01014                             error = error+1;
01015                         }
01016                     }
01017                 }
01018                 break;
01019             case STAT:
01020                 wakeup_idle(total_ic);
01021                 LTC681x_clrstat();
01022                 LTC681x_statst(2,self_test);
01023                 LTC681x_pollAdc();
01024                 wakeup_idle(total_ic);
01025                 error = LTC681x_rdstat(0,total_ic,ic);
01026                 for (int cic = 0; cic < total_ic; cic++) {
01027                     for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
01028                         if (ic[cic].stat.stat_codes[channel] != expected_result) {
01029                             error = error+1;
01030                         }
01031                     }
01032                 }
01033                 break;
01034 
01035             default:
01036                 error = -1;
01037                 break;
01038         }
01039     }
01040     return(error);
01041 }
01042 
01043 //runs the redundancy self test
01044 int16_t LTC681x_run_adc_redundancy_st(uint8_t adc_mode, uint8_t adc_reg, uint8_t total_ic, cell_asic ic[])
01045 {
01046     int16_t error = 0;
01047     for (int self_test = 1; self_test<3; self_test++) {
01048         wakeup_idle(total_ic);
01049         switch (adc_reg) {
01050             case AUX:
01051                 LTC681x_clraux();
01052                 LTC681x_adaxd(adc_mode,AUX_CH_ALL);
01053                 LTC681x_pollAdc();
01054                 wakeup_idle(total_ic);
01055                 error = LTC681x_rdaux(0, total_ic,ic);
01056                 for (int cic = 0; cic < total_ic; cic++) {
01057                     for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
01058                         if (ic[cic].aux.a_codes[channel] >= 65280) {
01059                             error = error+1;
01060                         }
01061                     }
01062                 }
01063                 break;
01064             case STAT:
01065                 LTC681x_clrstat();
01066                 LTC681x_adstatd(adc_mode,STAT_CH_ALL);
01067                 LTC681x_pollAdc();
01068                 wakeup_idle(total_ic);
01069                 error = LTC681x_rdstat(0,total_ic,ic);
01070                 for (int cic = 0; cic < total_ic; cic++) {
01071                     for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
01072                         if (ic[cic].stat.stat_codes[channel] >= 65280) {
01073                             error = error+1;
01074                         }
01075                     }
01076                 }
01077                 break;
01078 
01079             default:
01080                 error = -1;
01081                 break;
01082         }
01083     }
01084     return(error);
01085 }
01086 
01087 //Runs the datasheet algorithm for open wire
01088 void LTC681x_run_openwire(uint8_t total_ic, cell_asic ic[])
01089 {
01090     uint16_t OPENWIRE_THRESHOLD = 4000;
01091     const uint8_t  N_CHANNELS = ic[0].ic_reg.cell_channels;
01092 
01093     cell_asic pullUp_cell_codes[total_ic];
01094     cell_asic pullDwn_cell_codes[total_ic];
01095     cell_asic openWire_delta[total_ic];
01096     int8_t error;
01097 
01098     wakeup_sleep(total_ic);
01099     LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
01100     LTC681x_pollAdc();
01101     wakeup_idle(total_ic);
01102     LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
01103     LTC681x_pollAdc();
01104     wakeup_idle(total_ic);
01105     error = LTC681x_rdcv(0, total_ic,pullUp_cell_codes);
01106 
01107     wakeup_idle(total_ic);
01108     LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
01109     LTC681x_pollAdc();
01110     wakeup_idle(total_ic);
01111     LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
01112     LTC681x_pollAdc();
01113     wakeup_idle(total_ic);
01114     error = LTC681x_rdcv(0, total_ic,pullDwn_cell_codes);
01115 
01116     for (int cic=0; cic<total_ic; cic++) {
01117         ic[cic].system_open_wire =0;
01118         for (int cell=0; cell<N_CHANNELS; cell++) {
01119             if (pullDwn_cell_codes[cic].cells.c_codes[cell]>pullUp_cell_codes[cic].cells.c_codes[cell]) {
01120                 openWire_delta[cic].cells.c_codes[cell] = pullDwn_cell_codes[cic].cells.c_codes[cell] - pullUp_cell_codes[cic].cells.c_codes[cell]  ;
01121             } else {
01122                 openWire_delta[cic].cells.c_codes[cell] = 0;
01123             }
01124 
01125         }
01126     }
01127     for (int cic=0; cic<total_ic; cic++) {
01128         for (int cell=1; cell<N_CHANNELS; cell++) {
01129 
01130             if (openWire_delta[cic].cells.c_codes[cell]>OPENWIRE_THRESHOLD) {
01131                 ic[cic].system_open_wire += (1<<cell);
01132 
01133             }
01134         }
01135         if (pullUp_cell_codes[cic].cells.c_codes[0] == 0) {
01136             ic[cic].system_open_wire += 1;
01137         }
01138         if (pullUp_cell_codes[cic].cells.c_codes[N_CHANNELS-1] == 0) {
01139             ic[cic].system_open_wire += (1<<(N_CHANNELS));
01140         }
01141     }
01142 }
01143 
01144 // Runs the ADC overlap test for the IC
01145 uint16_t LTC681x_run_adc_overlap(uint8_t total_ic, cell_asic ic[])
01146 {
01147     uint16_t error = 0;
01148     int32_t measure_delta =0;
01149     int16_t failure_pos_limit = 20;
01150     int16_t failure_neg_limit = -20;
01151     wakeup_idle(total_ic);
01152     LTC681x_adol(MD_7KHZ_3KHZ,DCP_DISABLED);
01153     LTC681x_pollAdc();
01154     wakeup_idle(total_ic);
01155     error = LTC681x_rdcv(0, total_ic,ic);
01156     for (int cic = 0; cic<total_ic; cic++) {
01157         measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
01158         if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit)) {
01159             error = error | (1<<(cic-1));
01160         }
01161     }
01162     return(error);
01163 }
01164 
01165 //Helper function that increments PEC counters
01166 void LTC681x_check_pec(uint8_t total_ic,uint8_t reg, cell_asic ic[])
01167 {
01168     switch (reg) {
01169         case CFGR:
01170             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01171                 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].config.rx_pec_match;
01172                 ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].config.rx_pec_match;
01173             }
01174             break;
01175 
01176         case CFGRB:
01177             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01178                 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].configb.rx_pec_match;
01179                 ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].configb.rx_pec_match;
01180             }
01181             break;
01182         case CELL:
01183             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01184                 for (int i=0; i<ic[0].ic_reg.num_cv_reg; i++) {
01185                     ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].cells.pec_match[i];
01186                     ic[current_ic].crc_count.cell_pec[i] = ic[current_ic].crc_count.cell_pec[i] + ic[current_ic].cells.pec_match[i];
01187                 }
01188             }
01189             break;
01190         case AUX:
01191             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01192                 for (int i=0; i<ic[0].ic_reg.num_gpio_reg; i++) {
01193                     ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + (ic[current_ic].aux.pec_match[i]);
01194                     ic[current_ic].crc_count.aux_pec[i] = ic[current_ic].crc_count.aux_pec[i] + (ic[current_ic].aux.pec_match[i]);
01195                 }
01196             }
01197 
01198             break;
01199         case STAT:
01200             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01201 
01202                 for (int i=0; i<ic[0].ic_reg.num_stat_reg-1; i++) {
01203                     ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].stat.pec_match[i];
01204                     ic[current_ic].crc_count.stat_pec[i] = ic[current_ic].crc_count.stat_pec[i] + ic[current_ic].stat.pec_match[i];
01205                 }
01206             }
01207             break;
01208         default:
01209             break;
01210     }
01211 }
01212 
01213 //Helper Function to reset PEC counters
01214 void LTC681x_reset_crc_count(uint8_t total_ic, cell_asic ic[])
01215 {
01216     for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01217         ic[current_ic].crc_count.pec_count = 0;
01218         ic[current_ic].crc_count.cfgr_pec = 0;
01219         for (int i=0; i<6; i++) {
01220             ic[current_ic].crc_count.cell_pec[i]=0;
01221 
01222         }
01223         for (int i=0; i<4; i++) {
01224             ic[current_ic].crc_count.aux_pec[i]=0;
01225         }
01226         for (int i=0; i<2; i++) {
01227             ic[current_ic].crc_count.stat_pec[i]=0;
01228         }
01229     }
01230 }
01231 
01232 //Helper function to intialize CFG variables.
01233 void LTC681x_init_cfg(uint8_t total_ic, cell_asic ic[])
01234 {
01235     bool REFON = true;
01236     bool ADCOPT = false;
01237     bool gpioBits[5] = {true,true,true,true,true};
01238     bool dccBits[12] = {false,false,false,false,false,false,false,false,false,false,false,false};
01239     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01240         for (int j =0; j<6; j++) {
01241             ic[current_ic].config.tx_data[j] = 0;
01242             ic[current_ic].configb.tx_data[j] = 0;
01243         }
01244         LTC681x_set_cfgr(current_ic ,ic,REFON,ADCOPT,gpioBits,dccBits);
01245 
01246     }
01247 }
01248 
01249 //Helper function to set CFGR variable
01250 void LTC681x_set_cfgr(uint8_t nIC, cell_asic ic[], bool refon, bool adcopt, bool gpio[5],bool dcc[12])
01251 {
01252     LTC681x_set_cfgr_refon(nIC,ic,refon);
01253     LTC681x_set_cfgr_adcopt(nIC,ic,adcopt);
01254     LTC681x_set_cfgr_gpio(nIC,ic,gpio);
01255     LTC681x_set_cfgr_dis(nIC,ic,dcc);
01256 }
01257 
01258 //Helper function to set the REFON bit
01259 void LTC681x_set_cfgr_refon(uint8_t nIC, cell_asic ic[], bool refon)
01260 {
01261     if (refon) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|0x04;
01262     else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&0xFB;
01263 }
01264 
01265 //Helper function to set the adcopt bit
01266 void LTC681x_set_cfgr_adcopt(uint8_t nIC, cell_asic ic[], bool adcopt)
01267 {
01268     if (adcopt) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|0x01;
01269     else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&0xFE;
01270 }
01271 
01272 //Helper function to set GPIO bits
01273 void LTC681x_set_cfgr_gpio(uint8_t nIC, cell_asic ic[],bool gpio[5])
01274 {
01275     for (int i =0; i<5; i++) {
01276         if (gpio[i])ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|(0x01<<(i+3));
01277         else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&(~(0x01<<(i+3)));
01278     }
01279 }
01280 
01281 //Helper function to control discharge
01282 void LTC681x_set_cfgr_dis(uint8_t nIC, cell_asic ic[],bool dcc[12])
01283 {
01284     for (int i =0; i<8; i++) {
01285         if (dcc[i])ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4]|(0x01<<i);
01286         else ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4]& (~(0x01<<i));
01287     }
01288     for (int i =0; i<4; i++) {
01289         if (dcc[i+8])ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5]|(0x01<<i);
01290         else ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5]&(~(0x01<<i));
01291     }
01292 }
01293 
01294 //Helper Function to set uv value in CFG register
01295 void LTC681x_set_cfgr_uv(uint8_t nIC, cell_asic ic[],uint16_t uv)
01296 {
01297     uint16_t tmp = (uv/16)-1;
01298     ic[nIC].config.tx_data[1] = 0x00FF & tmp;
01299     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0xF0;
01300     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x0F00 & tmp)>>8);
01301 }
01302 
01303 //helper function to set OV value in CFG register
01304 void LTC681x_set_cfgr_ov(uint8_t nIC, cell_asic ic[],uint16_t ov)
01305 {
01306     uint16_t tmp = (ov/16);
01307     ic[nIC].config.tx_data[3] = 0x00FF & (tmp>>4);
01308     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0x0F;
01309     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x000F & tmp)<<4);
01310 }
01311 
01312 //Writes the comm register
01313 void LTC681x_wrcomm(uint8_t total_ic, //The number of ICs being written to
01314                     cell_asic ic[]
01315                    )
01316 {
01317     uint8_t cmd[2]= {0x07 , 0x21};
01318     uint8_t write_buffer[256];
01319     uint8_t write_count = 0;
01320     uint8_t c_ic = 0;
01321     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01322         if (ic->isospi_reverse == true) {
01323             c_ic = current_ic;
01324         } else {
01325             c_ic = total_ic - current_ic - 1;
01326         }
01327 
01328         for (uint8_t data = 0; data<6; data++) {
01329             write_buffer[write_count] = ic[c_ic].com.tx_data[data];
01330             write_count++;
01331         }
01332     }
01333     write_68(total_ic, cmd, write_buffer);
01334 }
01335 
01336 /*
01337 Reads COMM registers of a LTC6811 daisy chain
01338 */
01339 int8_t LTC681x_rdcomm(uint8_t total_ic, //Number of ICs in the system
01340                       cell_asic ic[]
01341                      )
01342 {
01343     uint8_t cmd[2]= {0x07 , 0x22};
01344     uint8_t read_buffer[256];
01345     int8_t pec_error = 0;
01346     uint16_t data_pec;
01347     uint16_t calc_pec;
01348     uint8_t c_ic=0;
01349     pec_error = read_68(total_ic, cmd, read_buffer);
01350     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01351         if (ic->isospi_reverse == false) {
01352             c_ic = current_ic;
01353         } else {
01354             c_ic = total_ic - current_ic - 1;
01355         }
01356 
01357         for (int byte=0; byte<8; byte++) {
01358             ic[c_ic].com.rx_data[byte] = read_buffer[byte+(8*current_ic)];
01359         }
01360         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
01361         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
01362         if (calc_pec != data_pec ) {
01363             ic[c_ic].com.rx_pec_match = 1;
01364         } else ic[c_ic].com.rx_pec_match = 0;
01365     }
01366     return(pec_error);
01367 }
01368 
01369 /*
01370 Shifts data in COMM register out over LTC6811 SPI/I2C port
01371 */
01372 void LTC681x_stcomm()
01373 {
01374 
01375     uint8_t cmd[4];
01376     uint16_t cmd_pec;
01377 
01378     cmd[0] = 0x07;
01379     cmd[1] = 0x23;
01380     cmd_pec = pec15_calc(2, cmd);
01381     cmd[2] = (uint8_t)(cmd_pec >> 8);
01382     cmd[3] = (uint8_t)(cmd_pec);
01383 
01384     cs_low();
01385     spi_write_array(4,cmd);
01386     for (int i = 0; i<9; i++) {
01387         spi_read_byte(0xFF);
01388     }
01389     cs_high();
01390 
01391 }
01392 
01393 // Writes the pwm register
01394 void LTC681x_wrpwm(uint8_t total_ic,
01395                    uint8_t pwmReg,
01396                    cell_asic ic[]
01397                   )
01398 {
01399     uint8_t cmd[2];
01400     uint8_t write_buffer[256];
01401     uint8_t write_count = 0;
01402     uint8_t c_ic = 0;
01403     if (pwmReg == 0) {
01404         cmd[0] = 0x00;
01405         cmd[1] = 0x20;
01406     } else {
01407         cmd[0] = 0x00;
01408         cmd[1] = 0x1C;
01409     }
01410 
01411     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01412         if (ic->isospi_reverse == true) {
01413             c_ic = current_ic;
01414         } else {
01415             c_ic = total_ic - current_ic - 1;
01416         }
01417         for (uint8_t data = 0; data<6; data++) {
01418             write_buffer[write_count] = ic[c_ic].pwm.tx_data[data];
01419             write_count++;
01420         }
01421     }
01422     write_68(total_ic, cmd, write_buffer);
01423 }
01424 
01425 
01426 /*
01427 Reads pwm registers of a LTC6811 daisy chain
01428 */
01429 int8_t LTC681x_rdpwm(uint8_t total_ic, //Number of ICs in the system
01430                      uint8_t pwmReg,
01431                      cell_asic ic[]
01432                     )
01433 {
01434 //    const uint8_t BYTES_IN_REG = 8;
01435 
01436     uint8_t cmd[4];
01437     uint8_t read_buffer[256];
01438     int8_t pec_error = 0;
01439     uint16_t data_pec;
01440     uint16_t calc_pec;
01441     uint8_t c_ic = 0;
01442 
01443     if (pwmReg == 0) {
01444         cmd[0] = 0x00;
01445         cmd[1] = 0x22;
01446     } else {
01447         cmd[0] = 0x00;
01448         cmd[1] = 0x1E;
01449     }
01450 
01451 
01452     pec_error = read_68(total_ic, cmd, read_buffer);
01453     for (uint8_t current_ic =0; current_ic<total_ic; current_ic++) {
01454         if (ic->isospi_reverse == false) {
01455             c_ic = current_ic;
01456         } else {
01457             c_ic = total_ic - current_ic - 1;
01458         }
01459         for (int byte=0; byte<8; byte++) {
01460             ic[c_ic].pwm.rx_data[byte] = read_buffer[byte+(8*current_ic)];
01461         }
01462         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
01463         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
01464         if (calc_pec != data_pec ) {
01465             ic[c_ic].pwm.rx_pec_match = 1;
01466         } else ic[c_ic].pwm.rx_pec_match = 0;
01467     }
01468     return(pec_error);
01469 }