LTC6811 Battery Management System with ADuCM3029.

Committer:
APS_Lab
Date:
Fri Feb 09 04:43:04 2018 +0000
Revision:
1:4dd3e328a30b
Parent:
0:f06ed53310a3
Improved for SPI.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
APS_Lab 0:f06ed53310a3 1 /*
APS_Lab 0:f06ed53310a3 2 General BMS Library
APS_Lab 0:f06ed53310a3 3 LTC681x.cpp
APS_Lab 0:f06ed53310a3 4 */
APS_Lab 0:f06ed53310a3 5
APS_Lab 0:f06ed53310a3 6 #include "mbed.h"
APS_Lab 0:f06ed53310a3 7
APS_Lab 0:f06ed53310a3 8 #include "LTC681x.h"
APS_Lab 0:f06ed53310a3 9 #include "bms.h"
APS_Lab 0:f06ed53310a3 10 //#include "LT_SPI.h"
APS_Lab 0:f06ed53310a3 11
APS_Lab 0:f06ed53310a3 12
APS_Lab 0:f06ed53310a3 13 void wakeup_idle(uint8_t total_ic)
APS_Lab 0:f06ed53310a3 14 {
APS_Lab 0:f06ed53310a3 15 for (int i =0; i<total_ic; i++) {
APS_Lab 1:4dd3e328a30b 16 cs_low();
APS_Lab 1:4dd3e328a30b 17 wait_ms(2); //Guarantees the isoSPI will be in ready mode
APS_Lab 0:f06ed53310a3 18 spi_read_byte(0xff);
APS_Lab 1:4dd3e328a30b 19 cs_high();
APS_Lab 0:f06ed53310a3 20 }
APS_Lab 0:f06ed53310a3 21 }
APS_Lab 0:f06ed53310a3 22
APS_Lab 0:f06ed53310a3 23 //Generic wakeup commannd to wake the LTC6813 from sleep
APS_Lab 0:f06ed53310a3 24 void wakeup_sleep(uint8_t total_ic)
APS_Lab 0:f06ed53310a3 25 {
APS_Lab 0:f06ed53310a3 26 for (int i =0; i<total_ic; i++) {
APS_Lab 1:4dd3e328a30b 27 cs_low();
APS_Lab 0:f06ed53310a3 28 delay_u(300); // Guarantees the LTC6813 will be in standby
APS_Lab 1:4dd3e328a30b 29 cs_high();
APS_Lab 0:f06ed53310a3 30 delay_u(10);
APS_Lab 0:f06ed53310a3 31 }
APS_Lab 0:f06ed53310a3 32 }
APS_Lab 0:f06ed53310a3 33
APS_Lab 0:f06ed53310a3 34 //Generic function to write 68xx commands. Function calculated PEC for tx_cmd data
APS_Lab 0:f06ed53310a3 35 void cmd_68(uint8_t tx_cmd[2])
APS_Lab 0:f06ed53310a3 36 {
APS_Lab 0:f06ed53310a3 37 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 38 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 39 // uint8_t md_bits;
APS_Lab 0:f06ed53310a3 40
APS_Lab 0:f06ed53310a3 41 cmd[0] = tx_cmd[0];
APS_Lab 0:f06ed53310a3 42 cmd[1] = tx_cmd[1];
APS_Lab 0:f06ed53310a3 43 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 44 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 45 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 1:4dd3e328a30b 46 cs_low();
APS_Lab 0:f06ed53310a3 47 spi_write_array(4,cmd);
APS_Lab 1:4dd3e328a30b 48 cs_high();
APS_Lab 0:f06ed53310a3 49 }
APS_Lab 0:f06ed53310a3 50
APS_Lab 0:f06ed53310a3 51 //Generic function to write 68xx commands and write payload data. Function calculated PEC for tx_cmd data
APS_Lab 0:f06ed53310a3 52 void write_68(uint8_t total_ic , uint8_t tx_cmd[2], uint8_t data[])
APS_Lab 0:f06ed53310a3 53 {
APS_Lab 0:f06ed53310a3 54 const uint8_t BYTES_IN_REG = 6;
APS_Lab 0:f06ed53310a3 55 const uint8_t CMD_LEN = 4+(8*total_ic);
APS_Lab 0:f06ed53310a3 56 uint8_t *cmd;
APS_Lab 0:f06ed53310a3 57 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 58 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 59 uint8_t cmd_index;
APS_Lab 0:f06ed53310a3 60
APS_Lab 0:f06ed53310a3 61 cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
APS_Lab 0:f06ed53310a3 62 cmd[0] = tx_cmd[0];
APS_Lab 0:f06ed53310a3 63 cmd[1] = tx_cmd[1];
APS_Lab 0:f06ed53310a3 64 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 65 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 66 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 67 cmd_index = 4;
APS_Lab 0:f06ed53310a3 68 for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--) { // executes for each LTC681x in daisy chain, this loops starts with
APS_Lab 0:f06ed53310a3 69 // the last IC on the stack. The first configuration written is
APS_Lab 0:f06ed53310a3 70 // received by the last IC in the daisy chain
APS_Lab 0:f06ed53310a3 71
APS_Lab 0:f06ed53310a3 72 for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
APS_Lab 0:f06ed53310a3 73 cmd[cmd_index] = data[((current_ic-1)*6)+current_byte];
APS_Lab 0:f06ed53310a3 74 cmd_index = cmd_index + 1;
APS_Lab 0:f06ed53310a3 75 }
APS_Lab 0:f06ed53310a3 76
APS_Lab 0:f06ed53310a3 77 data_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &data[(current_ic-1)*6]); // calculating the PEC for each Iss configuration register data
APS_Lab 0:f06ed53310a3 78 cmd[cmd_index] = (uint8_t)(data_pec >> 8);
APS_Lab 0:f06ed53310a3 79 cmd[cmd_index + 1] = (uint8_t)data_pec;
APS_Lab 0:f06ed53310a3 80 cmd_index = cmd_index + 2;
APS_Lab 0:f06ed53310a3 81 }
APS_Lab 0:f06ed53310a3 82
APS_Lab 0:f06ed53310a3 83
APS_Lab 1:4dd3e328a30b 84 cs_low();
APS_Lab 0:f06ed53310a3 85 spi_write_array(CMD_LEN, cmd);
APS_Lab 1:4dd3e328a30b 86 cs_high();
APS_Lab 0:f06ed53310a3 87 free(cmd);
APS_Lab 0:f06ed53310a3 88 }
APS_Lab 0:f06ed53310a3 89
APS_Lab 0:f06ed53310a3 90 //Generic function to write 68xx commands and read data. Function calculated PEC for tx_cmd data
APS_Lab 0:f06ed53310a3 91 int8_t read_68( uint8_t total_ic, uint8_t tx_cmd[2], uint8_t *rx_data)
APS_Lab 0:f06ed53310a3 92 {
APS_Lab 0:f06ed53310a3 93 const uint8_t BYTES_IN_REG = 8;
APS_Lab 0:f06ed53310a3 94 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 95 uint8_t data[256];
APS_Lab 0:f06ed53310a3 96 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 97 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 98 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 99 uint16_t received_pec;
APS_Lab 0:f06ed53310a3 100
APS_Lab 0:f06ed53310a3 101 // data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t)); // This is a problem because it can fail
APS_Lab 0:f06ed53310a3 102
APS_Lab 0:f06ed53310a3 103 cmd[0] = tx_cmd[0];
APS_Lab 0:f06ed53310a3 104 cmd[1] = tx_cmd[1];
APS_Lab 0:f06ed53310a3 105 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 106 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 107 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 108
APS_Lab 0:f06ed53310a3 109
APS_Lab 1:4dd3e328a30b 110 cs_low();
APS_Lab 0:f06ed53310a3 111 spi_write_read(cmd, 4, data, (BYTES_IN_REG*total_ic)); //Read the configuration data of all ICs on the daisy chain into
APS_Lab 1:4dd3e328a30b 112 cs_high(); //rx_data[] array
APS_Lab 0:f06ed53310a3 113
APS_Lab 0:f06ed53310a3 114 for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) { //executes for each LTC681x in the daisy chain and packs the data
APS_Lab 0:f06ed53310a3 115 //into the r_comm array as well as check the received Config data
APS_Lab 0:f06ed53310a3 116 //for any bit errors
APS_Lab 0:f06ed53310a3 117 for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) {
APS_Lab 0:f06ed53310a3 118 rx_data[(current_ic*8)+current_byte] = data[current_byte + (current_ic*BYTES_IN_REG)];
APS_Lab 0:f06ed53310a3 119 }
APS_Lab 0:f06ed53310a3 120 received_pec = (rx_data[(current_ic*8)+6]<<8) + rx_data[(current_ic*8)+7];
APS_Lab 0:f06ed53310a3 121 data_pec = pec15_calc(6, &rx_data[current_ic*8]);
APS_Lab 0:f06ed53310a3 122 if (received_pec != data_pec) {
APS_Lab 0:f06ed53310a3 123 pec_error = -1;
APS_Lab 0:f06ed53310a3 124 }
APS_Lab 0:f06ed53310a3 125 }
APS_Lab 0:f06ed53310a3 126
APS_Lab 0:f06ed53310a3 127
APS_Lab 0:f06ed53310a3 128 return(pec_error);
APS_Lab 0:f06ed53310a3 129 }
APS_Lab 0:f06ed53310a3 130
APS_Lab 0:f06ed53310a3 131
APS_Lab 0:f06ed53310a3 132 /*
APS_Lab 0:f06ed53310a3 133 Calculates and returns the CRC15
APS_Lab 0:f06ed53310a3 134 */
APS_Lab 0:f06ed53310a3 135 uint16_t pec15_calc(uint8_t len, //Number of bytes that will be used to calculate a PEC
APS_Lab 0:f06ed53310a3 136 uint8_t *data //Array of data that will be used to calculate a PEC
APS_Lab 0:f06ed53310a3 137 )
APS_Lab 0:f06ed53310a3 138 {
APS_Lab 0:f06ed53310a3 139 uint16_t remainder,addr;
APS_Lab 0:f06ed53310a3 140
APS_Lab 0:f06ed53310a3 141 remainder = 16;//initialize the PEC
APS_Lab 0:f06ed53310a3 142 for (uint8_t i = 0; i<len; i++) { // loops for each byte in data array
APS_Lab 0:f06ed53310a3 143 addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
APS_Lab 0:f06ed53310a3 144 //#ifdef MBED
APS_Lab 0:f06ed53310a3 145 remainder = (remainder<<8)^crc15Table[addr];
APS_Lab 0:f06ed53310a3 146 //#else
APS_Lab 0:f06ed53310a3 147 // remainder = (remainder<<8)^pgm_read_word_near(crc15Table+addr);
APS_Lab 0:f06ed53310a3 148 //#endif
APS_Lab 0:f06ed53310a3 149 }
APS_Lab 0:f06ed53310a3 150 return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
APS_Lab 0:f06ed53310a3 151 }
APS_Lab 0:f06ed53310a3 152
APS_Lab 0:f06ed53310a3 153 //Starts cell voltage conversion
APS_Lab 0:f06ed53310a3 154 void LTC681x_adcv(
APS_Lab 0:f06ed53310a3 155 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 156 uint8_t DCP, //Discharge Permit
APS_Lab 0:f06ed53310a3 157 uint8_t CH //Cell Channels to be measured
APS_Lab 0:f06ed53310a3 158 )
APS_Lab 0:f06ed53310a3 159 {
APS_Lab 0:f06ed53310a3 160 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 161 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 162
APS_Lab 0:f06ed53310a3 163 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 164 cmd[0] = md_bits + 0x02;
APS_Lab 0:f06ed53310a3 165 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 166 cmd[1] = md_bits + 0x60 + (DCP<<4) + CH;
APS_Lab 0:f06ed53310a3 167 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 168 }
APS_Lab 0:f06ed53310a3 169
APS_Lab 0:f06ed53310a3 170
APS_Lab 0:f06ed53310a3 171 //Starts cell voltage and SOC conversion
APS_Lab 0:f06ed53310a3 172 void LTC681x_adcvsc(
APS_Lab 0:f06ed53310a3 173 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 174 uint8_t DCP //Discharge Permit
APS_Lab 0:f06ed53310a3 175 )
APS_Lab 0:f06ed53310a3 176 {
APS_Lab 0:f06ed53310a3 177 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 178 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 179 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 180 cmd[0] = md_bits | 0x04;
APS_Lab 0:f06ed53310a3 181 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 182 cmd[1] = md_bits | 0x60 | (DCP<<4) | 0x07;
APS_Lab 0:f06ed53310a3 183 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 184
APS_Lab 0:f06ed53310a3 185 }
APS_Lab 0:f06ed53310a3 186
APS_Lab 0:f06ed53310a3 187 // Starts cell voltage and GPIO 1&2 conversion
APS_Lab 0:f06ed53310a3 188 void LTC681x_adcvax(
APS_Lab 0:f06ed53310a3 189 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 190 uint8_t DCP //Discharge Permit
APS_Lab 0:f06ed53310a3 191 )
APS_Lab 0:f06ed53310a3 192 {
APS_Lab 0:f06ed53310a3 193 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 194 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 195 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 196 cmd[0] = md_bits | 0x04;
APS_Lab 0:f06ed53310a3 197 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 198 cmd[1] = md_bits | ((DCP&0x01)<<4) + 0x6F;
APS_Lab 0:f06ed53310a3 199 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 200 }
APS_Lab 0:f06ed53310a3 201
APS_Lab 0:f06ed53310a3 202 //Starts cell voltage overlap conversion
APS_Lab 0:f06ed53310a3 203 void LTC681x_adol(
APS_Lab 0:f06ed53310a3 204 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 205 uint8_t DCP //Discharge Permit
APS_Lab 0:f06ed53310a3 206 )
APS_Lab 0:f06ed53310a3 207 {
APS_Lab 0:f06ed53310a3 208 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 209 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 210 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 211 cmd[0] = md_bits + 0x02;
APS_Lab 0:f06ed53310a3 212 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 213 cmd[1] = md_bits + (DCP<<4) +0x01;
APS_Lab 0:f06ed53310a3 214 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 215 }
APS_Lab 0:f06ed53310a3 216
APS_Lab 0:f06ed53310a3 217 //Starts cell voltage self test conversion
APS_Lab 0:f06ed53310a3 218 void LTC681x_cvst(
APS_Lab 0:f06ed53310a3 219 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 220 uint8_t ST //Self Test
APS_Lab 0:f06ed53310a3 221 )
APS_Lab 0:f06ed53310a3 222 {
APS_Lab 0:f06ed53310a3 223 uint8_t cmd[2];
APS_Lab 0:f06ed53310a3 224 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 225
APS_Lab 0:f06ed53310a3 226 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 227 cmd[0] = md_bits + 0x02;
APS_Lab 0:f06ed53310a3 228 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 229 cmd[1] = md_bits + ((ST)<<5) +0x07;
APS_Lab 0:f06ed53310a3 230 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 231
APS_Lab 0:f06ed53310a3 232 }
APS_Lab 0:f06ed53310a3 233
APS_Lab 0:f06ed53310a3 234 //Start an Auxiliary Register Self Test Conversion
APS_Lab 0:f06ed53310a3 235 void LTC681x_axst(
APS_Lab 0:f06ed53310a3 236 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 237 uint8_t ST //Self Test
APS_Lab 0:f06ed53310a3 238 )
APS_Lab 0:f06ed53310a3 239 {
APS_Lab 0:f06ed53310a3 240 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 241 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 242
APS_Lab 0:f06ed53310a3 243 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 244 cmd[0] = md_bits + 0x04;
APS_Lab 0:f06ed53310a3 245 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 246 cmd[1] = md_bits + ((ST&0x03)<<5) +0x07;
APS_Lab 0:f06ed53310a3 247 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 248
APS_Lab 0:f06ed53310a3 249 }
APS_Lab 0:f06ed53310a3 250
APS_Lab 0:f06ed53310a3 251 //Start a Status Register Self Test Conversion
APS_Lab 0:f06ed53310a3 252 void LTC681x_statst(
APS_Lab 0:f06ed53310a3 253 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 254 uint8_t ST //Self Test
APS_Lab 0:f06ed53310a3 255 )
APS_Lab 0:f06ed53310a3 256 {
APS_Lab 0:f06ed53310a3 257 uint8_t cmd[2];
APS_Lab 0:f06ed53310a3 258 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 259
APS_Lab 0:f06ed53310a3 260 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 261 cmd[0] = md_bits + 0x04;
APS_Lab 0:f06ed53310a3 262 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 263 cmd[1] = md_bits + ((ST&0x03)<<5) +0x0F;
APS_Lab 0:f06ed53310a3 264 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 265
APS_Lab 0:f06ed53310a3 266 }
APS_Lab 0:f06ed53310a3 267
APS_Lab 0:f06ed53310a3 268 //Sends the poll adc command
APS_Lab 0:f06ed53310a3 269 uint8_t LTC681x_pladc()
APS_Lab 0:f06ed53310a3 270 {
APS_Lab 0:f06ed53310a3 271 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 272 uint8_t adc_state = 0xFF;
APS_Lab 0:f06ed53310a3 273 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 274
APS_Lab 0:f06ed53310a3 275 cmd[0] = 0x07;
APS_Lab 0:f06ed53310a3 276 cmd[1] = 0x14;
APS_Lab 0:f06ed53310a3 277 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 278 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 279 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 280
APS_Lab 0:f06ed53310a3 281
APS_Lab 1:4dd3e328a30b 282 cs_low();
APS_Lab 0:f06ed53310a3 283 spi_write_array(4,cmd);
APS_Lab 0:f06ed53310a3 284 // adc_state = spi_read_byte(0xFF);
APS_Lab 1:4dd3e328a30b 285 cs_high();
APS_Lab 0:f06ed53310a3 286 return(adc_state);
APS_Lab 0:f06ed53310a3 287 }
APS_Lab 0:f06ed53310a3 288
APS_Lab 0:f06ed53310a3 289 //This function will block operation until the ADC has finished it's conversion
APS_Lab 0:f06ed53310a3 290 uint32_t LTC681x_pollAdc()
APS_Lab 0:f06ed53310a3 291 {
APS_Lab 0:f06ed53310a3 292 uint32_t counter = 0;
APS_Lab 0:f06ed53310a3 293 uint8_t finished = 0;
APS_Lab 0:f06ed53310a3 294 uint8_t current_time = 0;
APS_Lab 0:f06ed53310a3 295 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 296 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 297
APS_Lab 0:f06ed53310a3 298
APS_Lab 0:f06ed53310a3 299 cmd[0] = 0x07;
APS_Lab 0:f06ed53310a3 300 cmd[1] = 0x14;
APS_Lab 0:f06ed53310a3 301 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 302 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 303 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 304
APS_Lab 1:4dd3e328a30b 305 cs_low();
APS_Lab 0:f06ed53310a3 306 spi_write_array(4,cmd);
APS_Lab 0:f06ed53310a3 307
APS_Lab 0:f06ed53310a3 308 while ((counter<200000)&&(finished == 0)) {
APS_Lab 0:f06ed53310a3 309 current_time = spi_read_byte(0xff);
APS_Lab 0:f06ed53310a3 310 if (current_time>0) {
APS_Lab 0:f06ed53310a3 311 finished = 1;
APS_Lab 0:f06ed53310a3 312 } else {
APS_Lab 0:f06ed53310a3 313 counter = counter + 10;
APS_Lab 0:f06ed53310a3 314 }
APS_Lab 0:f06ed53310a3 315 }
APS_Lab 1:4dd3e328a30b 316 cs_high();
APS_Lab 1:4dd3e328a30b 317
APS_Lab 0:f06ed53310a3 318
APS_Lab 0:f06ed53310a3 319 return(counter);
APS_Lab 0:f06ed53310a3 320 }
APS_Lab 0:f06ed53310a3 321
APS_Lab 0:f06ed53310a3 322 //Start a GPIO and Vref2 Conversion
APS_Lab 0:f06ed53310a3 323 void LTC681x_adax(
APS_Lab 0:f06ed53310a3 324 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 325 uint8_t CHG //GPIO Channels to be measured)
APS_Lab 0:f06ed53310a3 326 )
APS_Lab 0:f06ed53310a3 327 {
APS_Lab 0:f06ed53310a3 328 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 329 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 330
APS_Lab 0:f06ed53310a3 331 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 332 cmd[0] = md_bits + 0x04;
APS_Lab 0:f06ed53310a3 333 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 334 cmd[1] = md_bits + 0x60 + CHG ;
APS_Lab 0:f06ed53310a3 335 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 336
APS_Lab 0:f06ed53310a3 337 }
APS_Lab 0:f06ed53310a3 338
APS_Lab 0:f06ed53310a3 339 //Start an GPIO Redundancy test
APS_Lab 0:f06ed53310a3 340 void LTC681x_adaxd(
APS_Lab 0:f06ed53310a3 341 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 342 uint8_t CHG //GPIO Channels to be measured)
APS_Lab 0:f06ed53310a3 343 )
APS_Lab 0:f06ed53310a3 344 {
APS_Lab 0:f06ed53310a3 345 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 346 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 347
APS_Lab 0:f06ed53310a3 348 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 349 cmd[0] = md_bits + 0x04;
APS_Lab 0:f06ed53310a3 350 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 351 cmd[1] = md_bits + CHG ;
APS_Lab 0:f06ed53310a3 352 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 353 }
APS_Lab 0:f06ed53310a3 354
APS_Lab 0:f06ed53310a3 355 //Start a Status ADC Conversion
APS_Lab 0:f06ed53310a3 356 void LTC681x_adstat(
APS_Lab 0:f06ed53310a3 357 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 358 uint8_t CHST //GPIO Channels to be measured
APS_Lab 0:f06ed53310a3 359 )
APS_Lab 0:f06ed53310a3 360 {
APS_Lab 0:f06ed53310a3 361 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 362 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 363
APS_Lab 0:f06ed53310a3 364 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 365 cmd[0] = md_bits + 0x04;
APS_Lab 0:f06ed53310a3 366 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 367 cmd[1] = md_bits + 0x68 + CHST ;
APS_Lab 0:f06ed53310a3 368 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 369 }
APS_Lab 0:f06ed53310a3 370
APS_Lab 0:f06ed53310a3 371 // Start a Status register redundancy test Conversion
APS_Lab 0:f06ed53310a3 372 void LTC681x_adstatd(
APS_Lab 0:f06ed53310a3 373 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 374 uint8_t CHST //GPIO Channels to be measured
APS_Lab 0:f06ed53310a3 375 )
APS_Lab 0:f06ed53310a3 376 {
APS_Lab 0:f06ed53310a3 377 uint8_t cmd[2];
APS_Lab 0:f06ed53310a3 378 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 379
APS_Lab 0:f06ed53310a3 380 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 381 cmd[0] = md_bits + 0x04;
APS_Lab 0:f06ed53310a3 382 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 383 cmd[1] = md_bits + 0x08 + CHST ;
APS_Lab 0:f06ed53310a3 384 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 385
APS_Lab 0:f06ed53310a3 386 }
APS_Lab 0:f06ed53310a3 387
APS_Lab 0:f06ed53310a3 388
APS_Lab 0:f06ed53310a3 389 // Start an open wire Conversion
APS_Lab 0:f06ed53310a3 390 void LTC681x_adow(
APS_Lab 0:f06ed53310a3 391 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 392 uint8_t PUP //Discharge Permit
APS_Lab 0:f06ed53310a3 393 )
APS_Lab 0:f06ed53310a3 394 {
APS_Lab 0:f06ed53310a3 395 uint8_t cmd[2];
APS_Lab 0:f06ed53310a3 396 uint8_t md_bits;
APS_Lab 0:f06ed53310a3 397 md_bits = (MD & 0x02) >> 1;
APS_Lab 0:f06ed53310a3 398 cmd[0] = md_bits + 0x02;
APS_Lab 0:f06ed53310a3 399 md_bits = (MD & 0x01) << 7;
APS_Lab 0:f06ed53310a3 400 cmd[1] = md_bits + 0x28 + (PUP<<6) ;//+ CH;
APS_Lab 0:f06ed53310a3 401 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 402 }
APS_Lab 0:f06ed53310a3 403
APS_Lab 0:f06ed53310a3 404 // Reads the raw cell voltage register data
APS_Lab 0:f06ed53310a3 405 void LTC681x_rdcv_reg(uint8_t reg, //Determines which cell voltage register is read back
APS_Lab 0:f06ed53310a3 406 uint8_t total_ic, //the number of ICs in the
APS_Lab 0:f06ed53310a3 407 uint8_t *data //An array of the unparsed cell codes
APS_Lab 0:f06ed53310a3 408 )
APS_Lab 0:f06ed53310a3 409 {
APS_Lab 0:f06ed53310a3 410 const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
APS_Lab 0:f06ed53310a3 411 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 412 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 413
APS_Lab 0:f06ed53310a3 414 if (reg == 1) { //1: RDCVA
APS_Lab 0:f06ed53310a3 415 cmd[1] = 0x04;
APS_Lab 0:f06ed53310a3 416 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 417 } else if (reg == 2) { //2: RDCVB
APS_Lab 0:f06ed53310a3 418 cmd[1] = 0x06;
APS_Lab 0:f06ed53310a3 419 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 420 } else if (reg == 3) { //3: RDCVC
APS_Lab 0:f06ed53310a3 421 cmd[1] = 0x08;
APS_Lab 0:f06ed53310a3 422 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 423 } else if (reg == 4) { //4: RDCVD
APS_Lab 0:f06ed53310a3 424 cmd[1] = 0x0A;
APS_Lab 0:f06ed53310a3 425 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 426 } else if (reg == 5) { //4: RDCVE
APS_Lab 0:f06ed53310a3 427 cmd[1] = 0x09;
APS_Lab 0:f06ed53310a3 428 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 429 } else if (reg == 6) { //4: RDCVF
APS_Lab 0:f06ed53310a3 430 cmd[1] = 0x0B;
APS_Lab 0:f06ed53310a3 431 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 432 }
APS_Lab 0:f06ed53310a3 433
APS_Lab 0:f06ed53310a3 434
APS_Lab 0:f06ed53310a3 435 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 436 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 437 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 438
APS_Lab 1:4dd3e328a30b 439 cs_low();
APS_Lab 0:f06ed53310a3 440 spi_write_read(cmd,4,data,(REG_LEN*total_ic));
APS_Lab 1:4dd3e328a30b 441 cs_high();
APS_Lab 0:f06ed53310a3 442
APS_Lab 0:f06ed53310a3 443 }
APS_Lab 0:f06ed53310a3 444
APS_Lab 0:f06ed53310a3 445 //helper function that parses voltage measurement registers
APS_Lab 0:f06ed53310a3 446 int8_t parse_cells(uint8_t current_ic, uint8_t cell_reg, uint8_t cell_data[], uint16_t *cell_codes, uint8_t *ic_pec)
APS_Lab 0:f06ed53310a3 447 {
APS_Lab 0:f06ed53310a3 448
APS_Lab 0:f06ed53310a3 449 const uint8_t BYT_IN_REG = 6;
APS_Lab 0:f06ed53310a3 450 const uint8_t CELL_IN_REG = 3;
APS_Lab 0:f06ed53310a3 451 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 452 uint16_t parsed_cell;
APS_Lab 0:f06ed53310a3 453 uint16_t received_pec;
APS_Lab 0:f06ed53310a3 454 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 455 uint8_t data_counter = current_ic*NUM_RX_BYT; //data counter
APS_Lab 0:f06ed53310a3 456
APS_Lab 0:f06ed53310a3 457
APS_Lab 0:f06ed53310a3 458 for (uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) { // This loop parses the read back data into cell voltages, it
APS_Lab 0:f06ed53310a3 459 // loops once for each of the 3 cell voltage codes in the register
APS_Lab 0:f06ed53310a3 460
APS_Lab 0:f06ed53310a3 461 parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);//Each cell code is received as two bytes and is combined to
APS_Lab 0:f06ed53310a3 462 // create the parsed cell voltage code
APS_Lab 0:f06ed53310a3 463 cell_codes[current_cell + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
APS_Lab 0:f06ed53310a3 464 data_counter = data_counter + 2; //Because cell voltage codes are two bytes the data counter
APS_Lab 0:f06ed53310a3 465 //must increment by two for each parsed cell code
APS_Lab 0:f06ed53310a3 466 }
APS_Lab 0:f06ed53310a3 467
APS_Lab 0:f06ed53310a3 468 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
APS_Lab 0:f06ed53310a3 469 //after the 6 cell voltage data bytes
APS_Lab 0:f06ed53310a3 470 data_pec = pec15_calc(BYT_IN_REG, &cell_data[(current_ic) * NUM_RX_BYT]);
APS_Lab 0:f06ed53310a3 471
APS_Lab 0:f06ed53310a3 472 if (received_pec != data_pec) {
APS_Lab 0:f06ed53310a3 473 pec_error = 1; //The pec_error variable is simply set negative if any PEC errors
APS_Lab 0:f06ed53310a3 474 ic_pec[cell_reg-1]=1;
APS_Lab 0:f06ed53310a3 475 } else {
APS_Lab 0:f06ed53310a3 476 ic_pec[cell_reg-1]=0;
APS_Lab 0:f06ed53310a3 477 }
APS_Lab 0:f06ed53310a3 478 data_counter=data_counter+2;
APS_Lab 0:f06ed53310a3 479 return(pec_error);
APS_Lab 0:f06ed53310a3 480 }
APS_Lab 0:f06ed53310a3 481
APS_Lab 0:f06ed53310a3 482 /*
APS_Lab 0:f06ed53310a3 483 The function reads a single GPIO voltage register and stores thre read data
APS_Lab 0:f06ed53310a3 484 in the *data point as a byte array. This function is rarely used outside of
APS_Lab 0:f06ed53310a3 485 the LTC6811_rdaux() command.
APS_Lab 0:f06ed53310a3 486 */
APS_Lab 0:f06ed53310a3 487 void LTC681x_rdaux_reg(uint8_t reg, //Determines which GPIO voltage register is read back
APS_Lab 0:f06ed53310a3 488 uint8_t total_ic, //The number of ICs in the system
APS_Lab 0:f06ed53310a3 489 uint8_t *data //Array of the unparsed auxiliary codes
APS_Lab 0:f06ed53310a3 490 )
APS_Lab 0:f06ed53310a3 491 {
APS_Lab 0:f06ed53310a3 492 const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
APS_Lab 0:f06ed53310a3 493 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 494 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 495
APS_Lab 0:f06ed53310a3 496
APS_Lab 0:f06ed53310a3 497 if (reg == 1) { //Read back auxiliary group A
APS_Lab 0:f06ed53310a3 498 cmd[1] = 0x0C;
APS_Lab 0:f06ed53310a3 499 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 500 } else if (reg == 2) { //Read back auxiliary group B
APS_Lab 0:f06ed53310a3 501 cmd[1] = 0x0e;
APS_Lab 0:f06ed53310a3 502 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 503 } else if (reg == 3) { //Read back auxiliary group C
APS_Lab 0:f06ed53310a3 504 cmd[1] = 0x0D;
APS_Lab 0:f06ed53310a3 505 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 506 } else if (reg == 4) { //Read back auxiliary group D
APS_Lab 0:f06ed53310a3 507 cmd[1] = 0x0F;
APS_Lab 0:f06ed53310a3 508 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 509 } else { //Read back auxiliary group A
APS_Lab 0:f06ed53310a3 510 cmd[1] = 0x0C;
APS_Lab 0:f06ed53310a3 511 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 512 }
APS_Lab 0:f06ed53310a3 513
APS_Lab 0:f06ed53310a3 514 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 515 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 516 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 517
APS_Lab 1:4dd3e328a30b 518 cs_low();
APS_Lab 0:f06ed53310a3 519 spi_write_read(cmd,4,data,(REG_LEN*total_ic));
APS_Lab 1:4dd3e328a30b 520 cs_high();
APS_Lab 0:f06ed53310a3 521
APS_Lab 0:f06ed53310a3 522 }
APS_Lab 0:f06ed53310a3 523
APS_Lab 0:f06ed53310a3 524 /*
APS_Lab 0:f06ed53310a3 525 The function reads a single stat register and stores the read data
APS_Lab 0:f06ed53310a3 526 in the *data point as a byte array. This function is rarely used outside of
APS_Lab 0:f06ed53310a3 527 the LTC6811_rdstat() command.
APS_Lab 0:f06ed53310a3 528 */
APS_Lab 0:f06ed53310a3 529 void LTC681x_rdstat_reg(uint8_t reg, //Determines which stat register is read back
APS_Lab 0:f06ed53310a3 530 uint8_t total_ic, //The number of ICs in the system
APS_Lab 0:f06ed53310a3 531 uint8_t *data //Array of the unparsed stat codes
APS_Lab 0:f06ed53310a3 532 )
APS_Lab 0:f06ed53310a3 533 {
APS_Lab 0:f06ed53310a3 534 const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
APS_Lab 0:f06ed53310a3 535 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 536 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 537
APS_Lab 0:f06ed53310a3 538
APS_Lab 0:f06ed53310a3 539 if (reg == 1) { //Read back statiliary group A
APS_Lab 0:f06ed53310a3 540 cmd[1] = 0x10;
APS_Lab 0:f06ed53310a3 541 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 542 } else if (reg == 2) { //Read back statiliary group B
APS_Lab 0:f06ed53310a3 543 cmd[1] = 0x12;
APS_Lab 0:f06ed53310a3 544 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 545 }
APS_Lab 0:f06ed53310a3 546
APS_Lab 0:f06ed53310a3 547 else { //Read back statiliary group A
APS_Lab 0:f06ed53310a3 548 cmd[1] = 0x10;
APS_Lab 0:f06ed53310a3 549 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 550 }
APS_Lab 0:f06ed53310a3 551
APS_Lab 0:f06ed53310a3 552 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 553 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 554 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 555
APS_Lab 1:4dd3e328a30b 556 cs_low();
APS_Lab 0:f06ed53310a3 557 spi_write_read(cmd,4,data,(REG_LEN*total_ic));
APS_Lab 1:4dd3e328a30b 558 cs_high();
APS_Lab 0:f06ed53310a3 559
APS_Lab 0:f06ed53310a3 560 }
APS_Lab 0:f06ed53310a3 561
APS_Lab 0:f06ed53310a3 562 /*
APS_Lab 0:f06ed53310a3 563 The command clears the cell voltage registers and intiallizes
APS_Lab 0:f06ed53310a3 564 all values to 1. The register will read back hexadecimal 0xFF
APS_Lab 0:f06ed53310a3 565 after the command is sent.
APS_Lab 0:f06ed53310a3 566 */
APS_Lab 0:f06ed53310a3 567 void LTC681x_clrcell()
APS_Lab 0:f06ed53310a3 568 {
APS_Lab 0:f06ed53310a3 569 uint8_t cmd[2]= {0x07 , 0x11};
APS_Lab 0:f06ed53310a3 570 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 571 }
APS_Lab 0:f06ed53310a3 572
APS_Lab 0:f06ed53310a3 573
APS_Lab 0:f06ed53310a3 574 /*
APS_Lab 0:f06ed53310a3 575 The command clears the Auxiliary registers and initializes
APS_Lab 0:f06ed53310a3 576 all values to 1. The register will read back hexadecimal 0xFF
APS_Lab 0:f06ed53310a3 577 after the command is sent.
APS_Lab 0:f06ed53310a3 578 */
APS_Lab 0:f06ed53310a3 579 void LTC681x_clraux()
APS_Lab 0:f06ed53310a3 580 {
APS_Lab 0:f06ed53310a3 581 uint8_t cmd[2]= {0x07 , 0x12};
APS_Lab 0:f06ed53310a3 582 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 583 }
APS_Lab 0:f06ed53310a3 584
APS_Lab 0:f06ed53310a3 585
APS_Lab 0:f06ed53310a3 586 /*
APS_Lab 0:f06ed53310a3 587 The command clears the Stat registers and intiallizes
APS_Lab 0:f06ed53310a3 588 all values to 1. The register will read back hexadecimal 0xFF
APS_Lab 0:f06ed53310a3 589 after the command is sent.
APS_Lab 0:f06ed53310a3 590
APS_Lab 0:f06ed53310a3 591 */
APS_Lab 0:f06ed53310a3 592 void LTC681x_clrstat()
APS_Lab 0:f06ed53310a3 593 {
APS_Lab 0:f06ed53310a3 594 uint8_t cmd[2]= {0x07 , 0x13};
APS_Lab 0:f06ed53310a3 595 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 596 }
APS_Lab 0:f06ed53310a3 597 /*
APS_Lab 0:f06ed53310a3 598 The command clears the Sctrl registers and initializes
APS_Lab 0:f06ed53310a3 599 all values to 0. The register will read back hexadecimal 0x00
APS_Lab 0:f06ed53310a3 600 after the command is sent.
APS_Lab 0:f06ed53310a3 601 */
APS_Lab 0:f06ed53310a3 602 void LTC681x_clrsctrl()
APS_Lab 0:f06ed53310a3 603 {
APS_Lab 0:f06ed53310a3 604 uint8_t cmd[2]= {0x00 , 0x18};
APS_Lab 0:f06ed53310a3 605 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 606 }
APS_Lab 0:f06ed53310a3 607 //Starts the Mux Decoder diagnostic self test
APS_Lab 0:f06ed53310a3 608 void LTC681x_diagn()
APS_Lab 0:f06ed53310a3 609 {
APS_Lab 0:f06ed53310a3 610 uint8_t cmd[2] = {0x07 , 0x15};
APS_Lab 0:f06ed53310a3 611 cmd_68(cmd);
APS_Lab 0:f06ed53310a3 612 }
APS_Lab 0:f06ed53310a3 613
APS_Lab 0:f06ed53310a3 614 //Reads and parses the LTC681x cell voltage registers.
APS_Lab 0:f06ed53310a3 615 uint8_t LTC681x_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
APS_Lab 0:f06ed53310a3 616 uint8_t total_ic, // the number of ICs in the system
APS_Lab 0:f06ed53310a3 617 cell_asic ic[] // Array of the parsed cell codes
APS_Lab 0:f06ed53310a3 618 )
APS_Lab 0:f06ed53310a3 619 {
APS_Lab 0:f06ed53310a3 620 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 621 uint8_t *cell_data;
APS_Lab 0:f06ed53310a3 622 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 623 cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
APS_Lab 0:f06ed53310a3 624
APS_Lab 0:f06ed53310a3 625 if (reg == 0) {
APS_Lab 0:f06ed53310a3 626 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
APS_Lab 0:f06ed53310a3 627 LTC681x_rdcv_reg(cell_reg, total_ic,cell_data );
APS_Lab 0:f06ed53310a3 628 for (int current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 629 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 630 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 631 } else {
APS_Lab 0:f06ed53310a3 632 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 633 }
APS_Lab 0:f06ed53310a3 634 pec_error = pec_error + parse_cells(current_ic,cell_reg, cell_data,
APS_Lab 0:f06ed53310a3 635 &ic[c_ic].cells.c_codes[0],
APS_Lab 0:f06ed53310a3 636 &ic[c_ic].cells.pec_match[0]);
APS_Lab 0:f06ed53310a3 637 }
APS_Lab 0:f06ed53310a3 638 }
APS_Lab 0:f06ed53310a3 639 }
APS_Lab 0:f06ed53310a3 640
APS_Lab 0:f06ed53310a3 641 else {
APS_Lab 0:f06ed53310a3 642 LTC681x_rdcv_reg(reg, total_ic,cell_data);
APS_Lab 0:f06ed53310a3 643
APS_Lab 0:f06ed53310a3 644 for (int current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 645 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 646 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 647 } else {
APS_Lab 0:f06ed53310a3 648 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 649 }
APS_Lab 0:f06ed53310a3 650 pec_error = pec_error + parse_cells(current_ic,reg, &cell_data[8*c_ic],
APS_Lab 0:f06ed53310a3 651 &ic[c_ic].cells.c_codes[0],
APS_Lab 0:f06ed53310a3 652 &ic[c_ic].cells.pec_match[0]);
APS_Lab 0:f06ed53310a3 653 }
APS_Lab 0:f06ed53310a3 654 }
APS_Lab 0:f06ed53310a3 655 LTC681x_check_pec(total_ic,CELL,ic);
APS_Lab 0:f06ed53310a3 656 free(cell_data);
APS_Lab 0:f06ed53310a3 657 return(pec_error);
APS_Lab 0:f06ed53310a3 658 }
APS_Lab 0:f06ed53310a3 659
APS_Lab 0:f06ed53310a3 660
APS_Lab 0:f06ed53310a3 661
APS_Lab 0:f06ed53310a3 662 /*
APS_Lab 0:f06ed53310a3 663 The function is used
APS_Lab 0:f06ed53310a3 664 to read the parsed GPIO codes of the LTC6811. This function will send the requested
APS_Lab 0:f06ed53310a3 665 read commands parse the data and store the gpio voltages in aux_codes variable
APS_Lab 0:f06ed53310a3 666 */
APS_Lab 0:f06ed53310a3 667 int8_t LTC681x_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
APS_Lab 0:f06ed53310a3 668 uint8_t total_ic,//the number of ICs in the system
APS_Lab 0:f06ed53310a3 669 cell_asic ic[]//A two dimensional array of the gpio voltage codes.
APS_Lab 0:f06ed53310a3 670 )
APS_Lab 0:f06ed53310a3 671 {
APS_Lab 0:f06ed53310a3 672 uint8_t *data;
APS_Lab 0:f06ed53310a3 673 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 674 uint8_t c_ic =0;
APS_Lab 0:f06ed53310a3 675 data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
APS_Lab 0:f06ed53310a3 676
APS_Lab 0:f06ed53310a3 677 if (reg == 0) {
APS_Lab 0:f06ed53310a3 678 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
APS_Lab 0:f06ed53310a3 679 LTC681x_rdaux_reg(gpio_reg, total_ic,data); //Reads the raw auxiliary register data into the data[] array
APS_Lab 0:f06ed53310a3 680 for (int current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 681 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 682 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 683 } else {
APS_Lab 0:f06ed53310a3 684 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 685 }
APS_Lab 0:f06ed53310a3 686 pec_error = parse_cells(current_ic,gpio_reg, data,
APS_Lab 0:f06ed53310a3 687 &ic[c_ic].aux.a_codes[0],
APS_Lab 0:f06ed53310a3 688 &ic[c_ic].aux.pec_match[0]);
APS_Lab 0:f06ed53310a3 689
APS_Lab 0:f06ed53310a3 690 }
APS_Lab 0:f06ed53310a3 691 }
APS_Lab 0:f06ed53310a3 692 } else {
APS_Lab 0:f06ed53310a3 693 LTC681x_rdaux_reg(reg, total_ic, data);
APS_Lab 0:f06ed53310a3 694
APS_Lab 0:f06ed53310a3 695 for (int current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 696 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 697 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 698 } else {
APS_Lab 0:f06ed53310a3 699 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 700 }
APS_Lab 0:f06ed53310a3 701 pec_error = parse_cells(current_ic,reg, data,
APS_Lab 0:f06ed53310a3 702 &ic[c_ic].aux.a_codes[0],
APS_Lab 0:f06ed53310a3 703 &ic[c_ic].aux.pec_match[0]);
APS_Lab 0:f06ed53310a3 704 }
APS_Lab 0:f06ed53310a3 705
APS_Lab 0:f06ed53310a3 706 }
APS_Lab 0:f06ed53310a3 707 LTC681x_check_pec(total_ic,AUX,ic);
APS_Lab 0:f06ed53310a3 708 free(data);
APS_Lab 0:f06ed53310a3 709 return (pec_error);
APS_Lab 0:f06ed53310a3 710 }
APS_Lab 0:f06ed53310a3 711
APS_Lab 0:f06ed53310a3 712 // Reads and parses the LTC681x stat registers.
APS_Lab 0:f06ed53310a3 713 int8_t LTC681x_rdstat(uint8_t reg, //Determines which Stat register is read back.
APS_Lab 0:f06ed53310a3 714 uint8_t total_ic,//the number of ICs in the system
APS_Lab 0:f06ed53310a3 715 cell_asic ic[]
APS_Lab 0:f06ed53310a3 716 )
APS_Lab 0:f06ed53310a3 717
APS_Lab 0:f06ed53310a3 718 {
APS_Lab 0:f06ed53310a3 719
APS_Lab 0:f06ed53310a3 720 const uint8_t BYT_IN_REG = 6;
APS_Lab 0:f06ed53310a3 721 const uint8_t GPIO_IN_REG = 3;
APS_Lab 0:f06ed53310a3 722
APS_Lab 0:f06ed53310a3 723 uint8_t *data;
APS_Lab 0:f06ed53310a3 724 uint8_t data_counter = 0;
APS_Lab 0:f06ed53310a3 725 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 726 uint16_t parsed_stat;
APS_Lab 0:f06ed53310a3 727 uint16_t received_pec;
APS_Lab 0:f06ed53310a3 728 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 729 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 730 data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
APS_Lab 0:f06ed53310a3 731
APS_Lab 0:f06ed53310a3 732 if (reg == 0) {
APS_Lab 0:f06ed53310a3 733
APS_Lab 0:f06ed53310a3 734 for (uint8_t stat_reg = 1; stat_reg< 3; stat_reg++) { //executes once for each of the LTC6811 stat voltage registers
APS_Lab 0:f06ed53310a3 735 data_counter = 0;
APS_Lab 0:f06ed53310a3 736 LTC681x_rdstat_reg(stat_reg, total_ic,data); //Reads the raw statiliary register data into the data[] array
APS_Lab 0:f06ed53310a3 737
APS_Lab 0:f06ed53310a3 738 for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6811 in the daisy chain
APS_Lab 0:f06ed53310a3 739 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 740 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 741 } else {
APS_Lab 0:f06ed53310a3 742 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 743 }
APS_Lab 0:f06ed53310a3 744 // current_ic is used as the IC counter
APS_Lab 0:f06ed53310a3 745 if (stat_reg ==1) {
APS_Lab 0:f06ed53310a3 746 for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
APS_Lab 0:f06ed53310a3 747 // loops once for each of the 3 gpio voltage codes in the register
APS_Lab 0:f06ed53310a3 748
APS_Lab 0:f06ed53310a3 749 parsed_stat = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
APS_Lab 0:f06ed53310a3 750 ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
APS_Lab 0:f06ed53310a3 751 data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
APS_Lab 0:f06ed53310a3 752
APS_Lab 0:f06ed53310a3 753 }
APS_Lab 0:f06ed53310a3 754 } else if (stat_reg == 2) {
APS_Lab 0:f06ed53310a3 755 parsed_stat = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
APS_Lab 0:f06ed53310a3 756 data_counter = data_counter +2;
APS_Lab 0:f06ed53310a3 757 ic[c_ic].stat.stat_codes[3] = parsed_stat;
APS_Lab 0:f06ed53310a3 758 ic[c_ic].stat.flags[0] = data[data_counter++];
APS_Lab 0:f06ed53310a3 759 ic[c_ic].stat.flags[1] = data[data_counter++];
APS_Lab 0:f06ed53310a3 760 ic[c_ic].stat.flags[2] = data[data_counter++];
APS_Lab 0:f06ed53310a3 761 ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
APS_Lab 0:f06ed53310a3 762 ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
APS_Lab 0:f06ed53310a3 763 }
APS_Lab 0:f06ed53310a3 764
APS_Lab 0:f06ed53310a3 765 received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
APS_Lab 0:f06ed53310a3 766 //after the 6 gpio voltage data bytes
APS_Lab 0:f06ed53310a3 767 data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
APS_Lab 0:f06ed53310a3 768
APS_Lab 0:f06ed53310a3 769 if (received_pec != data_pec) {
APS_Lab 0:f06ed53310a3 770 pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
APS_Lab 0:f06ed53310a3 771 ic[c_ic].stat.pec_match[stat_reg-1]=1;
APS_Lab 0:f06ed53310a3 772 //are detected in the received serial data
APS_Lab 0:f06ed53310a3 773 } else {
APS_Lab 0:f06ed53310a3 774 ic[c_ic].stat.pec_match[stat_reg-1]=0;
APS_Lab 0:f06ed53310a3 775 }
APS_Lab 0:f06ed53310a3 776
APS_Lab 0:f06ed53310a3 777 data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
APS_Lab 0:f06ed53310a3 778 //must be incremented by 2 bytes to point to the next ICs gpio voltage data
APS_Lab 0:f06ed53310a3 779 }
APS_Lab 0:f06ed53310a3 780
APS_Lab 0:f06ed53310a3 781
APS_Lab 0:f06ed53310a3 782 }
APS_Lab 0:f06ed53310a3 783
APS_Lab 0:f06ed53310a3 784 } else {
APS_Lab 0:f06ed53310a3 785
APS_Lab 0:f06ed53310a3 786 LTC681x_rdstat_reg(reg, total_ic, data);
APS_Lab 0:f06ed53310a3 787 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) { // executes for every LTC6811 in the daisy chain
APS_Lab 0:f06ed53310a3 788 // current_ic is used as an IC counter
APS_Lab 0:f06ed53310a3 789 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 790 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 791 } else {
APS_Lab 0:f06ed53310a3 792 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 793 }
APS_Lab 0:f06ed53310a3 794 if (reg ==1) {
APS_Lab 0:f06ed53310a3 795 for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) { // This loop parses the read back data into GPIO voltages, it
APS_Lab 0:f06ed53310a3 796 // loops once for each of the 3 gpio voltage codes in the register
APS_Lab 0:f06ed53310a3 797 parsed_stat = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
APS_Lab 0:f06ed53310a3 798 // create the parsed gpio voltage code
APS_Lab 0:f06ed53310a3 799
APS_Lab 0:f06ed53310a3 800 ic[c_ic].stat.stat_codes[current_gpio] = parsed_stat;
APS_Lab 0:f06ed53310a3 801 data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
APS_Lab 0:f06ed53310a3 802 //must increment by two for each parsed gpio voltage code
APS_Lab 0:f06ed53310a3 803
APS_Lab 0:f06ed53310a3 804 }
APS_Lab 0:f06ed53310a3 805 } else if (reg == 2) {
APS_Lab 0:f06ed53310a3 806 parsed_stat = data[data_counter++] + (data[data_counter++]<<8); //Each gpio codes is received as two bytes and is combined to
APS_Lab 0:f06ed53310a3 807 ic[c_ic].stat.stat_codes[3] = parsed_stat;
APS_Lab 0:f06ed53310a3 808 ic[c_ic].stat.flags[0] = data[data_counter++];
APS_Lab 0:f06ed53310a3 809 ic[c_ic].stat.flags[1] = data[data_counter++];
APS_Lab 0:f06ed53310a3 810 ic[c_ic].stat.flags[2] = data[data_counter++];
APS_Lab 0:f06ed53310a3 811 ic[c_ic].stat.mux_fail[0] = (data[data_counter] & 0x02)>>1;
APS_Lab 0:f06ed53310a3 812 ic[c_ic].stat.thsd[0] = data[data_counter++] & 0x01;
APS_Lab 0:f06ed53310a3 813 }
APS_Lab 0:f06ed53310a3 814
APS_Lab 0:f06ed53310a3 815
APS_Lab 0:f06ed53310a3 816 received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
APS_Lab 0:f06ed53310a3 817 //after the 6 gpio voltage data bytes
APS_Lab 0:f06ed53310a3 818 data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
APS_Lab 0:f06ed53310a3 819 if (received_pec != data_pec) {
APS_Lab 0:f06ed53310a3 820 pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
APS_Lab 0:f06ed53310a3 821 ic[c_ic].stat.pec_match[reg-1]=1;
APS_Lab 0:f06ed53310a3 822
APS_Lab 0:f06ed53310a3 823 }
APS_Lab 0:f06ed53310a3 824
APS_Lab 0:f06ed53310a3 825 data_counter=data_counter+2;
APS_Lab 0:f06ed53310a3 826 }
APS_Lab 0:f06ed53310a3 827 }
APS_Lab 0:f06ed53310a3 828 LTC681x_check_pec(total_ic,STAT,ic);
APS_Lab 0:f06ed53310a3 829 free(data);
APS_Lab 0:f06ed53310a3 830 return (pec_error);
APS_Lab 0:f06ed53310a3 831 }
APS_Lab 0:f06ed53310a3 832
APS_Lab 0:f06ed53310a3 833 //Write the LTC681x CFGRA
APS_Lab 0:f06ed53310a3 834 void LTC681x_wrcfg(uint8_t total_ic, //The number of ICs being written to
APS_Lab 0:f06ed53310a3 835 cell_asic ic[]
APS_Lab 0:f06ed53310a3 836 )
APS_Lab 0:f06ed53310a3 837 {
APS_Lab 0:f06ed53310a3 838 uint8_t cmd[2] = {0x00 , 0x01} ;
APS_Lab 0:f06ed53310a3 839 uint8_t write_buffer[256];
APS_Lab 0:f06ed53310a3 840 uint8_t write_count = 0;
APS_Lab 0:f06ed53310a3 841 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 842 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 843 if (ic->isospi_reverse == true) {
APS_Lab 0:f06ed53310a3 844 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 845 } else {
APS_Lab 0:f06ed53310a3 846 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 847 }
APS_Lab 0:f06ed53310a3 848
APS_Lab 0:f06ed53310a3 849 for (uint8_t data = 0; data<6; data++) {
APS_Lab 0:f06ed53310a3 850 write_buffer[write_count] = ic[c_ic].config.tx_data[data];
APS_Lab 0:f06ed53310a3 851 write_count++;
APS_Lab 0:f06ed53310a3 852 }
APS_Lab 0:f06ed53310a3 853 }
APS_Lab 0:f06ed53310a3 854 write_68(total_ic, cmd, write_buffer);
APS_Lab 0:f06ed53310a3 855 }
APS_Lab 0:f06ed53310a3 856
APS_Lab 0:f06ed53310a3 857 //Write the LTC681x CFGRB
APS_Lab 0:f06ed53310a3 858 void LTC681x_wrcfgb(uint8_t total_ic, //The number of ICs being written to
APS_Lab 0:f06ed53310a3 859 cell_asic ic[]
APS_Lab 0:f06ed53310a3 860 )
APS_Lab 0:f06ed53310a3 861 {
APS_Lab 0:f06ed53310a3 862 uint8_t cmd[2] = {0x00 , 0x24} ;
APS_Lab 0:f06ed53310a3 863 uint8_t write_buffer[256];
APS_Lab 0:f06ed53310a3 864 uint8_t write_count = 0;
APS_Lab 0:f06ed53310a3 865 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 866 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 867 if (ic->isospi_reverse == true) {
APS_Lab 0:f06ed53310a3 868 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 869 } else {
APS_Lab 0:f06ed53310a3 870 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 871 }
APS_Lab 0:f06ed53310a3 872
APS_Lab 0:f06ed53310a3 873 for (uint8_t data = 0; data<6; data++) {
APS_Lab 0:f06ed53310a3 874 write_buffer[write_count] = ic[c_ic].configb.tx_data[data];
APS_Lab 0:f06ed53310a3 875 write_count++;
APS_Lab 0:f06ed53310a3 876 }
APS_Lab 0:f06ed53310a3 877 }
APS_Lab 0:f06ed53310a3 878 write_68(total_ic, cmd, write_buffer);
APS_Lab 0:f06ed53310a3 879 }
APS_Lab 0:f06ed53310a3 880
APS_Lab 0:f06ed53310a3 881 //Read CFGA
APS_Lab 0:f06ed53310a3 882 int8_t LTC681x_rdcfg(uint8_t total_ic, //Number of ICs in the system
APS_Lab 0:f06ed53310a3 883 cell_asic ic[]
APS_Lab 0:f06ed53310a3 884 )
APS_Lab 0:f06ed53310a3 885 {
APS_Lab 0:f06ed53310a3 886 uint8_t cmd[2]= {0x00 , 0x02};
APS_Lab 0:f06ed53310a3 887 uint8_t read_buffer[256];
APS_Lab 0:f06ed53310a3 888 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 889 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 890 uint16_t calc_pec;
APS_Lab 0:f06ed53310a3 891 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 892 pec_error = read_68(total_ic, cmd, read_buffer);
APS_Lab 0:f06ed53310a3 893 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 894 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 895 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 896 } else {
APS_Lab 0:f06ed53310a3 897 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 898 }
APS_Lab 0:f06ed53310a3 899
APS_Lab 0:f06ed53310a3 900 for (int byte=0; byte<8; byte++) {
APS_Lab 0:f06ed53310a3 901 ic[c_ic].config.rx_data[byte] = read_buffer[byte+(8*current_ic)];
APS_Lab 0:f06ed53310a3 902 }
APS_Lab 0:f06ed53310a3 903 calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
APS_Lab 0:f06ed53310a3 904 data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
APS_Lab 0:f06ed53310a3 905 if (calc_pec != data_pec ) {
APS_Lab 0:f06ed53310a3 906 ic[c_ic].config.rx_pec_match = 1;
APS_Lab 0:f06ed53310a3 907 } else ic[c_ic].config.rx_pec_match = 0;
APS_Lab 0:f06ed53310a3 908 }
APS_Lab 0:f06ed53310a3 909 LTC681x_check_pec(total_ic,CFGR,ic);
APS_Lab 0:f06ed53310a3 910 return(pec_error);
APS_Lab 0:f06ed53310a3 911 }
APS_Lab 0:f06ed53310a3 912
APS_Lab 0:f06ed53310a3 913 //Reads CFGB
APS_Lab 0:f06ed53310a3 914 int8_t LTC681x_rdcfgb(uint8_t total_ic, //Number of ICs in the system
APS_Lab 0:f06ed53310a3 915 cell_asic ic[]
APS_Lab 0:f06ed53310a3 916 )
APS_Lab 0:f06ed53310a3 917 {
APS_Lab 0:f06ed53310a3 918 uint8_t cmd[2]= {0x00 , 0x26};
APS_Lab 0:f06ed53310a3 919 uint8_t read_buffer[256];
APS_Lab 0:f06ed53310a3 920 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 921 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 922 uint16_t calc_pec;
APS_Lab 0:f06ed53310a3 923 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 924 pec_error = read_68(total_ic, cmd, read_buffer);
APS_Lab 0:f06ed53310a3 925 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 926 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 927 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 928 } else {
APS_Lab 0:f06ed53310a3 929 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 930 }
APS_Lab 0:f06ed53310a3 931
APS_Lab 0:f06ed53310a3 932 for (int byte=0; byte<8; byte++) {
APS_Lab 0:f06ed53310a3 933 ic[c_ic].configb.rx_data[byte] = read_buffer[byte+(8*current_ic)];
APS_Lab 0:f06ed53310a3 934 }
APS_Lab 0:f06ed53310a3 935 calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
APS_Lab 0:f06ed53310a3 936 data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
APS_Lab 0:f06ed53310a3 937 if (calc_pec != data_pec ) {
APS_Lab 0:f06ed53310a3 938 ic[c_ic].configb.rx_pec_match = 1;
APS_Lab 0:f06ed53310a3 939 } else ic[c_ic].configb.rx_pec_match = 0;
APS_Lab 0:f06ed53310a3 940 }
APS_Lab 0:f06ed53310a3 941 LTC681x_check_pec(total_ic,CFGRB,ic);
APS_Lab 0:f06ed53310a3 942 return(pec_error);
APS_Lab 0:f06ed53310a3 943 }
APS_Lab 0:f06ed53310a3 944
APS_Lab 0:f06ed53310a3 945 //Looks up the result pattern for digital filter self test
APS_Lab 0:f06ed53310a3 946 uint16_t LTC681x_st_lookup(
APS_Lab 0:f06ed53310a3 947 uint8_t MD, //ADC Mode
APS_Lab 0:f06ed53310a3 948 uint8_t ST //Self Test
APS_Lab 0:f06ed53310a3 949 )
APS_Lab 0:f06ed53310a3 950 {
APS_Lab 0:f06ed53310a3 951 uint16_t test_pattern = 0;
APS_Lab 0:f06ed53310a3 952 if (MD == 1) {
APS_Lab 0:f06ed53310a3 953 if (ST == 1) {
APS_Lab 0:f06ed53310a3 954 test_pattern = 0x9565;
APS_Lab 0:f06ed53310a3 955 } else {
APS_Lab 0:f06ed53310a3 956 test_pattern = 0x6A9A;
APS_Lab 0:f06ed53310a3 957 }
APS_Lab 0:f06ed53310a3 958 } else {
APS_Lab 0:f06ed53310a3 959 if (ST == 1) {
APS_Lab 0:f06ed53310a3 960 test_pattern = 0x9555;
APS_Lab 0:f06ed53310a3 961 } else {
APS_Lab 0:f06ed53310a3 962 test_pattern = 0x6AAA;
APS_Lab 0:f06ed53310a3 963 }
APS_Lab 0:f06ed53310a3 964 }
APS_Lab 0:f06ed53310a3 965 return(test_pattern);
APS_Lab 0:f06ed53310a3 966 }
APS_Lab 0:f06ed53310a3 967
APS_Lab 0:f06ed53310a3 968 //Clears all of the DCC bits in the configuration registers
APS_Lab 0:f06ed53310a3 969 void clear_discharge(uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 970 {
APS_Lab 0:f06ed53310a3 971 for (int i=0; i<total_ic; i++) {
APS_Lab 0:f06ed53310a3 972 ic[i].config.tx_data[4] = 0;
APS_Lab 0:f06ed53310a3 973 ic[i].config.tx_data[5] = 0;
APS_Lab 0:f06ed53310a3 974 }
APS_Lab 0:f06ed53310a3 975 }
APS_Lab 0:f06ed53310a3 976
APS_Lab 0:f06ed53310a3 977 // Runs the Digital Filter Self Test
APS_Lab 0:f06ed53310a3 978 int16_t LTC681x_run_cell_adc_st(uint8_t adc_reg,uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 979 {
APS_Lab 0:f06ed53310a3 980 int16_t error = 0;
APS_Lab 0:f06ed53310a3 981 uint16_t expected_result = 0;
APS_Lab 0:f06ed53310a3 982 for (int self_test = 1; self_test<3; self_test++) {
APS_Lab 0:f06ed53310a3 983
APS_Lab 0:f06ed53310a3 984 expected_result = LTC681x_st_lookup(2,self_test);
APS_Lab 0:f06ed53310a3 985 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 986 switch (adc_reg) {
APS_Lab 0:f06ed53310a3 987 case CELL:
APS_Lab 0:f06ed53310a3 988 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 989 LTC681x_clrcell();
APS_Lab 0:f06ed53310a3 990 LTC681x_cvst(2,self_test);
APS_Lab 0:f06ed53310a3 991 LTC681x_pollAdc();//this isn't working
APS_Lab 0:f06ed53310a3 992 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 993 error = LTC681x_rdcv(0, total_ic,ic);
APS_Lab 0:f06ed53310a3 994 for (int cic = 0; cic < total_ic; cic++) {
APS_Lab 0:f06ed53310a3 995 for (int channel=0; channel< ic[cic].ic_reg.cell_channels; channel++) {
APS_Lab 0:f06ed53310a3 996 if (ic[cic].cells.c_codes[channel] != expected_result) {
APS_Lab 0:f06ed53310a3 997 error = error+1;
APS_Lab 0:f06ed53310a3 998 }
APS_Lab 0:f06ed53310a3 999 }
APS_Lab 0:f06ed53310a3 1000 }
APS_Lab 0:f06ed53310a3 1001 break;
APS_Lab 0:f06ed53310a3 1002 case AUX:
APS_Lab 0:f06ed53310a3 1003 error = 0;
APS_Lab 0:f06ed53310a3 1004 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1005 LTC681x_clraux();
APS_Lab 0:f06ed53310a3 1006 LTC681x_axst(2,self_test);
APS_Lab 0:f06ed53310a3 1007 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1008 delay_m(10);
APS_Lab 0:f06ed53310a3 1009 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1010 LTC681x_rdaux(0, total_ic,ic);
APS_Lab 0:f06ed53310a3 1011 for (int cic = 0; cic < total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1012 for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
APS_Lab 0:f06ed53310a3 1013 if (ic[cic].aux.a_codes[channel] != expected_result) {
APS_Lab 0:f06ed53310a3 1014 error = error+1;
APS_Lab 0:f06ed53310a3 1015 }
APS_Lab 0:f06ed53310a3 1016 }
APS_Lab 0:f06ed53310a3 1017 }
APS_Lab 0:f06ed53310a3 1018 break;
APS_Lab 0:f06ed53310a3 1019 case STAT:
APS_Lab 0:f06ed53310a3 1020 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1021 LTC681x_clrstat();
APS_Lab 0:f06ed53310a3 1022 LTC681x_statst(2,self_test);
APS_Lab 0:f06ed53310a3 1023 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1024 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1025 error = LTC681x_rdstat(0,total_ic,ic);
APS_Lab 0:f06ed53310a3 1026 for (int cic = 0; cic < total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1027 for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
APS_Lab 0:f06ed53310a3 1028 if (ic[cic].stat.stat_codes[channel] != expected_result) {
APS_Lab 0:f06ed53310a3 1029 error = error+1;
APS_Lab 0:f06ed53310a3 1030 }
APS_Lab 0:f06ed53310a3 1031 }
APS_Lab 0:f06ed53310a3 1032 }
APS_Lab 0:f06ed53310a3 1033 break;
APS_Lab 0:f06ed53310a3 1034
APS_Lab 0:f06ed53310a3 1035 default:
APS_Lab 0:f06ed53310a3 1036 error = -1;
APS_Lab 0:f06ed53310a3 1037 break;
APS_Lab 0:f06ed53310a3 1038 }
APS_Lab 0:f06ed53310a3 1039 }
APS_Lab 0:f06ed53310a3 1040 return(error);
APS_Lab 0:f06ed53310a3 1041 }
APS_Lab 0:f06ed53310a3 1042
APS_Lab 0:f06ed53310a3 1043 //runs the redundancy self test
APS_Lab 0:f06ed53310a3 1044 int16_t LTC681x_run_adc_redundancy_st(uint8_t adc_mode, uint8_t adc_reg, uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 1045 {
APS_Lab 0:f06ed53310a3 1046 int16_t error = 0;
APS_Lab 0:f06ed53310a3 1047 for (int self_test = 1; self_test<3; self_test++) {
APS_Lab 0:f06ed53310a3 1048 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1049 switch (adc_reg) {
APS_Lab 0:f06ed53310a3 1050 case AUX:
APS_Lab 0:f06ed53310a3 1051 LTC681x_clraux();
APS_Lab 0:f06ed53310a3 1052 LTC681x_adaxd(adc_mode,AUX_CH_ALL);
APS_Lab 0:f06ed53310a3 1053 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1054 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1055 error = LTC681x_rdaux(0, total_ic,ic);
APS_Lab 0:f06ed53310a3 1056 for (int cic = 0; cic < total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1057 for (int channel=0; channel< ic[cic].ic_reg.aux_channels; channel++) {
APS_Lab 0:f06ed53310a3 1058 if (ic[cic].aux.a_codes[channel] >= 65280) {
APS_Lab 0:f06ed53310a3 1059 error = error+1;
APS_Lab 0:f06ed53310a3 1060 }
APS_Lab 0:f06ed53310a3 1061 }
APS_Lab 0:f06ed53310a3 1062 }
APS_Lab 0:f06ed53310a3 1063 break;
APS_Lab 0:f06ed53310a3 1064 case STAT:
APS_Lab 0:f06ed53310a3 1065 LTC681x_clrstat();
APS_Lab 0:f06ed53310a3 1066 LTC681x_adstatd(adc_mode,STAT_CH_ALL);
APS_Lab 0:f06ed53310a3 1067 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1068 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1069 error = LTC681x_rdstat(0,total_ic,ic);
APS_Lab 0:f06ed53310a3 1070 for (int cic = 0; cic < total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1071 for (int channel=0; channel< ic[cic].ic_reg.stat_channels; channel++) {
APS_Lab 0:f06ed53310a3 1072 if (ic[cic].stat.stat_codes[channel] >= 65280) {
APS_Lab 0:f06ed53310a3 1073 error = error+1;
APS_Lab 0:f06ed53310a3 1074 }
APS_Lab 0:f06ed53310a3 1075 }
APS_Lab 0:f06ed53310a3 1076 }
APS_Lab 0:f06ed53310a3 1077 break;
APS_Lab 0:f06ed53310a3 1078
APS_Lab 0:f06ed53310a3 1079 default:
APS_Lab 0:f06ed53310a3 1080 error = -1;
APS_Lab 0:f06ed53310a3 1081 break;
APS_Lab 0:f06ed53310a3 1082 }
APS_Lab 0:f06ed53310a3 1083 }
APS_Lab 0:f06ed53310a3 1084 return(error);
APS_Lab 0:f06ed53310a3 1085 }
APS_Lab 0:f06ed53310a3 1086
APS_Lab 0:f06ed53310a3 1087 //Runs the datasheet algorithm for open wire
APS_Lab 0:f06ed53310a3 1088 void LTC681x_run_openwire(uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 1089 {
APS_Lab 0:f06ed53310a3 1090 uint16_t OPENWIRE_THRESHOLD = 4000;
APS_Lab 0:f06ed53310a3 1091 const uint8_t N_CHANNELS = ic[0].ic_reg.cell_channels;
APS_Lab 0:f06ed53310a3 1092
APS_Lab 0:f06ed53310a3 1093 cell_asic pullUp_cell_codes[total_ic];
APS_Lab 0:f06ed53310a3 1094 cell_asic pullDwn_cell_codes[total_ic];
APS_Lab 0:f06ed53310a3 1095 cell_asic openWire_delta[total_ic];
APS_Lab 0:f06ed53310a3 1096 int8_t error;
APS_Lab 0:f06ed53310a3 1097
APS_Lab 0:f06ed53310a3 1098 wakeup_sleep(total_ic);
APS_Lab 0:f06ed53310a3 1099 LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
APS_Lab 0:f06ed53310a3 1100 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1101 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1102 LTC681x_adow(MD_7KHZ_3KHZ,PULL_UP_CURRENT);
APS_Lab 0:f06ed53310a3 1103 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1104 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1105 error = LTC681x_rdcv(0, total_ic,pullUp_cell_codes);
APS_Lab 0:f06ed53310a3 1106
APS_Lab 0:f06ed53310a3 1107 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1108 LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
APS_Lab 0:f06ed53310a3 1109 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1110 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1111 LTC681x_adow(MD_7KHZ_3KHZ,PULL_DOWN_CURRENT);
APS_Lab 0:f06ed53310a3 1112 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1113 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1114 error = LTC681x_rdcv(0, total_ic,pullDwn_cell_codes);
APS_Lab 0:f06ed53310a3 1115
APS_Lab 0:f06ed53310a3 1116 for (int cic=0; cic<total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1117 ic[cic].system_open_wire =0;
APS_Lab 0:f06ed53310a3 1118 for (int cell=0; cell<N_CHANNELS; cell++) {
APS_Lab 0:f06ed53310a3 1119 if (pullDwn_cell_codes[cic].cells.c_codes[cell]>pullUp_cell_codes[cic].cells.c_codes[cell]) {
APS_Lab 0:f06ed53310a3 1120 openWire_delta[cic].cells.c_codes[cell] = pullDwn_cell_codes[cic].cells.c_codes[cell] - pullUp_cell_codes[cic].cells.c_codes[cell] ;
APS_Lab 0:f06ed53310a3 1121 } else {
APS_Lab 0:f06ed53310a3 1122 openWire_delta[cic].cells.c_codes[cell] = 0;
APS_Lab 0:f06ed53310a3 1123 }
APS_Lab 0:f06ed53310a3 1124
APS_Lab 0:f06ed53310a3 1125 }
APS_Lab 0:f06ed53310a3 1126 }
APS_Lab 0:f06ed53310a3 1127 for (int cic=0; cic<total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1128 for (int cell=1; cell<N_CHANNELS; cell++) {
APS_Lab 0:f06ed53310a3 1129
APS_Lab 0:f06ed53310a3 1130 if (openWire_delta[cic].cells.c_codes[cell]>OPENWIRE_THRESHOLD) {
APS_Lab 0:f06ed53310a3 1131 ic[cic].system_open_wire += (1<<cell);
APS_Lab 0:f06ed53310a3 1132
APS_Lab 0:f06ed53310a3 1133 }
APS_Lab 0:f06ed53310a3 1134 }
APS_Lab 0:f06ed53310a3 1135 if (pullUp_cell_codes[cic].cells.c_codes[0] == 0) {
APS_Lab 0:f06ed53310a3 1136 ic[cic].system_open_wire += 1;
APS_Lab 0:f06ed53310a3 1137 }
APS_Lab 0:f06ed53310a3 1138 if (pullUp_cell_codes[cic].cells.c_codes[N_CHANNELS-1] == 0) {
APS_Lab 0:f06ed53310a3 1139 ic[cic].system_open_wire += (1<<(N_CHANNELS));
APS_Lab 0:f06ed53310a3 1140 }
APS_Lab 0:f06ed53310a3 1141 }
APS_Lab 0:f06ed53310a3 1142 }
APS_Lab 0:f06ed53310a3 1143
APS_Lab 0:f06ed53310a3 1144 // Runs the ADC overlap test for the IC
APS_Lab 0:f06ed53310a3 1145 uint16_t LTC681x_run_adc_overlap(uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 1146 {
APS_Lab 0:f06ed53310a3 1147 uint16_t error = 0;
APS_Lab 0:f06ed53310a3 1148 int32_t measure_delta =0;
APS_Lab 0:f06ed53310a3 1149 int16_t failure_pos_limit = 20;
APS_Lab 0:f06ed53310a3 1150 int16_t failure_neg_limit = -20;
APS_Lab 0:f06ed53310a3 1151 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1152 LTC681x_adol(MD_7KHZ_3KHZ,DCP_DISABLED);
APS_Lab 0:f06ed53310a3 1153 LTC681x_pollAdc();
APS_Lab 0:f06ed53310a3 1154 wakeup_idle(total_ic);
APS_Lab 0:f06ed53310a3 1155 error = LTC681x_rdcv(0, total_ic,ic);
APS_Lab 0:f06ed53310a3 1156 for (int cic = 0; cic<total_ic; cic++) {
APS_Lab 0:f06ed53310a3 1157 measure_delta = (int32_t)ic[cic].cells.c_codes[6]-(int32_t)ic[cic].cells.c_codes[7];
APS_Lab 0:f06ed53310a3 1158 if ((measure_delta>failure_pos_limit) || (measure_delta<failure_neg_limit)) {
APS_Lab 0:f06ed53310a3 1159 error = error | (1<<(cic-1));
APS_Lab 0:f06ed53310a3 1160 }
APS_Lab 0:f06ed53310a3 1161 }
APS_Lab 0:f06ed53310a3 1162 return(error);
APS_Lab 0:f06ed53310a3 1163 }
APS_Lab 0:f06ed53310a3 1164
APS_Lab 0:f06ed53310a3 1165 //Helper function that increments PEC counters
APS_Lab 0:f06ed53310a3 1166 void LTC681x_check_pec(uint8_t total_ic,uint8_t reg, cell_asic ic[])
APS_Lab 0:f06ed53310a3 1167 {
APS_Lab 0:f06ed53310a3 1168 switch (reg) {
APS_Lab 0:f06ed53310a3 1169 case CFGR:
APS_Lab 0:f06ed53310a3 1170 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1171 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].config.rx_pec_match;
APS_Lab 0:f06ed53310a3 1172 ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].config.rx_pec_match;
APS_Lab 0:f06ed53310a3 1173 }
APS_Lab 0:f06ed53310a3 1174 break;
APS_Lab 0:f06ed53310a3 1175
APS_Lab 0:f06ed53310a3 1176 case CFGRB:
APS_Lab 0:f06ed53310a3 1177 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1178 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].configb.rx_pec_match;
APS_Lab 0:f06ed53310a3 1179 ic[current_ic].crc_count.cfgr_pec = ic[current_ic].crc_count.cfgr_pec + ic[current_ic].configb.rx_pec_match;
APS_Lab 0:f06ed53310a3 1180 }
APS_Lab 0:f06ed53310a3 1181 break;
APS_Lab 0:f06ed53310a3 1182 case CELL:
APS_Lab 0:f06ed53310a3 1183 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1184 for (int i=0; i<ic[0].ic_reg.num_cv_reg; i++) {
APS_Lab 0:f06ed53310a3 1185 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].cells.pec_match[i];
APS_Lab 0:f06ed53310a3 1186 ic[current_ic].crc_count.cell_pec[i] = ic[current_ic].crc_count.cell_pec[i] + ic[current_ic].cells.pec_match[i];
APS_Lab 0:f06ed53310a3 1187 }
APS_Lab 0:f06ed53310a3 1188 }
APS_Lab 0:f06ed53310a3 1189 break;
APS_Lab 0:f06ed53310a3 1190 case AUX:
APS_Lab 0:f06ed53310a3 1191 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1192 for (int i=0; i<ic[0].ic_reg.num_gpio_reg; i++) {
APS_Lab 0:f06ed53310a3 1193 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + (ic[current_ic].aux.pec_match[i]);
APS_Lab 0:f06ed53310a3 1194 ic[current_ic].crc_count.aux_pec[i] = ic[current_ic].crc_count.aux_pec[i] + (ic[current_ic].aux.pec_match[i]);
APS_Lab 0:f06ed53310a3 1195 }
APS_Lab 0:f06ed53310a3 1196 }
APS_Lab 0:f06ed53310a3 1197
APS_Lab 0:f06ed53310a3 1198 break;
APS_Lab 0:f06ed53310a3 1199 case STAT:
APS_Lab 0:f06ed53310a3 1200 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1201
APS_Lab 0:f06ed53310a3 1202 for (int i=0; i<ic[0].ic_reg.num_stat_reg-1; i++) {
APS_Lab 0:f06ed53310a3 1203 ic[current_ic].crc_count.pec_count = ic[current_ic].crc_count.pec_count + ic[current_ic].stat.pec_match[i];
APS_Lab 0:f06ed53310a3 1204 ic[current_ic].crc_count.stat_pec[i] = ic[current_ic].crc_count.stat_pec[i] + ic[current_ic].stat.pec_match[i];
APS_Lab 0:f06ed53310a3 1205 }
APS_Lab 0:f06ed53310a3 1206 }
APS_Lab 0:f06ed53310a3 1207 break;
APS_Lab 0:f06ed53310a3 1208 default:
APS_Lab 0:f06ed53310a3 1209 break;
APS_Lab 0:f06ed53310a3 1210 }
APS_Lab 0:f06ed53310a3 1211 }
APS_Lab 0:f06ed53310a3 1212
APS_Lab 0:f06ed53310a3 1213 //Helper Function to reset PEC counters
APS_Lab 0:f06ed53310a3 1214 void LTC681x_reset_crc_count(uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 1215 {
APS_Lab 0:f06ed53310a3 1216 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1217 ic[current_ic].crc_count.pec_count = 0;
APS_Lab 0:f06ed53310a3 1218 ic[current_ic].crc_count.cfgr_pec = 0;
APS_Lab 0:f06ed53310a3 1219 for (int i=0; i<6; i++) {
APS_Lab 0:f06ed53310a3 1220 ic[current_ic].crc_count.cell_pec[i]=0;
APS_Lab 0:f06ed53310a3 1221
APS_Lab 0:f06ed53310a3 1222 }
APS_Lab 0:f06ed53310a3 1223 for (int i=0; i<4; i++) {
APS_Lab 0:f06ed53310a3 1224 ic[current_ic].crc_count.aux_pec[i]=0;
APS_Lab 0:f06ed53310a3 1225 }
APS_Lab 0:f06ed53310a3 1226 for (int i=0; i<2; i++) {
APS_Lab 0:f06ed53310a3 1227 ic[current_ic].crc_count.stat_pec[i]=0;
APS_Lab 0:f06ed53310a3 1228 }
APS_Lab 0:f06ed53310a3 1229 }
APS_Lab 0:f06ed53310a3 1230 }
APS_Lab 0:f06ed53310a3 1231
APS_Lab 0:f06ed53310a3 1232 //Helper function to intialize CFG variables.
APS_Lab 0:f06ed53310a3 1233 void LTC681x_init_cfg(uint8_t total_ic, cell_asic ic[])
APS_Lab 0:f06ed53310a3 1234 {
APS_Lab 0:f06ed53310a3 1235 bool REFON = true;
APS_Lab 0:f06ed53310a3 1236 bool ADCOPT = false;
APS_Lab 0:f06ed53310a3 1237 bool gpioBits[5] = {true,true,true,true,true};
APS_Lab 0:f06ed53310a3 1238 bool dccBits[12] = {false,false,false,false,false,false,false,false,false,false,false,false};
APS_Lab 0:f06ed53310a3 1239 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1240 for (int j =0; j<6; j++) {
APS_Lab 0:f06ed53310a3 1241 ic[current_ic].config.tx_data[j] = 0;
APS_Lab 0:f06ed53310a3 1242 ic[current_ic].configb.tx_data[j] = 0;
APS_Lab 0:f06ed53310a3 1243 }
APS_Lab 0:f06ed53310a3 1244 LTC681x_set_cfgr(current_ic ,ic,REFON,ADCOPT,gpioBits,dccBits);
APS_Lab 0:f06ed53310a3 1245
APS_Lab 0:f06ed53310a3 1246 }
APS_Lab 0:f06ed53310a3 1247 }
APS_Lab 0:f06ed53310a3 1248
APS_Lab 0:f06ed53310a3 1249 //Helper function to set CFGR variable
APS_Lab 0:f06ed53310a3 1250 void LTC681x_set_cfgr(uint8_t nIC, cell_asic ic[], bool refon, bool adcopt, bool gpio[5],bool dcc[12])
APS_Lab 0:f06ed53310a3 1251 {
APS_Lab 0:f06ed53310a3 1252 LTC681x_set_cfgr_refon(nIC,ic,refon);
APS_Lab 0:f06ed53310a3 1253 LTC681x_set_cfgr_adcopt(nIC,ic,adcopt);
APS_Lab 0:f06ed53310a3 1254 LTC681x_set_cfgr_gpio(nIC,ic,gpio);
APS_Lab 0:f06ed53310a3 1255 LTC681x_set_cfgr_dis(nIC,ic,dcc);
APS_Lab 0:f06ed53310a3 1256 }
APS_Lab 0:f06ed53310a3 1257
APS_Lab 0:f06ed53310a3 1258 //Helper function to set the REFON bit
APS_Lab 0:f06ed53310a3 1259 void LTC681x_set_cfgr_refon(uint8_t nIC, cell_asic ic[], bool refon)
APS_Lab 0:f06ed53310a3 1260 {
APS_Lab 0:f06ed53310a3 1261 if (refon) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|0x04;
APS_Lab 0:f06ed53310a3 1262 else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&0xFB;
APS_Lab 0:f06ed53310a3 1263 }
APS_Lab 0:f06ed53310a3 1264
APS_Lab 0:f06ed53310a3 1265 //Helper function to set the adcopt bit
APS_Lab 0:f06ed53310a3 1266 void LTC681x_set_cfgr_adcopt(uint8_t nIC, cell_asic ic[], bool adcopt)
APS_Lab 0:f06ed53310a3 1267 {
APS_Lab 0:f06ed53310a3 1268 if (adcopt) ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|0x01;
APS_Lab 0:f06ed53310a3 1269 else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&0xFE;
APS_Lab 0:f06ed53310a3 1270 }
APS_Lab 0:f06ed53310a3 1271
APS_Lab 0:f06ed53310a3 1272 //Helper function to set GPIO bits
APS_Lab 0:f06ed53310a3 1273 void LTC681x_set_cfgr_gpio(uint8_t nIC, cell_asic ic[],bool gpio[5])
APS_Lab 0:f06ed53310a3 1274 {
APS_Lab 0:f06ed53310a3 1275 for (int i =0; i<5; i++) {
APS_Lab 0:f06ed53310a3 1276 if (gpio[i])ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]|(0x01<<(i+3));
APS_Lab 0:f06ed53310a3 1277 else ic[nIC].config.tx_data[0] = ic[nIC].config.tx_data[0]&(~(0x01<<(i+3)));
APS_Lab 0:f06ed53310a3 1278 }
APS_Lab 0:f06ed53310a3 1279 }
APS_Lab 0:f06ed53310a3 1280
APS_Lab 0:f06ed53310a3 1281 //Helper function to control discharge
APS_Lab 0:f06ed53310a3 1282 void LTC681x_set_cfgr_dis(uint8_t nIC, cell_asic ic[],bool dcc[12])
APS_Lab 0:f06ed53310a3 1283 {
APS_Lab 0:f06ed53310a3 1284 for (int i =0; i<8; i++) {
APS_Lab 0:f06ed53310a3 1285 if (dcc[i])ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4]|(0x01<<i);
APS_Lab 0:f06ed53310a3 1286 else ic[nIC].config.tx_data[4] = ic[nIC].config.tx_data[4]& (~(0x01<<i));
APS_Lab 0:f06ed53310a3 1287 }
APS_Lab 0:f06ed53310a3 1288 for (int i =0; i<4; i++) {
APS_Lab 0:f06ed53310a3 1289 if (dcc[i+8])ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5]|(0x01<<i);
APS_Lab 0:f06ed53310a3 1290 else ic[nIC].config.tx_data[5] = ic[nIC].config.tx_data[5]&(~(0x01<<i));
APS_Lab 0:f06ed53310a3 1291 }
APS_Lab 0:f06ed53310a3 1292 }
APS_Lab 0:f06ed53310a3 1293
APS_Lab 0:f06ed53310a3 1294 //Helper Function to set uv value in CFG register
APS_Lab 0:f06ed53310a3 1295 void LTC681x_set_cfgr_uv(uint8_t nIC, cell_asic ic[],uint16_t uv)
APS_Lab 0:f06ed53310a3 1296 {
APS_Lab 0:f06ed53310a3 1297 uint16_t tmp = (uv/16)-1;
APS_Lab 0:f06ed53310a3 1298 ic[nIC].config.tx_data[1] = 0x00FF & tmp;
APS_Lab 0:f06ed53310a3 1299 ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0xF0;
APS_Lab 0:f06ed53310a3 1300 ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x0F00 & tmp)>>8);
APS_Lab 0:f06ed53310a3 1301 }
APS_Lab 0:f06ed53310a3 1302
APS_Lab 0:f06ed53310a3 1303 //helper function to set OV value in CFG register
APS_Lab 0:f06ed53310a3 1304 void LTC681x_set_cfgr_ov(uint8_t nIC, cell_asic ic[],uint16_t ov)
APS_Lab 0:f06ed53310a3 1305 {
APS_Lab 0:f06ed53310a3 1306 uint16_t tmp = (ov/16);
APS_Lab 0:f06ed53310a3 1307 ic[nIC].config.tx_data[3] = 0x00FF & (tmp>>4);
APS_Lab 0:f06ed53310a3 1308 ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]&0x0F;
APS_Lab 0:f06ed53310a3 1309 ic[nIC].config.tx_data[2] = ic[nIC].config.tx_data[2]|((0x000F & tmp)<<4);
APS_Lab 0:f06ed53310a3 1310 }
APS_Lab 0:f06ed53310a3 1311
APS_Lab 0:f06ed53310a3 1312 //Writes the comm register
APS_Lab 0:f06ed53310a3 1313 void LTC681x_wrcomm(uint8_t total_ic, //The number of ICs being written to
APS_Lab 0:f06ed53310a3 1314 cell_asic ic[]
APS_Lab 0:f06ed53310a3 1315 )
APS_Lab 0:f06ed53310a3 1316 {
APS_Lab 0:f06ed53310a3 1317 uint8_t cmd[2]= {0x07 , 0x21};
APS_Lab 0:f06ed53310a3 1318 uint8_t write_buffer[256];
APS_Lab 0:f06ed53310a3 1319 uint8_t write_count = 0;
APS_Lab 0:f06ed53310a3 1320 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 1321 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1322 if (ic->isospi_reverse == true) {
APS_Lab 0:f06ed53310a3 1323 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 1324 } else {
APS_Lab 0:f06ed53310a3 1325 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 1326 }
APS_Lab 0:f06ed53310a3 1327
APS_Lab 0:f06ed53310a3 1328 for (uint8_t data = 0; data<6; data++) {
APS_Lab 0:f06ed53310a3 1329 write_buffer[write_count] = ic[c_ic].com.tx_data[data];
APS_Lab 0:f06ed53310a3 1330 write_count++;
APS_Lab 0:f06ed53310a3 1331 }
APS_Lab 0:f06ed53310a3 1332 }
APS_Lab 0:f06ed53310a3 1333 write_68(total_ic, cmd, write_buffer);
APS_Lab 0:f06ed53310a3 1334 }
APS_Lab 0:f06ed53310a3 1335
APS_Lab 0:f06ed53310a3 1336 /*
APS_Lab 0:f06ed53310a3 1337 Reads COMM registers of a LTC6811 daisy chain
APS_Lab 0:f06ed53310a3 1338 */
APS_Lab 0:f06ed53310a3 1339 int8_t LTC681x_rdcomm(uint8_t total_ic, //Number of ICs in the system
APS_Lab 0:f06ed53310a3 1340 cell_asic ic[]
APS_Lab 0:f06ed53310a3 1341 )
APS_Lab 0:f06ed53310a3 1342 {
APS_Lab 0:f06ed53310a3 1343 uint8_t cmd[2]= {0x07 , 0x22};
APS_Lab 0:f06ed53310a3 1344 uint8_t read_buffer[256];
APS_Lab 0:f06ed53310a3 1345 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 1346 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 1347 uint16_t calc_pec;
APS_Lab 0:f06ed53310a3 1348 uint8_t c_ic=0;
APS_Lab 0:f06ed53310a3 1349 pec_error = read_68(total_ic, cmd, read_buffer);
APS_Lab 0:f06ed53310a3 1350 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1351 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 1352 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 1353 } else {
APS_Lab 0:f06ed53310a3 1354 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 1355 }
APS_Lab 0:f06ed53310a3 1356
APS_Lab 0:f06ed53310a3 1357 for (int byte=0; byte<8; byte++) {
APS_Lab 0:f06ed53310a3 1358 ic[c_ic].com.rx_data[byte] = read_buffer[byte+(8*current_ic)];
APS_Lab 0:f06ed53310a3 1359 }
APS_Lab 0:f06ed53310a3 1360 calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
APS_Lab 0:f06ed53310a3 1361 data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
APS_Lab 0:f06ed53310a3 1362 if (calc_pec != data_pec ) {
APS_Lab 0:f06ed53310a3 1363 ic[c_ic].com.rx_pec_match = 1;
APS_Lab 0:f06ed53310a3 1364 } else ic[c_ic].com.rx_pec_match = 0;
APS_Lab 0:f06ed53310a3 1365 }
APS_Lab 0:f06ed53310a3 1366 return(pec_error);
APS_Lab 0:f06ed53310a3 1367 }
APS_Lab 0:f06ed53310a3 1368
APS_Lab 0:f06ed53310a3 1369 /*
APS_Lab 0:f06ed53310a3 1370 Shifts data in COMM register out over LTC6811 SPI/I2C port
APS_Lab 0:f06ed53310a3 1371 */
APS_Lab 0:f06ed53310a3 1372 void LTC681x_stcomm()
APS_Lab 0:f06ed53310a3 1373 {
APS_Lab 0:f06ed53310a3 1374
APS_Lab 0:f06ed53310a3 1375 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 1376 uint16_t cmd_pec;
APS_Lab 0:f06ed53310a3 1377
APS_Lab 0:f06ed53310a3 1378 cmd[0] = 0x07;
APS_Lab 0:f06ed53310a3 1379 cmd[1] = 0x23;
APS_Lab 0:f06ed53310a3 1380 cmd_pec = pec15_calc(2, cmd);
APS_Lab 0:f06ed53310a3 1381 cmd[2] = (uint8_t)(cmd_pec >> 8);
APS_Lab 0:f06ed53310a3 1382 cmd[3] = (uint8_t)(cmd_pec);
APS_Lab 0:f06ed53310a3 1383
APS_Lab 1:4dd3e328a30b 1384 cs_low();
APS_Lab 0:f06ed53310a3 1385 spi_write_array(4,cmd);
APS_Lab 0:f06ed53310a3 1386 for (int i = 0; i<9; i++) {
APS_Lab 0:f06ed53310a3 1387 spi_read_byte(0xFF);
APS_Lab 0:f06ed53310a3 1388 }
APS_Lab 1:4dd3e328a30b 1389 cs_high();
APS_Lab 0:f06ed53310a3 1390
APS_Lab 0:f06ed53310a3 1391 }
APS_Lab 0:f06ed53310a3 1392
APS_Lab 0:f06ed53310a3 1393 // Writes the pwm register
APS_Lab 0:f06ed53310a3 1394 void LTC681x_wrpwm(uint8_t total_ic,
APS_Lab 0:f06ed53310a3 1395 uint8_t pwmReg,
APS_Lab 0:f06ed53310a3 1396 cell_asic ic[]
APS_Lab 0:f06ed53310a3 1397 )
APS_Lab 0:f06ed53310a3 1398 {
APS_Lab 0:f06ed53310a3 1399 uint8_t cmd[2];
APS_Lab 0:f06ed53310a3 1400 uint8_t write_buffer[256];
APS_Lab 0:f06ed53310a3 1401 uint8_t write_count = 0;
APS_Lab 0:f06ed53310a3 1402 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 1403 if (pwmReg == 0) {
APS_Lab 0:f06ed53310a3 1404 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 1405 cmd[1] = 0x20;
APS_Lab 0:f06ed53310a3 1406 } else {
APS_Lab 0:f06ed53310a3 1407 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 1408 cmd[1] = 0x1C;
APS_Lab 0:f06ed53310a3 1409 }
APS_Lab 0:f06ed53310a3 1410
APS_Lab 0:f06ed53310a3 1411 for (uint8_t current_ic = 0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1412 if (ic->isospi_reverse == true) {
APS_Lab 0:f06ed53310a3 1413 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 1414 } else {
APS_Lab 0:f06ed53310a3 1415 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 1416 }
APS_Lab 0:f06ed53310a3 1417 for (uint8_t data = 0; data<6; data++) {
APS_Lab 0:f06ed53310a3 1418 write_buffer[write_count] = ic[c_ic].pwm.tx_data[data];
APS_Lab 0:f06ed53310a3 1419 write_count++;
APS_Lab 0:f06ed53310a3 1420 }
APS_Lab 0:f06ed53310a3 1421 }
APS_Lab 0:f06ed53310a3 1422 write_68(total_ic, cmd, write_buffer);
APS_Lab 0:f06ed53310a3 1423 }
APS_Lab 0:f06ed53310a3 1424
APS_Lab 0:f06ed53310a3 1425
APS_Lab 0:f06ed53310a3 1426 /*
APS_Lab 0:f06ed53310a3 1427 Reads pwm registers of a LTC6811 daisy chain
APS_Lab 0:f06ed53310a3 1428 */
APS_Lab 0:f06ed53310a3 1429 int8_t LTC681x_rdpwm(uint8_t total_ic, //Number of ICs in the system
APS_Lab 0:f06ed53310a3 1430 uint8_t pwmReg,
APS_Lab 0:f06ed53310a3 1431 cell_asic ic[]
APS_Lab 0:f06ed53310a3 1432 )
APS_Lab 0:f06ed53310a3 1433 {
APS_Lab 0:f06ed53310a3 1434 // const uint8_t BYTES_IN_REG = 8;
APS_Lab 0:f06ed53310a3 1435
APS_Lab 0:f06ed53310a3 1436 uint8_t cmd[4];
APS_Lab 0:f06ed53310a3 1437 uint8_t read_buffer[256];
APS_Lab 0:f06ed53310a3 1438 int8_t pec_error = 0;
APS_Lab 0:f06ed53310a3 1439 uint16_t data_pec;
APS_Lab 0:f06ed53310a3 1440 uint16_t calc_pec;
APS_Lab 0:f06ed53310a3 1441 uint8_t c_ic = 0;
APS_Lab 0:f06ed53310a3 1442
APS_Lab 0:f06ed53310a3 1443 if (pwmReg == 0) {
APS_Lab 0:f06ed53310a3 1444 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 1445 cmd[1] = 0x22;
APS_Lab 0:f06ed53310a3 1446 } else {
APS_Lab 0:f06ed53310a3 1447 cmd[0] = 0x00;
APS_Lab 0:f06ed53310a3 1448 cmd[1] = 0x1E;
APS_Lab 0:f06ed53310a3 1449 }
APS_Lab 0:f06ed53310a3 1450
APS_Lab 0:f06ed53310a3 1451
APS_Lab 0:f06ed53310a3 1452 pec_error = read_68(total_ic, cmd, read_buffer);
APS_Lab 0:f06ed53310a3 1453 for (uint8_t current_ic =0; current_ic<total_ic; current_ic++) {
APS_Lab 0:f06ed53310a3 1454 if (ic->isospi_reverse == false) {
APS_Lab 0:f06ed53310a3 1455 c_ic = current_ic;
APS_Lab 0:f06ed53310a3 1456 } else {
APS_Lab 0:f06ed53310a3 1457 c_ic = total_ic - current_ic - 1;
APS_Lab 0:f06ed53310a3 1458 }
APS_Lab 0:f06ed53310a3 1459 for (int byte=0; byte<8; byte++) {
APS_Lab 0:f06ed53310a3 1460 ic[c_ic].pwm.rx_data[byte] = read_buffer[byte+(8*current_ic)];
APS_Lab 0:f06ed53310a3 1461 }
APS_Lab 0:f06ed53310a3 1462 calc_pec = pec15_calc(6,&read_buffer[8*current_ic]);
APS_Lab 0:f06ed53310a3 1463 data_pec = read_buffer[7+(8*current_ic)] | (read_buffer[6+(8*current_ic)]<<8);
APS_Lab 0:f06ed53310a3 1464 if (calc_pec != data_pec ) {
APS_Lab 0:f06ed53310a3 1465 ic[c_ic].pwm.rx_pec_match = 1;
APS_Lab 0:f06ed53310a3 1466 } else ic[c_ic].pwm.rx_pec_match = 0;
APS_Lab 0:f06ed53310a3 1467 }
APS_Lab 0:f06ed53310a3 1468 return(pec_error);
APS_Lab 0:f06ed53310a3 1469 }