| 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 */
96 void LTC6804_initialize()
97 {
98 quikeval_SPI_connect();
99 spi_enable(SPI_CLOCK_DIV16);
100 set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
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 ***********************************************************************************************/
150 void LTC6804_adcv()
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
169 output_low(LTC6804_CS);
170 spi_write_array(4,cmd);
171 output_high(LTC6804_CS);
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 *********************************************************************************************************/
195 void LTC6804_adax()
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.
207 output_low(LTC6804_CS);
208 spi_write_array(4,cmd);
209 output_high(LTC6804_CS);
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);
414 output_low(LTC6804_CS);
415 spi_write_read(cmd,4,&data[current_ic*8],8);
416 output_high(LTC6804_CS);
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);
608 output_low(LTC6804_CS);
609 spi_write_read(cmd,4,&data[current_ic*8],8);
610 output_high(LTC6804_CS);
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 ************************************************************/
628 void LTC6804_clrcell()
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
646 output_low(LTC6804_CS);
647 spi_write_read(cmd,4,0,0);
648 output_high(LTC6804_CS);
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 ***************************************************************/
667 void LTC6804_clraux()
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
684 output_low(LTC6804_CS);
685 spi_write_read(cmd,4,0,0);
686 output_high(LTC6804_CS);
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);
760 output_low(LTC6804_CS);
761 spi_write_array(4,cmd);
762 spi_write_array(8,&cmd[4+(8*current_ic)]);
763 output_high(LTC6804_CS);
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);
823 output_low(LTC6804_CS);
824 spi_write_read(cmd,4,&rx_data[current_ic*8],8);
825 output_high(LTC6804_CS);
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 *****************************************************/
862 void wakeup_idle()
863 {
864 output_low(LTC6804_CS);
865 delayMicroseconds(10); //Guarantees the isoSPI will be in ready mode
866 output_high(LTC6804_CS);
867 }
868
869 /*!****************************************************
870 \brief Wake the LTC6804 from the sleep state
871
872 Generic wakeup commannd to wake the LTC6804 from sleep
873 *****************************************************/
874 void wakeup_sleep()
875 {
876 output_low(LTC6804_CS);
877 delay(1); // Guarantees the LTC6804 will be in standby
878 output_high(LTC6804_CS);
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
ADAX
uint8_t ADAX[2]
GPIO conversion command.
Definition: LTC68042.cpp:86
CELL_CH_ALL
#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
spi_write_read
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
wakeup_sleep
void wakeup_sleep()
Definition: LTC68042.cpp:874
output_high
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
spi_write_array
void spi_write_array(uint8_t len, uint8_t data[])
Writes an array of bytes out of the SPI port.
Definition: LTC68042.cpp:912
LTC6804_rdaux
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
Linduino.h
Header File for Linduino Libraries and Demo Code.
spi_write
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
AUX_CH_ALL
#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
LTC6804_CS
#define LTC6804_CS
Definition: LTC68041.h:55
spi_enable
void spi_enable(uint8_t spi_clock_divider)
Setup the processor for hardware SPI communication.
Definition: LT_SPI.cpp:160
LTC6804_clrcell
void LTC6804_clrcell()
Clears the LTC6804 cell voltage registers.
Definition: LTC68042.cpp:628
set_adc
void set_adc(uint8_t MD, uint8_t DCP, uint8_t CH, uint8_t CHG)
Definition: LTC68042.cpp:117
data
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
pec15_calc
uint16_t pec15_calc(uint8_t len, uint8_t *data)
Definition: LTC68042.cpp:891
crc15Table
static const unsigned int crc15Table[256]
Definition: LTC68041.h:90
LTC6804_rdcv_reg
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
output_low
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
MD_NORMAL
#define MD_NORMAL
Definition: LTC68041.h:126
LTC6804_wrcfg
void LTC6804_wrcfg(uint8_t total_ic, uint8_t config[][6])
Write the LTC6804 configuration register.
Definition: LTC68042.cpp:718
LTC68042.h
LTC6804-2 Multicell Battery Monitor.
LTC6804_adcv
void LTC6804_adcv()
Definition: LTC68042.cpp:150
LTC6804_rdcv
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
LTC6804_initialize
void LTC6804_initialize()
This function will initialize all 6804 variables and the SPI port.
Definition: LTC68042.cpp:96
wakeup_idle
void wakeup_idle()
Definition: LTC68042.cpp:862
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
NUM_RX_BYT
#define NUM_RX_BYT
Definition: LTC681x.h:108
quikeval_SPI_connect
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
spi_read
int8_t spi_read(int8_t data)
The data byte to be written.
Definition: LT_SPI.cpp:189
LTC6804_rdcfg
int8_t LTC6804_rdcfg(uint8_t total_ic, uint8_t r_config[][8])
Definition: LTC68042.cpp:798
aux_codes
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
DCP_DISABLED
#define DCP_DISABLED
Definition: LTC68041.h:183
LTC6804_clraux
void LTC6804_clraux()
Clears the LTC6804 Auxiliary registers.
Definition: LTC68042.cpp:667
ADCV
uint8_t ADCV[2]
6804 conversion command variables.
Definition: LTC68042.cpp:85
i
static int i
Definition: DC2430A.ino:184
LTC6804_adax
void LTC6804_adax()
Definition: LTC68042.cpp:195
cell_codes
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
LTC6804_rdaux_reg
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