Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: INA226
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 }
Generated on Sat Jul 16 2022 17:26:48 by
