| 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
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-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
118 output_low(LTC6803_CS);
119 spi_write_array(CMD_LEN, cmd);
120 output_high(LTC6803_CS);
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
145 output_low(LTC6803_CS);
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
174 void LTC6803_stcvad()
175 {
176 output_low(LTC6803_CS);
177 spi_write(0x10);
178 spi_write(0xB0);
179 output_high(LTC6803_CS);
180 }
181
182
183 //Function to start Temp channel voltage measurement
184 void LTC6803_sttmpad()
185 {
186 output_low(LTC6803_CS);
187 spi_write(0x30);
188 spi_write(0x50);
189 output_high(LTC6803_CS);
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
204 output_low(LTC6803_CS);
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 }
214 output_high(LTC6803_CS);
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
255 output_low(LTC6803_CS);
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 }
265 output_high(LTC6803_CS);
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 }
spi_write_array
void spi_write_array(uint8_t len, uint8_t data[])
Definition: LTC68031.cpp:349
spi_write_read
void spi_write_read(uint8_t tx_Data[], uint8_t tx_len, uint8_t *rx_data, uint8_t rx_len)
Definition: LTC68031.cpp:361
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.
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
LTC68031.h
LTC6803-1 Multicell Battery Monitor.
output_low
#define output_low(pin)
Set "pin" low.
Definition: Linduino.h:72
pec8_calc
uint8_t pec8_calc(uint8_t len, uint8_t *data)
Function that calculates PEC byte.
Definition: LTC68031.cpp:305
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
LTC6803_sttmpad
void LTC6803_sttmpad()
Function to start Temp channel voltage measurement.
Definition: LTC68031.cpp:184
spi_read
int8_t spi_read(int8_t data)
The data byte to be written.
Definition: LT_SPI.cpp:189
LTC6803_wrcfg
void LTC6803_wrcfg(uint8_t total_ic, uint8_t config[][6])
Function that writes configuration of LTC6803-1/-3.
Definition: LTC68031.cpp:90
LTC6803_rdtmp
int8_t LTC6803_rdtmp(uint8_t total_ic, uint16_t temp_codes[][3])
Function that reads Temp Voltage registers.
Definition: LTC68031.cpp:195
LTC6803_initialize
void LTC6803_initialize()
Initializes the SPI port.
Definition: LTC68031.cpp:79
i
static int i
Definition: DC2430A.ino:184
LTC6803_rdcv
uint8_t LTC6803_rdcv(uint8_t total_ic, uint16_t cell_codes[][12])
Function that reads Cell Voltage registers.
Definition: LTC68031.cpp:246
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_rdcfg
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
LTC6803_stcvad
void LTC6803_stcvad()
Function to start Cell Voltage measurement.
Definition: LTC68031.cpp:174