| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

LTC68032.cpp
Go to the documentation of this file.
1 /*!
2 LTC6803-2 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-2, multiple devices can be connected in
11 parallel with one host processor connection for all
12 devices.
13 @endverbatim
14
15 http://www.linear.com/product/LTC6803-2
16
17 http://www.linear.com/product/LTC6803-2#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 LTC68032 LTC6803-2: Multicell Battery Monitor
59 //! @}
60
61 /*! @file
62 @ingroup LTC68032
63 Library for LTC6803-2 Multicell Battery Monitor
64 */
65
66 #include <stdint.h>
67 #include <Arduino.h>
68 #include "Linduino.h"
69 #include "LT_SPI.h"
70 #include "LTC68032.h"
71 #include <SPI.h>
72
73 /***************************************************************************
74 ***********6803 Functions***************************************************
75 ***************************************************************************/
76
77
78 //!Initializes the SPI port
79 void LTC6803_initialize()
80 {
81 quikeval_SPI_connect();
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-2/-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 = 4+7;
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 for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++)
100 {
101 cmd[0] = 0x80 + current_ic;
102 cmd[1] = pec8_calc(1,cmd);
103
104 cmd[2] = 0x01;
105 cmd[3] = 0xc7;
106
107 cmd_index = 4;
108
109
110 for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
111 {
112 cmd[cmd_index] = config[current_ic][current_byte];
113 cmd_index = cmd_index + 1;
114 }
115
116 cfg_pec = pec8_calc(BYTES_IN_REG, &config[current_ic][0]); // calculating the PEC for each ICs configuration register data
117 cmd[cmd_index ] = (uint8_t)cfg_pec;
118 cmd_index = cmd_index + 1;
119
120
121 output_low(LTC6803_CS);
122 spi_write_array(CMD_LEN, cmd);
123 output_high(LTC6803_CS);
124 }
125 free(cmd);
126 }
127
128
129 //!Function that reads configuration of LTC6803-2/-3
130 int8_t LTC6803_rdcfg(uint8_t total_ic, //Number of ICs in the system
131 uint8_t r_config[][7] //A two dimensional array that the function stores the read configuration data.
132 )
133 {
134 uint8_t BYTES_IN_REG = 7;
135
136 uint8_t cmd[4];
137 uint8_t *rx_data;
138 int8_t pec_error = 0;
139 uint8_t data_pec;
140 uint8_t received_pec;
141
142 rx_data = (uint8_t *) malloc((BYTES_IN_REG*total_ic)*sizeof(uint8_t));
143
144
145
146 for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) //executes for each LTC6803 in the daisy chain and packs the data
147 {
148 //into the r_config array as well as check the received Config data
149 //for any bit errors
150
151 cmd[0] = 0x80 + current_ic;
152 cmd[1] = pec8_calc(1,cmd);
153 cmd[2] = 0x02;
154 cmd[3] = 0xCE;
155
156
157 output_low(LTC6803_CS);
158 spi_write_read(cmd, 4, rx_data, (BYTES_IN_REG*total_ic));
159 output_high(LTC6803_CS);
160
161
162 for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
163 {
164 r_config[current_ic][current_byte] = rx_data[current_byte];
165 }
166
167 received_pec = r_config[current_ic][6];
168 data_pec = pec8_calc(6, &r_config[current_ic][0]);
169 if (received_pec != data_pec)
170 {
171 pec_error = -1;
172 }
173 }
174
175 free(rx_data);
176 return(pec_error);
177 }
178
179
180 //!Function that starts Cell Voltage measurement
181 void LTC6803_stcvad()
182 {
183 output_low(LTC6803_CS);
184 spi_write(0x10);
185 spi_write(0xB0);
186 output_high(LTC6803_CS);
187 }
188
189
190 //! Function that Temp channel voltage measurement
191 void LTC6803_sttmpad()
192 {
193 output_low(LTC6803_CS);
194 spi_write(0x30);
195 spi_write(0x50);
196 output_high(LTC6803_CS);
197 }
198
199
200
201 //!Function that reads Temp Voltage registers
202 int8_t LTC6803_rdtmp(uint8_t total_ic, uint16_t temp_codes[][3])
203 {
204 int data_counter = 0;
205 int pec_error = 0;
206 uint8_t data_pec = 0;
207 uint8_t received_pec = 0;
208 uint8_t cmd[4];
209 uint8_t *rx_data;
210 rx_data = (uint8_t *) malloc((7)*sizeof(uint8_t));
211 for (int i=0; i<total_ic; i++)
212 {
213 cmd[0] = 0x80 + i;
214 cmd[1] = pec8_calc(1,cmd);
215 cmd[2] = 0x0E;
216 cmd[3] = 0xEA;
217 output_low(LTC6803_CS);
218 spi_write_read(cmd, 4,rx_data,6);
219 output_high(LTC6803_CS);
220
221 received_pec = rx_data[5];
222 data_pec = pec8_calc(5, &rx_data[0]);
223 if (received_pec != data_pec)
224 {
225 pec_error = -1;
226 }
227
228 int cell_counter = 0;
229 data_counter = 0;
230 int temp,temp2;
231
232 temp = rx_data[data_counter++];
233 temp2 = (rx_data[data_counter]& 0x0F)<<8;
234 temp_codes[i][0] = temp + temp2 -512;
235 temp2 = (rx_data[data_counter++])>>4;
236 temp = (rx_data[data_counter++])<<4;
237 temp_codes[i][1] = temp+temp2 -512;
238 temp2 = (rx_data[data_counter++]);
239 temp = (rx_data[data_counter++]& 0x0F)<<8;
240 temp_codes[i][2] = temp+temp2 -512;
241 }
242 free(rx_data);
243 return(pec_error);
244 }
245
246
247 //! Function that reads Cell Voltage registers
248
249 uint8_t LTC6803_rdcv( uint8_t total_ic, uint16_t cell_codes[][12])
250 {
251 int data_counter =0;
252 int pec_error = 0;
253 uint8_t data_pec = 0;
254 uint8_t received_pec = 0;
255 uint8_t *rx_data;
256 uint8_t cmd[4];
257 rx_data = (uint8_t *) malloc((19)*sizeof(uint8_t));
258
259 for (int i=0; i<total_ic; i++)
260 {
261 cmd[0] = 0x80 + i;
262 cmd[1] = pec8_calc(1,cmd);
263 cmd[2] = 0x04;
264 cmd[3] = 0xDC;
265 output_low(LTC6803_CS);
266 spi_write_read(cmd, 4,rx_data,19);
267 output_high(LTC6803_CS);
268
269 received_pec = rx_data[18];
270 data_pec = pec8_calc(18, &rx_data[0]);
271 if (received_pec != data_pec)
272 {
273 pec_error = -1;
274 }
275
276 int cell_counter = 0;
277 data_counter = 0;
278 uint16_t temp,temp2;
279
280 for (int k = 0; k<12; k=k+2)
281 {
282 temp = rx_data[data_counter++];
283 temp2 = (uint16_t)(rx_data[data_counter]&0x0F)<<8;
284 cell_codes[i][k] = temp + temp2 -512;
285 temp2 = (rx_data[data_counter++])>>4;
286 temp = (rx_data[data_counter++])<<4;
287 cell_codes[i][k+1] = temp+temp2 -512;
288 }
289
290 }
291 free(rx_data);
292 return(pec_error);
293 }
294
295 //!Function that calculates PEC byte
296
297 uint8_t pec8_calc(uint8_t len, uint8_t *data)
298 {
299
300 uint8_t remainder = 0x41;//PEC_SEED;
301
302
303 /*
304 * Perform modulo-2 division, a byte at a time.
305 */
306 for (int byte = 0; byte < len; ++byte)
307 {
308 /*
309 * Bring the next byte into the remainder.
310 */
311 remainder ^= data[byte];
312
313 /*
314 * Perform modulo-2 division, a bit at a time.
315 */
316 for (uint8_t bit = 8; bit > 0; --bit)
317 {
318 /*
319 * Try to divide the current data bit.
320 */
321 if (remainder & 128)
322 {
323 remainder = (remainder << 1) ^ PEC_POLY;
324 }
325 else
326 {
327 remainder = (remainder << 1);
328 }
329 }
330 }
331
332 /*
333 * The final remainder is the CRC result.
334 */
335 return (remainder);
336
337 }
338
339
340 //! Writes an array of bytes out of the SPI port
341 void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
342 uint8_t data[] //Array of bytes to be written on the SPI port
343 )
344 {
345 for (uint8_t i = 0; i < len; i++)
346 {
347 spi_write((int8_t)data[i]);
348 }
349 }
350
351
352 //!Writes and read a set number of bytes using the SPI port.
353 void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
354 uint8_t tx_len, //length of the tx data arry
355 uint8_t *rx_data,//Input: array that will store the data read by the SPI port
356 uint8_t rx_len //Option: number of bytes to be read from the SPI port
357 )
358 {
359 for (uint8_t i = 0; i < tx_len; i++)
360 {
361 spi_write(tx_Data[i]);
362
363 }
364
365 for (uint8_t i = 0; i < rx_len; i++)
366 {
367 rx_data[i] = (uint8_t)spi_read(0xFF);
368 }
369
370 }
pec8_calc
uint8_t pec8_calc(uint8_t len, uint8_t *data)
Function that calculates PEC byte.
Definition: LTC68032.cpp:297
LTC6803_sttmpad
void LTC6803_sttmpad()
Function that Temp channel voltage measurement.
Definition: LTC68032.cpp:191
LTC68032.h
LTC6803-2 Multicell Battery Monitor.
output_high
#define output_high(pin)
Set "pin" high.
Definition: Linduino.h:75
LTC6803_CS
#define LTC6803_CS
Definition: LTC68031.h:55
Linduino.h
Header File for Linduino Libraries and Demo Code.
LTC6803_wrcfg
void LTC6803_wrcfg(uint8_t total_ic, uint8_t config[][6])
Function that writes configuration of LTC6803-1/-3.
Definition: LTC68032.cpp:90
LTC6803_stcvad
void LTC6803_stcvad()
Function that starts Cell Voltage measurement.
Definition: LTC68032.cpp:181
spi_write
void spi_write(int8_t data)
Write a data byte using the SPI hardware.
Definition: LT_SPI.cpp:176
spi_enable
void spi_enable(uint8_t spi_clock_divider)
Setup the processor for hardware SPI communication.
Definition: LT_SPI.cpp:160
data
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
temp_codes
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
spi_write_array
void spi_write_array(uint8_t len, uint8_t data[])
Writes an array of bytes out of the SPI port.
Definition: LTC68032.cpp:341
output_low
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
LTC6803_initialize
void LTC6803_initialize()
Initializes the SPI port.
Definition: LTC68032.cpp:79
PEC_POLY
#define PEC_POLY
Definition: LTC68031.h:58
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
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
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: LTC68032.cpp:353
i
static int i
Definition: DC2430A.ino:184
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
LTC6803_rdcv
uint8_t LTC6803_rdcv(uint8_t total_ic, uint16_t cell_codes[][12])
Function that reads Cell Voltage registers.
Definition: LTC68032.cpp:249
LTC6803_rdtmp
int8_t LTC6803_rdtmp(uint8_t total_ic, uint16_t temp_codes[][3])
Function that reads Temp Voltage registers.
Definition: LTC68032.cpp:202
LTC6803_rdcfg
int8_t LTC6803_rdcfg(uint8_t total_ic, uint8_t r_config[][7])
Function that reads configuration of LTC6803-2/-3.
Definition: LTC68032.cpp:130