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