Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
LTC68031.cpp
Go to the documentation of this file.
1 /*!
2  LTC6803-1 Multicell Battery Monitor
3 
4 @verbatim
5  The LTC6803 is a 2nd generation multicell battery stack
6  monitor that measures up to 12 series connected cells. The
7  cell measurement range of -0.3V to 5V makes the LTC6803
8  suitable for most battery chemistries.
9 
10  Using the LTC6803-1, multiple devices are connected in
11  a daisy-chain with one host processor connection for all
12  devices.
13 @endverbatim
14 
15 http://www.linear.com/product/LTC6803-1
16 
17 http://www.linear.com/product/LTC6803-1#demoboards
18 
19 
20 Copyright 2018(c) Analog Devices, Inc.
21 
22 All rights reserved.
23 
24 Redistribution and use in source and binary forms, with or without
25 modification, are permitted provided that the following conditions are met:
26  - Redistributions of source code must retain the above copyright
27  notice, this list of conditions and the following disclaimer.
28  - Redistributions in binary form must reproduce the above copyright
29  notice, this list of conditions and the following disclaimer in
30  the documentation and/or other materials provided with the
31  distribution.
32  - Neither the name of Analog Devices, Inc. nor the names of its
33  contributors may be used to endorse or promote products derived
34  from this software without specific prior written permission.
35  - The use of this software may or may not infringe the patent rights
36  of one or more patent holders. This license does not release you
37  from the requirement that you obtain separate licenses from these
38  patent holders to use this software.
39  - Use of the software either in source or binary form, must be run
40  on or directly connected to an Analog Devices Inc. component.
41 
42 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
43 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
44 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
46 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
48 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
51 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 
53 Copyright 2015 Linear Technology Corp. (LTC)
54 ***********************************************************/
55 
56 //! @ingroup BMS
57 //! @{
58 //! @defgroup LTC68031 LTC6803-1: Multicell Battery Monitor
59 //! @}
60 
61 /*! @file
62  @ingroup LTC68031
63  Library for LTC6803-1 Multicell Battery Monitor
64 */
65 
66 #include <stdint.h>
67 #include <Arduino.h>
68 #include "Linduino.h"
69 #include "LT_SPI.h"
70 #include "LTC68031.h"
71 #include <SPI.h>
72 
73 /***************************************************************************
74 ***********6803 Functions***************************************************
75 ***************************************************************************/
76 
77 
78 //Initializes the SPI port
80 {
82  spi_enable(SPI_CLOCK_DIV16); // This will set the Linduino to have a 1MHz Clock
83 
84 }
85 
86 
87 
88 
89 //Function that writes configuration of LTC6803-1/-3
90 void LTC6803_wrcfg(uint8_t total_ic,uint8_t config[][6])
91 {
92  uint8_t BYTES_IN_REG = 6;
93  uint8_t CMD_LEN = 2+(7*total_ic);
94  uint8_t *cmd;
95  uint16_t cfg_pec;
96  uint8_t cmd_index; //command counter
97 
98  cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
99 
100  cmd[0] = 0x01;
101  cmd[1] = 0xc7;
102 
103  cmd_index = 2;
104  for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--)
105  {
106 
107  for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
108  {
109  cmd[cmd_index] = config[current_ic-1][current_byte];
110  cmd_index = cmd_index + 1;
111  }
112 
113  cfg_pec = pec8_calc(BYTES_IN_REG, &config[current_ic-1][0]); // calculating the PEC for each ICs configuration register data
114  cmd[cmd_index ] = (uint8_t)cfg_pec;
115  cmd_index = cmd_index + 1;
116  }
117 
119  spi_write_array(CMD_LEN, cmd);
121  free(cmd);
122 }
123 
124 
125 //brief Function that reads configuration of LTC6803-1/-3
126 int8_t LTC6803_rdcfg(uint8_t total_ic, //Number of ICs in the system
127  uint8_t r_config[][7] //A two dimensional array that the function stores the read configuration data.
128  )
129 {
130  uint8_t BYTES_IN_REG = 7;
131 
132  uint8_t cmd[2];
133  uint8_t *rx_data;
134  int8_t pec_error = 0;
135  uint8_t data_pec;
136  uint8_t received_pec;
137 
138  rx_data = (uint8_t *) malloc((BYTES_IN_REG*total_ic)*sizeof(uint8_t));
139 
140  //1
141  cmd[0] = 0x02;
142  cmd[1] = 0xCE;
143 
144 
146  spi_write_read(cmd, 2, rx_data, (BYTES_IN_REG*total_ic)); //Read the configuration data of all ICs on the daisy chain into
147  output_high(LTC6803_CS); //rx_data[] array
148 
149  for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) //executes for each LTC6803 in the daisy chain and packs the data
150  {
151  //into the r_config array as well as check the received Config data
152  //for any bit errors
153  //4.a
154  for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
155  {
156  r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
157  }
158  //4.b
159  received_pec = r_config[current_ic][6];
160  data_pec = pec8_calc(6, &r_config[current_ic][0]);
161  if (received_pec != data_pec)
162  {
163  pec_error = -1;
164  }
165  }
166 
167  free(rx_data);
168  //5
169  return(pec_error);
170 }
171 
172 
173 //Function to start Cell Voltage measurement
175 {
177  spi_write(0x10);
178  spi_write(0xB0);
180 }
181 
182 
183 //Function to start Temp channel voltage measurement
185 {
187  spi_write(0x30);
188  spi_write(0x50);
190 }
191 
192 
193 
194 //Function that reads Temp Voltage registers
195 int8_t LTC6803_rdtmp(uint8_t total_ic, uint16_t temp_codes[][3])
196 {
197  int data_counter = 0;
198  int pec_error = 0;
199  uint8_t data_pec = 0;
200  uint8_t received_pec = 0;
201  uint8_t *rx_data;
202  rx_data = (uint8_t *) malloc((6*total_ic)*sizeof(uint8_t));
203 
205  spi_write(0x0E);
206  spi_write(0xEA);
207  for (int i=0; i<total_ic; i++)
208  {
209  for ( int j = 0; j<6 ; j++)
210  {
211  rx_data[data_counter++] =spi_read(0xFF);
212  }
213  }
215 
216  int cell_counter = 0;
217  data_counter = 0;
218  int temp,temp2;
219 
220  for (int j =0; j<total_ic; j++)
221  {
222  received_pec = rx_data[5 +(6*j)];
223  data_pec = pec8_calc(5, &rx_data[(6*j)]);
224  if (received_pec != data_pec)
225  {
226  pec_error = -1;
227  }
228 
229  temp = rx_data[data_counter++];
230  temp2 = (rx_data[data_counter]& 0x0F)<<8;
231  temp_codes[j][0] = temp + temp2 -512;
232  temp2 = (rx_data[data_counter++])>>4;
233  temp = (rx_data[data_counter++])<<4;
234  temp_codes[j][1] = temp+temp2 -512;
235  temp2 = (rx_data[data_counter++]);
236  temp = (rx_data[data_counter++]& 0x0F)<<8;
237  temp_codes[j][2] = temp+temp2 -512;
238  data_counter++;
239  }
240  free(rx_data);
241  return(pec_error);
242 }
243 
244 
245 // Function that reads Cell Voltage registers
246 uint8_t LTC6803_rdcv( uint8_t total_ic, uint16_t cell_codes[][12])
247 {
248  int data_counter =0;
249  int pec_error = 0;
250  uint8_t data_pec = 0;
251  uint8_t received_pec = 0;
252  uint8_t *rx_data;
253  rx_data = (uint8_t *) malloc((19*total_ic)*sizeof(uint8_t));
254 
256  spi_write(0x04);
257  spi_write(0xDC);
258  for (int i=0; i<total_ic; i++)
259  {
260  for ( int j = 0; j<19 ; j++)
261  {
262  rx_data[data_counter++] =spi_read(0xFF);
263  }
264  }
266 
267  int cell_counter = 0;
268  data_counter = 0;
269  uint16_t temp,temp2;
270 
271 
272  for (int j =0; j<total_ic; j++)
273  {
274 
275  received_pec = rx_data[18 +(19*j)];
276  data_pec = pec8_calc(18, &rx_data[(19*j)]);
277  if (received_pec != data_pec)
278  {
279  pec_error = -1;
280  }
281 
282  for (int k = 0; k<12; k=k+2)
283  {
284 
285  temp = rx_data[data_counter++];
286 
287  temp2 = (uint16_t)(rx_data[data_counter]&0x0F)<<8;
288 
289  cell_codes[j][k] = temp + temp2 -512;
290  temp2 = (rx_data[data_counter++])>>4;
291 
292  temp = (rx_data[data_counter++])<<4;
293 
294  cell_codes[j][k+1] = temp+temp2 -512;
295  }
296  data_counter++;
297  }
298  free(rx_data);
299  return(pec_error);
300 }
301 
302 
303 
304 //Function that calculates PEC byte
305 uint8_t pec8_calc(uint8_t len, uint8_t *data)
306 {
307 
308  uint8_t remainder = 0x41;//PEC_SEED;
309 
310 
311  /*
312  * Perform modulo-2 division, a byte at a time.
313  */
314  for (int byte = 0; byte < len; ++byte)
315  {
316  /*
317  * Bring the next byte into the remainder.
318  */
319  remainder ^= data[byte];
320 
321  /*
322  * Perform modulo-2 division, a bit at a time.
323  */
324  for (uint8_t bit = 8; bit > 0; --bit)
325  {
326  /*
327  * Try to divide the current data bit.
328  */
329  if (remainder & 128)
330  {
331  remainder = (remainder << 1) ^ PEC_POLY;
332  }
333  else
334  {
335  remainder = (remainder << 1);
336  }
337  }
338  }
339 
340  /*
341  * The final remainder is the CRC result.
342  */
343  return (remainder);
344 
345 }
346 
347 
348 //Writes an array of bytes out of the SPI port
349 void spi_write_array(uint8_t len,
350  uint8_t data[]
351  )
352 {
353  for (uint8_t i = 0; i < len; i++)
354  {
355  spi_write((int8_t)data[i]);
356  }
357 }
358 
359 
360 //Writes and read a set number of bytes using the SPI port.
361 void spi_write_read(uint8_t tx_Data[],
362  uint8_t tx_len,
363  uint8_t *rx_data,
364  uint8_t rx_len
365  )
366 {
367  for (uint8_t i = 0; i < tx_len; i++)
368  {
369  spi_write(tx_Data[i]);
370 
371  }
372 
373  for (uint8_t i = 0; i < rx_len; i++)
374  {
375  rx_data[i] = (uint8_t)spi_read(0xFF);
376  }
377 
378 }
void spi_write_array(uint8_t len, uint8_t data[])
Definition: LTC68031.cpp:349
void spi_write_read(uint8_t tx_Data[], uint8_t tx_len, uint8_t *rx_data, uint8_t rx_len)
Definition: LTC68031.cpp:361
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
#define LTC6803_CS
Definition: LTC68031.h:55
Header File for Linduino Libraries and Demo Code.
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
void spi_enable(uint8_t spi_clock_divider)
Setup the processor for hardware SPI communication.
Definition: LT_SPI.cpp:160
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
static uint16_t temp_codes[TOTAL_IC][3]
The Temp codes will be stored in the temp_codes[][3] array in the following format: ...
Definition: DC1651A.ino:117
LTC6803-1 Multicell Battery Monitor.
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
uint8_t pec8_calc(uint8_t len, uint8_t *data)
Function that calculates PEC byte.
Definition: LTC68031.cpp:305
#define PEC_POLY
Definition: LTC68031.h:58
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
void LTC6803_sttmpad()
Function to start Temp channel voltage measurement.
Definition: LTC68031.cpp:184
int8_t spi_read(int8_t data)
The data byte to be written.
Definition: LT_SPI.cpp:189
void LTC6803_wrcfg(uint8_t total_ic, uint8_t config[][6])
Function that writes configuration of LTC6803-1/-3.
Definition: LTC68031.cpp:90
int8_t LTC6803_rdtmp(uint8_t total_ic, uint16_t temp_codes[][3])
Function that reads Temp Voltage registers.
Definition: LTC68031.cpp:195
void LTC6803_initialize()
Initializes the SPI port.
Definition: LTC68031.cpp:79
static int i
Definition: DC2430A.ino:184
uint8_t LTC6803_rdcv(uint8_t total_ic, uint16_t cell_codes[][12])
Function that reads Cell Voltage registers.
Definition: LTC68031.cpp:246
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
int8_t LTC6803_rdcfg(uint8_t total_ic, uint8_t r_config[][7])
Function that reads configuration of LTC6803-1/-3.
Definition: LTC68031.cpp:126
void LTC6803_stcvad()
Function to start Cell Voltage measurement.
Definition: LTC68031.cpp:174