Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
LTC68042.cpp
Go to the documentation of this file.
1 /*!
2  LTC6804-2 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-2, multiple devices are connected in
14  parallel to the host processor, with each device
15  individually addressed.
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 LTC68042 LTC6804-2: Multicell Battery Monitor
62 //! @}
63 
64 /*! @file
65  @ingroup LTC68042
66  Library for LTC6804-2 Multicell Battery Monitor
67 */
68 
69 #include <stdint.h>
70 #include <Arduino.h>
71 #include "Linduino.h"
72 #include "LT_SPI.h"
73 #include "LTC68042.h"
74 #include <SPI.h>
75 
76 /*
77  ADC control Variables for LTC6804
78 */
79 
80 
81 
82 /*!
83  6804 conversion command variables.
84 */
85 uint8_t ADCV[2]; //!< Cell Voltage conversion command.
86 uint8_t ADAX[2]; //!< GPIO conversion command.
87 
88 
89 /*!
90  \brief This function will initialize all 6804 variables and the SPI port.
91 
92  input:
93  ------
94  IC: number of ICs being controlled. The address of the ICs in a LTC6804-2 network will start at 0 and continue in an ascending order.
95 */
97 {
99  spi_enable(SPI_CLOCK_DIV16);
101 }
102 
103 /*!******************************************************************************************************************
104  \brief Maps global ADC control variables to the appropriate control bytes for each of the different ADC commands
105 
106 @param[in] uint8_t MD The adc conversion mode
107 @param[in] uint8_t DCP Controls if Discharge is permitted during cell conversions
108 @param[in] uint8_t CH Determines which cells are measured during an ADC conversion command
109 @param[in] uint8_t CHG Determines which GPIO channels are measured during Auxiliary conversion command
110 
111  Command Code: \n
112  |command | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
113  |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
114  |ADCV: | 0 | 1 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CH[2] | CH[1] | CH[0] |
115  |ADAX: | 1 | 0 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CHG[2]| CHG[1]| CHG[0]|
116  ******************************************************************************************************************/
117 void set_adc(uint8_t MD, //ADC Mode
118  uint8_t DCP, //Discharge Permit
119  uint8_t CH, //Cell Channels to be measured
120  uint8_t CHG //GPIO Channels to be measured
121  )
122 {
123  uint8_t md_bits;
124 
125  md_bits = (MD & 0x02) >> 1;
126  ADCV[0] = md_bits + 0x02;
127  md_bits = (MD & 0x01) << 7;
128  ADCV[1] = md_bits + 0x60 + (DCP<<4) + CH;
129 
130  md_bits = (MD & 0x02) >> 1;
131  ADAX[0] = md_bits + 0x04;
132  md_bits = (MD & 0x01) << 7;
133  ADAX[1] = md_bits + 0x60 + CHG ;
134 
135 }
136 
137 
138 /*!*********************************************************************************************
139  \brief Starts cell voltage conversion
140 
141  Starts ADC conversions of the LTC6804 Cpin inputs.
142  The type of ADC conversion done is set using the associated global variables:
143  |Variable|Function |
144  |--------|----------------------------------------------|
145  | MD | Determines the filter corner of the ADC |
146  | CH | Determines which cell channels are converted |
147  | DCP | Determines if Discharge is Permitted |
148 
149 ***********************************************************************************************/
151 {
152 
153  uint8_t cmd[4];
154  uint16_t temp_pec;
155 
156  //1
157  cmd[0] = ADCV[0];
158  cmd[1] = ADCV[1];
159 
160  //2
161  temp_pec = pec15_calc(2, ADCV);
162  cmd[2] = (uint8_t)(temp_pec >> 8);
163  cmd[3] = (uint8_t)(temp_pec);
164 
165  //3
166  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
167 
168  //4
170  spi_write_array(4,cmd);
172 
173 }
174 /*
175  LTC6804_adcv Function sequence:
176 
177  1. Load adcv command into cmd array
178  2. Calculate adcv cmd PEC and load pec into cmd array
179  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
180  4. send broadcast adcv command to LTC6804 stack
181 */
182 
183 
184 /*!******************************************************************************************************
185  \brief Start an GPIO Conversion
186 
187  Starts an ADC conversions of the LTC6804 GPIO inputs.
188  The type of ADC conversion done is set using the associated global variables:
189  |Variable|Function |
190  |--------|----------------------------------------------|
191  | MD | Determines the filter corner of the ADC |
192  | CHG | Determines which GPIO channels are converted |
193 
194 *********************************************************************************************************/
196 {
197  uint8_t cmd[4];
198  uint16_t temp_pec;
199 
200  cmd[0] = ADAX[0];
201  cmd[1] = ADAX[1];
202  temp_pec = pec15_calc(2, ADAX);
203  cmd[2] = (uint8_t)(temp_pec >> 8);
204  cmd[3] = (uint8_t)(temp_pec);
205 
206  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
208  spi_write_array(4,cmd);
210 
211 }
212 /*
213  LTC6804_adax Function sequence:
214 
215  1. Load adax command into cmd array
216  2. Calculate adax cmd PEC and load pec into cmd array
217  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
218  4. send broadcast adax command to LTC6804 stack
219 */
220 
221 
222 /***********************************************//**
223  \brief Reads and parses the LTC6804 cell voltage registers.
224 
225  The function is used to read the cell codes of the LTC6804.
226  This function will send the requested read commands parse the data
227  and store the cell voltages in cell_codes variable.
228 
229 
230 @param[in] uint8_t reg; This controls which cell voltage register is read back.
231 
232  0: Read back all Cell registers
233 
234  1: Read back cell group A
235 
236  2: Read back cell group B
237 
238  3: Read back cell group C
239 
240  4: Read back cell group D
241 
242 @param[in] uint8_t total_ic; This is the number of ICs in the network
243 
244 
245 @param[out] uint16_t cell_codes[]; An array of the parsed cell codes from lowest to highest. The cell codes will
246  be stored in the cell_codes[] array in the following format:
247  | cell_codes[0]| cell_codes[1] | cell_codes[2]| ..... | cell_codes[11]| cell_codes[12]| cell_codes[13] | ..... |
248  |---------------|----------------|--------------|--------------|----------------|----------------|----------------|----------|
249  |IC1 Cell 1 |IC1 Cell 2 |IC1 Cell 3 | ..... | IC1 Cell 12 |IC2 Cell 1 |IC2 Cell 2 | ..... |
250 
251  @return int8_t, PEC Status.
252 
253  0: No PEC error detected
254 
255  -1: PEC error detected, retry read
256  *************************************************/
257 uint8_t LTC6804_rdcv(uint8_t reg,
258  uint8_t total_ic,
259  uint16_t cell_codes[][12]
260  )
261 {
262 
263  const uint8_t NUM_RX_BYT = 8;
264  const uint8_t BYT_IN_REG = 6;
265  const uint8_t CELL_IN_REG = 3;
266 
267  uint8_t *cell_data;
268  int8_t pec_error = 0;
269  uint16_t parsed_cell;
270  uint16_t received_pec;
271  uint16_t data_pec;
272  uint8_t data_counter=0; //data counter
273  cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
274  //1.a
275  if (reg == 0)
276  {
277  //a.i
278  for (uint8_t cell_reg = 1; cell_reg<5; cell_reg++) //executes once for each of the LTC6804 cell voltage registers
279  {
280  data_counter = 0;
281  LTC6804_rdcv_reg(cell_reg, total_ic,cell_data);
282  for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the stack
283  {
284  // current_ic is used as an IC counter
285  //a.ii
286  for (uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) // This loop parses the read back data. Loops
287  {
288  // once for each cell voltages in the register
289  parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);
290  cell_codes[current_ic][current_cell + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
291  data_counter = data_counter + 2;
292  }
293  //a.iii
294  received_pec = (cell_data[data_counter] << 8) + cell_data[data_counter+1];
295  data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT ]);
296  if (received_pec != data_pec)
297  {
298  pec_error = -1;
299  }
300  data_counter=data_counter+2;
301  }
302  }
303  }
304 //1.b
305  else
306  {
307  //b.i
308 
309  LTC6804_rdcv_reg(reg, total_ic,cell_data);
310  for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the stack
311  {
312  // current_ic is used as an IC counter
313  //b.ii
314  for (uint8_t current_cell = 0; current_cell < CELL_IN_REG; current_cell++) // This loop parses the read back data. Loops
315  {
316  // once for each cell voltage in the register
317  parsed_cell = cell_data[data_counter] + (cell_data[data_counter+1]<<8);
318  cell_codes[current_ic][current_cell + ((reg - 1) * CELL_IN_REG)] = 0x0000FFFF & parsed_cell;
319  data_counter= data_counter + 2;
320  }
321  //b.iii
322  received_pec = (cell_data[data_counter] << 8 )+ cell_data[data_counter + 1];
323  data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
324  if (received_pec != data_pec)
325  {
326  pec_error = -1;
327  }
328  }
329  }
330  free(cell_data);
331 //2
332  return(pec_error);
333 }
334 /*
335  LTC6804_rdcv Sequence
336 
337  1. Switch Statement:
338  a. Reg = 0
339  i. Read cell voltage registers A-D for every IC in the stack
340  ii. Parse raw cell voltage data in cell_codes array
341  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
342  b. Reg != 0
343  i.Read single cell voltage register for all ICs in stack
344  ii. Parse raw cell voltage data in cell_codes array
345  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
346  2. Return pec_error flag
347 */
348 
349 
350 /***********************************************//**
351  \brief Read the raw data from the LTC6804 cell voltage register
352 
353  The function reads a single cell voltage register and stores the read data
354  in the *data point as a byte array. This function is rarely used outside of
355  the LTC6804_rdcv() command.
356 
357  @param[in] uint8_t reg; This controls which cell voltage register is read back.
358 
359  1: Read back cell group A
360 
361  2: Read back cell group B
362 
363  3: Read back cell group C
364 
365  4: Read back cell group D
366 
367  @param[in] uint8_t total_ic; This is the number of ICs in the network
368 
369  @param[out] uint8_t *data; An array of the unparsed cell codes
370  *************************************************/
371 void LTC6804_rdcv_reg(uint8_t reg,
372  uint8_t total_ic,
373  uint8_t *data
374  )
375 {
376  uint8_t cmd[4];
377  uint16_t temp_pec;
378 
379  //1
380  if (reg == 1)
381  {
382  cmd[1] = 0x04;
383  cmd[0] = 0x00;
384  }
385  else if (reg == 2)
386  {
387  cmd[1] = 0x06;
388  cmd[0] = 0x00;
389  }
390  else if (reg == 3)
391  {
392  cmd[1] = 0x08;
393  cmd[0] = 0x00;
394  }
395  else if (reg == 4)
396  {
397  cmd[1] = 0x0A;
398  cmd[0] = 0x00;
399  }
400 
401  //2
402 
403 
404  //3
405  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
406 
407  //4
408  for (int current_ic = 0; current_ic<total_ic; current_ic++)
409  {
410  cmd[0] = 0x80 + (current_ic<<3); //Setting address
411  temp_pec = pec15_calc(2, cmd);
412  cmd[2] = (uint8_t)(temp_pec >> 8);
413  cmd[3] = (uint8_t)(temp_pec);
415  spi_write_read(cmd,4,&data[current_ic*8],8);
417  }
418 }
419 /*
420  LTC6804_rdcv_reg Function Process:
421  1. Determine Command and initialize command array
422  2. Calculate Command PEC
423  3. Wake up isoSPI, this step is optional
424  4. Send Global Command to LTC6804 stack
425 */
426 
427 
428 /***********************************************************************************//**
429  \brief Reads and parses the LTC6804 auxiliary registers.
430 
431  The function is used
432  to read the parsed GPIO codes of the LTC6804. This function will send the requested
433  read commands parse the data and store the gpio voltages in aux_codes variable
434 
435  @param[in] uint8_t reg; This controls which GPIO voltage register is read back.
436 
437  0: Read back all auxiliary registers
438 
439  1: Read back auxiliary group A
440 
441  2: Read back auxiliary group B
442 
443 
444  @param[in] uint8_t total_ic; This is the number of ICs in the network
445 
446  @param[out] uint8_t aux_codes[]; An array of the aux codes from lowest to highest. The GPIO codes will
447  be stored in the aux_codes[] array in the following format:
448  | aux_codes[0]| aux_codes[1] | aux_codes[2]| aux_codes[3]| aux_codes[4]| aux_codes[5]| aux_codes[6] |aux_codes[7]| ..... |
449  |--------------|--------------|--------------|--------------|--------------|--------------|--------------|------------|-----------|
450  |IC1 GPIO1 |IC1 GPIO2 |IC1 GPIO3 |IC1 GPIO4 |IC1 GPIO5 |IC1 Vref2 |IC2 GPIO1 |IC2 GPIO2 | ..... |
451 
452 
453  @return int8_t, PEC Status.
454 
455  0: No PEC error detected
456 
457  -1: PEC error detected, retry read
458  *************************************************/
459 int8_t LTC6804_rdaux(uint8_t reg,
460  uint8_t total_ic,
461  uint16_t aux_codes[][6]
462  )
463 {
464 
465 
466  const uint8_t NUM_RX_BYT = 8;
467  const uint8_t BYT_IN_REG = 6;
468  const uint8_t GPIO_IN_REG = 3;
469 
470  uint8_t *data;
471  uint8_t data_counter = 0;
472  int8_t pec_error = 0;
473  uint16_t received_pec;
474  uint16_t data_pec;
475  data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
476  //1.a
477  if (reg == 0)
478  {
479  //a.i
480  for (uint8_t gpio_reg = 1; gpio_reg<3; gpio_reg++) //executes once for each of the LTC6804 aux voltage registers
481  {
482  data_counter = 0;
483  LTC6804_rdaux_reg(gpio_reg, total_ic,data);
484  for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // This loop executes once for each LTC6804
485  {
486  // current_ic is used as an IC counter
487  //a.ii
488  for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) // This loop parses GPIO voltages stored in the register
489  {
490 
491  aux_codes[current_ic][current_gpio +((gpio_reg-1)*GPIO_IN_REG)] = data[data_counter] + (data[data_counter+1]<<8);
492  data_counter=data_counter+2;
493 
494  }
495  //a.iii
496  received_pec = (data[data_counter]<<8)+ data[data_counter+1];
497  data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
498  if (received_pec != data_pec)
499  {
500  pec_error = -1;
501  }
502 
503  data_counter=data_counter+2;
504  }
505 
506 
507  }
508 
509  }
510  else
511  {
512  //b.i
513  LTC6804_rdaux_reg(reg, total_ic, data);
514  for (int current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the stack
515  {
516  // current_ic is used as an IC counter
517  //b.ii
518  for (int current_gpio = 0; current_gpio<GPIO_IN_REG; current_gpio++) // This loop parses the read back data. Loops
519  {
520  // once for each aux voltage in the register
521  aux_codes[current_ic][current_gpio +((reg-1)*GPIO_IN_REG)] = 0x0000FFFF & (data[data_counter] + (data[data_counter+1]<<8));
522  data_counter=data_counter+2;
523  }
524  //b.iii
525  received_pec = (data[data_counter]<<8) + data[data_counter+1];
526  data_pec = pec15_calc(6, &data[current_ic*8]);
527  if (received_pec != data_pec)
528  {
529  pec_error = -1;
530  }
531  }
532  }
533  free(data);
534  return (pec_error);
535 }
536 /*
537  LTC6804_rdaux Sequence
538 
539  1. Switch Statement:
540  a. Reg = 0
541  i. Read GPIO voltage registers A-D for every IC in the stack
542  ii. Parse raw GPIO voltage data in cell_codes array
543  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
544  b. Reg != 0
545  i.Read single GPIO voltage register for all ICs in stack
546  ii. Parse raw GPIO voltage data in cell_codes array
547  iii. Check the PEC of the data read back vs the calculated PEC for each read register command
548  2. Return pec_error flag
549 */
550 
551 
552 /***********************************************//**
553  \brief Read the raw data from the LTC6804 auxiliary register
554 
555  The function reads a single GPIO voltage register and stores thre read data
556  in the *data point as a byte array. This function is rarely used outside of
557  the LTC6804_rdaux() command.
558 
559  @param[in] uint8_t reg; This controls which GPIO voltage register is read back.
560 
561  1: Read back auxiliary group A
562 
563  2: Read back auxiliary group B
564 
565 
566  @param[in] uint8_t total_ic; This is the number of ICs in the stack
567 
568  @param[out] uint8_t *data; An array of the unparsed aux codes
569  *************************************************/
570 void LTC6804_rdaux_reg(uint8_t reg,
571  uint8_t total_ic,
572  uint8_t *data
573  )
574 {
575  uint8_t cmd[4];
576  uint16_t cmd_pec;
577 
578  //1
579  if (reg == 1)
580  {
581  cmd[1] = 0x0C;
582  cmd[0] = 0x00;
583  }
584  else if (reg == 2)
585  {
586  cmd[1] = 0x0e;
587  cmd[0] = 0x00;
588  }
589  else
590  {
591  cmd[1] = 0x0C;
592  cmd[0] = 0x00;
593  }
594  //2
595  cmd_pec = pec15_calc(2, cmd);
596  cmd[2] = (uint8_t)(cmd_pec >> 8);
597  cmd[3] = (uint8_t)(cmd_pec);
598 
599  //3
600  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake, this command can be removed.
601  //4
602  for (int current_ic = 0; current_ic<total_ic; current_ic++)
603  {
604  cmd[0] = 0x80 + (current_ic<<3); //Setting address
605  cmd_pec = pec15_calc(2, cmd);
606  cmd[2] = (uint8_t)(cmd_pec >> 8);
607  cmd[3] = (uint8_t)(cmd_pec);
609  spi_write_read(cmd,4,&data[current_ic*8],8);
611  }
612 }
613 /*
614  LTC6804_rdaux_reg Function Process:
615  1. Determine Command and initialize command array
616  2. Calculate Command PEC
617  3. Wake up isoSPI, this step is optional
618  4. Send Global Command to LTC6804 stack
619 */
620 
621 /********************************************************//**
622  \brief Clears the LTC6804 cell voltage registers
623 
624  The command clears the cell voltage registers and intiallizes
625  all values to 1. The register will read back hexadecimal 0xFF
626  after the command is sent.
627 ************************************************************/
629 {
630  uint8_t cmd[4];
631  uint16_t cmd_pec;
632 
633  //1
634  cmd[0] = 0x07;
635  cmd[1] = 0x11;
636 
637  //2
638  cmd_pec = pec15_calc(2, cmd);
639  cmd[2] = (uint8_t)(cmd_pec >> 8);
640  cmd[3] = (uint8_t)(cmd_pec );
641 
642  //3
643  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
644 
645  //4
647  spi_write_read(cmd,4,0,0);
649 }
650 /*
651  LTC6804_clrcell Function sequence:
652 
653  1. Load clrcell command into cmd array
654  2. Calculate clrcell cmd PEC and load pec into cmd array
655  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
656  4. send broadcast clrcell command to LTC6804 stack
657 */
658 
659 
660 /***********************************************************//**
661  \brief Clears the LTC6804 Auxiliary registers
662 
663  The command clears the Auxiliary registers and intiallizes
664  all values to 1. The register will read back hexadecimal 0xFF
665  after the command is sent.
666 ***************************************************************/
668 {
669  uint8_t cmd[4];
670  uint16_t cmd_pec;
671 
672  //1
673  cmd[0] = 0x07;
674  cmd[1] = 0x12;
675 
676  //2
677  cmd_pec = pec15_calc(2, cmd);
678  cmd[2] = (uint8_t)(cmd_pec >> 8);
679  cmd[3] = (uint8_t)(cmd_pec);
680 
681  //3
682  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
683  //4
685  spi_write_read(cmd,4,0,0);
687 }
688 /*
689  LTC6804_clraux Function sequence:
690 
691  1. Load clraux command into cmd array
692  2. Calculate clraux cmd PEC and load pec into cmd array
693  3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
694  4. send broadcast clraux command to LTC6804 stack
695 */
696 
697 
698 /*****************************************************//**
699  \brief Write the LTC6804 configuration register
700 
701  This command will write the configuration registers of the stacks
702  connected in a stack stack. The configuration is written in descending
703  order so the last device's configuration is written first.
704 
705 
706 @param[in] uint8_t total_ic; The number of ICs being written.
707 
708 @param[in] uint8_t *config an array of the configuration data that will be written, the array should contain the 6 bytes for each
709  IC in the stack. The lowest IC in the stack should be the first 6 byte block in the array. The array should
710  have the following format:
711  | config[0]| config[1] | config[2]| config[3]| config[4]| config[5]| config[6] | config[7]| config[8]| ..... |
712  |-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
713  |IC1 CFGR0 |IC1 CFGR1 |IC1 CFGR2 |IC1 CFGR3 |IC1 CFGR4 |IC1 CFGR5 |IC2 CFGR0 |IC2 CFGR1 | IC2 CFGR2 | ..... |
714 
715  The function will calculate the needed PEC codes for the write data
716  and then transmit data to the ICs on a stack.
717 ********************************************************/
718 void LTC6804_wrcfg(uint8_t total_ic,uint8_t config[][6])
719 {
720  const uint8_t BYTES_IN_REG = 6;
721  const uint8_t CMD_LEN = 4+(8*total_ic);
722  uint8_t *cmd;
723  uint16_t temp_pec;
724  uint8_t cmd_index; //command counter
725 
726  cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
727  //1
728  cmd[0] = 0x00;
729  cmd[1] = 0x01;
730  cmd[2] = 0x3d;
731  cmd[3] = 0x6e;
732 
733  //2
734  cmd_index = 4;
735  for (uint8_t current_ic = 0; current_ic < total_ic ; current_ic++) // executes for each LTC6804 in stack,
736  {
737  for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) // executes for each byte in the CFGR register
738  {
739  // i is the byte counter
740 
741  cmd[cmd_index] = config[current_ic][current_byte]; //adding the config data to the array to be sent
742  cmd_index = cmd_index + 1;
743  }
744  //3
745  temp_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &config[current_ic][0]);// calculating the PEC for each board
746  cmd[cmd_index] = (uint8_t)(temp_pec >> 8);
747  cmd[cmd_index + 1] = (uint8_t)temp_pec;
748  cmd_index = cmd_index + 2;
749  }
750 
751  //4
752  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
753  //5
754  for (int current_ic = 0; current_ic<total_ic; current_ic++)
755  {
756  cmd[0] = 0x80 + (current_ic<<3); //Setting address
757  temp_pec = pec15_calc(2, cmd);
758  cmd[2] = (uint8_t)(temp_pec >> 8);
759  cmd[3] = (uint8_t)(temp_pec);
761  spi_write_array(4,cmd);
762  spi_write_array(8,&cmd[4+(8*current_ic)]);
764  }
765  free(cmd);
766 }
767 /*
768  1. Load cmd array with the write configuration command and PEC
769  2. Load the cmd with LTC6804 configuration data
770  3. Calculate the pec for the LTC6804 configuration data being transmitted
771  4. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
772  5. Write configuration of each LTC6804 on the stack
773 
774 */
775 
776 /*!******************************************************
777  \brief Reads configuration registers of a LTC6804 stack
778 
779 
780 
781 
782 @param[in] uint8_t total_ic: number of ICs in the stack
783 
784 @param[out] uint8_t *r_config: array that the function will write configuration data to. The configuration data for each IC
785 is stored in blocks of 8 bytes with the configuration data of the lowest IC on the stack in the first 8 bytes
786 of the array, the second IC in the second 8 byte etc. Below is an table illustrating the array organization:
787 
788 |r_config[0]|r_config[1]|r_config[2]|r_config[3]|r_config[4]|r_config[5]|r_config[6] |r_config[7] |r_config[8]|r_config[9]| ..... |
789 |-----------|-----------|-----------|-----------|-----------|-----------|-------------|------------|-----------|-----------|-----------|
790 |IC1 CFGR0 |IC1 CFGR1 |IC1 CFGR2 |IC1 CFGR3 |IC1 CFGR4 |IC1 CFGR5 |IC1 PEC High |IC1 PEC Low |IC2 CFGR0 |IC2 CFGR1 | ..... |
791 
792 
793 @return int8_t PEC Status.
794  0: Data read back has matching PEC
795 
796  -1: Data read back has incorrect PEC
797 ********************************************************/
798 int8_t LTC6804_rdcfg(uint8_t total_ic, uint8_t r_config[][8])
799 {
800  const uint8_t BYTES_IN_REG = 8;
801 
802  uint8_t cmd[4];
803  uint8_t *rx_data;
804  int8_t pec_error = 0;
805  uint16_t data_pec;
806  uint16_t received_pec;
807  rx_data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t));
808  //1
809  cmd[0] = 0x00;
810  cmd[1] = 0x02;
811  cmd[2] = 0x2b;
812  cmd[3] = 0x0A;
813 
814  //2
815  wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
816  //3
817  for (int current_ic = 0; current_ic<total_ic; current_ic++)
818  {
819  cmd[0] = 0x80 + (current_ic<<3); //Setting address
820  data_pec = pec15_calc(2, cmd);
821  cmd[2] = (uint8_t)(data_pec >> 8);
822  cmd[3] = (uint8_t)(data_pec);
824  spi_write_read(cmd,4,&rx_data[current_ic*8],8);
826  }
827 
828  for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) //executes for each LTC6804 in the stack
829  {
830  //4.a
831  for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
832  {
833  r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
834  }
835  //4.b
836  received_pec = (r_config[current_ic][6]<<8) + r_config[current_ic][7];
837  data_pec = pec15_calc(6, &r_config[current_ic][0]);
838  if (received_pec != data_pec)
839  {
840  pec_error = -1;
841  }
842  }
843  free(rx_data);
844  //5
845  return(pec_error);
846 }
847 /*
848  1. Load cmd array with the write configuration command and PEC
849  2. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
850  3. read configuration of each LTC6804 on the stack
851  4. For each LTC6804 in the stack
852  a. load configuration data into r_config array
853  b. calculate PEC of received data and compare against calculated PEC
854  5. Return PEC Error
855 
856 */
857 
858 /*!****************************************************
859  \brief Wake isoSPI up from idle state
860  Generic wakeup commannd to wake isoSPI up out of idle
861  *****************************************************/
863 {
865  delayMicroseconds(10); //Guarantees the isoSPI will be in ready mode
867 }
868 
869 /*!****************************************************
870  \brief Wake the LTC6804 from the sleep state
871 
872  Generic wakeup commannd to wake the LTC6804 from sleep
873  *****************************************************/
875 {
877  delay(1); // Guarantees the LTC6804 will be in standby
879 }
880 /*!**********************************************************
881  \brief calaculates and returns the CRC15
882 
883 
884 @param[in] uint8_t len: the length of the data array being passed to the function
885 
886 @param[in] uint8_t data[] : the array of data that the PEC will be generated from
887 
888 
889 @return The calculated pec15 as an unsigned int16_t
890 ***********************************************************/
891 uint16_t pec15_calc(uint8_t len, uint8_t *data)
892 {
893  uint16_t remainder,addr;
894 
895  remainder = 16;//initialize the PEC
896  for (uint8_t i = 0; i<len; i++) // loops for each byte in data array
897  {
898  addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
899  remainder = (remainder<<8)^crc15Table[addr];
900  }
901  return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
902 }
903 
904 
905 /*!
906  \brief Writes an array of bytes out of the SPI port
907 
908  @param[in] uint8_t len length of the data array being written on the SPI port
909  @param[in] uint8_t data[] the data array to be written on the SPI port
910 
911 */
912 void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
913  uint8_t data[] //Array of bytes to be written on the SPI port
914  )
915 {
916  for (uint8_t i = 0; i < len; i++)
917  {
918  spi_write((char)data[i]);
919  }
920 }
921 /*!
922  \brief Writes and read a set number of bytes using the SPI port.
923 
924 @param[in] uint8_t tx_data[] array of data to be written on the SPI port
925 @param[in] uint8_t tx_len length of the tx_data array
926 @param[out] uint8_t rx_data array that read data will be written too.
927 @param[in] uint8_t rx_len number of bytes to be read from the SPI port.
928 
929 */
930 
931 void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
932  uint8_t tx_len, //length of the tx data arry
933  uint8_t *rx_data,//Input: array that will store the data read by the SPI port
934  uint8_t rx_len //Option: number of bytes to be read from the SPI port
935  )
936 {
937  for (uint8_t i = 0; i < tx_len; i++)
938  {
939  spi_write(tx_Data[i]);
940 
941  }
942 
943  for (uint8_t i = 0; i < rx_len; i++)
944  {
945  rx_data[i] = (uint8_t)spi_read(0xFF);
946  }
947 
948 }
949 
950 
951 
uint8_t ADAX[2]
GPIO conversion command.
Definition: LTC68042.cpp:86
#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
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: LTC68042.cpp:931
void wakeup_sleep()
Definition: LTC68042.cpp:874
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
void spi_write_array(uint8_t len, uint8_t data[])
Writes an array of bytes out of the SPI port.
Definition: LTC68042.cpp:912
int8_t LTC6804_rdaux(uint8_t reg, uint8_t total_ic, uint16_t aux_codes[][6])
Reads and parses the LTC6804 auxiliary registers.
Definition: LTC68042.cpp:459
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_clrcell()
Clears the LTC6804 cell voltage registers.
Definition: LTC68042.cpp:628
void set_adc(uint8_t MD, uint8_t DCP, uint8_t CH, uint8_t CHG)
Definition: LTC68042.cpp:117
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
uint16_t pec15_calc(uint8_t len, uint8_t *data)
Definition: LTC68042.cpp:891
static const unsigned int crc15Table[256]
Definition: LTC68041.h:90
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: LTC68042.cpp:371
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
#define MD_NORMAL
Definition: LTC68041.h:126
void LTC6804_wrcfg(uint8_t total_ic, uint8_t config[][6])
Write the LTC6804 configuration register.
Definition: LTC68042.cpp:718
LTC6804-2 Multicell Battery Monitor.
void LTC6804_adcv()
Definition: LTC68042.cpp:150
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: LTC68042.cpp:257
void LTC6804_initialize()
This function will initialize all 6804 variables and the SPI port.
Definition: LTC68042.cpp:96
void wakeup_idle()
Definition: LTC68042.cpp:862
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
#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
int8_t LTC6804_rdcfg(uint8_t total_ic, uint8_t r_config[][8])
Definition: LTC68042.cpp:798
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
#define DCP_DISABLED
Definition: LTC68041.h:183
void LTC6804_clraux()
Clears the LTC6804 Auxiliary registers.
Definition: LTC68042.cpp:667
uint8_t ADCV[2]
6804 conversion command variables.
Definition: LTC68042.cpp:85
static int i
Definition: DC2430A.ino:184
void LTC6804_adax()
Definition: LTC68042.cpp:195
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
void LTC6804_rdaux_reg(uint8_t reg, uint8_t total_ic, uint8_t *data)
Read the raw data from the LTC6804 auxiliary register.
Definition: LTC68042.cpp:570