DC2100A  1.2.0
Bi-Directional Cell Balancer Using the LTC3300-1 and the LTC6804-2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
LTC6804-2.c
Go to the documentation of this file.
1 /*
2  Linear Technology DC2100A Demonstration Board.
3  Driver File for LTC6804-2 Multicell Battery Monitors.
4  All datasheet references in this file refer to Linear Technology Corp. document 680412fa.pdf.
5 
6  @verbatim
7  The LTC6804 is a 3rd generation multicell battery stack
8  monitor that measures up to 12 series connected battery
9  cells with a total measurement error of less than 1.2mV. The
10  cell measurement range of 0V to 5V makes the LTC6804
11  suitable for most battery chemistries. All 12 cell voltages
12  can be captured in 290us, and lower data acquisition rates
13  can be selected for high noise reduction.
14  Multiple LTC6804 devices can be connected in series,
15  permitting simultaneous cell monitoring of long, high voltage
16  battery strings. Each LTC6804 has an isoSPI interface
17  for high speed, RF-immune, local area communications.
18  Using the LTC6804-2, multiple devices are connected in
19  a daisy-chain with one host processor connection for all
20  devices. Using the LTC6804-2, multiple devices are connected
21  in parallel to the host processor, with each device
22  individually addressed.
23  Additional features include passive balancing for each cell,
24  an onboard 5V regulator, and 5 general purpose I/O lines.
25  In sleep mode, current consumption is reduced to 4uA.
26  The LTC6804 can be powered directly from the battery,
27  or from an isolated supply.
28  @endverbatim
29 
30  http://www.linear.com/product/LTC6804
31 
32  http://www.linear.com/product/LTC6804#demoboards
33 
34  REVISION HISTORY
35  $Revision: 699 $
36  $Date: 2014-09-09 16:02:09 -0400 (Tue, 09 Sep 2014) $
37 
38  Copyright (c) 2013, Linear Technology Corp.(LTC)
39  All rights reserved.
40 
41  Redistribution and use in source and binary forms, with or without
42  modification, are permitted provided that the following conditions are met:
43 
44  1. Redistributions of source code must retain the above copyright notice, this
45  list of conditions and the following disclaimer.
46  2. Redistributions in binary form must reproduce the above copyright notice,
47  this list of conditions and the following disclaimer in the documentation
48  and/or other materials provided with the distribution.
49 
50  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
51  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
52  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
54  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
55  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
59  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 
61  The views and conclusions contained in the software and documentation are those
62  of the authors and should not be interpreted as representing official policies,
63  either expressed or implied, of Linear Technology Corp.
64 
65 */
66 
67 //! @defgroup LTC6804-2 LTC6804-2 Multicell Battery Monitors.
68 
69 /*! @file
70  @ingroup LTC6804-2
71  Driver File for LTC6804-2 Multicell Battery Monitors.
72 */
73 
74 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
75 // Includes
76 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
77 #include "Typedefs.h"
78 #include "LTC6804-2.h"
79 #include "LTC6804-2_Config.h"
80 #include "LTC6804-2_Registers.h"
81 #include <string.h>
82 
83 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
84 // Definitions
85 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
86 
87 // Timing parameters for state transitions defined by datasheet Figure 1.
88 // Electrical Characteristics from datasheet pages 7 and 8 contain worst case values.
89 #define LTC6804_TWAKE 300 // us, max value
90 #define LTC6804_TSLEEP 1800 // ms, min value
91 #define LTC6804_TREADY 10 // us, max value
92 #define LTC6804_TIDLE 4300 // us, min value
93 #define LTC6804_TDWELL 1 // us, min value of 240ns in datasheet is outside resolution of uP timer.
94 
95 #define LTC6804_NUM_CELLV_ADC_PER_REGISTER_GROUP (LTC6804_REGISTER_GROUP_SIZE / LTC6804_ADC_SIZE) // Number of cell voltage ADC measurements per register group
96 #define LTC6804_NUM_REGISTER_GROUP_READS_FOR_ALL_CELLV (LTC6804_NUM_CELLV_ADC / LTC6804_NUM_CELLV_ADC_PER_REGISTER_GROUP) // Number of register groups that must be read to get all cell voltage ADC measurements
97 #define LTC6804_NUM_REGISTER_GROUP_READS_FOR_TWO_CELLV (2) // Number of register groups that must be read to get a pair of cell voltage ADC measurements
98 #define LTC6804_NUM_AUX_ADC_PER_REGISTER_GROUP (LTC6804_REGISTER_GROUP_SIZE / LTC6804_ADC_SIZE)
99 
100 #define LTC6804_NUM_COMM_BYTES_PER_REGISTER_GROUP 3 // Number of I2C/SPI bytes contained in the COMM register group
101 
102 // Relationship between input SPI clocks and I2C/SPI output clocks, as per page 32 of datasheet.
103 #define LTC6804_SPI_CLOCK_CYCLES_PER_STCOMM_BYTE 24
104 #define LTC6804_SPI_BYTES_PER_STCOMM_BYTE (LTC6804_SPI_CLOCK_CYCLES_PER_STCOMM_BYTE/BITS_PER_BYTE)
105 
106 // input clocks, when used to drive the I2C/SPI output clocks, as per table 19 of datasheet
107 #define LTC6804_BAUD_RATE_DIVISOR 2 // tCLK/(SCL Clock Frequency) in table 19 of datasheet
108 
109 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
110 // Global Data
111 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
112 
113 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
114 // Local Data
115 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
116 // Table used perform PEC calculation defined by datasheet figure 22.
117 const unsigned int16 ltc6804_pec_seed_value = 16;
118 const unsigned int16 ltc6804_pec_table[256] =
119 { 0x0000, 0xc599, 0xceab, 0x0b32, 0xd8cf, 0x1d56, 0x1664, 0xd3fd, 0xf407, 0x319e, 0x3aac,
120  0xff35, 0x2cc8, 0xe951, 0xe263, 0x27fa, 0xad97, 0x680e, 0x633c, 0xa6a5, 0x7558, 0xb0c1,
121  0xbbf3, 0x7e6a, 0x5990, 0x9c09, 0x973b, 0x52a2, 0x815f, 0x44c6, 0x4ff4, 0x8a6d, 0x5b2e,
122  0x9eb7, 0x9585, 0x501c, 0x83e1, 0x4678, 0x4d4a, 0x88d3, 0xaf29, 0x6ab0, 0x6182, 0xa41b,
123  0x77e6, 0xb27f, 0xb94d, 0x7cd4, 0xf6b9, 0x3320, 0x3812, 0xfd8b, 0x2e76, 0xebef, 0xe0dd,
124  0x2544, 0x02be, 0xc727, 0xcc15, 0x098c, 0xda71, 0x1fe8, 0x14da, 0xd143, 0xf3c5, 0x365c,
125  0x3d6e, 0xf8f7, 0x2b0a, 0xee93, 0xe5a1, 0x2038, 0x07c2, 0xc25b, 0xc969, 0x0cf0, 0xdf0d,
126  0x1a94, 0x11a6, 0xd43f, 0x5e52, 0x9bcb, 0x90f9, 0x5560, 0x869d, 0x4304, 0x4836, 0x8daf,
127  0xaa55, 0x6fcc, 0x64fe, 0xa167, 0x729a, 0xb703, 0xbc31, 0x79a8, 0xa8eb, 0x6d72, 0x6640,
128  0xa3d9, 0x7024, 0xb5bd, 0xbe8f, 0x7b16, 0x5cec, 0x9975, 0x9247, 0x57de, 0x8423, 0x41ba,
129  0x4a88, 0x8f11, 0x057c, 0xc0e5, 0xcbd7, 0xe4e, 0xddb3, 0x182a, 0x1318, 0xd681, 0xf17b,
130  0x34e2, 0x3fd0, 0xfa49, 0x29b4, 0xec2d, 0xe71f, 0x2286, 0xa213, 0x678a, 0x6cb8, 0xa921,
131  0x7adc, 0xbf45, 0xb477, 0x71ee, 0x5614, 0x938d, 0x98bf, 0x5d26, 0x8edb, 0x4b42, 0x4070,
132  0x85e9, 0x0f84, 0xca1d, 0xc12f, 0x04b6, 0xd74b, 0x12d2, 0x19e0, 0xdc79, 0xfb83, 0x3e1a, 0x3528,
133  0xf0b1, 0x234c, 0xe6d5, 0xede7, 0x287e, 0xf93d, 0x3ca4, 0x3796, 0xf20f, 0x21f2, 0xe46b, 0xef59,
134  0x2ac0, 0x0d3a, 0xc8a3, 0xc391, 0x0608, 0xd5f5, 0x106c, 0x1b5e, 0xdec7, 0x54aa, 0x9133, 0x9a01,
135  0x5f98, 0x8c65, 0x49fc, 0x42ce, 0x8757, 0xa0ad, 0x6534, 0x6e06, 0xab9f, 0x7862, 0xbdfb, 0xb6c9,
136  0x7350, 0x51d6, 0x944f, 0x9f7d, 0x5ae4, 0x8919, 0x4c80, 0x47b2, 0x822b, 0xa5d1, 0x6048, 0x6b7a,
137  0xaee3, 0x7d1e, 0xb887, 0xb3b5, 0x762c, 0xfc41, 0x39d8, 0x32ea, 0xf773, 0x248e, 0xe117, 0xea25,
138  0x2fbc, 0x0846, 0xcddf, 0xc6ed, 0x0374, 0xd089, 0x1510, 0x1e22, 0xdbbb, 0x0af8, 0xcf61, 0xc453,
139  0x01ca, 0xd237, 0x17ae, 0x1c9c, 0xd905, 0xfeff, 0x3b66, 0x3054, 0xf5cd, 0x2630, 0xe3a9, 0xe89b,
140  0x2d02, 0xa76f, 0x62f6, 0x69c4, 0xac5d, 0x7fa0, 0xba39, 0xb10b, 0x7492, 0x5368, 0x96f1, 0x9dc3,
141  0x585a, 0x8ba7, 0x4e3e, 0x450c, 0x8095
142 };
143 
144 unsigned int8 ltc6804_gpio_pulldown; // Since the GPIOx values in the CFGR register group read differently than what was written, the only way
145  // to read/modify/write other values in this register are to have local storage for the written values.
146 
147 int8 ltc6804_adcopt; // When starting an ADC conversion at a sample frequency, the adcopt must be correctly set. Local storage allows driver
148  // to quickly detect whether the adcopt bit needs to be changed in the CFG register without reading a register group unnecessarily.
149 
150 unsigned int32 ltc6804_wakeup_timestamp; // in LTC6804_CONFIG_TIMER_RESOLUTION, timestamp for the last time that the LTC6804 system received a wakeup signal.
151 
152 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
153 // Local Prototypes
154 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
155 void ltc6804_wakeup(void);
156 void ltc6804_get_adcopt_and_md(int8 conversion_mode, int8* adcopt_ptr, int8* md_ptr);
157 void ltc6804_adc_opt_set(int8 board_num, int8 adcopt);
158 void ltc6804_command_code_send(int16 command_code, BOOLEAN reg_group_command);
159 void ltc6804_register_group_write(int8* register_group);
160 BOOLEAN ltc6804_register_group_read(int8* register_group);
161 void ltc6804_cfgr_modify(int8 board_num, int8* register_mask_ptr, int8* register_value_ptr);
162 void ltc6804_clock_out(int16 bytes_to_send, int16 baud_khz);
163 inline unsigned int16 ltc6804_pec_lookup(char data, unsigned int16 remainder);
164 
165 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
166 // Global Functions
167 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
168 
169 // Initializes the LTC6804-2 code module.
170 void LTC6804_Init(void)
171 {
172  // init I/O pulldowns to be all off
173  ltc6804_gpio_pulldown = ((1 << LTC6804_NUM_GPIO) - 1);
174 
175  // init ADCOPT to nonsensical value so that it will always be set the first time.
176  ltc6804_adcopt = 0xFF;
177 
178  // Initialize wakeup timestamp to ensure that SLEEP is assumed for first communication with LTC6804
179  ltc6804_wakeup_timestamp = LTC6804_CONFIG_TIMER - (LTC6804_TSLEEP * LTC6804_CONFIG_TIMER_RESOLUTION / MS_PER_S);
180 
181  return;
182 }
183 
184 // Read/Modify/Write the Config register such that the GPIOs are at the values specified in the gpio_value_bitmap.
185 void LTC6804_GPIO_Set(int8 board_num, int8 gpio_bitmap)
186 {
187  struct {
188  int8 mask[LTC6804_REGISTER_GROUP_SIZE];
189  int8 value[LTC6804_REGISTER_GROUP_SIZE];
190  } register_modify;
191 
192  ltc6804_gpio_pulldown = gpio_bitmap; // Remember this written value, as all other read/modify/write operations on the
193  // CFGR register will need to write this value instead of the read value.
194 
195  // Start with clear mask and value, and then set up gpio mask/value
196  memset(&register_modify.mask[1], 0, sizeof(register_modify)-1);
197  register_modify.mask[0] = LTC6804_CFGR0_GPIOx_MASK;
198  register_modify.value[0] = LTC6804_CFGR0_GPIOx(ltc6804_gpio_pulldown);
199 
200  ltc6804_cfgr_modify(board_num, register_modify.mask, register_modify.value);
201 
202  return;
203 }
204 
205 // Read/Modify/Write the Config to turn the Reference on and off.
206 void LTC6804_Refon_Set(int8 board_num, BOOLEAN refon)
207 {
208  struct {
209  int8 mask[LTC6804_REGISTER_GROUP_SIZE];
210  int8 value[LTC6804_REGISTER_GROUP_SIZE];
211  } register_modify;
212 
213  // Start with clear mask and value, and then set up gpio mask/value
214  memset(&register_modify.mask[1], 0, sizeof(register_modify)-1);
215  register_modify.mask[0] = LTC6804_CFGR0_GPIOx_MASK;
216  register_modify.value[0] = LTC6804_CFGR0_GPIOx(ltc6804_gpio_pulldown);
217 
218  // Create Mask to set Ref On
219  register_modify.mask[0] |= LTC6804_CFGR0_REFON_MASK;
220 
221  // Set Value for Ref
222  register_modify.value[0] |= LTC6804_CFGR0_REFON(refon);
223 
224  ltc6804_cfgr_modify(board_num, register_modify.mask, register_modify.value);
225 
226  return;
227 }
228 
229 // Read/Modify/Write the Config register such that the undervoltage and overvoltage values are those specified.
230 void LTC6804_UVOV_Thresholds_Set(int8 board_num, int16 vuv_value, int16 vov_value)
231 {
232  struct {
233  int8 mask[LTC6804_REGISTER_GROUP_SIZE];
234  int8 value[LTC6804_REGISTER_GROUP_SIZE];
235  } register_modify;
236 
237  // Start with clear mask and value, and then set up gpio mask/value
238  memset(&register_modify.mask[1], 0, sizeof(register_modify)-1);
239  register_modify.mask[0] = LTC6804_CFGR0_GPIOx_MASK;
240  register_modify.value[0] = LTC6804_CFGR0_GPIOx(ltc6804_gpio_pulldown);
241 
242  // Create Mask to set VUV and VOV
243  *((int16*)(register_modify.mask+1)) |= LTC6804_CFGR1_VUV_MASK;
244  *((int16*)(register_modify.mask+2)) |= LTC6804_CFGR2_VOV_MASK;
245 
246  // Set Value for VUV and VOV
247  *((int16*)(register_modify.value+1)) |= LTC6804_CFGR1_VUV(vuv_value);
248  *((int16*)(register_modify.value+2)) |= LTC6804_CFGR2_VOV(vov_value);
249 
250  ltc6804_cfgr_modify(board_num, register_modify.mask, register_modify.value);
251 
252  return;
253 }
254 
255 // Read/Modify/Write the Config register such that the discharger and discharge timeout values are those specified.
256 void LTC6804_Dischargers_Set(int8 board_num, int16 discharge_bitmap, int16 timeout_value)
257 {
258  struct {
259  int8 mask[LTC6804_REGISTER_GROUP_SIZE];
260  int8 value[LTC6804_REGISTER_GROUP_SIZE];
261  } register_modify;
262 
263  // Start with clear mask and value, and then set up gpio mask/value
264  memset(&register_modify.mask[1], 0, sizeof(register_modify)-1);
265  register_modify.mask[0] = LTC6804_CFGR0_GPIOx_MASK;
266  register_modify.value[0] = LTC6804_CFGR0_GPIOx(ltc6804_gpio_pulldown);
267 
268  // Create Mask to set discharger and discharge timeout values
269  *((int16*)(register_modify.mask+4)) |= LTC6804_CFGR4_DCCx_MASK;
270  register_modify.mask[5] |= LTC6804_CFGR5_DCTO_MASK;
271 
272  // Set Value for discharger and discharge timeout values
273  *((int16*)(register_modify.value+4)) |= LTC6804_CFGR4_DCCx(discharge_bitmap);
274  register_modify.value[5] |= LTC6804_CFGR5_DCTO(timeout_value);
275 
276  ltc6804_cfgr_modify(board_num, register_modify.mask, register_modify.value);
277 
278  return;
279 }
280 
281 // Gets the LTC6804 under-voltage and over-voltage thresholds in LTC6804_UVOV_RESOLUTION units.
282 BOOLEAN LTC6804_UVOV_Thresholds_Get(int8 board_num, unsigned int16* vuv_value, unsigned int16* vov_value)
283 {
284  BOOLEAN success = TRUE;
285  int8 address;
286  unsigned int16 command_code;
287  unsigned int8 cfgr[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Configuration Register Group B + PEC
288 
289  // Get the board address from the board number
290  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
291 
292  // Wakeup 6804 in case it has entered SLEEP or IDLE.
293  ltc6804_wakeup();
294 
295  command_code = LTC6804_COMMAND_CODE_RDCFG(address);
296 
297  // Send the command code
298  ltc6804_command_code_send(command_code, TRUE);
299 
300  // Read the Status Register
301  if(ltc6804_register_group_read(cfgr) == TRUE)
302  {
303  *vuv_value = *((int16*)(cfgr+1)) & LTC6804_CFGR1_VUV_MASK;
304  *vov_value = (*((int16*)(cfgr+2)) & LTC6804_CFGR2_VOV_MASK) >> 4;
305  }
306  else
307  {
308  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, cfgr, sizeof(cfgr));
309  success = FALSE;
310  }
311 
312  return success;
313 }
314 
315 // Gets the LTC6804 flags indicating under-voltage and over-voltage conditions are present.
316 BOOLEAN LTC6804_UVOV_Flags_Get(int8 board_num, int16* vuv_flags, int16* vov_flags)
317 {
318  BOOLEAN success = TRUE;
319  int8 address;
320  unsigned int16 command_code;
321  unsigned int8 stbr[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Status Register Group B + PEC
322  int8 byte_num;
323  int8 bit_num;
324  int8 bit_mask_in;
325  int16 bit_mask_out;
326 
327  // Get the board address from the board number
328  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
329 
330  // Wakeup 6804 in case it has entered SLEEP or IDLE.
331  ltc6804_wakeup();
332 
333  command_code = LTC6804_COMMAND_CODE_RDSTATB(address);
334 
335  // Send the command code
336  ltc6804_command_code_send(command_code, TRUE);
337 
338  // Read the Status Register
339  if(ltc6804_register_group_read(stbr) == TRUE)
340  {
341  // Initialize so that uvov flags will be separated into uv and ov by loop below
342  bit_mask_out = 0x0001;
343  *vuv_flags = 0;
344  *vov_flags = 0;
345 
346  // Interpret data in register group according to datasheet Table 44
347  for (byte_num = 2; byte_num < 5; byte_num++)
348  {
349  bit_mask_in = 0x01;
350 
351  for (bit_num = 0; bit_num < 8; bit_num += 2)
352  {
353  if(stbr[byte_num] & bit_mask_in) *vuv_flags |= bit_mask_out;
354  bit_mask_in <<= 1;
355 
356  if(stbr[byte_num] & bit_mask_in) *vov_flags |= bit_mask_out;
357  bit_mask_in <<= 1;
358 
359  bit_mask_out <<= 1;
360  }
361  }
362  }
363  else
364  {
365  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, stbr, sizeof(stbr));
366  success = FALSE;
367  }
368 
369  return success;
370 }
371 
372 // Gets the LTC6804 revision.
373 BOOLEAN LTC6804_Revision_Get(int8 board_num, unsigned int8* revision)
374 {
375  BOOLEAN success = TRUE;
376  int8 address;
377  unsigned int16 command_code;
378  unsigned int8 stbr[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Status Register Group B + PEC
379 
380  // Get the board address from the board number
381  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
382 
383  // Wakeup 6804 in case it has entered SLEEP or IDLE.
384  ltc6804_wakeup();
385 
386  command_code = LTC6804_COMMAND_CODE_RDSTATB(address);
387 
388  // Send the command code
389  ltc6804_command_code_send(command_code, TRUE);
390 
391  // Read the Status Register
392  if(ltc6804_register_group_read(stbr) == TRUE)
393  {
394  *revision = stbr[5] >> 4;
395  }
396  else
397  {
398  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, stbr, sizeof(stbr));
399  success = FALSE;
400  }
401 
402  return success;
403 }
404 
405 // Gets the LTC6804 ADC Reference status, where 1 = ON and 0 = OFF.
406 BOOLEAN LTC6804_Refon_Get(int8 board_num, int8* refon)
407 {
408  BOOLEAN success = TRUE;
409  int8 address;
410  unsigned int16 command_code;
411  unsigned int8 cfgr[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Configuration Register Group B + PEC
412 
413  // Get the board address from the board number
414  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
415 
416  // Wakeup 6804 in case it has entered SLEEP or IDLE.
417  ltc6804_wakeup();
418 
419  command_code = LTC6804_COMMAND_CODE_RDCFG(address);
420 
421  // Send the command code
422  ltc6804_command_code_send(command_code, TRUE);
423 
424  // Read the Status Register
425  if(ltc6804_register_group_read(cfgr) == TRUE)
426  {
427  if (cfgr[0] & LTC6804_CFGR0_REFON_MASK)
428  {
429  *refon = TRUE;
430  }
431  else
432  {
433  *refon = FALSE;
434  }
435  }
436  else
437  {
438  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, cfgr, sizeof(cfgr));
439  success = FALSE;
440  }
441 
442  return success;
443 }
444 
445 
446 // Clears the LTC6804 Cell Voltage ADC registers. This is useful to detect if the conversion was started properly when the results are read.
447 void LTC6804_Cell_ADC_Clear(int8 board_num)
448 {
449  int8 address;
450  unsigned int16 command_code;
451 
452  // Get the board address from the board number
453  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
454 
455  // Wakeup 6804 in case it has entered SLEEP or IDLE.
456  ltc6804_wakeup();
457 
458  // Build the command code
459  command_code = LTC6804_COMMAND_CODE_CLRCELL(address);
460 
461  // Send the command code
462  ltc6804_command_code_send(command_code, FALSE);
463 
464  return;
465 }
466 
467 // Starts the LTC6804 Cell Voltage ADC conversion at the specified conversion mode.
468 void LTC6804_Cell_ADC_Start(int8 board_num, LTC6804_CONVERSION_MODE_T mode, LTC6804_CH_CELL_TYPE cell_select, BOOLEAN discharge_permitted)
469 {
470  int8 address;
471  unsigned int16 command_code;
472  int8 adcopt;
473  int8 md;
474 
475  // Get the board address from the board number
476  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
477 
478  // Get adcopt and md values to achieve the desired sample rate.
479  ltc6804_get_adcopt_and_md(mode, &adcopt, &md);
480 
481  // Set adcopt in the cfg register, if necessary
482  if( ltc6804_adcopt != adcopt)
483  {
484  ltc6804_adc_opt_set(board_num, adcopt);
485  }
486  else
487  {
488  // Wakeup 6804 in case it has entered SLEEP or IDLE.
489  ltc6804_wakeup();
490  }
491 
492  // Build the command code to start ADC conversion
493  command_code = LTC6804_COMMAND_CODE_ADCV(address, md, (discharge_permitted ? LTC6804_DCP_DISCHARGE_PERMITTED : LTC6804_DCP_DISCHARGE_NOT_PERMITTED), cell_select);
494 
495  // Send the command code
496  ltc6804_command_code_send(command_code, FALSE);
497 
498  return;
499 }
500 
501 // Reads the LTC6804 Cell Voltage ADC conversion results.
502 BOOLEAN LTC6804_Cell_ADC_Read(int8 board_num, LTC6804_CH_CELL_TYPE cell_select, unsigned int16* adc_value_ptr)
503 {
504  BOOLEAN success = TRUE;
505  int8 address;
506  unsigned int16 command_code;
507  unsigned int8 reg_count;
508  unsigned int8 reg_index;
509  unsigned int8 reg_inc;
510  unsigned int8 byte_index;
511  unsigned int8 cv_r[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Cell Voltage Register Groups + PEC
512  int8 byte_num;
513 
514  // Determine how many cell ADC results were requested and where that data is located in register groups
515  if(LTC6804_CH_ALL == cell_select)
516  {
517  reg_count = LTC6804_NUM_REGISTER_GROUP_READS_FOR_ALL_CELLV;
518  reg_index = 0;
519  reg_inc = (LTC6804_COMMAND_CODE_BASE_RDCVB - LTC6804_COMMAND_CODE_BASE_RDCVA);
520  byte_index = 0;
521  }
522  else
523  {
524  reg_count = LTC6804_NUM_REGISTER_GROUP_READS_FOR_TWO_CELLV;
525  reg_index = (cell_select - 1) / LTC6804_NUM_CELLV_ADC_PER_REGISTER_GROUP;
526  reg_inc = (LTC6804_COMMAND_CODE_BASE_RDCVC - LTC6804_COMMAND_CODE_BASE_RDCVA);
527  byte_index = ((cell_select - 1) % LTC6804_NUM_CELLV_ADC_PER_REGISTER_GROUP) * LTC6804_ADC_SIZE;
528  }
529 
530  // Get the board address from the board number
531  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
532 
533  // Wakeup 6804 in case it has entered SLEEP or IDLE.
534  ltc6804_wakeup();
535 
536  command_code = LTC6804_COMMAND_CODE_RDCVA(address) + reg_index * (LTC6804_COMMAND_CODE_BASE_RDCVB - LTC6804_COMMAND_CODE_BASE_RDCVA);
537 
538  do
539  {
540  // Send the command code
541  ltc6804_command_code_send(command_code, TRUE);
542 
543  // Read the ADC results
544  if(ltc6804_register_group_read(cv_r) == TRUE)
545  {
546  // Interpret data in register group according to datasheet Table 37, Table 38, Table 39, and Table 40
547  if(LTC6804_CH_ALL == cell_select)
548  {
549  for (byte_num = 0; byte_num < LTC6804_REGISTER_GROUP_SIZE; byte_num += LTC6804_ADC_SIZE)
550  {
551  *adc_value_ptr++ = ((int16) cv_r[byte_num + 1] << 8) + cv_r[byte_num];
552  }
553  }
554  else
555  {
556  *adc_value_ptr++ = ((int16) cv_r[byte_index + 1] << 8) + cv_r[byte_index];
557  }
558 
559  // Increment command code to request next register group
560  command_code += reg_inc;
561 
562  // Count the register groups that have been requested
563  reg_count--;
564  }
565  else
566  {
567  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, cv_r, sizeof(cv_r));
568  reg_count = 0; // Bail out of command after first bad read.
569  success = FALSE;
570  }
571 
572  } while(reg_count);
573 
574  return success;
575 }
576 
577 // Clears the LTC6804 GPIO ADC registers. This is useful to detect if the conversion was started properly when the results are read.
578 void LTC6804_GPIO_ADC_Clear(int8 board_num)
579 {
580  int8 address;
581  unsigned int16 command_code;
582 
583  // Get the board address from the board number
584  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
585 
586  // Wakeup 6804 in case it has entered SLEEP or IDLE.
587  ltc6804_wakeup();
588 
589  // Build the command code
590  command_code = LTC6804_COMMAND_CODE_CLRAUX(address);
591 
592  // Send the command code
593  ltc6804_command_code_send(command_code, FALSE);
594 
595  return;
596 }
597 
598 // Starts the specified LTC6804 GPIO ADC conversion at the specified conversion mode.
600 {
601  int8 address;
602  unsigned int16 command_code;
603  int8 adcopt;
604  int8 md;
605 
606  // Get the board address from the board number
607  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
608 
609  // Get adcopt and md values to achieve the desired sample rate.
610  ltc6804_get_adcopt_and_md(mode, &adcopt, &md);
611 
612  // Set adcopt in the cfg register, if necessary
613  if( ltc6804_adcopt != adcopt)
614  {
615  ltc6804_adc_opt_set(board_num, adcopt);
616  }
617  else
618  {
619  // Wakeup 6804 in case it has entered SLEEP or IDLE.
620  ltc6804_wakeup();
621  }
622 
623  // Build the command code
624  command_code = LTC6804_COMMAND_CODE_ADAX(address, md, gpio_select);
625 
626  // Send the command code
627  ltc6804_command_code_send(command_code, FALSE);
628 
629  return;
630 }
631 
632 // Reads the specified LTC6804 GPIO ADC conversion results.
633 BOOLEAN LTC6804_GPIO_ADC_Read(int8 board_num, LTC6804_CHG_GPIO_TYPE gpio_select, int16* adc_value_ptr)
634 {
635  BOOLEAN success = TRUE;
636  int8 address;
637  unsigned int16 command_code;
638  unsigned int8 gpio_index;
639  unsigned int8 gpio_count;
640  unsigned int8 avar[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Auxiliary Register Group + PEC
641  int8 byte_num;
642 
643  // Determine how many gpio ADC results were requested and where that data is located in register group
644  if(LTC6804_CHG_GPIO_ALL == gpio_select)
645  {
646  gpio_count = LTC6804_NUM_AUX_ADC;
647  gpio_index = 0;
648  }
649  else
650  {
651  gpio_count = 1;
652  gpio_index = gpio_select - LTC6804_CHG_GPIO1;
653  }
654 
655  // Get the board address from the board number
656  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
657 
658  // Wakeup 6804 in case it has entered SLEEP or IDLE.
659  ltc6804_wakeup();
660 
661  do
662  {
663  // Determine if this result is in Auxiliary Register Group A or B
664  if(gpio_index < LTC6804_NUM_AUX_ADC_PER_REGISTER_GROUP)
665  {
666  // Build the command code
667  command_code = LTC6804_COMMAND_CODE_RDAUXA(address);
668  }
669  else
670  {
671  // Build the command code
672  command_code = LTC6804_COMMAND_CODE_RDAUXB(address);
673  }
674 
675  // Send the command code
676  ltc6804_command_code_send(command_code, TRUE);
677 
678  // Read the ADC results
679  if(ltc6804_register_group_read(avar) == TRUE)
680  {
681  // Interpret data in register group according to datasheet Table 41 and Table 42
682  byte_num = (gpio_index % LTC6804_NUM_AUX_ADC_PER_REGISTER_GROUP) * LTC6804_ADC_SIZE;
683  while((byte_num < LTC6804_REGISTER_GROUP_SIZE) && (gpio_count > 0))
684  {
685  *adc_value_ptr++ = ((int16) avar[byte_num + 1] << 8) + avar[byte_num];
686  gpio_count--;
687  byte_num += LTC6804_ADC_SIZE;
688  }
689  }
690  else
691  {
692  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, avar, sizeof(avar));
693  gpio_count = 0; // Bail out of command after first bad read.
694  success = FALSE;
695  }
696 
697  } while(gpio_count);
698 
699  return success;
700 }
701 
702 // Writes a string of bytes to the LTC6804 I2C port implemented on its GPIO pins.
703 void LTC6804_I2C_Write(int8 board_num, BOOLEAN start, BOOLEAN stop, int8* data_ptr, int16 num_bytes, int16 baud_khz)
704 {
705  int8 address;
706  unsigned int16 command_code;
707  unsigned int8 comm[LTC6804_REGISTER_GROUP_SIZE];
708  int8* comm_ptr;
709  int8 bytes_to_send;
710  int8 byte_num;
711 
712  // Get the board address from the board number
713  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
714 
715  // Wakeup 6804 in case it has entered SLEEP or IDLE.
716  ltc6804_wakeup();
717 
718  while (num_bytes)
719  {
720  // Send the WRCOMM command code
721  command_code = LTC6804_COMMAND_CODE_WRCOMM(address);
722  ltc6804_command_code_send(command_code, TRUE);
723 
724  // Build COMM Register Group
725  bytes_to_send = 0;
726  comm_ptr = comm;
727 
728  // First I2C byte might be a start or a stop, and will always transmit something (else we wouldn't be in this loop)
729  *comm_ptr++ = ((start ? LTC6804_ICOM_I2C_WRITE_START : LTC6804_ICOM_I2C_WRITE_BLANK) << 4) + UPPER_NIBBLE(*data_ptr);
730  *comm_ptr++ = (LOWER_NIBBLE(*data_ptr) << 4) + ((num_bytes == 1) && stop ? LTC6804_FCOM_WRITE_I2C_NACK_STOP : LTC6804_FCOM_WRITE_I2C_NACK);
731 
732  start = FALSE;
733  data_ptr++;
734  num_bytes--;
735  bytes_to_send++;
736 
737  // Second and Third I2C byte might be a stop or no transmit. Note that 1st byte is special case, and handled above this loop
738  for(byte_num = 1; byte_num < LTC6804_NUM_COMM_BYTES_PER_REGISTER_GROUP; byte_num++)
739  {
740  *comm_ptr++ = ((num_bytes ? LTC6804_ICOM_I2C_WRITE_BLANK : LTC6804_ICOM_I2C_WRITE_NO_TRANSMIT) << 4) + UPPER_NIBBLE(*data_ptr);
741  *comm_ptr++ = (LOWER_NIBBLE(*data_ptr) << 4) + ((num_bytes == 1) && stop ? LTC6804_FCOM_WRITE_I2C_NACK_STOP : LTC6804_FCOM_WRITE_I2C_NACK);
742  if(num_bytes)
743  {
744  data_ptr++;
745  num_bytes--;
746  bytes_to_send++;
747  }
748  }
749 
750  // Write COMM Register Group
751  ltc6804_register_group_write(comm);
752 
753  // Send the STRCOMM Command
754  command_code = LTC6804_COMMAND_CODE_STCOMM(address);
755  ltc6804_command_code_send(command_code, TRUE);
756 
757  //Send the number clocks to send the COMM Register Group data to the I2C
758  ltc6804_clock_out(bytes_to_send, baud_khz);
759  }
760 }
761 
762 // Writes one byte, and then reads a string of bytes to the LTC6804 I2C port implemented on its GPIO pins.
763 BOOLEAN LTC6804_I2C_Read(int8 board_num, BOOLEAN start, BOOLEAN stop, int8* data_ptr, int16 num_bytes, int16 baud_khz)
764 {
765  BOOLEAN success = TRUE;
766  int8 address;
767  unsigned int16 command_code;
768  unsigned int8 comm[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Comm Register Group + PEC
769  int8* comm_ptr;
770  int8 bytes_to_send;
771  int8 byte_num;
772 
773  // Get the board address from the board number
774  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
775 
776  // Wakeup 6804 in case it has entered SLEEP or IDLE.
777  ltc6804_wakeup();
778 
779  while (num_bytes)
780  {
781  // Send the WRCOMM command code
782  command_code = LTC6804_COMMAND_CODE_WRCOMM(address);
783  ltc6804_command_code_send(command_code, TRUE);
784 
785  // Build COMM Register Group
786  bytes_to_send = 0;
787  comm_ptr = comm;
788 
789  // First I2C byte might be a start or a stop, and will always transmit something (else we wouldn't be in this loop)
790  if(start)
791  {
792  *comm_ptr++ = (LTC6804_ICOM_I2C_WRITE_START << 4) + UPPER_NIBBLE(*data_ptr);
793  *comm_ptr++ = (LOWER_NIBBLE(*data_ptr) << 4) + LTC6804_FCOM_WRITE_I2C_NACK;
794  }
795  else
796  {
797  *comm_ptr++ = ((LTC6804_ICOM_I2C_WRITE_BLANK) << 4) + UPPER_NIBBLE(LTC6804_COMM_READ_DUMMY);
798  *comm_ptr++ = (LOWER_NIBBLE(LTC6804_COMM_READ_DUMMY) << 4) + ((num_bytes == 1) && stop ? LTC6804_FCOM_WRITE_I2C_NACK_STOP : LTC6804_FCOM_WRITE_I2C_ACK);
799  }
800  num_bytes--;
801  bytes_to_send++;
802 
803  // Second and Third I2C byte might be a stop or no transmit. Note that 1st byte is special case, and handled above this loop
804  for(byte_num = 1; byte_num < LTC6804_NUM_COMM_BYTES_PER_REGISTER_GROUP; byte_num++)
805  {
806  *comm_ptr++ = ((num_bytes ? LTC6804_ICOM_I2C_WRITE_BLANK : LTC6804_ICOM_I2C_WRITE_NO_TRANSMIT) << 4) + UPPER_NIBBLE(LTC6804_COMM_READ_DUMMY);
807  *comm_ptr++ = (LOWER_NIBBLE(LTC6804_COMM_READ_DUMMY) << 4) + ((num_bytes == 1) && stop ? LTC6804_FCOM_WRITE_I2C_NACK_STOP : LTC6804_FCOM_WRITE_I2C_ACK);
808  if(num_bytes)
809  {
810  num_bytes--;
811  bytes_to_send++;
812  }
813  }
814 
815  // Write COMM Register Group
816  ltc6804_register_group_write(comm);
817 
818  // Send the STRCOMM Command
819  command_code = LTC6804_COMMAND_CODE_STCOMM(address);
820  ltc6804_command_code_send(command_code, TRUE);
821 
822  //Send the number clocks to send the COMM Register Group data to the I2C
823  ltc6804_clock_out(bytes_to_send, baud_khz);
824 
825  // Send the RDCOMM command code
826  command_code = LTC6804_COMMAND_CODE_RDCOMM(address);
827  ltc6804_command_code_send(command_code, TRUE);
828 
829  // Read COMM register group and verify pec
830  if(ltc6804_register_group_read(comm) == TRUE)
831  {
832  // Interpret data in register group according to datasheet Table 45
833  comm_ptr = comm;
834 
835  while(bytes_to_send--)
836  {
837  *data_ptr = (((*comm_ptr) << 4) & 0xF0) + ((*(comm_ptr + 1)) >> 4);
838  if(start) // ignore the first byte, which is a readback of the i2c address sent after the start bit
839  {
840  start = FALSE;
841  }
842  else
843  {
844  data_ptr++;
845  }
846  comm_ptr += 2;
847  }
848  }
849  else
850  {
851  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, comm, sizeof(comm));
852  num_bytes = 0; // Bail out of command after first bad read.
853  success = FALSE;
854  }
855  }
856 
857  return success;
858 }
859 
860 // Writes a string of bytes to the LTC6804 SPI port implemented on its GPIO pins.
861 void LTC6804_SPI_Write(int8 board_num, BOOLEAN start, BOOLEAN stop, int8* data_ptr, int16 num_bytes, int16 baud_khz)
862 {
863  int8 address;
864  unsigned int16 command_code;
865  unsigned int8 comm[LTC6804_REGISTER_GROUP_SIZE];
866  int8* comm_ptr;
867  int8 bytes_to_send;
868  int8 byte_num;
869 
870  // Get the board address from the board number
871  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
872 
873  // Wakeup 6804 in case it has entered SLEEP or IDLE.
874  ltc6804_wakeup();
875 
876  while (num_bytes)
877  {
878  // Send the WRCOMM command code
879  command_code = LTC6804_COMMAND_CODE_WRCOMM(address);
880  ltc6804_command_code_send(command_code, TRUE);
881 
882  // Build COMM Register Group
883  bytes_to_send = 0;
884  comm_ptr = comm;
885 
886  for(byte_num = 0; byte_num < LTC6804_NUM_COMM_BYTES_PER_REGISTER_GROUP; byte_num++)
887  {
888  *comm_ptr++ = ((num_bytes ? LTC6804_ICOM_SPI_WRITE_CSB_LOW : LTC6804_ICOM_SPI_WRITE_NO_TRANSMIT) << 4) + UPPER_NIBBLE(*data_ptr);
889  *comm_ptr++ = (LOWER_NIBBLE(*data_ptr) << 4) + ((num_bytes <= 1) && stop ? LTC6804_FCOM_SPI_WRITE_CSB_HIGH : LTC6804_FCOM_SPI_WRITE_CSB_LOW);
890  if(num_bytes)
891  {
892  data_ptr++;
893  num_bytes--;
894  bytes_to_send++;
895  }
896  }
897 
898  // Send COMM Register Group
899  ltc6804_register_group_write(comm);
900 
901  // Send the STRCOMM Command
902  command_code = LTC6804_COMMAND_CODE_STCOMM(address);
903  ltc6804_command_code_send(command_code, TRUE);
904 
905  //Send the number clocks to send the COMM Register Group data to the SPI
906  ltc6804_clock_out(bytes_to_send, baud_khz);
907  }
908 
909 }
910 
911 // Writes one byte, and then reads a string of bytes to the LTC6804 SPI port implemented on its GPIO pins.
912 BOOLEAN LTC6804_SPI_Read(int8 board_num, BOOLEAN start, BOOLEAN stop, int8* data_ptr, int16 num_bytes, int16 baud_khz)
913 {
914  BOOLEAN success = TRUE;
915  int8 address;
916  unsigned int16 command_code;
917  unsigned int8 comm[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Comm Register Group + PEC
918  int8* comm_ptr;
919  int8 bytes_to_send;
920  int8 byte_num;
921 
922  // Get the board address from the board number
923  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num);
924 
925  // Wakeup 6804 in case it has entered SLEEP or IDLE.
926  ltc6804_wakeup();
927 
928  while (num_bytes)
929  {
930  // Send the WRCOMM command code
931  command_code = LTC6804_COMMAND_CODE_WRCOMM(address);
932  ltc6804_command_code_send(command_code, TRUE);
933 
934  // Build COMM Register Group
935  bytes_to_send = 0;
936  comm_ptr = comm;
937 
938  // First SPI byte might be a start or a stop, and will always be something (else we wouldn't be in this loop)
939  if(start)
940  {
941  *comm_ptr++ = (LTC6804_ICOM_SPI_WRITE_CSB_LOW << 4) + UPPER_NIBBLE(*data_ptr);
942  *comm_ptr++ = (LOWER_NIBBLE(*data_ptr) << 4) + LTC6804_FCOM_SPI_WRITE_CSB_LOW;
943  }
944  else
945  {
946  *comm_ptr++ = (LTC6804_ICOM_SPI_WRITE_CSB_LOW << 4) + UPPER_NIBBLE(LTC6804_COMM_READ_DUMMY);
947  *comm_ptr++ = (LOWER_NIBBLE(LTC6804_COMM_READ_DUMMY) << 4) + ((num_bytes <= 1) && stop ? LTC6804_FCOM_SPI_WRITE_CSB_HIGH : LTC6804_FCOM_SPI_WRITE_CSB_LOW);
948  }
949  num_bytes--;
950  bytes_to_send++;
951 
952  for(byte_num = 1; byte_num < LTC6804_NUM_COMM_BYTES_PER_REGISTER_GROUP; byte_num++)
953  {
954  *comm_ptr++ = (LTC6804_ICOM_SPI_WRITE_CSB_LOW << 4) + UPPER_NIBBLE(LTC6804_COMM_READ_DUMMY);
955  *comm_ptr++ = (LOWER_NIBBLE(LTC6804_COMM_READ_DUMMY) << 4) + ((num_bytes <= 1) && stop ? LTC6804_FCOM_SPI_WRITE_CSB_HIGH : LTC6804_FCOM_SPI_WRITE_CSB_LOW);
956  if(num_bytes)
957  {
958  num_bytes--;
959  bytes_to_send++;
960  }
961  }
962 
963  // Write COMM Register Group
964  ltc6804_register_group_write(comm);
965 
966  // Send the STRCOMM Command
967  command_code = LTC6804_COMMAND_CODE_STCOMM(address);
968  ltc6804_command_code_send(command_code, TRUE);
969 
970  //Send the number clocks to send the COMM Register Group data to the I2C
971  ltc6804_clock_out(bytes_to_send, baud_khz);
972 
973  // Send the RDCOMM command code
974  command_code = LTC6804_COMMAND_CODE_RDCOMM(address);
975  ltc6804_command_code_send(command_code, TRUE);
976 
977  // Read COMM register group and verify pec
978  if(ltc6804_register_group_read(comm) == TRUE)
979  {
980  // Interpret data in register group according to datasheet Table 45
981  comm_ptr = comm;
982 
983  while(bytes_to_send--)
984  {
985  *data_ptr = (((*comm_ptr) << 4) & 0xF0) + ((*(comm_ptr + 1)) >> 4);
986  if(start) // ignore the first byte, which is a readback of the i2c address sent after the start bit
987  {
988  start = FALSE;
989  }
990  else
991  {
992  data_ptr++;
993  }
994  comm_ptr += 2;
995  }
996  }
997  else
998  {
999  LTC6804_CONFIG_ERROR_CRC(board_num, command_code, comm, sizeof(comm));
1000  num_bytes = 0; // Bail out of command after first bad read.
1001  success = FALSE;
1002  }
1003  }
1004 
1005  return success;
1006 }
1007 
1008 //! Calculates the LTC6804 CRC over a string of bytes as per datasheet figure 22.
1009 unsigned int16 LTC6804_PEC_Calc(char *data, int length)
1010 {
1011  unsigned int16 remainder;
1012 
1013  remainder = ltc6804_pec_seed_value;
1014 
1015  for (int i = 0; i < length; i++)
1016  {
1017  remainder = ltc6804_pec_lookup(data[i], remainder);
1018  }
1019 
1020  return (remainder * 2); //The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
1021 }
1022 
1023 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1024 // Local Functions
1025 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1026 
1027 
1028 // Wakes up LTC6804 by lowering and raising CS as per datasheet Figure 21.
1029 void ltc6804_wakeup(void)
1030 {
1031  unsigned int32 wakeup_timestamp_new;
1032 
1033  // Check timestamp to determine if a short or long delay is required after wakeup signal.
1034  wakeup_timestamp_new = LTC6804_CONFIG_TIMER;
1035 
1036  output_low(LT6804_CONFIG_CS);
1037  LTC6804_CONFIG_DELAY_US(LTC6804_TDWELL);
1038  output_high(LT6804_CONFIG_CS);
1039 
1040  if((wakeup_timestamp_new - ltc6804_wakeup_timestamp) < (LTC6804_TSLEEP * LTC6804_CONFIG_TIMER_RESOLUTION / MS_PER_S))
1041  {
1042  // If wakeup signal sent less than LTC6804_TSLEEP time ago, then a short delay of LTC6804_TREADY is required.
1043  LTC6804_CONFIG_DELAY_US(LTC6804_TREADY);
1044  }
1045  else
1046  {
1047  // If wakeup signal sent more than LTC6804_TSLEEP time ago, then a long delay of LTC6804_TWAKE is required.
1048  LTC6804_CONFIG_DELAY_US(LTC6804_TWAKE);
1049  }
1050 
1051  ltc6804_wakeup_timestamp = wakeup_timestamp_new;
1052 
1053  return;
1054 }
1055 
1056 // Returns adcopt and md values to achieve the desired sample rate.
1057 void ltc6804_get_adcopt_and_md(int8 conversion_mode, int8* adcopt_ptr, int8* md_ptr)
1058 {
1059  // Select adcopt for this sample rate.
1060  switch(conversion_mode)
1061  {
1063  *adcopt_ptr = LTC6804_ADCOPT_0;
1064  *md_ptr = LTC6804_MD_MODE_FAST;
1065  break;
1067  *adcopt_ptr = LTC6804_ADCOPT_1;
1068  *md_ptr = LTC6804_MD_MODE_FAST;
1069  break;
1071  *adcopt_ptr = LTC6804_ADCOPT_0;
1072  *md_ptr = LTC6804_MD_MODE_NORMAL;
1073  break;
1075  *adcopt_ptr = LTC6804_ADCOPT_1;
1076  *md_ptr = LTC6804_MD_MODE_NORMAL;
1077  break;
1079  *adcopt_ptr = LTC6804_ADCOPT_1;
1080  *md_ptr = LTC6804_MD_MODE_FILTERED;
1081  break;
1083  default:
1084  *adcopt_ptr = LTC6804_ADCOPT_0;
1085  *md_ptr = LTC6804_MD_MODE_FILTERED;
1086  break;
1087  }
1088 
1089  return;
1090 }
1091 
1092 // Read/Modify/Write the Cfg Register to set the ADC option bit.
1093 void ltc6804_adc_opt_set(int8 board_num, int8 adcopt)
1094 {
1095  struct
1096  {
1097  int8 mask[LTC6804_REGISTER_GROUP_SIZE];
1098  int8 value[LTC6804_REGISTER_GROUP_SIZE];
1099  } register_modify;
1100 
1101  // Start with clear mask and value, and then set up gpio mask/value
1102  memset(&register_modify.mask[1], 0, sizeof(register_modify) - 1);
1103  register_modify.mask[0] = LTC6804_CFGR0_GPIOx_MASK;
1104  register_modify.value[0] = LTC6804_CFGR0_GPIOx(ltc6804_gpio_pulldown);
1105 
1106  // Create Mask to set ADC Option
1107  register_modify.mask[0] |= LTC6804_CFGR0_ADCOPT_MASK;
1108 
1109  // Set Value for ADC Option
1110  register_modify.value[0] |= LTC6804_CFGR0_ADCOPT(adcopt);
1111 
1112  ltc6804_cfgr_modify(board_num, register_modify.mask, register_modify.value);
1113 
1114  // Remember last value set for ADC Option
1115  ltc6804_adcopt = adcopt;
1116 
1117  return;
1118 }
1119 
1120 // Writes a command to the LTC6804
1121 void ltc6804_command_code_send(int16 command_code, BOOLEAN reg_group_command)
1122 {
1123  unsigned int8 writebyte[LTC6804_COMMAND_SIZE + LTC6804_PEC_SIZE];
1124  unsigned int16 pec;
1125 
1126  // Pull CS low to start write
1127  output_low(LT6804_CONFIG_CS);
1128 
1129  // Build the Command Code and Send
1130  writebyte[0] = UPPER_BYTE(command_code);
1131  writebyte[1] = LOWER_BYTE(command_code);
1133 
1134  // Calculate PEC and Send
1135  pec = LTC6804_PEC_Calc(writebyte, LTC6804_COMMAND_SIZE);
1136  writebyte[LTC6804_COMMAND_SIZE + 0] = UPPER_BYTE(pec);
1137  writebyte[LTC6804_COMMAND_SIZE + 1] = LOWER_BYTE(pec);
1139 
1140  // If no register group to follow, release CS to end write
1141  if (reg_group_command == FALSE)
1142  {
1143  while(LTC6804_CONFIG_SPI_BUFFER_DONE() == FALSE); // Wait for SPI transmission to be done before releasing CS
1144 
1145  output_high(LT6804_CONFIG_CS); // End the communication
1146  }
1147 
1148  return;
1149 }
1150 
1151 // Writes a register group to the LTC6804
1152 void ltc6804_register_group_write(int8* register_group)
1153 {
1154  unsigned int8 writebyte[LTC6804_PEC_SIZE];
1155  unsigned int16 pec;
1156 
1157  // Send register group bytes
1159 
1160  // Calculate PEC and Send
1161  pec = LTC6804_PEC_Calc(register_group, LTC6804_REGISTER_GROUP_SIZE);
1162  writebyte[0] = UPPER_BYTE(pec);
1163  writebyte[1] = LOWER_BYTE(pec);
1165 
1166  while(LTC6804_CONFIG_SPI_BUFFER_DONE() == FALSE); // Wait for SPI transmission to be done before releasing CS
1167 
1168  output_high(LT6804_CONFIG_CS); // End the communication
1169 
1170  return;
1171 }
1172 
1173 // Reads a register group from the LTC6804 and verifies the PEC
1174 BOOLEAN ltc6804_register_group_read(int8* register_group)
1175 {
1176  int8 byte_num;
1177  unsigned int16 pec_calc;
1178 
1179  // Start to receive the register group bytes from the SPI.
1181 
1182  // Initialize PEC calculation
1183  pec_calc = ltc6804_pec_seed_value;
1184 
1185  // Read register group bytes one at a time, so that the PEC can be calculated as they're being received.
1186  for (byte_num = 0; byte_num < LTC6804_REGISTER_GROUP_SIZE; byte_num++)
1187  {
1188  while(LTC6804_CONFIG_SPI_BUFFER_RECEIVE_BYTES_AVAILABLE(&register_group[byte_num]) == 0); // Wait for a byte to be received
1189  pec_calc = ltc6804_pec_lookup(register_group[byte_num], pec_calc); // Calculate PEC for this byte
1190  }
1191 
1192  // Complete PEC calculation
1193  pec_calc <<= 1; //The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
1194 
1195  // Wait for PEC bytes to be received
1196  while(LTC6804_CONFIG_SPI_BUFFER_RECEIVE_BYTES_AVAILABLE(&register_group[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE - 1]) == 0);
1197 
1198  // End the communication
1199  output_high(LT6804_CONFIG_CS);
1200 
1201  // Verify PEC and return result
1202  if((UPPER_BYTE(pec_calc) != register_group[LTC6804_REGISTER_GROUP_SIZE]) ||
1203  (LOWER_BYTE(pec_calc) != register_group[LTC6804_REGISTER_GROUP_SIZE + 1]))
1204  {
1205  return FALSE;
1206  }
1207  return TRUE;
1208 }
1209 
1210 
1211 // Clocks a number of bytes out of the i2c/spi at a set output baud rate, and then returns the baud rate to that for the LTC6804
1212 void ltc6804_clock_out(int16 bytes_to_send, int16 baud_khz)
1213 {
1214  int8 dummy;
1215  int8 byte_num;
1216 
1217  while(LTC6804_CONFIG_SPI_BUFFER_DONE() == FALSE); // Wait for SPI transmission to be done before changing the baud rate
1218 
1219  // Set baud rate to input value for LTC6804, that results in the desired output baud rate.
1220  LTC6804_CONFIG_SPI_SET_BAUD( MIN(baud_khz * LTC6804_BAUD_RATE_DIVISOR, LTC6804_BAUD_RATE) );
1221 
1222  dummy = 0xFF; // Keep transmit lines high as you provide clock for STCOMM command.
1223 
1224  //Send the number of clocks needed to send bytes (3 * 8 * number of bytes) in COMM register group
1225  for (byte_num = 0; byte_num < LTC6804_SPI_BYTES_PER_STCOMM_BYTE * bytes_to_send; byte_num++)
1226  {
1227  LTC6804_CONFIG_SPI_BUFFER_SEND_START(&dummy, sizeof(dummy));
1228  }
1229 
1230  while(LTC6804_CONFIG_SPI_BUFFER_DONE() == FALSE); // Wait for SPI transmission to be done before releasing CS
1231 
1232  // End the communication
1233  output_high(LT6804_CONFIG_CS);
1234 
1235  // Return baud rate to max allowed by the LTC6804
1237 
1238  return;
1239 }
1240 
1241 // Reads, Modifies, and Writes bits in the Configuration Register Group.
1242 // If a broadcast is desired, then this code actually implemented as some of the bits in the Configuration Register Group are unique to each board.
1243 void ltc6804_cfgr_modify(int8 board_num, int8* register_mask_ptr, int8* register_value_ptr)
1244 {
1245  int8 address;
1246  unsigned int16 command_code;
1247  unsigned int8 cfgr[LTC6804_REGISTER_GROUP_SIZE + LTC6804_PEC_SIZE]; // storage for the Configuration Register Group + PEC
1248  int8 byte_num;
1249  int8 board_loop_num;
1250  int8 board_limit_num;
1251 
1252  // Since broadcast reads can't be performed in the 6804-2, this must be handled with a loop.
1253  if(board_num == LTC6804_BROADCAST)
1254  {
1255  board_loop_num = 0;
1256  board_limit_num = LTC6804_CONFIG_NUM_BOARDS;
1257  }
1258  else
1259  {
1260  board_loop_num = board_num;
1261  board_limit_num = board_num;
1262  }
1263 
1264  do
1265  {
1266  // Get the board address from the board number
1267  address = LTC6804_CONFIG_GET_BOARD_ADDRESS(board_loop_num);
1268 
1269  // Wakeup 6804 in case it has entered SLEEP or IDLE.
1270  ltc6804_wakeup();
1271 
1272  // Send the RDCFG command code.
1273  command_code = LTC6804_COMMAND_CODE_RDCFG(address);
1274  ltc6804_command_code_send(command_code, TRUE);
1275 
1276  // Read the Configuration Register Group
1277  // If PEC is correct for read data, modify masked bits and write back
1278  if(ltc6804_register_group_read(cfgr) == TRUE)
1279  {
1280 
1281  // Modify the Configuration Register Group, with only the masked bits modified
1282  for (byte_num = 0; byte_num < LTC6804_REGISTER_GROUP_SIZE; byte_num++)
1283  {
1284  cfgr[byte_num] &= ~(*(register_mask_ptr + byte_num));
1285  cfgr[byte_num] |= (*(register_value_ptr + byte_num));
1286  }
1287 
1288  // Send the WRCFG command code
1289  command_code = LTC6804_COMMAND_CODE_WRCFG(address);
1290  ltc6804_command_code_send(command_code, TRUE);
1291 
1292  // Send Configuration Register Group Write
1293  ltc6804_register_group_write(cfgr);
1294  }
1295  else
1296  {
1297  LTC6804_CONFIG_ERROR_CRC(board_loop_num, command_code, cfgr, sizeof(cfgr));
1298  board_loop_num = board_limit_num = 0; // Bail out of command after first bad read.
1299  }
1300 
1301  board_loop_num++;
1302  } while (board_loop_num < board_limit_num);
1303 
1304  return;
1305 }
1306 
1307 // calculates the pec for one byte, and returns the intermediate calculation
1308 inline unsigned int16 ltc6804_pec_lookup(char data, unsigned int16 remainder)
1309 {
1310  unsigned int8 addr;
1311 
1312  addr = ((remainder >> 7) ^ data) & 0xff; //calculate PEC table address
1313  remainder = (remainder << 8) ^ ltc6804_pec_table[addr]; //get value from CRC15Table;
1314 
1315  return remainder;
1316 }
BOOLEAN LTC6804_UVOV_Flags_Get(int8 board_num, int16 *vuv_flags, int16 *vov_flags)
Gets the LTC6804 flags indicating under-voltage and over-voltage conditions are present.
Definition: LTC6804-2.c:316
GPIO 1-5, 2nd Ref.
Definition: LTC6804-2.h:115
All Cells.
Definition: LTC6804-2.h:100
#define LTC6804_CONFIG_SPI_BUFFER_SEND_START(buffer, num_bytes)
Configures the function called to start sending a string of bytes to the LTC6804. ...
#define LTC6804_NUM_AUX_ADC
Number of auxiliary ADC measurements.
Definition: LTC6804-2.h:92
void LTC6804_Refon_Set(int8 board_num, BOOLEAN refon)
Turns the LTC6804 ADC Reference on and off.
Definition: LTC6804-2.c:206
BOOLEAN LTC6804_UVOV_Thresholds_Get(int8 board_num, unsigned int16 *vuv_value, unsigned int16 *vov_value)
Gets the LTC6804 under-voltage and over-voltage thresholds in LTC6804_UVOV_RESOLUTION units...
Definition: LTC6804-2.c:282
void LTC6804_UVOV_Thresholds_Set(int8 board_num, int16 vuv_value, int16 vov_value)
Sets the LTC6804 under-voltage and over-voltage thresholds in LTC6804_UVOV_RESOLUTION units...
Definition: LTC6804-2.c:230
void LTC6804_I2C_Write(int8 board_num, BOOLEAN start, BOOLEAN stop, int8 *data_ptr, int16 num_bytes, int16 baud_khz)
Writes a string of bytes to the LTC6804 I2C port implemented on its GPIO pins.
Definition: LTC6804-2.c:703
#define LTC6804_BROADCAST
Code for application code to indicate an LTC6804 command is to be broadcast to all boards...
Definition: LTC6804-2.h:89
void LTC6804_Dischargers_Set(int8 board_num, int16 discharge_bitmap, int16 timeout_value)
Sets the LTC6804 discharger pin levels and timeout values.
Definition: LTC6804-2.c:256
#define LTC6804_CONFIG_DELAY_US(us)
Function for delaying a specified number of us.
BOOLEAN LTC6804_Revision_Get(int8 board_num, unsigned int8 *revision)
Gets the LTC6804 revision.
Definition: LTC6804-2.c:373
void LTC6804_Init(void)
Initializes the LTC6804-2 code module.
Definition: LTC6804-2.c:170
void LTC6804_SPI_Write(int8 board_num, BOOLEAN start, BOOLEAN stop, int8 *data_ptr, int16 num_bytes, int16 baud_khz)
Writes a string of bytes to the LTC6804 SPI port implemented on its GPIO pins.
Definition: LTC6804-2.c:861
#define LTC6804_CONFIG_TIMER_RESOLUTION
Resolution of LTC6804_CONFIG_TIMER in ticks per second.
BOOLEAN LTC6804_Cell_ADC_Read(int8 board_num, LTC6804_CH_CELL_TYPE cell_select, unsigned int16 *adc_value_ptr)
Reads the LTC6804 Cell Voltage ADC conversion results.
Definition: LTC6804-2.c:502
#define LTC6804_CONFIG_SPI_SET_BAUD(baud_khz)
Configures the function called to set the baud rate to the LTC6804.
#define LTC6804_PEC_SIZE
15 bit PEC, requires int16 data type
Definition: LTC6804-2.h:188
BOOLEAN LTC6804_I2C_Read(int8 board_num, BOOLEAN start, BOOLEAN stop, int8 *data_ptr, int16 num_bytes, int16 baud_khz)
Writes one byte, and then reads a string of bytes to the LTC6804 I2C port implemented on its GPIO pin...
Definition: LTC6804-2.c:763
#define LT6804_CONFIG_CS
Configures CS pin used to communicate with LTC6804-2. Note that code module directly controls CS for ...
#define LTC6804_CONFIG_NUM_BOARDS
The number of LTC6804 addresses used in this system. This is used for loops over all available LTC680...
void LTC6804_Cell_ADC_Start(int8 board_num, LTC6804_CONVERSION_MODE_T mode, LTC6804_CH_CELL_TYPE cell_select, BOOLEAN discharge_permitted)
Starts the LTC6804 Cell Voltage ADC conversion at the specified conversion mode.
Definition: LTC6804-2.c:468
#define LTC6804_NUM_GPIO
Number of GPIO pins available on LTC6804.
Definition: LTC6804-2.h:91
LTC6804_CONVERSION_MODE_T
Definition: LTC6804-2.h:142
void LTC6804_Cell_ADC_Clear(int8 board_num)
Clears the LTC6804 Cell Voltage ADC registers.
Definition: LTC6804-2.c:447
API Header File for LTC6804-2 Multicell Battery Monitors.
7kHz conversion mode
Definition: LTC6804-2.h:145
#define LTC6804_CONFIG_SPI_BUFFER_RECEIVE_START(buffer, num_bytes)
Note - This LTC6804 driver is designed for a buffered SPI peripheral (DMA, Interrupt driven...
#define LTC6804_BAUD_RATE
in kHz, Max input SPI Frequency (1/tCLK from datasheet)
Definition: LTC6804-2.h:190
unsigned int16 LTC6804_PEC_Calc(char *data, int length)
Calculates the LTC6804 CRC over a string of bytes as per datasheet figure 22.
Definition: LTC6804-2.c:1009
#define LTC6804_COMMAND_SIZE
bytes per command
Definition: LTC6804-2.h:186
void LTC6804_GPIO_Set(int8 board_num, int8 gpio_bitmap)
Sets the LTC6804 GPIO Pull Downs.
Definition: LTC6804-2.c:185
BOOLEAN LTC6804_SPI_Read(int8 board_num, BOOLEAN start, BOOLEAN stop, int8 *data_ptr, int16 num_bytes, int16 baud_khz)
Writes one byte, and then reads a string of bytes to the LTC6804 SPI port implemented on its GPIO pin...
Definition: LTC6804-2.c:912
#define LTC6804_CONFIG_ERROR_CRC(address, command, data_ptr, num_bytes)
Configures interface through which LTC6804-2 driver module reports its CRC errors.
#define LTC6804_CONFIG_TIMER
Configures Free Running Timer used to determine if the LTC6804 needs a LTC6804_TWAKE or LTC6804_TREAD...
26Hz conversion mode
Definition: LTC6804-2.h:148
void LTC6804_GPIO_ADC_Start(int8 board_num, LTC6804_CONVERSION_MODE_T mode, LTC6804_CHG_GPIO_TYPE gpio_select)
Starts the specified LTC6804 GPIO ADC conversion at the specified conversion mode.
Definition: LTC6804-2.c:599
Driver Registers for LTC6804-2 Multicell Battery Monitors.
2kHz conversion mode
Definition: LTC6804-2.h:147
27kHz conversion mode
Definition: LTC6804-2.h:143
3kHz conversion mode
Definition: LTC6804-2.h:146
BOOLEAN LTC6804_GPIO_ADC_Read(int8 board_num, LTC6804_CHG_GPIO_TYPE gpio_select, int16 *adc_value_ptr)
Reads the specified LTC6804 GPIO ADC conversion results.
Definition: LTC6804-2.c:633
Driver Configuration Header File for LTC6804-2 Multicell Battery Monitors.
void LTC6804_GPIO_ADC_Clear(int8 board_num)
Clears the LTC6804 GPIO ADC registers.
Definition: LTC6804-2.c:578
#define LTC6804_ADC_SIZE
16 bit ADC results
Definition: LTC6804-2.h:189
#define LTC6804_CONFIG_SPI_BUFFER_RECEIVE_BYTES_AVAILABLE(buffer)
Configures the function called to return the number of bytes received in a buffer.
#define LTC6804_CONFIG_GET_BOARD_ADDRESS(board_num)
Returns the physical address for a LTC6804 in the system given its logical address.
#define LTC6804_CONFIG_SPI_BUFFER_DONE()
Configures the function called to check if the last SPI communication to LTC6804 is done and SPI is r...
LTC6804_CHG_GPIO_TYPE
Definition: LTC6804-2.h:114
BOOLEAN LTC6804_Refon_Get(int8 board_num, int8 *refon)
Gets the LTC6804 ADC Reference status, where 1 = ON and 0 = OFF.
Definition: LTC6804-2.c:406
14kHz conversion mode
Definition: LTC6804-2.h:144
#define LTC6804_REGISTER_GROUP_SIZE
bytes per register group
Definition: LTC6804-2.h:187
LTC6804_CH_CELL_TYPE
Definition: LTC6804-2.h:99