KIT Solar Car Project / Mbed OS BMS_3029

Dependencies:   INA226

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++) {                 //
00627         
00628             LTC681x_rdcv_reg(cell_reg, total_ic,cell_data );
00629             for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00630                 if (ic->isospi_reverse == false) {
00631                     c_ic = current_ic;
00632                 } else {
00633                     c_ic = total_ic - current_ic - 1;
00634                 }
00635                 pec_error = pec_error + parse_cells(current_ic,cell_reg, cell_data,
00636                                                     &ic[c_ic].cells.c_codes[0],
00637                                                     &ic[c_ic].cells.pec_match[0]);
00638             }
00639         }
00640     }
00641 
00642     else {
00643         LTC681x_rdcv_reg(reg, total_ic,cell_data);
00644 
00645         for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00646             if (ic->isospi_reverse == false) {
00647                 c_ic = current_ic;
00648             } else {
00649                 c_ic = total_ic - current_ic - 1;
00650             }
00651             pec_error = pec_error + parse_cells(current_ic,reg, &cell_data[8*c_ic],
00652                                                 &ic[c_ic].cells.c_codes[0],
00653                                                 &ic[c_ic].cells.pec_match[0]);
00654         }
00655     }
00656     LTC681x_check_pec(total_ic,CELL,ic);
00657     free(cell_data);
00658     return(pec_error);
00659 }
00660 
00661 
00662 
00663 /*
00664 The function is used
00665 to read the  parsed GPIO codes of the LTC6811. This function will send the requested
00666 read commands parse the data and store the gpio voltages in aux_codes variable
00667 */
00668 int8_t LTC681x_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
00669                      uint8_t total_ic,//the number of ICs in the system
00670                      cell_asic ic[]//A two dimensional array of the gpio voltage codes.
00671                     )
00672 {
00673     uint8_t *data;
00674     int8_t pec_error = 0;
00675     uint8_t c_ic =0;
00676     data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
00677 
00678     if (reg == 0) {
00679         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
00680             LTC681x_rdaux_reg(gpio_reg, total_ic,data);                 //Reads the raw auxiliary register data into the data[] array
00681             for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00682                 if (ic->isospi_reverse == false) {
00683                     c_ic = current_ic;
00684                 } else {
00685                     c_ic = total_ic - current_ic - 1;
00686                 }
00687                 pec_error = parse_cells(current_ic,gpio_reg, data,
00688                                         &ic[c_ic].aux.a_codes[0],
00689                                         &ic[c_ic].aux.pec_match[0]);
00690 
00691             }
00692         }
00693     } else {
00694         LTC681x_rdaux_reg(reg, total_ic, data);
00695 
00696         for (int current_ic = 0; current_ic<total_ic; current_ic++) {
00697             if (ic->isospi_reverse == false) {
00698                 c_ic = current_ic;
00699             } else {
00700                 c_ic = total_ic - current_ic - 1;
00701             }
00702             pec_error = parse_cells(current_ic,reg, data,
00703                                     &ic[c_ic].aux.a_codes[0],
00704                                     &ic[c_ic].aux.pec_match[0]);
00705         }
00706 
00707     }
00708     LTC681x_check_pec(total_ic,AUX,ic);
00709     free(data);
00710     return (pec_error);
00711 }
00712 
00713 // Reads and parses the LTC681x stat registers.
00714 int8_t LTC681x_rdstat(uint8_t reg, //Determines which Stat  register is read back.
00715                       uint8_t total_ic,//the number of ICs in the system
00716                       cell_asic ic[]
00717                      )
00718 
00719 {
00720 
00721     const uint8_t BYT_IN_REG = 6;
00722     const uint8_t GPIO_IN_REG = 3;
00723 
00724     uint8_t *data;
00725     uint8_t data_counter = 0;
00726     int8_t pec_error = 0;
00727     uint16_t parsed_stat;
00728     uint16_t received_pec;
00729     uint16_t data_pec;
00730     uint8_t c_ic = 0;
00731     data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
00732 
00733     if (reg == 0) {
00734 
00735         for (uint8_t stat_reg = 1; stat_reg< 3; stat_reg++) {                    //executes once for each of the LTC6811 stat voltage registers
00736             data_counter = 0;
00737             LTC681x_rdstat_reg(stat_reg, total_ic,data);                            //Reads the raw statiliary register data into the data[] array
00738 
00739             for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) {    // executes for every LTC6811 in the daisy chain
00740                 if (ic->isospi_reverse == false) {
00741                     c_ic = current_ic;
00742                 } else {
00743                     c_ic = total_ic - current_ic - 1;
00744                 }
00745                 // current_ic is used as the IC counter
00746                 if (stat_reg ==1) {
00747                     for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
00748                         // loops once for each of the 3 gpio voltage codes in the register
00749 
00750                         parsed_stat = data[data_counter] + (data[data_counter+1]<<8);              //Each gpio codes is received as two bytes and is combined to
00751                         ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
00752                         data_counter=data_counter+2;                                               //Because gpio voltage codes are two bytes the data counter
00753 
00754                     }
00755                 } else if (stat_reg == 2) {
00756                     parsed_stat = data[data_counter] + (data[data_counter+1]<<8);              //Each gpio codes is received as two bytes and is combined to
00757                     data_counter = data_counter +2;
00758                     ic[c_ic].stat.stat_codes[3] = parsed_stat;
00759                     ic[c_ic].stat.flags[0] = data[data_counter++];
00760                     ic[c_ic].stat.flags[1] = data[data_counter++];
00761                     ic[c_ic].stat.flags[2] = data[data_counter++];
00762                     ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
00763                     ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
00764                 }
00765 
00766                 received_pec = (data[data_counter]<<8)+ data[data_counter+1];          //The received PEC for the current_ic is transmitted as the 7th and 8th
00767                 //after the 6 gpio voltage data bytes
00768                 data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
00769 
00770                 if (received_pec != data_pec) {
00771                     pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
00772                     ic[c_ic].stat.pec_match[stat_reg-1]=1;
00773                     //are detected in the received serial data
00774                 } else {
00775                     ic[c_ic].stat.pec_match[stat_reg-1]=0;
00776                 }
00777 
00778                 data_counter=data_counter+2;                        //Because the transmitted PEC code is 2 bytes long the data_counter
00779                 //must be incremented by 2 bytes to point to the next ICs gpio voltage data
00780             }
00781 
00782 
00783         }
00784 
00785     } else {
00786 
00787         LTC681x_rdstat_reg(reg, total_ic, data);
00788         for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {          // executes for every LTC6811 in the daisy chain
00789             // current_ic is used as an IC counter
00790             if (ic->isospi_reverse == false) {
00791                 c_ic = current_ic;
00792             } else {
00793                 c_ic = total_ic - current_ic - 1;
00794             }
00795             if (reg ==1) {
00796                 for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
00797                     // loops once for each of the 3 gpio voltage codes in the register
00798                     parsed_stat = data[data_counter] + (data[data_counter+1]<<8);              //Each gpio codes is received as two bytes and is combined to
00799                     // create the parsed gpio voltage code
00800 
00801                     ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
00802                     data_counter=data_counter+2;                        //Because gpio voltage codes are two bytes the data counter
00803                     //must increment by two for each parsed gpio voltage code
00804 
00805                 }
00806             } else if (reg == 2) {
00807                 parsed_stat = data[data_counter++] + (data[data_counter++]<<8);              //Each gpio codes is received as two bytes and is combined to
00808                 ic[c_ic].stat.stat_codes[3] = parsed_stat;
00809                 ic[c_ic].stat.flags[0] = data[data_counter++];
00810                 ic[c_ic].stat.flags[1] = data[data_counter++];
00811                 ic[c_ic].stat.flags[2] = data[data_counter++];
00812                 ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
00813                 ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
00814             }
00815 
00816 
00817             received_pec = (data[data_counter]<<8)+ data[data_counter+1];          //The received PEC for the current_ic is transmitted as the 7th and 8th
00818             //after the 6 gpio voltage data bytes
00819             data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
00820             if (received_pec != data_pec) {
00821                 pec_error = -1;                             //The pec_error variable is simply set negative if any PEC errors
00822                 ic[c_ic].stat.pec_match[reg-1]=1;
00823 
00824             }
00825 
00826             data_counter=data_counter+2;
00827         }
00828     }
00829     LTC681x_check_pec(total_ic,STAT,ic);
00830     free(data);
00831     return (pec_error);
00832 }
00833 
00834 //Write the LTC681x CFGRA
00835 void LTC681x_wrcfg(uint8_t total_ic, //The number of ICs being written to
00836                    cell_asic ic[]
00837                   )
00838 {
00839     uint8_t cmd[2] = {0x00 , 0x01} ;
00840     uint8_t write_buffer[256];
00841     uint8_t write_count = 0;
00842     uint8_t c_ic = 0;
00843     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00844         if (ic->isospi_reverse == true) {
00845             c_ic = current_ic;
00846         } else {
00847             c_ic = total_ic - current_ic - 1;
00848         }
00849 
00850         for (uint8_t data = 0; data<6; data++) {
00851             write_buffer[write_count] = ic[c_ic].config.tx_data[data];
00852             write_count++;
00853         }
00854     }
00855     write_68(total_ic, cmd, write_buffer);
00856 }
00857 
00858 //Write the LTC681x CFGRB
00859 void LTC681x_wrcfgb(uint8_t total_ic, //The number of ICs being written to
00860                     cell_asic ic[]
00861                    )
00862 {
00863     uint8_t cmd[2] = {0x00 , 0x24} ;
00864     uint8_t write_buffer[256];
00865     uint8_t write_count = 0;
00866     uint8_t c_ic = 0;
00867     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00868         if (ic->isospi_reverse == true) {
00869             c_ic = current_ic;
00870         } else {
00871             c_ic = total_ic - current_ic - 1;
00872         }
00873 
00874         for (uint8_t data = 0; data<6; data++) {
00875             write_buffer[write_count] = ic[c_ic].configb.tx_data[data];
00876             write_count++;
00877         }
00878     }
00879     write_68(total_ic, cmd, write_buffer);
00880 }
00881 
00882 //Read CFGA
00883 int8_t LTC681x_rdcfg(uint8_t total_ic, //Number of ICs in the system
00884                      cell_asic ic[]
00885                     )
00886 {
00887     uint8_t cmd[2]= {0x00 , 0x02};
00888     uint8_t read_buffer[256];
00889     int8_t pec_error = 0;
00890     uint16_t data_pec;
00891     uint16_t calc_pec;
00892     uint8_t c_ic = 0;
00893     pec_error = read_68(total_ic, cmd, read_buffer);
00894     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00895         if (ic->isospi_reverse == false) {
00896             c_ic = current_ic;
00897         } else {
00898             c_ic = total_ic - current_ic - 1;
00899         }
00900 
00901         for (int byte=0; byte<8; byte++) {
00902             ic[c_ic].config.rx_data[byte] = read_buffer[byte+(8*current_ic)];
00903         }
00904         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
00905         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
00906         if (calc_pec != data_pec ) {
00907             ic[c_ic].config.rx_pec_match = 1;
00908         } else ic[c_ic].config.rx_pec_match = 0;
00909     }
00910     LTC681x_check_pec(total_ic,CFGR,ic);
00911     return(pec_error);
00912 }
00913 
00914 //Reads CFGB
00915 int8_t LTC681x_rdcfgb(uint8_t total_ic, //Number of ICs in the system
00916                       cell_asic ic[]
00917                      )
00918 {
00919     uint8_t cmd[2]= {0x00 , 0x26};
00920     uint8_t read_buffer[256];
00921     int8_t pec_error = 0;
00922     uint16_t data_pec;
00923     uint16_t calc_pec;
00924     uint8_t c_ic = 0;
00925     pec_error = read_68(total_ic, cmd, read_buffer);
00926     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
00927         if (ic->isospi_reverse == false) {
00928             c_ic = current_ic;
00929         } else {
00930             c_ic = total_ic - current_ic - 1;
00931         }
00932 
00933         for (int byte=0; byte<8; byte++) {
00934             ic[c_ic].configb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
00935         }
00936         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
00937         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
00938         if (calc_pec != data_pec ) {
00939             ic[c_ic].configb.rx_pec_match = 1;
00940         } else ic[c_ic].configb.rx_pec_match = 0;
00941     }
00942     LTC681x_check_pec(total_ic,CFGRB,ic);
00943     return(pec_error);
00944 }
00945 
00946 //Looks up the result pattern for digital filter self test
00947 uint16_t LTC681x_st_lookup(
00948     uint8_t MD, //ADC Mode
00949     uint8_t ST //Self Test
00950 )
00951 {
00952     uint16_t test_pattern = 0;
00953     if (MD == 1) {
00954         if (ST == 1) {
00955             test_pattern = 0x9565;
00956         } else {
00957             test_pattern = 0x6A9A;
00958         }
00959     } else {
00960         if (ST == 1) {
00961             test_pattern = 0x9555;
00962         } else {
00963             test_pattern = 0x6AAA;
00964         }
00965     }
00966     return(test_pattern);
00967 }
00968 
00969 //Clears all of the DCC bits in the configuration registers
00970 void clear_discharge(uint8_t total_ic, cell_asic ic[])
00971 {
00972     for (int i=0; i<total_ic; i++) {
00973         ic[i].config.tx_data[4] = 0;
00974         ic[i].config.tx_data[5] = 0;
00975     }
00976 }
00977 
00978 // Runs the Digital Filter Self Test
00979 int16_t LTC681x_run_cell_adc_st(uint8_t adc_reg,uint8_t total_ic, cell_asic ic[])
00980 {
00981     int16_t error = 0;
00982     uint16_t expected_result = 0;
00983     for (int self_test = 1; self_test<3; self_test++) {
00984 
00985         expected_result = LTC681x_st_lookup(2,self_test);
00986         wakeup_idle(total_ic);
00987         switch (adc_reg) {
00988             case CELL:
00989                 wakeup_idle(total_ic);
00990                 LTC681x_clrcell();
00991                 LTC681x_cvst(2,self_test);
00992                 LTC681x_pollAdc();//this isn't working
00993                 wakeup_idle(total_ic);
00994                 error = LTC681x_rdcv(0, total_ic,ic);
00995                 for (int cic = 0; cic < total_ic; cic++) {
00996                     for (int channel=0; channel< ic[cic].ic_reg.cell_channels; channel++) {
00997                         if (ic[cic].cells.c_codes[channel] != expected_result) {
00998                             error = error+1;
00999                         }
01000                     }
01001                 }
01002                 break;
01003             case AUX:
01004                 error = 0;
01005                 wakeup_idle(total_ic);
01006                 LTC681x_clraux();
01007                 LTC681x_axst(2,self_test);
01008                 LTC681x_pollAdc();
01009                 delay_m(10);
01010                 wakeup_idle(total_ic);
01011                 LTC681x_rdaux(0, total_ic,ic);
01012                 for (int cic = 0; cic < total_ic; cic++) {
01013                     for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
01014                         if (ic[cic].aux.a_codes[channel] != expected_result) {
01015                             error = error+1;
01016                         }
01017                     }
01018                 }
01019                 break;
01020             case STAT:
01021                 wakeup_idle(total_ic);
01022                 LTC681x_clrstat();
01023                 LTC681x_statst(2,self_test);
01024                 LTC681x_pollAdc();
01025                 wakeup_idle(total_ic);
01026                 error = LTC681x_rdstat(0,total_ic,ic);
01027                 for (int cic = 0; cic < total_ic; cic++) {
01028                     for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
01029                         if (ic[cic].stat.stat_codes[channel] != expected_result) {
01030                             error = error+1;
01031                         }
01032                     }
01033                 }
01034                 break;
01035 
01036             default:
01037                 error = -1;
01038                 break;
01039         }
01040     }
01041     return(error);
01042 }
01043 
01044 //runs the redundancy self test
01045 int16_t LTC681x_run_adc_redundancy_st(uint8_t adc_mode, uint8_t adc_reg, uint8_t total_ic, cell_asic ic[])
01046 {
01047     int16_t error = 0;
01048     for (int self_test = 1; self_test<3; self_test++) {
01049         wakeup_idle(total_ic);
01050         switch (adc_reg) {
01051             case AUX:
01052                 LTC681x_clraux();
01053                 LTC681x_adaxd(adc_mode,AUX_CH_ALL);
01054                 LTC681x_pollAdc();
01055                 wakeup_idle(total_ic);
01056                 error = LTC681x_rdaux(0, total_ic,ic);
01057                 for (int cic = 0; cic < total_ic; cic++) {
01058                     for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
01059                         if (ic[cic].aux.a_codes[channel] >= 65280) {
01060                             error = error+1;
01061                         }
01062                     }
01063                 }
01064                 break;
01065             case STAT:
01066                 LTC681x_clrstat();
01067                 LTC681x_adstatd(adc_mode,STAT_CH_ALL);
01068                 LTC681x_pollAdc();
01069                 wakeup_idle(total_ic);
01070                 error = LTC681x_rdstat(0,total_ic,ic);
01071                 for (int cic = 0; cic < total_ic; cic++) {
01072                     for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
01073                         if (ic[cic].stat.stat_codes[channel] >= 65280) {
01074                             error = error+1;
01075                         }
01076                     }
01077                 }
01078                 break;
01079 
01080             default:
01081                 error = -1;
01082                 break;
01083         }
01084     }
01085     return(error);
01086 }
01087 
01088 //Runs the datasheet algorithm for open wire //オープンワイヤに対してデータシートアルゴリズムを実行します
01089 void LTC681x_run_openwire(uint8_t total_ic, cell_asic ic[])
01090 {
01091     uint16_t OPENWIRE_THRESHOLD = 4000;
01092     const uint8_t  N_CHANNELS = ic[0].ic_reg.cell_channels;
01093 
01094     cell_asic pullUp_cell_codes[total_ic];
01095     cell_asic pullDwn_cell_codes[total_ic];
01096     cell_asic openWire_delta[total_ic];
01097     int8_t error;
01098 
01099     wakeup_sleep(total_ic);
01100     LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
01101     LTC681x_pollAdc();
01102     wakeup_idle(total_ic);
01103     LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
01104     LTC681x_pollAdc();
01105     wakeup_idle(total_ic);
01106     error = LTC681x_rdcv(0, total_ic,pullUp_cell_codes);
01107 
01108     wakeup_idle(total_ic);
01109     LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
01110     LTC681x_pollAdc();
01111     wakeup_idle(total_ic);
01112     LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
01113     LTC681x_pollAdc();
01114     wakeup_idle(total_ic);
01115     error = LTC681x_rdcv(0, total_ic,pullDwn_cell_codes);
01116 
01117     for (int cic=0; cic<total_ic; cic++) {
01118         ic[cic].system_open_wire =0;
01119         for (int cell=0; cell<N_CHANNELS; cell++) {
01120             if (pullDwn_cell_codes[cic].cells.c_codes[cell]>pullUp_cell_codes[cic].cells.c_codes[cell]) {
01121                 openWire_delta[cic].cells.c_codes[cell] = pullDwn_cell_codes[cic].cells.c_codes[cell] - pullUp_cell_codes[cic].cells.c_codes[cell]  ;
01122             } else {
01123                 openWire_delta[cic].cells.c_codes[cell] = 0;
01124             }
01125 
01126         }
01127     }
01128     for (int cic=0; cic<total_ic; cic++) {
01129         for (int cell=1; cell<N_CHANNELS; cell++) {
01130 
01131             if (openWire_delta[cic].cells.c_codes[cell]>OPENWIRE_THRESHOLD) {
01132                 ic[cic].system_open_wire += (1<<cell);
01133 
01134             }
01135         }
01136         if (pullUp_cell_codes[cic].cells.c_codes[0] == 0) {
01137             ic[cic].system_open_wire += 1;
01138         }
01139         if (pullUp_cell_codes[cic].cells.c_codes[N_CHANNELS-1] == 0) {
01140             ic[cic].system_open_wire += (1<<(N_CHANNELS));
01141         }
01142     }
01143 }
01144 
01145 // Runs the ADC overlap test for the IC
01146 uint16_t LTC681x_run_adc_overlap(uint8_t total_ic, cell_asic ic[])
01147 {
01148     uint16_t error = 0;
01149     int32_t measure_delta =0;
01150     int16_t failure_pos_limit = 20;
01151     int16_t failure_neg_limit = -20;
01152     wakeup_idle(total_ic);
01153     LTC681x_adol(MD_7KHZ_3KHZ,DCP_DISABLED);
01154     LTC681x_pollAdc();
01155     wakeup_idle(total_ic);
01156     error = LTC681x_rdcv(0, total_ic,ic);
01157     for (int cic = 0; cic<total_ic; cic++) {
01158         measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
01159         if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit)) {
01160             error = error | (1<<(cic-1));
01161         }
01162     }
01163     return(error);
01164 }
01165 
01166 //Helper function that increments PEC counters
01167 void LTC681x_check_pec(uint8_t total_ic,uint8_t reg, cell_asic ic[])
01168 {
01169     switch (reg) {
01170         case CFGR:
01171             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01172                 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].config.rx_pec_match;
01173                 ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].config.rx_pec_match;
01174             }
01175             break;
01176 
01177         case CFGRB:
01178             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01179                 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].configb.rx_pec_match;
01180                 ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].configb.rx_pec_match;
01181             }
01182             break;
01183         case CELL:
01184             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01185                 for (int i=0; i<ic[0].ic_reg.num_cv_reg; i++) {
01186                     ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].cells.pec_match[i];
01187                     ic[current_ic].crc_count.cell_pec[i] = ic[current_ic].crc_count.cell_pec[i] + ic[current_ic].cells.pec_match[i];
01188                 }
01189             }
01190             break;
01191         case AUX:
01192             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01193                 for (int i=0; i<ic[0].ic_reg.num_gpio_reg; i++) {
01194                     ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + (ic[current_ic].aux.pec_match[i]);
01195                     ic[current_ic].crc_count.aux_pec[i] = ic[current_ic].crc_count.aux_pec[i] + (ic[current_ic].aux.pec_match[i]);
01196                 }
01197             }
01198 
01199             break;
01200         case STAT:
01201             for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01202 
01203                 for (int i=0; i<ic[0].ic_reg.num_stat_reg-1; i++) {
01204                     ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].stat.pec_match[i];
01205                     ic[current_ic].crc_count.stat_pec[i] = ic[current_ic].crc_count.stat_pec[i] + ic[current_ic].stat.pec_match[i];
01206                 }
01207             }
01208             break;
01209         default:
01210             break;
01211     }
01212 }
01213 
01214 //Helper Function to reset PEC counters
01215 void LTC681x_reset_crc_count(uint8_t total_ic, cell_asic ic[])
01216 {
01217     for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
01218         ic[current_ic].crc_count.pec_count = 0;
01219         ic[current_ic].crc_count.cfgr_pec = 0;
01220         for (int i=0; i<6; i++) {
01221             ic[current_ic].crc_count.cell_pec[i]=0;
01222 
01223         }
01224         for (int i=0; i<4; i++) {
01225             ic[current_ic].crc_count.aux_pec[i]=0;
01226         }
01227         for (int i=0; i<2; i++) {
01228             ic[current_ic].crc_count.stat_pec[i]=0;
01229         }
01230     }
01231 }
01232 
01233 //Helper function to intialize CFG variables.
01234 void LTC681x_init_cfg(uint8_t total_ic, cell_asic ic[])
01235 {
01236     bool REFON = true;
01237     bool ADCOPT = false;
01238     bool gpioBits[5] = {true,true,true,true,true};
01239     bool dccBits[12] = {false,false,false,false,false,false,false,false,false,false,false,false};
01240     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01241         for (int j =0; j<6; j++) {
01242             ic[current_ic].config.tx_data[j] = 0;
01243             ic[current_ic].configb.tx_data[j] = 0;
01244         }
01245         LTC681x_set_cfgr(current_ic ,ic,REFON,ADCOPT,gpioBits,dccBits);
01246 
01247     }
01248 }
01249 
01250 //Helper function to set CFGR variable
01251 void LTC681x_set_cfgr(uint8_t nIC, cell_asic ic[], bool refon, bool adcopt, bool gpio[5],bool dcc[12])
01252 {
01253     LTC681x_set_cfgr_refon(nIC,ic,refon);
01254     LTC681x_set_cfgr_adcopt(nIC,ic,adcopt);
01255     LTC681x_set_cfgr_gpio(nIC,ic,gpio);
01256     LTC681x_set_cfgr_dis(nIC,ic,dcc);
01257 }
01258 
01259 //Helper function to set the REFON bit
01260 void LTC681x_set_cfgr_refon(uint8_t nIC, cell_asic ic[], bool refon)
01261 {
01262     if (refon) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|0x04;
01263     else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&0xFB;
01264 }
01265 
01266 //Helper function to set the adcopt bit
01267 void LTC681x_set_cfgr_adcopt(uint8_t nIC, cell_asic ic[], bool adcopt)
01268 {
01269     if (adcopt) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|0x01;
01270     else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&0xFE;
01271 }
01272 
01273 //Helper function to set GPIO bits
01274 void LTC681x_set_cfgr_gpio(uint8_t nIC, cell_asic ic[],bool gpio[5])
01275 {
01276     for (int i =0; i<5; i++) {
01277         if (gpio[i])ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|(0x01<<(i+3));
01278         else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&(~(0x01<<(i+3)));
01279     }
01280 }
01281 
01282 //Helper function to control discharge
01283 void LTC681x_set_cfgr_dis(uint8_t nIC, cell_asic ic[],bool dcc[12])
01284 {
01285     for (int i =0; i<8; i++) {
01286         if (dcc[i])ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4]|(0x01<<i);
01287         else ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4]& (~(0x01<<i));
01288     }
01289     for (int i =0; i<4; i++) {
01290         if (dcc[i+8])ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5]|(0x01<<i);
01291         else ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5]&(~(0x01<<i));
01292     }
01293 }
01294 
01295 //Helper Function to set uv value in CFG register
01296 void LTC681x_set_cfgr_uv(uint8_t nIC, cell_asic ic[],uint16_t uv)
01297 {
01298     uint16_t tmp = (uv/16)-1;
01299     ic[nIC].config.tx_data[1] = 0x00FF & tmp;
01300     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0xF0;
01301     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x0F00 & tmp)>>8);
01302 }
01303 
01304 //helper function to set OV value in CFG register
01305 void LTC681x_set_cfgr_ov(uint8_t nIC, cell_asic ic[],uint16_t ov)
01306 {
01307     uint16_t tmp = (ov/16);
01308     ic[nIC].config.tx_data[3] = 0x00FF & (tmp>>4);
01309     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0x0F;
01310     ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x000F & tmp)<<4);
01311 }
01312 
01313 //Writes the comm register
01314 void LTC681x_wrcomm(uint8_t total_ic, //The number of ICs being written to
01315                     cell_asic ic[]
01316                    )
01317 {
01318     uint8_t cmd[2]= {0x07 , 0x21};
01319     uint8_t write_buffer[256];
01320     uint8_t write_count = 0;
01321     uint8_t c_ic = 0;
01322     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01323         if (ic->isospi_reverse == true) {
01324             c_ic = current_ic;
01325         } else {
01326             c_ic = total_ic - current_ic - 1;
01327         }
01328 
01329         for (uint8_t data = 0; data<6; data++) {
01330             write_buffer[write_count] = ic[c_ic].com.tx_data[data];
01331             write_count++;
01332         }
01333     }
01334     write_68(total_ic, cmd, write_buffer);
01335 }
01336 
01337 /*
01338 Reads COMM registers of a LTC6811 daisy chain
01339 */
01340 int8_t LTC681x_rdcomm(uint8_t total_ic, //Number of ICs in the system
01341                       cell_asic ic[]
01342                      )
01343 {
01344     uint8_t cmd[2]= {0x07 , 0x22};
01345     uint8_t read_buffer[256];
01346     int8_t pec_error = 0;
01347     uint16_t data_pec;
01348     uint16_t calc_pec;
01349     uint8_t c_ic=0;
01350     pec_error = read_68(total_ic, cmd, read_buffer);
01351     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01352         if (ic->isospi_reverse == false) {
01353             c_ic = current_ic;
01354         } else {
01355             c_ic = total_ic - current_ic - 1;
01356         }
01357 
01358         for (int byte=0; byte<8; byte++) {
01359             ic[c_ic].com.rx_data[byte] = read_buffer[byte+(8*current_ic)];
01360         }
01361         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
01362         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
01363         if (calc_pec != data_pec ) {
01364             ic[c_ic].com.rx_pec_match = 1;
01365         } else ic[c_ic].com.rx_pec_match = 0;
01366     }
01367     return(pec_error);
01368 }
01369 
01370 /*
01371 Shifts data in COMM register out over LTC6811 SPI/I2C port
01372 */
01373 void LTC681x_stcomm()
01374 {
01375 
01376     uint8_t cmd[4];
01377     uint16_t cmd_pec;
01378 
01379     cmd[0] = 0x07;
01380     cmd[1] = 0x23;
01381     cmd_pec = pec15_calc(2, cmd);
01382     cmd[2] = (uint8_t)(cmd_pec >> 8);
01383     cmd[3] = (uint8_t)(cmd_pec);
01384 
01385     cs_low();
01386     spi_write_array(4,cmd);
01387     for (int i = 0; i<9; i++) {
01388         spi_read_byte(0xFF);
01389     }
01390     cs_high();
01391 
01392 }
01393 
01394 // Writes the pwm register
01395 void LTC681x_wrpwm(uint8_t total_ic,
01396                    uint8_t pwmReg,
01397                    cell_asic ic[]
01398                   )
01399 {
01400     uint8_t cmd[2];
01401     uint8_t write_buffer[256];
01402     uint8_t write_count = 0;
01403     uint8_t c_ic = 0;
01404     if (pwmReg == 0) {
01405         cmd[0] = 0x00;
01406         cmd[1] = 0x20;
01407     } else {
01408         cmd[0] = 0x00;
01409         cmd[1] = 0x1C;
01410     }
01411 
01412     for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
01413         if (ic->isospi_reverse == true) {
01414             c_ic = current_ic;
01415         } else {
01416             c_ic = total_ic - current_ic - 1;
01417         }
01418         for (uint8_t data = 0; data<6; data++) {
01419             write_buffer[write_count] = ic[c_ic].pwm.tx_data[data];
01420             write_count++;
01421         }
01422     }
01423     write_68(total_ic, cmd, write_buffer);
01424 }
01425 
01426 
01427 /*
01428 Reads pwm registers of a LTC6811 daisy chain
01429 */
01430 int8_t LTC681x_rdpwm(uint8_t total_ic, //Number of ICs in the system
01431                      uint8_t pwmReg,
01432                      cell_asic ic[]
01433                     )
01434 {
01435 //    const uint8_t BYTES_IN_REG = 8;
01436 
01437     uint8_t cmd[4];
01438     uint8_t read_buffer[256];
01439     int8_t pec_error = 0;
01440     uint16_t data_pec;
01441     uint16_t calc_pec;
01442     uint8_t c_ic = 0;
01443 
01444     if (pwmReg == 0) {
01445         cmd[0] = 0x00;
01446         cmd[1] = 0x22;
01447     } else {
01448         cmd[0] = 0x00;
01449         cmd[1] = 0x1E;
01450     }
01451 
01452 
01453     pec_error = read_68(total_ic, cmd, read_buffer);
01454     for (uint8_t current_ic =0; current_ic<total_ic; current_ic++) {
01455         if (ic->isospi_reverse == false) {
01456             c_ic = current_ic;
01457         } else {
01458             c_ic = total_ic - current_ic - 1;
01459         }
01460         for (int byte=0; byte<8; byte++) {
01461             ic[c_ic].pwm.rx_data[byte] = read_buffer[byte+(8*current_ic)];
01462         }
01463         calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
01464         data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
01465         if (calc_pec != data_pec ) {
01466             ic[c_ic].pwm.rx_pec_match = 1;
01467         } else ic[c_ic].pwm.rx_pec_match = 0;
01468     }
01469     return(pec_error);
01470 }