Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
LTC68041.cpp
Go to the documentation of this file.
1 /*!
2  LTC6804-1 Multicell Battery Monitor
3 
4 @verbatim
5  The LTC6804 is a 3rd generation multicell battery stack
6  monitor that measures up to 12 series connected battery
7  cells with a total measurement error of less than 1.2mV. The
8  cell measurement range of 0V to 5V makes the LTC6804
9  suitable for most battery chemistries. All 12 cell voltages
10  can be captured in 290uS, and lower data acquisition rates
11  can be selected for high noise reduction.
12 
13  Using the LTC6804-1, multiple devices are connected in
14  a daisy-chain with one host processor connection for all
15  devices.
16 @endverbatim
17 
18 http://www.linear.com/product/LTC6804-1
19 
20 http://www.linear.com/product/LTC6804-1#demoboards
21 
22 
23 Copyright 2018(c) Analog Devices, Inc.
24 
25 All rights reserved.
26 
27 Redistribution and use in source and binary forms, with or without
28 modification, are permitted provided that the following conditions are met:
29  - Redistributions of source code must retain the above copyright
30  notice, this list of conditions and the following disclaimer.
31  - Redistributions in binary form must reproduce the above copyright
32  notice, this list of conditions and the following disclaimer in
33  the documentation and/or other materials provided with the
34  distribution.
35  - Neither the name of Analog Devices, Inc. nor the names of its
36  contributors may be used to endorse or promote products derived
37  from this software without specific prior written permission.
38  - The use of this software may or may not infringe the patent rights
39  of one or more patent holders. This license does not release you
40  from the requirement that you obtain separate licenses from these
41  patent holders to use this software.
42  - Use of the software either in source or binary form, must be run
43  on or directly connected to an Analog Devices Inc. component.
44 
45 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
46 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
47 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
49 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
50 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
51 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
52 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
53 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
54 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 
56 Copyright 2013 Linear Technology Corp. (LTC)
57 ***********************************************************/
58 
59 //! @ingroup BMS
60 //! @{
61 //! @defgroup LTC68041 LTC6804-1: Multicell Battery Monitor
62 //! @}
63 
64 /*! @file
65  @ingroup LTC68041
66  Library for LTC6804-1 Multicell Battery Monitor
67 */
68 
69 #include <stdint.h>
70 #include <Arduino.h>
71 #include "Linduino.h"
72 #include "LT_SPI.h"
73 #include "LTC68041.h"
74 #include <SPI.h>
75 
76 
77 
78 /*!
79  6804 conversion command variables.
80 */
81 uint8_t ADCV[2]; //!< Cell Voltage conversion command.
82 uint8_t ADAX[2]; //!< GPIO conversion command.
83 
84 
85 /*!
86  \brief This function will initialize all 6804 variables and the SPI port.
87 
88  This function will initialize the Linduino to communicate with the LTC6804 with a 1MHz SPI clock.
89  The Function also intializes the ADCV and ADAX commands to convert all cell and GPIO voltages in
90  the Normal ADC mode.
91 */
93 {
95  spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
97 }
98 
99 /*!*******************************************************************************************************************
100  \brief Maps global ADC control variables to the appropriate control bytes for each of the different ADC commands
101 
102 @param[in] uint8_t MD The adc conversion mode
103 @param[in] uint8_t DCP Controls if Discharge is permitted during cell conversions
104 @param[in] uint8_t CH Determines which cells are measured during an ADC conversion command
105 @param[in] uint8_t CHG Determines which GPIO channels are measured during Auxiliary conversion command
106 
107 Command Code:
108 -------------
109 
110 |command | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
111 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
112 |ADCV: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CH[2] | CH[1] | CH[0] |
113 |ADAX: | 0 | 0 | 0 | 0 | 0 | 1 | 0 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CHG[2]| CHG[1]| CHG[0]|
114  ******************************************************************************************************************/
115 void set_adc(uint8_t MD, //ADC Mode
116  uint8_t DCP, //Discharge Permit
117  uint8_t CH, //Cell Channels to be measured
118  uint8_t CHG //GPIO Channels to be measured
119  )
120 {
121  uint8_t md_bits;
122 
123  md_bits = (MD & 0x02) >> 1;
124  ADCV[0] = md_bits + 0x02;
125  md_bits = (MD & 0x01) << 7;
126  ADCV[1] = md_bits + 0x60 + (DCP<<4) + CH;
127 
128  md_bits = (MD & 0x02) >> 1;
129  ADAX[0] = md_bits + 0x04;
130  md_bits = (MD & 0x01) << 7;
131  ADAX[1] = md_bits + 0x60 + CHG ;
132 
133 }
134 
135 
136 /*!*********************************************************************************************
137  \brief Starts cell voltage conversion
138 
139  Starts ADC conversions of the LTC6804 Cpin inputs.
140  The type of ADC conversion executed can be changed by setting the associated global variables:
141  |Variable|Function |
142  |--------|----------------------------------------------|
143  | MD | Determines the filter corner of the ADC |
144  | CH | Determines which cell channels are converted |
145  | DCP | Determines if Discharge is Permitted |
146 
147 Command Code:
148 -------------
149 
150 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
151 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
152 |ADCV: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CH[2] | CH[1] | CH[0] |
153 ***********************************************************************************************/
155 {
156 
157  uint8_t cmd[4];
158  uint16_t cmd_pec;
159 
160  //1
161  cmd[0] = ADCV[0];
162  cmd[1] = ADCV[1];
163 
164  //2
165  cmd_pec = pec15_calc(2, ADCV);
166  cmd[2] = (uint8_t)(cmd_pec >> 8);
167  cmd[3] = (uint8_t)(cmd_pec);
168 
169  //3
170  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
171 
172  //4
174  spi_write_array(4,cmd);
176 
177 }
178 /*
179  LTC6804_adcv Function sequence:
180 
181  1. Load adcv command into cmd array
182  2. Calculate adcv cmd PEC and load pec into cmd array
183  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
184  4. send broadcast adcv command to LTC6804 daisy chain
185 */
186 
187 
188 /*!******************************************************************************************************
189  \brief Start an GPIO Conversion
190 
191  Starts an ADC conversions of the LTC6804 GPIO inputs.
192  The type of ADC conversion executed can be changed by setting the associated global variables:
193  |Variable|Function |
194  |--------|----------------------------------------------|
195  | MD | Determines the filter corner of the ADC |
196  | CHG | Determines which GPIO channels are converted |
197 
198 
199 Command Code:
200 -------------
201 
202 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
203 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
204 |ADAX: | 0 | 0 | 0 | 0 | 0 | 1 | 0 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CHG[2]| CHG[1]| CHG[0]|
205 *********************************************************************************************************/
207 {
208  uint8_t cmd[4];
209  uint16_t cmd_pec;
210 
211  cmd[0] = ADAX[0];
212  cmd[1] = ADAX[1];
213  cmd_pec = pec15_calc(2, ADAX);
214  cmd[2] = (uint8_t)(cmd_pec >> 8);
215  cmd[3] = (uint8_t)(cmd_pec);
216 
217  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
219  spi_write_array(4,cmd);
221 
222 }
223 /*
224  LTC6804_adax Function sequence:
225 
226  1. Load adax command into cmd array
227  2. Calculate adax cmd PEC and load pec into cmd array
228  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
229  4. send broadcast adax command to LTC6804 daisy chain
230 */
231 
232 
233 /***********************************************//**
234  \brief Reads and parses the LTC6804 cell voltage registers.
235 
236  The function is used to read the cell codes of the LTC6804.
237  This function will send the requested read commands parse the data
238  and store the cell voltages in cell_codes variable.
239 
240  @param[in] uint8_t reg; This controls which cell voltage register is read back.
241 
242  0: Read back all Cell registers
243 
244  1: Read back cell group A
245 
246  2: Read back cell group B
247 
248  3: Read back cell group C
249 
250  4: Read back cell group D
251 
252  @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain(-1 only)
253 
254  @param[out] uint16_t cell_codes[]; An array of the parsed cell codes from lowest to highest. The cell codes will
255  be stored in the cell_codes[] array in the following format:
256  | cell_codes[0][0]| cell_codes[0][1] | cell_codes[0][2]| ..... | cell_codes[0][11]| cell_codes[1][0] | cell_codes[1][1]| ..... |
257  |------------------|------------------|------------------|--------------|-------------------|-------------------|-----------------|----------|
258  |IC1 Cell 1 |IC1 Cell 2 |IC1 Cell 3 | ..... | IC1 Cell 12 |IC2 Cell 1 |IC2 Cell 2 | ..... |
259 
260  @return int8_t, PEC Status.
261 
262  0: No PEC error detected
263 
264  -1: PEC error detected, retry read
265 
266 
267  *************************************************/
268 uint8_t LTC6804_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
269  uint8_t total_ic, // the number of ICs in the system
270  uint16_t cell_codes[][12] // Array of the parsed cell codes
271  )
272 {
273 
274  const uint8_t NUM_RX_BYT = 8;
275  const uint8_t BYT_IN_REG = 6;
276  const uint8_t CELL_IN_REG = 3;
277 
278  uint8_t *cell_data;
279  uint8_t pec_error = 0;
280  uint16_t parsed_cell;
281  uint16_t received_pec;
282  uint16_t data_pec;
283  uint8_t data_counter=0; //data counter
284  cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
285  //1.a
286  if (reg == 0)
287  {
288  //a.i
289  for (uint8_t cell_reg = 1; cell_reg<5; cell_reg++) //executes once for each of the LTC6804 cell voltage registers
290  {
291  data_counter = 0;
292  LTC6804_rdcv_reg(cell_reg, total_ic,cell_data ); //Reads a single Cell voltage register
293 
294  for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
295  {
296  // current_ic is used as the IC counter
297 
298  //a.ii
299  for (uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) // This loop parses the read back data into cell voltages, it
300  {
301  // loops once for each of the 3 cell voltage codes in the register
302 
303  parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);//Each cell code is received as two bytes and is combined to
304  // create the parsed cell voltage code
305 
306  cell_codes[current_ic][current_cell + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
307  data_counter = data_counter + 2; //Because cell voltage codes are two bytes the data counter
308  //must increment by two for each parsed cell code
309  }
310  //a.iii
311  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
312  //after the 6 cell voltage data bytes
313  data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
314  if (received_pec != data_pec)
315  {
316  pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
317  //are detected in the serial data
318  }
319  data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
320  //must be incremented by 2 bytes to point to the next ICs cell voltage data
321  }
322  }
323  }
324 //1.b
325  else
326  {
327  //b.i
328  LTC6804_rdcv_reg(reg, total_ic,cell_data);
329  for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
330  {
331  // current_ic is used as the IC counter
332  //b.ii
333  for (uint8_t current_cell = 0; current_cell < CELL_IN_REG; current_cell++) // This loop parses the read back data into cell voltages, it
334  {
335  // loops once for each of the 3 cell voltage codes in the register
336 
337  parsed_cell = cell_data[data_counter] + (cell_data[data_counter+1]<<8); //Each cell code is received as two bytes and is combined to
338  // create the parsed cell voltage code
339 
340  cell_codes[current_ic][current_cell + ((reg - 1) * CELL_IN_REG)] = 0x0000FFFF & parsed_cell;
341  data_counter= data_counter + 2; //Because cell voltage codes are two bytes the data counter
342  //must increment by two for each parsed cell code
343  }
344  //b.iii
345  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
346  //after the 6 cell voltage data bytes
347  data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
348  if (received_pec != data_pec)
349  {
350  pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
351  //are detected in the serial data
352  }
353  data_counter= data_counter + 2; //Because the transmitted PEC code is 2 bytes long the data_counter
354  //must be incremented by 2 bytes to point to the next ICs cell voltage data
355  }
356  }
357 
358 //2
359  free(cell_data);
360  return(pec_error);
361 }
362 /*
363  LTC6804_rdcv Sequence
364 
365  1. Switch Statement:
366  a. Reg = 0
367  i. Read cell voltage registers A-D for every IC in the daisy chain
368  ii. Parse raw cell voltage data in cell_codes array
369  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
370  b. Reg != 0
371  i.Read single cell voltage register for all ICs in daisy chain
372  ii. Parse raw cell voltage data in cell_codes array
373  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
374  2. Return pec_error flag
375 */
376 
377 
378 /***********************************************//**
379  \brief Read the raw data from the LTC6804 cell voltage register
380 
381  The function reads a single cell voltage register and stores the read data
382  in the *data point as a byte array. This function is rarely used outside of
383  the LTC6804_rdcv() command.
384 
385  @param[in] uint8_t reg; This controls which cell voltage register is read back.
386 
387  1: Read back cell group A
388 
389  2: Read back cell group B
390 
391  3: Read back cell group C
392 
393  4: Read back cell group D
394 
395  @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain(-1 only)
396 
397  @param[out] uint8_t *data; An array of the unparsed cell codes
398 
399 Command Code:
400 -------------
401 
402 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
403 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
404 |RDCVA: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
405 |RDCVB: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
406 |RDCVC: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
407 |RDCVD: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
408 
409  *************************************************/
410 void LTC6804_rdcv_reg(uint8_t reg, //Determines which cell voltage register is read back
411  uint8_t total_ic, //the number of ICs in the
412  uint8_t *data //An array of the unparsed cell codes
413  )
414 {
415  const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
416  uint8_t cmd[4];
417  uint16_t cmd_pec;
418 
419  //1
420  if (reg == 1) //1: RDCVA
421  {
422  cmd[1] = 0x04;
423  cmd[0] = 0x00;
424  }
425  else if (reg == 2) //2: RDCVB
426  {
427  cmd[1] = 0x06;
428  cmd[0] = 0x00;
429  }
430  else if (reg == 3) //3: RDCVC
431  {
432  cmd[1] = 0x08;
433  cmd[0] = 0x00;
434  }
435  else if (reg == 4) //4: RDCVD
436  {
437  cmd[1] = 0x0A;
438  cmd[0] = 0x00;
439  }
440 
441  //2
442  cmd_pec = pec15_calc(2, cmd);
443  cmd[2] = (uint8_t)(cmd_pec >> 8);
444  cmd[3] = (uint8_t)(cmd_pec);
445 
446  //3
447  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
448 
449  //4
451  spi_write_read(cmd,4,data,(REG_LEN*total_ic));
453 
454 }
455 /*
456  LTC6804_rdcv_reg Function Process:
457  1. Determine Command and initialize command array
458  2. Calculate Command PEC
459  3. Wake up isoSPI, this step is optional
460  4. Send Global Command to LTC6804 daisy chain
461 */
462 
463 
464 /***********************************************************************************//**
465  \brief Reads and parses the LTC6804 auxiliary registers.
466 
467  The function is used
468  to read the parsed GPIO codes of the LTC6804. This function will send the requested
469  read commands parse the data and store the gpio voltages in aux_codes variable
470 
471 @param[in] uint8_t reg; This controls which GPIO voltage register is read back.
472 
473  0: Read back all auxiliary registers
474 
475  1: Read back auxiliary group A
476 
477  2: Read back auxiliary group B
478 
479 
480 @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain(-1 only)
481 
482 
483  @param[out] uint16_t aux_codes[][6]; A two dimensional array of the gpio voltage codes. The GPIO codes will
484  be stored in the aux_codes[][6] array in the following format:
485  | aux_codes[0][0]| aux_codes[0][1] | aux_codes[0][2]| aux_codes[0][3]| aux_codes[0][4]| aux_codes[0][5]| aux_codes[1][0] |aux_codes[1][1]| ..... |
486  |-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|---------------|-----------|
487  |IC1 GPIO1 |IC1 GPIO2 |IC1 GPIO3 |IC1 GPIO4 |IC1 GPIO5 |IC1 Vref2 |IC2 GPIO1 |IC2 GPIO2 | ..... |
488 
489 @return int8_t, PEC Status
490 
491  0: No PEC error detected
492 
493  -1: PEC error detected, retry read
494  *************************************************/
495 int8_t LTC6804_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
496  uint8_t total_ic,//the number of ICs in the system
497  uint16_t aux_codes[][6]//A two dimensional array of the gpio voltage codes.
498  )
499 {
500 
501 
502  const uint8_t NUM_RX_BYT = 8;
503  const uint8_t BYT_IN_REG = 6;
504  const uint8_t GPIO_IN_REG = 3;
505 
506  uint8_t *data;
507  uint8_t data_counter = 0;
508  int8_t pec_error = 0;
509  uint16_t parsed_aux;
510  uint16_t received_pec;
511  uint16_t data_pec;
512  data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
513  //1.a
514  if (reg == 0)
515  {
516  //a.i
517  for (uint8_t gpio_reg = 1; gpio_reg<3; gpio_reg++) //executes once for each of the LTC6804 aux voltage registers
518  {
519  data_counter = 0;
520  LTC6804_rdaux_reg(gpio_reg, total_ic,data); //Reads the raw auxiliary register data into the data[] array
521 
522  for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
523  {
524  // current_ic is used as the IC counter
525 
526  //a.ii
527  for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) // This loop parses the read back data into GPIO voltages, it
528  {
529  // loops once for each of the 3 gpio voltage codes in the register
530 
531  parsed_aux = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
532  // create the parsed gpio voltage code
533 
534  aux_codes[current_ic][current_gpio +((gpio_reg-1)*GPIO_IN_REG)] = parsed_aux;
535  data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
536  //must increment by two for each parsed gpio voltage code
537 
538  }
539  //a.iii
540  received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
541  //after the 6 gpio voltage data bytes
542  data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
543  if (received_pec != data_pec)
544  {
545  pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
546  //are detected in the received serial data
547  }
548 
549  data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
550  //must be incremented by 2 bytes to point to the next ICs gpio voltage data
551  }
552 
553 
554  }
555 
556  }
557  else
558  {
559  //b.i
560  LTC6804_rdaux_reg(reg, total_ic, data);
561  for (int current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
562  {
563  // current_ic is used as an IC counter
564 
565  //b.ii
566  for (int current_gpio = 0; current_gpio<GPIO_IN_REG; current_gpio++) // This loop parses the read back data. Loops
567  {
568  // once for each aux voltage in the register
569 
570  parsed_aux = (data[data_counter] + (data[data_counter+1]<<8)); //Each gpio codes is received as two bytes and is combined to
571  // create the parsed gpio voltage code
572  aux_codes[current_ic][current_gpio +((reg-1)*GPIO_IN_REG)] = parsed_aux;
573  data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
574  //must increment by two for each parsed gpio voltage code
575  }
576  //b.iii
577  received_pec = (data[data_counter]<<8) + data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
578  //after the 6 gpio voltage data bytes
579  data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
580  if (received_pec != data_pec)
581  {
582  pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
583  //are detected in the received serial data
584  }
585 
586  data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
587  //must be incremented by 2 bytes to point to the next ICs gpio voltage data
588  }
589  }
590  free(data);
591  return (pec_error);
592 }
593 /*
594  LTC6804_rdaux Sequence
595 
596  1. Switch Statement:
597  a. Reg = 0
598  i. Read GPIO voltage registers A-D for every IC in the daisy chain
599  ii. Parse raw GPIO voltage data in cell_codes array
600  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
601  b. Reg != 0
602  i.Read single GPIO voltage register for all ICs in daisy chain
603  ii. Parse raw GPIO voltage data in cell_codes array
604  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
605  2. Return pec_error flag
606 */
607 
608 
609 /***********************************************//**
610  \brief Read the raw data from the LTC6804 auxiliary register
611 
612  The function reads a single GPIO voltage register and stores thre read data
613  in the *data point as a byte array. This function is rarely used outside of
614  the LTC6804_rdaux() command.
615 
616  @param[in] uint8_t reg; This controls which GPIO voltage register is read back.
617 
618  1: Read back auxiliary group A
619 
620  2: Read back auxiliary group B
621 
622 
623 @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain
624 
625 @param[out] uint8_t *data; An array of the unparsed aux codes
626 
627 
628 
629 Command Code:
630 -------------
631 
632 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
633 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
634 |RDAUXA: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
635 |RDAUXB: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
636 
637  *************************************************/
638 void LTC6804_rdaux_reg(uint8_t reg, //Determines which GPIO voltage register is read back
639  uint8_t total_ic, //The number of ICs in the system
640  uint8_t *data //Array of the unparsed auxiliary codes
641  )
642 {
643  const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
644  uint8_t cmd[4];
645  uint16_t cmd_pec;
646 
647  //1
648  if (reg == 1) //Read back auxiliary group A
649  {
650  cmd[1] = 0x0C;
651  cmd[0] = 0x00;
652  }
653  else if (reg == 2) //Read back auxiliary group B
654  {
655  cmd[1] = 0x0e;
656  cmd[0] = 0x00;
657  }
658  else //Read back auxiliary group A
659  {
660  cmd[1] = 0x0C;
661  cmd[0] = 0x00;
662  }
663  //2
664  cmd_pec = pec15_calc(2, cmd);
665  cmd[2] = (uint8_t)(cmd_pec >> 8);
666  cmd[3] = (uint8_t)(cmd_pec);
667 
668  //3
669  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake, this command can be removed.
670  //4
672  spi_write_read(cmd,4,data,(REG_LEN*total_ic));
674 
675 }
676 /*
677  LTC6804_rdaux_reg Function Process:
678  1. Determine Command and initialize command array
679  2. Calculate Command PEC
680  3. Wake up isoSPI, this step is optional
681  4. Send Global Command to LTC6804 daisy chain
682 */
683 
684 /********************************************************//**
685  \brief Clears the LTC6804 cell voltage registers
686 
687  The command clears the cell voltage registers and intiallizes
688  all values to 1. The register will read back hexadecimal 0xFF
689  after the command is sent.
690 
691 
692 Command Code:
693 -------------
694 
695 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
696 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
697 |CLRCELL: | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
698 ************************************************************/
700 {
701  uint8_t cmd[4];
702  uint16_t cmd_pec;
703 
704  //1
705  cmd[0] = 0x07;
706  cmd[1] = 0x11;
707 
708  //2
709  cmd_pec = pec15_calc(2, cmd);
710  cmd[2] = (uint8_t)(cmd_pec >> 8);
711  cmd[3] = (uint8_t)(cmd_pec );
712 
713  //3
714  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
715 
716  //4
718  spi_write_read(cmd,4,0,0);
720 }
721 /*
722  LTC6804_clrcell Function sequence:
723 
724  1. Load clrcell command into cmd array
725  2. Calculate clrcell cmd PEC and load pec into cmd array
726  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
727  4. send broadcast clrcell command to LTC6804 daisy chain
728 */
729 
730 
731 /***********************************************************//**
732  \brief Clears the LTC6804 Auxiliary registers
733 
734  The command clears the Auxiliary registers and intiallizes
735  all values to 1. The register will read back hexadecimal 0xFF
736  after the command is sent.
737 
738 
739 Command Code:
740 -------------
741 
742 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
743 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
744 |CLRAUX: | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 2 | 0 |
745 ***************************************************************/
747 {
748  uint8_t cmd[4];
749  uint16_t cmd_pec;
750 
751  //1
752  cmd[0] = 0x07;
753  cmd[1] = 0x12;
754 
755  //2
756  cmd_pec = pec15_calc(2, cmd);
757  cmd[2] = (uint8_t)(cmd_pec >> 8);
758  cmd[3] = (uint8_t)(cmd_pec);
759 
760  //3
761  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
762  //4
764  spi_write_read(cmd,4,0,0);
766 }
767 /*
768  LTC6804_clraux Function sequence:
769 
770  1. Load clraux command into cmd array
771  2. Calculate clraux cmd PEC and load pec into cmd array
772  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
773  4. send broadcast clraux command to LTC6804 daisy chain
774 */
775 
776 
777 /*****************************************************//**
778  \brief Write the LTC6804 configuration register
779 
780  This command will write the configuration registers of the LTC6804-1s
781  connected in a daisy chain stack. The configuration is written in descending
782  order so the last device's configuration is written first.
783 
784  @param[in] uint8_t total_ic; The number of ICs being written to.
785 
786  @param[in] uint8_t config[][6] is a two dimensional array of the configuration data that will be written, the array should contain the 6 bytes for each
787  IC in the daisy chain. The lowest IC in the daisy chain should be the first 6 byte block in the array. The array should
788  have the following format:
789  | config[0][0]| config[0][1] | config[0][2]| config[0][3]| config[0][4]| config[0][5]| config[1][0] | config[1][1]| config[1][2]| ..... |
790  |--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|-----------|
791  |IC1 CFGR0 |IC1 CFGR1 |IC1 CFGR2 |IC1 CFGR3 |IC1 CFGR4 |IC1 CFGR5 |IC2 CFGR0 |IC2 CFGR1 | IC2 CFGR2 | ..... |
792 
793  The function will calculate the needed PEC codes for the write data
794  and then transmit data to the ICs on a daisy chain.
795 
796 
797 Command Code:
798 -------------
799 | | CMD[0] | CMD[1] |
800 |---------------|---------------------------------------------------------------|---------------------------------------------------------------|
801 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
802 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
803 |WRCFG: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
804 ********************************************************/
805 void LTC6804_wrcfg(uint8_t total_ic, //The number of ICs being written to
806  uint8_t config[][6] //A two dimensional array of the configuration data that will be written
807  )
808 {
809  const uint8_t BYTES_IN_REG = 6;
810  const uint8_t CMD_LEN = 4+(8*total_ic);
811  uint8_t *cmd;
812  uint16_t cfg_pec;
813  uint8_t cmd_index; //command counter
814 
815  cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
816 
817  //1
818  cmd[0] = 0x00;
819  cmd[1] = 0x01;
820  cmd[2] = 0x3d;
821  cmd[3] = 0x6e;
822 
823  //2
824  cmd_index = 4;
825  for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--) // executes for each LTC6804 in daisy chain, this loops starts with
826  {
827  // the last IC on the stack. The first configuration written is
828  // received by the last IC in the daisy chain
829 
830  for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) // executes for each of the 6 bytes in the CFGR register
831  {
832  // current_byte is the byte counter
833 
834  cmd[cmd_index] = config[current_ic-1][current_byte]; //adding the config data to the array to be sent
835  cmd_index = cmd_index + 1;
836  }
837  //3
838  cfg_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &config[current_ic-1][0]); // calculating the PEC for each ICs configuration register data
839  cmd[cmd_index] = (uint8_t)(cfg_pec >> 8);
840  cmd[cmd_index + 1] = (uint8_t)cfg_pec;
841  cmd_index = cmd_index + 2;
842  }
843 
844  //4
845  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
846  //5
848  spi_write_array(CMD_LEN, cmd);
850  free(cmd);
851 }
852 /*
853  WRCFG Sequence:
854 
855  1. Load cmd array with the write configuration command and PEC
856  2. Load the cmd with LTC6804 configuration data
857  3. Calculate the pec for the LTC6804 configuration data being transmitted
858  4. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
859  5. Write configuration data to the LTC6804 daisy chain
860 
861 */
862 
863 /*!******************************************************
864  \brief Reads configuration registers of a LTC6804 daisy chain
865 
866 @param[in] uint8_t total_ic: number of ICs in the daisy chain
867 
868 @param[out] uint8_t r_config[][8] is a two dimensional array that the function stores the read configuration data. The configuration data for each IC
869 is stored in blocks of 8 bytes with the configuration data of the lowest IC on the stack in the first 8 bytes
870 block of the array, the second IC in the second 8 byte etc. Below is an table illustrating the array organization:
871 
872 |r_config[0][0]|r_config[0][1]|r_config[0][2]|r_config[0][3]|r_config[0][4]|r_config[0][5]|r_config[0][6] |r_config[0][7] |r_config[1][0]|r_config[1][1]| ..... |
873 |--------------|--------------|--------------|--------------|--------------|--------------|----------------|---------------|--------------|--------------|-----------|
874 |IC1 CFGR0 |IC1 CFGR1 |IC1 CFGR2 |IC1 CFGR3 |IC1 CFGR4 |IC1 CFGR5 |IC1 PEC High |IC1 PEC Low |IC2 CFGR0 |IC2 CFGR1 | ..... |
875 
876 
877 @return int8_t, PEC Status.
878 
879  0: Data read back has matching PEC
880 
881  -1: Data read back has incorrect PEC
882 
883 
884 Command Code:
885 -------------
886 
887 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
888 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
889 |RDCFG: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
890 ********************************************************/
891 int8_t LTC6804_rdcfg(uint8_t total_ic, //Number of ICs in the system
892  uint8_t r_config[][8] //A two dimensional array that the function stores the read configuration data.
893  )
894 {
895  const uint8_t BYTES_IN_REG = 8;
896 
897  uint8_t cmd[4];
898  uint8_t *rx_data;
899  int8_t pec_error = 0;
900  uint16_t data_pec;
901  uint16_t received_pec;
902 
903  rx_data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t));
904 
905  //1
906  cmd[0] = 0x00;
907  cmd[1] = 0x02;
908  cmd[2] = 0x2b;
909  cmd[3] = 0x0A;
910 
911  //2
912  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
913  //3
915  spi_write_read(cmd, 4, rx_data, (BYTES_IN_REG*total_ic)); //Read the configuration data of all ICs on the daisy chain into
916  output_high(LTC6804_CS); //rx_data[] array
917 
918  for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) //executes for each LTC6804 in the daisy chain and packs the data
919  {
920  //into the r_config array as well as check the received Config data
921  //for any bit errors
922  //4.a
923  for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
924  {
925  r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
926  }
927  //4.b
928  received_pec = (r_config[current_ic][6]<<8) + r_config[current_ic][7];
929  data_pec = pec15_calc(6, &r_config[current_ic][0]);
930  if (received_pec != data_pec)
931  {
932  pec_error = -1;
933  }
934  }
935 
936  free(rx_data);
937  //5
938  return(pec_error);
939 }
940 /*
941  RDCFG Sequence:
942 
943  1. Load cmd array with the write configuration command and PEC
944  2. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
945  3. Send command and read back configuration data
946  4. For each LTC6804 in the daisy chain
947  a. load configuration data into r_config array
948  b. calculate PEC of received data and compare against calculated PEC
949  5. Return PEC Error
950 
951 */
952 
953 /*!****************************************************
954  \brief Wake isoSPI up from idle state
955  Generic wakeup commannd to wake isoSPI up out of idle
956  *****************************************************/
958 {
960  delayMicroseconds(2); //Guarantees the isoSPI will be in ready mode
962 }
963 
964 /*!****************************************************
965  \brief Wake the LTC6804 from the sleep state
966 
967  Generic wakeup commannd to wake the LTC6804 from sleep
968  *****************************************************/
970 {
972  delay(1); // Guarantees the LTC6804 will be in standby
974 }
975 /*!**********************************************************
976  \brief calaculates and returns the CRC15
977 
978  @param[in] uint8_t len: the length of the data array being passed to the function
979 
980  @param[in] uint8_t data[] : the array of data that the PEC will be generated from
981 
982 
983  @returns The calculated pec15 as an unsigned int
984 ***********************************************************/
985 uint16_t pec15_calc(uint8_t len, //Number of bytes that will be used to calculate a PEC
986  uint8_t *data //Array of data that will be used to calculate a PEC
987  )
988 {
989  uint16_t remainder,addr;
990 
991  remainder = 16;//initialize the PEC
992  for (uint8_t i = 0; i<len; i++) // loops for each byte in data array
993  {
994  addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
995  remainder = (remainder<<8)^crc15Table[addr];
996  }
997  return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
998 }
999 
1000 
1001 /*!
1002  \brief Writes an array of bytes out of the SPI port
1003 
1004  @param[in] uint8_t len length of the data array being written on the SPI port
1005  @param[in] uint8_t data[] the data array to be written on the SPI port
1006 
1007 */
1008 void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
1009  uint8_t data[] //Array of bytes to be written on the SPI port
1010  )
1011 {
1012  for (uint8_t i = 0; i < len; i++)
1013  {
1014  spi_write((int8_t)data[i]);
1015  }
1016 }
1017 
1018 /*!
1019  \brief Writes and read a set number of bytes using the SPI port.
1020 
1021 @param[in] uint8_t tx_data[] array of data to be written on the SPI port
1022 @param[in] uint8_t tx_len length of the tx_data array
1023 @param[out] uint8_t rx_data array that read data will be written too.
1024 @param[in] uint8_t rx_len number of bytes to be read from the SPI port.
1025 
1026 */
1027 
1028 void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
1029  uint8_t tx_len, //length of the tx data arry
1030  uint8_t *rx_data,//Input: array that will store the data read by the SPI port
1031  uint8_t rx_len //Option: number of bytes to be read from the SPI port
1032  )
1033 {
1034  for (uint8_t i = 0; i < tx_len; i++)
1035  {
1036  spi_write(tx_Data[i]);
1037 
1038  }
1039 
1040  for (uint8_t i = 0; i < rx_len; i++)
1041  {
1042  rx_data[i] = (uint8_t)spi_read(0xFF);
1043  }
1044 
1045 }
1046 
1047 
1048 
int8_t LTC6804_rdcfg(uint8_t total_ic, uint8_t r_config[][8])
Definition: LTC68041.cpp:891
uint8_t ADCV[2]
6804 conversion command variables.
Definition: LTC68041.cpp:81
int8_t LTC6804_rdaux(uint8_t reg, uint8_t total_ic, uint16_t aux_codes[][6])
Reads and parses the LTC6804 auxiliary registers.
Definition: LTC68041.cpp:495
void LTC6804_adcv()
Definition: LTC68041.cpp:154
void wakeup_sleep()
Definition: LTC68041.cpp:969
#define CELL_CH_ALL
CH Dec Channels to convert 0000 All Cells 0011 Cell 1 and Cell 7 0102 Cell 2 and Cell 8 0113 Cell 3 ...
Definition: LTC68041.h:142
uint8_t ADAX[2]
GPIO conversion command.
Definition: LTC68041.cpp:82
void LTC6804_clrcell()
Clears the LTC6804 cell voltage registers.
Definition: LTC68041.cpp:699
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
void spi_write_read(uint8_t tx_Data[], uint8_t tx_len, uint8_t *rx_data, uint8_t rx_len)
Writes and read a set number of bytes using the SPI port.
Definition: LTC68041.cpp:1028
Header File for Linduino Libraries and Demo Code.
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
#define AUX_CH_ALL
CHG Dec Channels to convert 000 0 All GPIOS and 2nd Ref 001 1 GPIO 1 010 2 GPIO 2 011 3 GPIO 3 100 4...
Definition: LTC68041.h:164
#define LTC6804_CS
Definition: LTC68041.h:55
void spi_enable(uint8_t spi_clock_divider)
Setup the processor for hardware SPI communication.
Definition: LT_SPI.cpp:160
void LTC6804_clraux()
Clears the LTC6804 Auxiliary registers.
Definition: LTC68041.cpp:746
void LTC6804_initialize()
This function will initialize all 6804 variables and the SPI port.
Definition: LTC68041.cpp:92
void LTC6804_rdcv_reg(uint8_t reg, uint8_t total_ic, uint8_t *data)
Read the raw data from the LTC6804 cell voltage register.
Definition: LTC68041.cpp:410
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
static const unsigned int crc15Table[256]
Definition: LTC68041.h:90
void wakeup_idle()
Definition: LTC68041.cpp:957
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
#define MD_NORMAL
Definition: LTC68041.h:126
uint16_t pec15_calc(uint8_t len, uint8_t *data)
Definition: LTC68041.cpp:985
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
void LTC6804_rdaux_reg(uint8_t reg, uint8_t total_ic, uint8_t *data)
Read the raw data from the LTC6804 auxiliary register.
Definition: LTC68041.cpp:638
void set_adc(uint8_t MD, uint8_t DCP, uint8_t CH, uint8_t CHG)
Definition: LTC68041.cpp:115
#define NUM_RX_BYT
Definition: LTC681x.h:108
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
int8_t spi_read(int8_t data)
The data byte to be written.
Definition: LT_SPI.cpp:189
static uint16_t aux_codes[TOTAL_IC][6]
The GPIO codes will be stored in the aux_codes[][6] array in the following format: ...
Definition: DC1894.ino:117
void LTC6804_adax()
Definition: LTC68041.cpp:206
#define DCP_DISABLED
Definition: LTC68041.h:183
LTC6804-1 Multicell Battery Monitor.
uint8_t LTC6804_rdcv(uint8_t reg, uint8_t total_ic, uint16_t cell_codes[][12])
Reads and parses the LTC6804 cell voltage registers.
Definition: LTC68041.cpp:268
static int i
Definition: DC2430A.ino:184
void LTC6804_wrcfg(uint8_t total_ic, uint8_t config[][6])
Write the LTC6804 configuration register.
Definition: LTC68041.cpp:805
void spi_write_array(uint8_t len, uint8_t data[])
Writes an array of bytes out of the SPI port.
Definition: LTC68041.cpp:1008
static uint16_t cell_codes[TOTAL_IC][12]
The cell codes will be stored in the cell_codes[][12] array in the following format: ...
Definition: DC1651A.ino:108