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