LTC681x

Committer:
roger5641
Date:
Sun Nov 12 01:21:42 2017 +0000
Revision:
0:c1ea93720ab4
ver1

Who changed what in which revision?

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