KIT Solar Car Project / Mbed 2 deprecated BMS_v1

Dependencies:   mbed INA226

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LTC681x.cpp Source File

LTC681x.cpp

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