TLMoto

Dependents:   BMS_2 BMS_4 BMS_8

Committer:
ser1516
Date:
Fri Sep 09 13:46:07 2016 +0000
Revision:
0:f6b9d13870f2
Child:
1:c55c4c93681f
imprime ate a celula 4

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ser1516 0:f6b9d13870f2 1 /*!
ser1516 0:f6b9d13870f2 2 LTC6804-1 Multicell Battery Monitor
ser1516 0:f6b9d13870f2 3
ser1516 0:f6b9d13870f2 4 @verbatim
ser1516 0:f6b9d13870f2 5 The LTC6804 is a 3rd generation multicell battery stack
ser1516 0:f6b9d13870f2 6 monitor that measures up to 12 series connected battery
ser1516 0:f6b9d13870f2 7 cells with a total measurement error of less than 1.2mV. The
ser1516 0:f6b9d13870f2 8 cell measurement range of 0V to 5V makes the LTC6804
ser1516 0:f6b9d13870f2 9 suitable for most battery chemistries. All 12 cell voltages
ser1516 0:f6b9d13870f2 10 can be captured in 290uS, and lower data acquisition rates
ser1516 0:f6b9d13870f2 11 can be selected for high noise reduction.
ser1516 0:f6b9d13870f2 12
ser1516 0:f6b9d13870f2 13 Using the LTC6804-1, multiple devices are connected in
ser1516 0:f6b9d13870f2 14 a daisy-chain with one host processor connection for all
ser1516 0:f6b9d13870f2 15 devices.
ser1516 0:f6b9d13870f2 16 @endverbatim
ser1516 0:f6b9d13870f2 17
ser1516 0:f6b9d13870f2 18 http://www.linear.com/product/LTC6804-1
ser1516 0:f6b9d13870f2 19
ser1516 0:f6b9d13870f2 20 http://www.linear.com/product/LTC6804-1#demoboards
ser1516 0:f6b9d13870f2 21
ser1516 0:f6b9d13870f2 22 REVISION HISTORY
ser1516 0:f6b9d13870f2 23 $Revision: 4437 $
ser1516 0:f6b9d13870f2 24 $Date: 2015-12-01 08:26:42 -0800 (Tue, 01 Dec 2015) $
ser1516 0:f6b9d13870f2 25
ser1516 0:f6b9d13870f2 26 Copyright (c) 2013, Linear Technology Corp.(LTC)
ser1516 0:f6b9d13870f2 27 All rights reserved.
ser1516 0:f6b9d13870f2 28
ser1516 0:f6b9d13870f2 29 Redistribution and use in source and binary forms, with or without
ser1516 0:f6b9d13870f2 30 modification, are permitted provided that the following conditions are met:
ser1516 0:f6b9d13870f2 31
ser1516 0:f6b9d13870f2 32 1. Redistributions of source code must retain the above copyright notice, this
ser1516 0:f6b9d13870f2 33 list of conditions and the following disclaimer.
ser1516 0:f6b9d13870f2 34 2. Redistributions in binary form must reproduce the above copyright notice,
ser1516 0:f6b9d13870f2 35 this list of conditions and the following disclaimer in the documentation
ser1516 0:f6b9d13870f2 36 and/or other materials provided with the distribution.
ser1516 0:f6b9d13870f2 37
ser1516 0:f6b9d13870f2 38 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ser1516 0:f6b9d13870f2 39 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
ser1516 0:f6b9d13870f2 40 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
ser1516 0:f6b9d13870f2 41 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ser1516 0:f6b9d13870f2 42 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
ser1516 0:f6b9d13870f2 43 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
ser1516 0:f6b9d13870f2 44 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ser1516 0:f6b9d13870f2 45 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
ser1516 0:f6b9d13870f2 46 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
ser1516 0:f6b9d13870f2 47 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ser1516 0:f6b9d13870f2 48
ser1516 0:f6b9d13870f2 49 The views and conclusions contained in the software and documentation are those
ser1516 0:f6b9d13870f2 50 of the authors and should not be interpreted as representing official policies,
ser1516 0:f6b9d13870f2 51 either expressed or implied, of Linear Technology Corp.
ser1516 0:f6b9d13870f2 52
ser1516 0:f6b9d13870f2 53 The Linear Technology Linduino is not affiliated with the official Arduino team.
ser1516 0:f6b9d13870f2 54 However, the Linduino is only possible because of the Arduino team's commitment
ser1516 0:f6b9d13870f2 55 to the open-source community. Please, visit http://www.arduino.cc and
ser1516 0:f6b9d13870f2 56 http://store.arduino.cc , and consider a purchase that will help fund their
ser1516 0:f6b9d13870f2 57 ongoing work.
ser1516 0:f6b9d13870f2 58
ser1516 0:f6b9d13870f2 59 Copyright 2013 Linear Technology Corp. (LTC)
ser1516 0:f6b9d13870f2 60 ***********************************************************/
ser1516 0:f6b9d13870f2 61 //! @defgroup LTC68041 LTC6804-1: Multicell Battery Monitor
ser1516 0:f6b9d13870f2 62
ser1516 0:f6b9d13870f2 63 /*! @file
ser1516 0:f6b9d13870f2 64 @ingroup LTC68041
ser1516 0:f6b9d13870f2 65 Library for LTC6804-1 Multicell Battery Monitor
ser1516 0:f6b9d13870f2 66 */
ser1516 0:f6b9d13870f2 67
ser1516 0:f6b9d13870f2 68 #include <stdint.h>
ser1516 0:f6b9d13870f2 69 #include "LTC68041.h"
ser1516 0:f6b9d13870f2 70 #include <SPI.h>
ser1516 0:f6b9d13870f2 71 #include "mbed.h"
ser1516 0:f6b9d13870f2 72
ser1516 0:f6b9d13870f2 73
ser1516 0:f6b9d13870f2 74
ser1516 0:f6b9d13870f2 75 void output_low(uint8_t pin){
ser1516 0:f6b9d13870f2 76 pin = 0;
ser1516 0:f6b9d13870f2 77 }
ser1516 0:f6b9d13870f2 78
ser1516 0:f6b9d13870f2 79 void output_high(uint8_t pin){
ser1516 0:f6b9d13870f2 80 pin = 1;
ser1516 0:f6b9d13870f2 81 }
ser1516 0:f6b9d13870f2 82
ser1516 0:f6b9d13870f2 83
ser1516 0:f6b9d13870f2 84 /*!
ser1516 0:f6b9d13870f2 85 6804 conversion command variables.
ser1516 0:f6b9d13870f2 86 */
ser1516 0:f6b9d13870f2 87 uint8_t ADCV[2]; //!< Cell Voltage conversion command.
ser1516 0:f6b9d13870f2 88 uint8_t ADAX[2]; //!< GPIO conversion command.
ser1516 0:f6b9d13870f2 89
ser1516 0:f6b9d13870f2 90 // SPI 1
ser1516 0:f6b9d13870f2 91
ser1516 0:f6b9d13870f2 92 SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK);
ser1516 0:f6b9d13870f2 93 DigitalOut spi_cs(PB_6);
ser1516 0:f6b9d13870f2 94 // SPI 2
ser1516 0:f6b9d13870f2 95 //SPI spi(PC_1, PC_2, PB_10);
ser1516 0:f6b9d13870f2 96 //DigitalOut spi_cs(PB_12);
ser1516 0:f6b9d13870f2 97
ser1516 0:f6b9d13870f2 98
ser1516 0:f6b9d13870f2 99
ser1516 0:f6b9d13870f2 100 /*!
ser1516 0:f6b9d13870f2 101 \brief This function will initialize all 6804 variables and the SPI port.
ser1516 0:f6b9d13870f2 102
ser1516 0:f6b9d13870f2 103 This function will initialize the Linduino to communicate with the LTC6804 with a 1MHz SPI clock.
ser1516 0:f6b9d13870f2 104 The Function also intializes the ADCV and ADAX commands to convert all cell and GPIO voltages in
ser1516 0:f6b9d13870f2 105 the Normal ADC mode.
ser1516 0:f6b9d13870f2 106 */
ser1516 0:f6b9d13870f2 107 void LTC6804_initialize()
ser1516 0:f6b9d13870f2 108 {
ser1516 0:f6b9d13870f2 109
ser1516 0:f6b9d13870f2 110 spi.frequency(1000000);
ser1516 0:f6b9d13870f2 111 spi.format(8,3); //8bits data; mode = CPHA = 1 and CPOL = 1.
ser1516 0:f6b9d13870f2 112
ser1516 0:f6b9d13870f2 113 set_adc(MD_NORMAL,DCP_DISABLED,CELL_CH_ALL,AUX_CH_ALL);
ser1516 0:f6b9d13870f2 114 }
ser1516 0:f6b9d13870f2 115
ser1516 0:f6b9d13870f2 116 /*!*******************************************************************************************************************
ser1516 0:f6b9d13870f2 117 \brief Maps global ADC control variables to the appropriate control bytes for each of the different ADC commands
ser1516 0:f6b9d13870f2 118
ser1516 0:f6b9d13870f2 119 @param[in] uint8_t MD The adc conversion mode
ser1516 0:f6b9d13870f2 120 @param[in] uint8_t DCP Controls if Discharge is permitted during cell conversions
ser1516 0:f6b9d13870f2 121 @param[in] uint8_t CH Determines which cells are measured during an ADC conversion command
ser1516 0:f6b9d13870f2 122 @param[in] uint8_t CHG Determines which GPIO channels are measured during Auxiliary conversion command
ser1516 0:f6b9d13870f2 123
ser1516 0:f6b9d13870f2 124 Command Code:
ser1516 0:f6b9d13870f2 125 -------------
ser1516 0:f6b9d13870f2 126
ser1516 0:f6b9d13870f2 127 |command | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 128 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 129 |ADCV: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CH[2] | CH[1] | CH[0] |
ser1516 0:f6b9d13870f2 130 |ADAX: | 0 | 0 | 0 | 0 | 0 | 1 | 0 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CHG[2]| CHG[1]| CHG[0]|
ser1516 0:f6b9d13870f2 131 ******************************************************************************************************************/
ser1516 0:f6b9d13870f2 132 void set_adc(uint8_t MD, //ADC Mode
ser1516 0:f6b9d13870f2 133 uint8_t DCP, //Discharge Permit
ser1516 0:f6b9d13870f2 134 uint8_t CH, //Cell Channels to be measured
ser1516 0:f6b9d13870f2 135 uint8_t CHG //GPIO Channels to be measured
ser1516 0:f6b9d13870f2 136 )
ser1516 0:f6b9d13870f2 137 {
ser1516 0:f6b9d13870f2 138 uint8_t md_bits;
ser1516 0:f6b9d13870f2 139
ser1516 0:f6b9d13870f2 140 md_bits = (MD & 0x02) >> 1;
ser1516 0:f6b9d13870f2 141 ADCV[0] = md_bits + 0x02;
ser1516 0:f6b9d13870f2 142 md_bits = (MD & 0x01) << 7;
ser1516 0:f6b9d13870f2 143 ADCV[1] = md_bits + 0x60 + (DCP<<4) + CH;
ser1516 0:f6b9d13870f2 144
ser1516 0:f6b9d13870f2 145 md_bits = (MD & 0x02) >> 1;
ser1516 0:f6b9d13870f2 146 ADAX[0] = md_bits + 0x04;
ser1516 0:f6b9d13870f2 147 md_bits = (MD & 0x01) << 7;
ser1516 0:f6b9d13870f2 148 ADAX[1] = md_bits + 0x60 + CHG ;
ser1516 0:f6b9d13870f2 149
ser1516 0:f6b9d13870f2 150 }
ser1516 0:f6b9d13870f2 151
ser1516 0:f6b9d13870f2 152
ser1516 0:f6b9d13870f2 153 /*!*********************************************************************************************
ser1516 0:f6b9d13870f2 154 \brief Starts cell voltage conversion
ser1516 0:f6b9d13870f2 155
ser1516 0:f6b9d13870f2 156 Starts ADC conversions of the LTC6804 Cpin inputs.
ser1516 0:f6b9d13870f2 157 The type of ADC conversion executed can be changed by setting the associated global variables:
ser1516 0:f6b9d13870f2 158 |Variable|Function |
ser1516 0:f6b9d13870f2 159 |--------|----------------------------------------------|
ser1516 0:f6b9d13870f2 160 | MD | Determines the filter corner of the ADC |
ser1516 0:f6b9d13870f2 161 | CH | Determines which cell channels are converted |
ser1516 0:f6b9d13870f2 162 | DCP | Determines if Discharge is Permitted |
ser1516 0:f6b9d13870f2 163
ser1516 0:f6b9d13870f2 164 Command Code:
ser1516 0:f6b9d13870f2 165 -------------
ser1516 0:f6b9d13870f2 166
ser1516 0:f6b9d13870f2 167 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 168 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 169 |ADCV: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CH[2] | CH[1] | CH[0] |
ser1516 0:f6b9d13870f2 170 ***********************************************************************************************/
ser1516 0:f6b9d13870f2 171 void LTC6804_adcv()
ser1516 0:f6b9d13870f2 172 {
ser1516 0:f6b9d13870f2 173
ser1516 0:f6b9d13870f2 174 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 175 uint16_t cmd_pec;
ser1516 0:f6b9d13870f2 176
ser1516 0:f6b9d13870f2 177 //1
ser1516 0:f6b9d13870f2 178 cmd[0] = ADCV[0];
ser1516 0:f6b9d13870f2 179 cmd[1] = ADCV[1];
ser1516 0:f6b9d13870f2 180
ser1516 0:f6b9d13870f2 181 //2
ser1516 0:f6b9d13870f2 182 cmd_pec = pec15_calc(2, ADCV);
ser1516 0:f6b9d13870f2 183 cmd[2] = (uint8_t)(cmd_pec >> 8);
ser1516 0:f6b9d13870f2 184 cmd[3] = (uint8_t)(cmd_pec);
ser1516 0:f6b9d13870f2 185
ser1516 0:f6b9d13870f2 186 //3
ser1516 0:f6b9d13870f2 187 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
ser1516 0:f6b9d13870f2 188
ser1516 0:f6b9d13870f2 189 //4
ser1516 0:f6b9d13870f2 190 spi_cs=0;
ser1516 0:f6b9d13870f2 191 spi_write_array(4,cmd);
ser1516 0:f6b9d13870f2 192 spi_cs=1;
ser1516 0:f6b9d13870f2 193
ser1516 0:f6b9d13870f2 194 }
ser1516 0:f6b9d13870f2 195 /*
ser1516 0:f6b9d13870f2 196 LTC6804_adcv Function sequence:
ser1516 0:f6b9d13870f2 197
ser1516 0:f6b9d13870f2 198 1. Load adcv command into cmd array
ser1516 0:f6b9d13870f2 199 2. Calculate adcv cmd PEC and load pec into cmd array
ser1516 0:f6b9d13870f2 200 3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
ser1516 0:f6b9d13870f2 201 4. send broadcast adcv command to LTC6804 daisy chain
ser1516 0:f6b9d13870f2 202 */
ser1516 0:f6b9d13870f2 203
ser1516 0:f6b9d13870f2 204
ser1516 0:f6b9d13870f2 205 /*!******************************************************************************************************
ser1516 0:f6b9d13870f2 206 \brief Start an GPIO Conversion
ser1516 0:f6b9d13870f2 207
ser1516 0:f6b9d13870f2 208 Starts an ADC conversions of the LTC6804 GPIO inputs.
ser1516 0:f6b9d13870f2 209 The type of ADC conversion executed can be changed by setting the associated global variables:
ser1516 0:f6b9d13870f2 210 |Variable|Function |
ser1516 0:f6b9d13870f2 211 |--------|----------------------------------------------|
ser1516 0:f6b9d13870f2 212 | MD | Determines the filter corner of the ADC |
ser1516 0:f6b9d13870f2 213 | CHG | Determines which GPIO channels are converted |
ser1516 0:f6b9d13870f2 214
ser1516 0:f6b9d13870f2 215
ser1516 0:f6b9d13870f2 216 Command Code:
ser1516 0:f6b9d13870f2 217 -------------
ser1516 0:f6b9d13870f2 218
ser1516 0:f6b9d13870f2 219 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 220 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 221 |ADAX: | 0 | 0 | 0 | 0 | 0 | 1 | 0 | MD[1] | MD[2] | 1 | 1 | DCP | 0 | CHG[2]| CHG[1]| CHG[0]|
ser1516 0:f6b9d13870f2 222 *********************************************************************************************************/
ser1516 0:f6b9d13870f2 223 void LTC6804_adax()
ser1516 0:f6b9d13870f2 224 {
ser1516 0:f6b9d13870f2 225 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 226 uint16_t cmd_pec;
ser1516 0:f6b9d13870f2 227
ser1516 0:f6b9d13870f2 228 cmd[0] = ADAX[0];
ser1516 0:f6b9d13870f2 229 cmd[1] = ADAX[1];
ser1516 0:f6b9d13870f2 230 cmd_pec = pec15_calc(2, ADAX);
ser1516 0:f6b9d13870f2 231 cmd[2] = (uint8_t)(cmd_pec >> 8);
ser1516 0:f6b9d13870f2 232 cmd[3] = (uint8_t)(cmd_pec);
ser1516 0:f6b9d13870f2 233
ser1516 0:f6b9d13870f2 234 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
ser1516 0:f6b9d13870f2 235 spi_cs=0;
ser1516 0:f6b9d13870f2 236 spi_write_array(4,cmd);
ser1516 0:f6b9d13870f2 237 spi_cs=1;
ser1516 0:f6b9d13870f2 238
ser1516 0:f6b9d13870f2 239 }
ser1516 0:f6b9d13870f2 240 /*
ser1516 0:f6b9d13870f2 241 LTC6804_adax Function sequence:
ser1516 0:f6b9d13870f2 242
ser1516 0:f6b9d13870f2 243 1. Load adax command into cmd array
ser1516 0:f6b9d13870f2 244 2. Calculate adax cmd PEC and load pec into cmd array
ser1516 0:f6b9d13870f2 245 3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
ser1516 0:f6b9d13870f2 246 4. send broadcast adax command to LTC6804 daisy chain
ser1516 0:f6b9d13870f2 247 */
ser1516 0:f6b9d13870f2 248
ser1516 0:f6b9d13870f2 249
ser1516 0:f6b9d13870f2 250 /***********************************************//**
ser1516 0:f6b9d13870f2 251 \brief Reads and parses the LTC6804 cell voltage registers.
ser1516 0:f6b9d13870f2 252
ser1516 0:f6b9d13870f2 253 The function is used to read the cell codes of the LTC6804.
ser1516 0:f6b9d13870f2 254 This function will send the requested read commands parse the data
ser1516 0:f6b9d13870f2 255 and store the cell voltages in cell_codes variable.
ser1516 0:f6b9d13870f2 256
ser1516 0:f6b9d13870f2 257 @param[in] uint8_t reg; This controls which cell voltage register is read back.
ser1516 0:f6b9d13870f2 258
ser1516 0:f6b9d13870f2 259 0: Read back all Cell registers
ser1516 0:f6b9d13870f2 260
ser1516 0:f6b9d13870f2 261 1: Read back cell group A
ser1516 0:f6b9d13870f2 262
ser1516 0:f6b9d13870f2 263 2: Read back cell group B
ser1516 0:f6b9d13870f2 264
ser1516 0:f6b9d13870f2 265 3: Read back cell group C
ser1516 0:f6b9d13870f2 266
ser1516 0:f6b9d13870f2 267 4: Read back cell group D
ser1516 0:f6b9d13870f2 268
ser1516 0:f6b9d13870f2 269 @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain(-1 only)
ser1516 0:f6b9d13870f2 270
ser1516 0:f6b9d13870f2 271 @param[out] uint16_t cell_codes[]; An array of the parsed cell codes from lowest to highest. The cell codes will
ser1516 0:f6b9d13870f2 272 be stored in the cell_codes[] array in the following format:
ser1516 0:f6b9d13870f2 273 | cell_codes[0][0]| cell_codes[0][1] | cell_codes[0][2]| ..... | cell_codes[0][11]| cell_codes[1][0] | cell_codes[1][1]| ..... |
ser1516 0:f6b9d13870f2 274 |------------------|------------------|------------------|--------------|-------------------|-------------------|-----------------|----------|
ser1516 0:f6b9d13870f2 275 |IC1 Cell 1 |IC1 Cell 2 |IC1 Cell 3 | ..... | IC1 Cell 12 |IC2 Cell 1 |IC2 Cell 2 | ..... |
ser1516 0:f6b9d13870f2 276
ser1516 0:f6b9d13870f2 277 @return int8_t, PEC Status.
ser1516 0:f6b9d13870f2 278
ser1516 0:f6b9d13870f2 279 0: No PEC error detected
ser1516 0:f6b9d13870f2 280
ser1516 0:f6b9d13870f2 281 -1: PEC error detected, retry read
ser1516 0:f6b9d13870f2 282
ser1516 0:f6b9d13870f2 283
ser1516 0:f6b9d13870f2 284 *************************************************/
ser1516 0:f6b9d13870f2 285 uint8_t LTC6804_rdcv(uint8_t reg, // Controls which cell voltage register is read back.
ser1516 0:f6b9d13870f2 286 uint8_t total_ic, // the number of ICs in the system
ser1516 0:f6b9d13870f2 287 uint16_t cell_codes[][12] // Array of the parsed cell codes
ser1516 0:f6b9d13870f2 288 )
ser1516 0:f6b9d13870f2 289 {
ser1516 0:f6b9d13870f2 290
ser1516 0:f6b9d13870f2 291 const uint8_t NUM_RX_BYT = 8;
ser1516 0:f6b9d13870f2 292 const uint8_t BYT_IN_REG = 6;
ser1516 0:f6b9d13870f2 293 const uint8_t CELL_IN_REG = 3;
ser1516 0:f6b9d13870f2 294
ser1516 0:f6b9d13870f2 295 uint8_t *cell_data;
ser1516 0:f6b9d13870f2 296 uint8_t pec_error = 0;
ser1516 0:f6b9d13870f2 297 uint16_t parsed_cell;
ser1516 0:f6b9d13870f2 298 uint16_t received_pec;
ser1516 0:f6b9d13870f2 299 uint16_t data_pec;
ser1516 0:f6b9d13870f2 300 uint8_t data_counter=0; //data counter
ser1516 0:f6b9d13870f2 301 cell_data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
ser1516 0:f6b9d13870f2 302 //1.a
ser1516 0:f6b9d13870f2 303 if (reg == 0)
ser1516 0:f6b9d13870f2 304 {
ser1516 0:f6b9d13870f2 305 //a.i
ser1516 0:f6b9d13870f2 306 for (uint8_t cell_reg = 1; cell_reg<5; cell_reg++) //executes once for each of the LTC6804 cell voltage registers
ser1516 0:f6b9d13870f2 307 {
ser1516 0:f6b9d13870f2 308 data_counter = 0;
ser1516 0:f6b9d13870f2 309 LTC6804_rdcv_reg(cell_reg, total_ic,cell_data ); //Reads a single Cell voltage register
ser1516 0:f6b9d13870f2 310
ser1516 0:f6b9d13870f2 311 for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
ser1516 0:f6b9d13870f2 312 {
ser1516 0:f6b9d13870f2 313 // current_ic is used as the IC counter
ser1516 0:f6b9d13870f2 314
ser1516 0:f6b9d13870f2 315 //a.ii
ser1516 0:f6b9d13870f2 316 for (uint8_t current_cell = 0; current_cell<CELL_IN_REG; current_cell++) // This loop parses the read back data into cell voltages, it
ser1516 0:f6b9d13870f2 317 {
ser1516 0:f6b9d13870f2 318 // loops once for each of the 3 cell voltage codes in the register
ser1516 0:f6b9d13870f2 319
ser1516 0:f6b9d13870f2 320 parsed_cell = cell_data[data_counter] + (cell_data[data_counter + 1] << 8);//Each cell code is received as two bytes and is combined to
ser1516 0:f6b9d13870f2 321 // create the parsed cell voltage code
ser1516 0:f6b9d13870f2 322
ser1516 0:f6b9d13870f2 323 cell_codes[current_ic][current_cell + ((cell_reg - 1) * CELL_IN_REG)] = parsed_cell;
ser1516 0:f6b9d13870f2 324 data_counter = data_counter + 2; //Because cell voltage codes are two bytes the data counter
ser1516 0:f6b9d13870f2 325 //must increment by two for each parsed cell code
ser1516 0:f6b9d13870f2 326 }
ser1516 0:f6b9d13870f2 327 //a.iii
ser1516 0:f6b9d13870f2 328 received_pec = (cell_data[data_counter] << 8) + cell_data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
ser1516 0:f6b9d13870f2 329 //after the 6 cell voltage data bytes
ser1516 0:f6b9d13870f2 330 data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
ser1516 0:f6b9d13870f2 331 if (received_pec != data_pec)
ser1516 0:f6b9d13870f2 332 {
ser1516 0:f6b9d13870f2 333 pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
ser1516 0:f6b9d13870f2 334 //are detected in the serial data
ser1516 0:f6b9d13870f2 335 }
ser1516 0:f6b9d13870f2 336 data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
ser1516 0:f6b9d13870f2 337 //must be incremented by 2 bytes to point to the next ICs cell voltage data
ser1516 0:f6b9d13870f2 338 }
ser1516 0:f6b9d13870f2 339 }
ser1516 0:f6b9d13870f2 340 }
ser1516 0:f6b9d13870f2 341 //1.b
ser1516 0:f6b9d13870f2 342 else
ser1516 0:f6b9d13870f2 343 {
ser1516 0:f6b9d13870f2 344 //b.i
ser1516 0:f6b9d13870f2 345 LTC6804_rdcv_reg(reg, total_ic,cell_data);
ser1516 0:f6b9d13870f2 346 for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
ser1516 0:f6b9d13870f2 347 {
ser1516 0:f6b9d13870f2 348 // current_ic is used as the IC counter
ser1516 0:f6b9d13870f2 349 //b.ii
ser1516 0:f6b9d13870f2 350 for (uint8_t current_cell = 0; current_cell < CELL_IN_REG; current_cell++) // This loop parses the read back data into cell voltages, it
ser1516 0:f6b9d13870f2 351 {
ser1516 0:f6b9d13870f2 352 // loops once for each of the 3 cell voltage codes in the register
ser1516 0:f6b9d13870f2 353
ser1516 0:f6b9d13870f2 354 parsed_cell = cell_data[data_counter] + (cell_data[data_counter+1]<<8); //Each cell code is received as two bytes and is combined to
ser1516 0:f6b9d13870f2 355 // create the parsed cell voltage code
ser1516 0:f6b9d13870f2 356
ser1516 0:f6b9d13870f2 357 cell_codes[current_ic][current_cell + ((reg - 1) * CELL_IN_REG)] = 0x0000FFFF & parsed_cell;
ser1516 0:f6b9d13870f2 358 data_counter= data_counter + 2; //Because cell voltage codes are two bytes the data counter
ser1516 0:f6b9d13870f2 359 //must increment by two for each parsed cell code
ser1516 0:f6b9d13870f2 360 }
ser1516 0:f6b9d13870f2 361 //b.iii
ser1516 0:f6b9d13870f2 362 received_pec = (cell_data[data_counter] << 8 )+ cell_data[data_counter + 1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
ser1516 0:f6b9d13870f2 363 //after the 6 cell voltage data bytes
ser1516 0:f6b9d13870f2 364 data_pec = pec15_calc(BYT_IN_REG, &cell_data[current_ic * NUM_RX_BYT]);
ser1516 0:f6b9d13870f2 365 if (received_pec != data_pec)
ser1516 0:f6b9d13870f2 366 {
ser1516 0:f6b9d13870f2 367 pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
ser1516 0:f6b9d13870f2 368 //are detected in the serial data
ser1516 0:f6b9d13870f2 369 }
ser1516 0:f6b9d13870f2 370 data_counter= data_counter + 2; //Because the transmitted PEC code is 2 bytes long the data_counter
ser1516 0:f6b9d13870f2 371 //must be incremented by 2 bytes to point to the next ICs cell voltage data
ser1516 0:f6b9d13870f2 372 }
ser1516 0:f6b9d13870f2 373 }
ser1516 0:f6b9d13870f2 374
ser1516 0:f6b9d13870f2 375 //2
ser1516 0:f6b9d13870f2 376 free(cell_data);
ser1516 0:f6b9d13870f2 377 return(pec_error);
ser1516 0:f6b9d13870f2 378 }
ser1516 0:f6b9d13870f2 379 /*
ser1516 0:f6b9d13870f2 380 LTC6804_rdcv Sequence
ser1516 0:f6b9d13870f2 381
ser1516 0:f6b9d13870f2 382 1. Switch Statement:
ser1516 0:f6b9d13870f2 383 a. Reg = 0
ser1516 0:f6b9d13870f2 384 i. Read cell voltage registers A-D for every IC in the daisy chain
ser1516 0:f6b9d13870f2 385 ii. Parse raw cell voltage data in cell_codes array
ser1516 0:f6b9d13870f2 386 iii. Check the PEC of the data read back vs the calculated PEC for each read register command
ser1516 0:f6b9d13870f2 387 b. Reg != 0
ser1516 0:f6b9d13870f2 388 i.Read single cell voltage register for all ICs in daisy chain
ser1516 0:f6b9d13870f2 389 ii. Parse raw cell voltage data in cell_codes array
ser1516 0:f6b9d13870f2 390 iii. Check the PEC of the data read back vs the calculated PEC for each read register command
ser1516 0:f6b9d13870f2 391 2. Return pec_error flag
ser1516 0:f6b9d13870f2 392 */
ser1516 0:f6b9d13870f2 393
ser1516 0:f6b9d13870f2 394
ser1516 0:f6b9d13870f2 395 /***********************************************//**
ser1516 0:f6b9d13870f2 396 \brief Read the raw data from the LTC6804 cell voltage register
ser1516 0:f6b9d13870f2 397
ser1516 0:f6b9d13870f2 398 The function reads a single cell voltage register and stores the read data
ser1516 0:f6b9d13870f2 399 in the *data point as a byte array. This function is rarely used outside of
ser1516 0:f6b9d13870f2 400 the LTC6804_rdcv() command.
ser1516 0:f6b9d13870f2 401
ser1516 0:f6b9d13870f2 402 @param[in] uint8_t reg; This controls which cell voltage register is read back.
ser1516 0:f6b9d13870f2 403
ser1516 0:f6b9d13870f2 404 1: Read back cell group A
ser1516 0:f6b9d13870f2 405
ser1516 0:f6b9d13870f2 406 2: Read back cell group B
ser1516 0:f6b9d13870f2 407
ser1516 0:f6b9d13870f2 408 3: Read back cell group C
ser1516 0:f6b9d13870f2 409
ser1516 0:f6b9d13870f2 410 4: Read back cell group D
ser1516 0:f6b9d13870f2 411
ser1516 0:f6b9d13870f2 412 @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain(-1 only)
ser1516 0:f6b9d13870f2 413
ser1516 0:f6b9d13870f2 414 @param[out] uint8_t *data; An array of the unparsed cell codes
ser1516 0:f6b9d13870f2 415
ser1516 0:f6b9d13870f2 416 Command Code:
ser1516 0:f6b9d13870f2 417 -------------
ser1516 0:f6b9d13870f2 418
ser1516 0:f6b9d13870f2 419 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 420 |-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 421 |RDCVA: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
ser1516 0:f6b9d13870f2 422 |RDCVB: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
ser1516 0:f6b9d13870f2 423 |RDCVC: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
ser1516 0:f6b9d13870f2 424 |RDCVD: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
ser1516 0:f6b9d13870f2 425
ser1516 0:f6b9d13870f2 426 *************************************************/
ser1516 0:f6b9d13870f2 427 void LTC6804_rdcv_reg(uint8_t reg, //Determines which cell voltage register is read back
ser1516 0:f6b9d13870f2 428 uint8_t total_ic, //the number of ICs in the
ser1516 0:f6b9d13870f2 429 uint8_t *data //An array of the unparsed cell codes
ser1516 0:f6b9d13870f2 430 )
ser1516 0:f6b9d13870f2 431 {
ser1516 0:f6b9d13870f2 432 const uint8_t REG_LEN = 8; //number of bytes in each ICs register + 2 bytes for the PEC
ser1516 0:f6b9d13870f2 433 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 434 uint16_t cmd_pec;
ser1516 0:f6b9d13870f2 435
ser1516 0:f6b9d13870f2 436 //1
ser1516 0:f6b9d13870f2 437 if (reg == 1) //1: RDCVA
ser1516 0:f6b9d13870f2 438 {
ser1516 0:f6b9d13870f2 439 cmd[1] = 0x04;
ser1516 0:f6b9d13870f2 440 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 441 }
ser1516 0:f6b9d13870f2 442 else if (reg == 2) //2: RDCVB
ser1516 0:f6b9d13870f2 443 {
ser1516 0:f6b9d13870f2 444 cmd[1] = 0x06;
ser1516 0:f6b9d13870f2 445 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 446 }
ser1516 0:f6b9d13870f2 447 else if (reg == 3) //3: RDCVC
ser1516 0:f6b9d13870f2 448 {
ser1516 0:f6b9d13870f2 449 cmd[1] = 0x08;
ser1516 0:f6b9d13870f2 450 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 451 }
ser1516 0:f6b9d13870f2 452 else if (reg == 4) //4: RDCVD
ser1516 0:f6b9d13870f2 453 {
ser1516 0:f6b9d13870f2 454 cmd[1] = 0x0A;
ser1516 0:f6b9d13870f2 455 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 456 }
ser1516 0:f6b9d13870f2 457
ser1516 0:f6b9d13870f2 458 //2
ser1516 0:f6b9d13870f2 459 cmd_pec = pec15_calc(2, cmd);
ser1516 0:f6b9d13870f2 460 cmd[2] = (uint8_t)(cmd_pec >> 8);
ser1516 0:f6b9d13870f2 461 cmd[3] = (uint8_t)(cmd_pec);
ser1516 0:f6b9d13870f2 462
ser1516 0:f6b9d13870f2 463 //3
ser1516 0:f6b9d13870f2 464 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
ser1516 0:f6b9d13870f2 465
ser1516 0:f6b9d13870f2 466 //4
ser1516 0:f6b9d13870f2 467 spi_cs=0;
ser1516 0:f6b9d13870f2 468 spi_write_read(cmd,4,data,(REG_LEN*total_ic));
ser1516 0:f6b9d13870f2 469 spi_cs=1;
ser1516 0:f6b9d13870f2 470
ser1516 0:f6b9d13870f2 471 }
ser1516 0:f6b9d13870f2 472 /*
ser1516 0:f6b9d13870f2 473 LTC6804_rdcv_reg Function Process:
ser1516 0:f6b9d13870f2 474 1. Determine Command and initialize command array
ser1516 0:f6b9d13870f2 475 2. Calculate Command PEC
ser1516 0:f6b9d13870f2 476 3. Wake up isoSPI, this step is optional
ser1516 0:f6b9d13870f2 477 4. Send Global Command to LTC6804 daisy chain
ser1516 0:f6b9d13870f2 478 */
ser1516 0:f6b9d13870f2 479
ser1516 0:f6b9d13870f2 480
ser1516 0:f6b9d13870f2 481 /***********************************************************************************//**
ser1516 0:f6b9d13870f2 482 \brief Reads and parses the LTC6804 auxiliary registers.
ser1516 0:f6b9d13870f2 483
ser1516 0:f6b9d13870f2 484 The function is used
ser1516 0:f6b9d13870f2 485 to read the parsed GPIO codes of the LTC6804. This function will send the requested
ser1516 0:f6b9d13870f2 486 read commands parse the data and store the gpio voltages in aux_codes variable
ser1516 0:f6b9d13870f2 487
ser1516 0:f6b9d13870f2 488 @param[in] uint8_t reg; This controls which GPIO voltage register is read back.
ser1516 0:f6b9d13870f2 489
ser1516 0:f6b9d13870f2 490 0: Read back all auxiliary registers
ser1516 0:f6b9d13870f2 491
ser1516 0:f6b9d13870f2 492 1: Read back auxiliary group A
ser1516 0:f6b9d13870f2 493
ser1516 0:f6b9d13870f2 494 2: Read back auxiliary group B
ser1516 0:f6b9d13870f2 495
ser1516 0:f6b9d13870f2 496
ser1516 0:f6b9d13870f2 497 @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain(-1 only)
ser1516 0:f6b9d13870f2 498
ser1516 0:f6b9d13870f2 499
ser1516 0:f6b9d13870f2 500 @param[out] uint16_t aux_codes[][6]; A two dimensional array of the gpio voltage codes. The GPIO codes will
ser1516 0:f6b9d13870f2 501 be stored in the aux_codes[][6] array in the following format:
ser1516 0:f6b9d13870f2 502 | aux_codes[0][0]| aux_codes[0][1] | aux_codes[0][2]| aux_codes[0][3]| aux_codes[0][4]| aux_codes[0][5]| aux_codes[1][0] |aux_codes[1][1]| ..... |
ser1516 0:f6b9d13870f2 503 |-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|-----------------|---------------|-----------|
ser1516 0:f6b9d13870f2 504 |IC1 GPIO1 |IC1 GPIO2 |IC1 GPIO3 |IC1 GPIO4 |IC1 GPIO5 |IC1 Vref2 |IC2 GPIO1 |IC2 GPIO2 | ..... |
ser1516 0:f6b9d13870f2 505
ser1516 0:f6b9d13870f2 506 @return int8_t, PEC Status
ser1516 0:f6b9d13870f2 507
ser1516 0:f6b9d13870f2 508 0: No PEC error detected
ser1516 0:f6b9d13870f2 509
ser1516 0:f6b9d13870f2 510 -1: PEC error detected, retry read
ser1516 0:f6b9d13870f2 511 *************************************************/
ser1516 0:f6b9d13870f2 512 int8_t LTC6804_rdaux(uint8_t reg, //Determines which GPIO voltage register is read back.
ser1516 0:f6b9d13870f2 513 uint8_t total_ic,//the number of ICs in the system
ser1516 0:f6b9d13870f2 514 uint16_t aux_codes[][6]//A two dimensional array of the gpio voltage codes.
ser1516 0:f6b9d13870f2 515 )
ser1516 0:f6b9d13870f2 516 {
ser1516 0:f6b9d13870f2 517
ser1516 0:f6b9d13870f2 518
ser1516 0:f6b9d13870f2 519 const uint8_t NUM_RX_BYT = 8;
ser1516 0:f6b9d13870f2 520 const uint8_t BYT_IN_REG = 6;
ser1516 0:f6b9d13870f2 521 const uint8_t GPIO_IN_REG = 3;
ser1516 0:f6b9d13870f2 522
ser1516 0:f6b9d13870f2 523 uint8_t *data;
ser1516 0:f6b9d13870f2 524 uint8_t data_counter = 0;
ser1516 0:f6b9d13870f2 525 int8_t pec_error = 0;
ser1516 0:f6b9d13870f2 526 uint16_t parsed_aux;
ser1516 0:f6b9d13870f2 527 uint16_t received_pec;
ser1516 0:f6b9d13870f2 528 uint16_t data_pec;
ser1516 0:f6b9d13870f2 529 data = (uint8_t *) malloc((NUM_RX_BYT*total_ic)*sizeof(uint8_t));
ser1516 0:f6b9d13870f2 530 //1.a
ser1516 0:f6b9d13870f2 531 if (reg == 0)
ser1516 0:f6b9d13870f2 532 {
ser1516 0:f6b9d13870f2 533 //a.i
ser1516 0:f6b9d13870f2 534 for (uint8_t gpio_reg = 1; gpio_reg<3; gpio_reg++) //executes once for each of the LTC6804 aux voltage registers
ser1516 0:f6b9d13870f2 535 {
ser1516 0:f6b9d13870f2 536 data_counter = 0;
ser1516 0:f6b9d13870f2 537 LTC6804_rdaux_reg(gpio_reg, total_ic,data); //Reads the raw auxiliary register data into the data[] array
ser1516 0:f6b9d13870f2 538
ser1516 0:f6b9d13870f2 539 for (uint8_t current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
ser1516 0:f6b9d13870f2 540 {
ser1516 0:f6b9d13870f2 541 // current_ic is used as the IC counter
ser1516 0:f6b9d13870f2 542
ser1516 0:f6b9d13870f2 543 //a.ii
ser1516 0:f6b9d13870f2 544 for (uint8_t current_gpio = 0; current_gpio< GPIO_IN_REG; current_gpio++) // This loop parses the read back data into GPIO voltages, it
ser1516 0:f6b9d13870f2 545 {
ser1516 0:f6b9d13870f2 546 // loops once for each of the 3 gpio voltage codes in the register
ser1516 0:f6b9d13870f2 547
ser1516 0:f6b9d13870f2 548 parsed_aux = data[data_counter] + (data[data_counter+1]<<8); //Each gpio codes is received as two bytes and is combined to
ser1516 0:f6b9d13870f2 549 // create the parsed gpio voltage code
ser1516 0:f6b9d13870f2 550
ser1516 0:f6b9d13870f2 551 aux_codes[current_ic][current_gpio +((gpio_reg-1)*GPIO_IN_REG)] = parsed_aux;
ser1516 0:f6b9d13870f2 552 data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
ser1516 0:f6b9d13870f2 553 //must increment by two for each parsed gpio voltage code
ser1516 0:f6b9d13870f2 554
ser1516 0:f6b9d13870f2 555 }
ser1516 0:f6b9d13870f2 556 //a.iii
ser1516 0:f6b9d13870f2 557 received_pec = (data[data_counter]<<8)+ data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
ser1516 0:f6b9d13870f2 558 //after the 6 gpio voltage data bytes
ser1516 0:f6b9d13870f2 559 data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
ser1516 0:f6b9d13870f2 560 if (received_pec != data_pec)
ser1516 0:f6b9d13870f2 561 {
ser1516 0:f6b9d13870f2 562 pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
ser1516 0:f6b9d13870f2 563 //are detected in the received serial data
ser1516 0:f6b9d13870f2 564 }
ser1516 0:f6b9d13870f2 565
ser1516 0:f6b9d13870f2 566 data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
ser1516 0:f6b9d13870f2 567 //must be incremented by 2 bytes to point to the next ICs gpio voltage data
ser1516 0:f6b9d13870f2 568 }
ser1516 0:f6b9d13870f2 569
ser1516 0:f6b9d13870f2 570
ser1516 0:f6b9d13870f2 571 }
ser1516 0:f6b9d13870f2 572
ser1516 0:f6b9d13870f2 573 }
ser1516 0:f6b9d13870f2 574 else
ser1516 0:f6b9d13870f2 575 {
ser1516 0:f6b9d13870f2 576 //b.i
ser1516 0:f6b9d13870f2 577 LTC6804_rdaux_reg(reg, total_ic, data);
ser1516 0:f6b9d13870f2 578 for (int current_ic = 0 ; current_ic < total_ic; current_ic++) // executes for every LTC6804 in the daisy chain
ser1516 0:f6b9d13870f2 579 {
ser1516 0:f6b9d13870f2 580 // current_ic is used as an IC counter
ser1516 0:f6b9d13870f2 581
ser1516 0:f6b9d13870f2 582 //b.ii
ser1516 0:f6b9d13870f2 583 for (int current_gpio = 0; current_gpio<GPIO_IN_REG; current_gpio++) // This loop parses the read back data. Loops
ser1516 0:f6b9d13870f2 584 {
ser1516 0:f6b9d13870f2 585 // once for each aux voltage in the register
ser1516 0:f6b9d13870f2 586
ser1516 0:f6b9d13870f2 587 parsed_aux = (data[data_counter] + (data[data_counter+1]<<8)); //Each gpio codes is received as two bytes and is combined to
ser1516 0:f6b9d13870f2 588 // create the parsed gpio voltage code
ser1516 0:f6b9d13870f2 589 aux_codes[current_ic][current_gpio +((reg-1)*GPIO_IN_REG)] = parsed_aux;
ser1516 0:f6b9d13870f2 590 data_counter=data_counter+2; //Because gpio voltage codes are two bytes the data counter
ser1516 0:f6b9d13870f2 591 //must increment by two for each parsed gpio voltage code
ser1516 0:f6b9d13870f2 592 }
ser1516 0:f6b9d13870f2 593 //b.iii
ser1516 0:f6b9d13870f2 594 received_pec = (data[data_counter]<<8) + data[data_counter+1]; //The received PEC for the current_ic is transmitted as the 7th and 8th
ser1516 0:f6b9d13870f2 595 //after the 6 gpio voltage data bytes
ser1516 0:f6b9d13870f2 596 data_pec = pec15_calc(BYT_IN_REG, &data[current_ic*NUM_RX_BYT]);
ser1516 0:f6b9d13870f2 597 if (received_pec != data_pec)
ser1516 0:f6b9d13870f2 598 {
ser1516 0:f6b9d13870f2 599 pec_error = -1; //The pec_error variable is simply set negative if any PEC errors
ser1516 0:f6b9d13870f2 600 //are detected in the received serial data
ser1516 0:f6b9d13870f2 601 }
ser1516 0:f6b9d13870f2 602
ser1516 0:f6b9d13870f2 603 data_counter=data_counter+2; //Because the transmitted PEC code is 2 bytes long the data_counter
ser1516 0:f6b9d13870f2 604 //must be incremented by 2 bytes to point to the next ICs gpio voltage data
ser1516 0:f6b9d13870f2 605 }
ser1516 0:f6b9d13870f2 606 }
ser1516 0:f6b9d13870f2 607 free(data);
ser1516 0:f6b9d13870f2 608 return (pec_error);
ser1516 0:f6b9d13870f2 609 }
ser1516 0:f6b9d13870f2 610 /*
ser1516 0:f6b9d13870f2 611 LTC6804_rdaux Sequence
ser1516 0:f6b9d13870f2 612
ser1516 0:f6b9d13870f2 613 1. Switch Statement:
ser1516 0:f6b9d13870f2 614 a. Reg = 0
ser1516 0:f6b9d13870f2 615 i. Read GPIO voltage registers A-D for every IC in the daisy chain
ser1516 0:f6b9d13870f2 616 ii. Parse raw GPIO voltage data in cell_codes array
ser1516 0:f6b9d13870f2 617 iii. Check the PEC of the data read back vs the calculated PEC for each read register command
ser1516 0:f6b9d13870f2 618 b. Reg != 0
ser1516 0:f6b9d13870f2 619 i.Read single GPIO voltage register for all ICs in daisy chain
ser1516 0:f6b9d13870f2 620 ii. Parse raw GPIO voltage data in cell_codes array
ser1516 0:f6b9d13870f2 621 iii. Check the PEC of the data read back vs the calculated PEC for each read register command
ser1516 0:f6b9d13870f2 622 2. Return pec_error flag
ser1516 0:f6b9d13870f2 623 */
ser1516 0:f6b9d13870f2 624
ser1516 0:f6b9d13870f2 625
ser1516 0:f6b9d13870f2 626 /***********************************************//**
ser1516 0:f6b9d13870f2 627 \brief Read the raw data from the LTC6804 auxiliary register
ser1516 0:f6b9d13870f2 628
ser1516 0:f6b9d13870f2 629 The function reads a single GPIO voltage register and stores thre read data
ser1516 0:f6b9d13870f2 630 in the *data point as a byte array. This function is rarely used outside of
ser1516 0:f6b9d13870f2 631 the LTC6804_rdaux() command.
ser1516 0:f6b9d13870f2 632
ser1516 0:f6b9d13870f2 633 @param[in] uint8_t reg; This controls which GPIO voltage register is read back.
ser1516 0:f6b9d13870f2 634
ser1516 0:f6b9d13870f2 635 1: Read back auxiliary group A
ser1516 0:f6b9d13870f2 636
ser1516 0:f6b9d13870f2 637 2: Read back auxiliary group B
ser1516 0:f6b9d13870f2 638
ser1516 0:f6b9d13870f2 639
ser1516 0:f6b9d13870f2 640 @param[in] uint8_t total_ic; This is the number of ICs in the daisy chain
ser1516 0:f6b9d13870f2 641
ser1516 0:f6b9d13870f2 642 @param[out] uint8_t *data; An array of the unparsed aux codes
ser1516 0:f6b9d13870f2 643
ser1516 0:f6b9d13870f2 644
ser1516 0:f6b9d13870f2 645
ser1516 0:f6b9d13870f2 646 Command Code:
ser1516 0:f6b9d13870f2 647 -------------
ser1516 0:f6b9d13870f2 648
ser1516 0:f6b9d13870f2 649 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 650 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 651 |RDAUXA: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
ser1516 0:f6b9d13870f2 652 |RDAUXB: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
ser1516 0:f6b9d13870f2 653
ser1516 0:f6b9d13870f2 654 *************************************************/
ser1516 0:f6b9d13870f2 655 void LTC6804_rdaux_reg(uint8_t reg, //Determines which GPIO voltage register is read back
ser1516 0:f6b9d13870f2 656 uint8_t total_ic, //The number of ICs in the system
ser1516 0:f6b9d13870f2 657 uint8_t *data //Array of the unparsed auxiliary codes
ser1516 0:f6b9d13870f2 658 )
ser1516 0:f6b9d13870f2 659 {
ser1516 0:f6b9d13870f2 660 const uint8_t REG_LEN = 8; // number of bytes in the register + 2 bytes for the PEC
ser1516 0:f6b9d13870f2 661 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 662 uint16_t cmd_pec;
ser1516 0:f6b9d13870f2 663
ser1516 0:f6b9d13870f2 664 //1
ser1516 0:f6b9d13870f2 665 if (reg == 1) //Read back auxiliary group A
ser1516 0:f6b9d13870f2 666 {
ser1516 0:f6b9d13870f2 667 cmd[1] = 0x0C;
ser1516 0:f6b9d13870f2 668 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 669 }
ser1516 0:f6b9d13870f2 670 else if (reg == 2) //Read back auxiliary group B
ser1516 0:f6b9d13870f2 671 {
ser1516 0:f6b9d13870f2 672 cmd[1] = 0x0e;
ser1516 0:f6b9d13870f2 673 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 674 }
ser1516 0:f6b9d13870f2 675 else //Read back auxiliary group A
ser1516 0:f6b9d13870f2 676 {
ser1516 0:f6b9d13870f2 677 cmd[1] = 0x0C;
ser1516 0:f6b9d13870f2 678 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 679 }
ser1516 0:f6b9d13870f2 680 //2
ser1516 0:f6b9d13870f2 681 cmd_pec = pec15_calc(2, cmd);
ser1516 0:f6b9d13870f2 682 cmd[2] = (uint8_t)(cmd_pec >> 8);
ser1516 0:f6b9d13870f2 683 cmd[3] = (uint8_t)(cmd_pec);
ser1516 0:f6b9d13870f2 684
ser1516 0:f6b9d13870f2 685 //3
ser1516 0:f6b9d13870f2 686 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake, this command can be removed.
ser1516 0:f6b9d13870f2 687 //4
ser1516 0:f6b9d13870f2 688 spi_cs=0;
ser1516 0:f6b9d13870f2 689 spi_write_read(cmd,4,data,(REG_LEN*total_ic));
ser1516 0:f6b9d13870f2 690 spi_cs=1;
ser1516 0:f6b9d13870f2 691
ser1516 0:f6b9d13870f2 692 }
ser1516 0:f6b9d13870f2 693 /*
ser1516 0:f6b9d13870f2 694 LTC6804_rdaux_reg Function Process:
ser1516 0:f6b9d13870f2 695 1. Determine Command and initialize command array
ser1516 0:f6b9d13870f2 696 2. Calculate Command PEC
ser1516 0:f6b9d13870f2 697 3. Wake up isoSPI, this step is optional
ser1516 0:f6b9d13870f2 698 4. Send Global Command to LTC6804 daisy chain
ser1516 0:f6b9d13870f2 699 */
ser1516 0:f6b9d13870f2 700
ser1516 0:f6b9d13870f2 701 /********************************************************//**
ser1516 0:f6b9d13870f2 702 \brief Clears the LTC6804 cell voltage registers
ser1516 0:f6b9d13870f2 703
ser1516 0:f6b9d13870f2 704 The command clears the cell voltage registers and intiallizes
ser1516 0:f6b9d13870f2 705 all values to 1. The register will read back hexadecimal 0xFF
ser1516 0:f6b9d13870f2 706 after the command is sent.
ser1516 0:f6b9d13870f2 707
ser1516 0:f6b9d13870f2 708
ser1516 0:f6b9d13870f2 709 Command Code:
ser1516 0:f6b9d13870f2 710 -------------
ser1516 0:f6b9d13870f2 711
ser1516 0:f6b9d13870f2 712 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 713 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 714 |CLRCELL: | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
ser1516 0:f6b9d13870f2 715 ************************************************************/
ser1516 0:f6b9d13870f2 716 void LTC6804_clrcell()
ser1516 0:f6b9d13870f2 717 {
ser1516 0:f6b9d13870f2 718 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 719 uint16_t cmd_pec;
ser1516 0:f6b9d13870f2 720
ser1516 0:f6b9d13870f2 721 //1
ser1516 0:f6b9d13870f2 722 cmd[0] = 0x07;
ser1516 0:f6b9d13870f2 723 cmd[1] = 0x11;
ser1516 0:f6b9d13870f2 724
ser1516 0:f6b9d13870f2 725 //2
ser1516 0:f6b9d13870f2 726 cmd_pec = pec15_calc(2, cmd);
ser1516 0:f6b9d13870f2 727 cmd[2] = (uint8_t)(cmd_pec >> 8);
ser1516 0:f6b9d13870f2 728 cmd[3] = (uint8_t)(cmd_pec );
ser1516 0:f6b9d13870f2 729
ser1516 0:f6b9d13870f2 730 //3
ser1516 0:f6b9d13870f2 731 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
ser1516 0:f6b9d13870f2 732
ser1516 0:f6b9d13870f2 733 //4
ser1516 0:f6b9d13870f2 734 spi_cs=0;
ser1516 0:f6b9d13870f2 735 spi_write_read(cmd,4,0,0);
ser1516 0:f6b9d13870f2 736 spi_cs=1;
ser1516 0:f6b9d13870f2 737 }
ser1516 0:f6b9d13870f2 738 /*
ser1516 0:f6b9d13870f2 739 LTC6804_clrcell Function sequence:
ser1516 0:f6b9d13870f2 740
ser1516 0:f6b9d13870f2 741 1. Load clrcell command into cmd array
ser1516 0:f6b9d13870f2 742 2. Calculate clrcell cmd PEC and load pec into cmd array
ser1516 0:f6b9d13870f2 743 3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
ser1516 0:f6b9d13870f2 744 4. send broadcast clrcell command to LTC6804 daisy chain
ser1516 0:f6b9d13870f2 745 */
ser1516 0:f6b9d13870f2 746
ser1516 0:f6b9d13870f2 747
ser1516 0:f6b9d13870f2 748 /***********************************************************//**
ser1516 0:f6b9d13870f2 749 \brief Clears the LTC6804 Auxiliary registers
ser1516 0:f6b9d13870f2 750
ser1516 0:f6b9d13870f2 751 The command clears the Auxiliary registers and intiallizes
ser1516 0:f6b9d13870f2 752 all values to 1. The register will read back hexadecimal 0xFF
ser1516 0:f6b9d13870f2 753 after the command is sent.
ser1516 0:f6b9d13870f2 754
ser1516 0:f6b9d13870f2 755
ser1516 0:f6b9d13870f2 756 Command Code:
ser1516 0:f6b9d13870f2 757 -------------
ser1516 0:f6b9d13870f2 758
ser1516 0:f6b9d13870f2 759 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 760 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 761 |CLRAUX: | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 2 | 0 |
ser1516 0:f6b9d13870f2 762 ***************************************************************/
ser1516 0:f6b9d13870f2 763 void LTC6804_clraux()
ser1516 0:f6b9d13870f2 764 {
ser1516 0:f6b9d13870f2 765 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 766 uint16_t cmd_pec;
ser1516 0:f6b9d13870f2 767
ser1516 0:f6b9d13870f2 768 //1
ser1516 0:f6b9d13870f2 769 cmd[0] = 0x07;
ser1516 0:f6b9d13870f2 770 cmd[1] = 0x12;
ser1516 0:f6b9d13870f2 771
ser1516 0:f6b9d13870f2 772 //2
ser1516 0:f6b9d13870f2 773 cmd_pec = pec15_calc(2, cmd);
ser1516 0:f6b9d13870f2 774 cmd[2] = (uint8_t)(cmd_pec >> 8);
ser1516 0:f6b9d13870f2 775 cmd[3] = (uint8_t)(cmd_pec);
ser1516 0:f6b9d13870f2 776
ser1516 0:f6b9d13870f2 777 //3
ser1516 0:f6b9d13870f2 778 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
ser1516 0:f6b9d13870f2 779 //4
ser1516 0:f6b9d13870f2 780 spi_cs=0;
ser1516 0:f6b9d13870f2 781 spi_write_read(cmd,4,0,0);
ser1516 0:f6b9d13870f2 782 spi_cs=1;
ser1516 0:f6b9d13870f2 783 }
ser1516 0:f6b9d13870f2 784 /*
ser1516 0:f6b9d13870f2 785 LTC6804_clraux Function sequence:
ser1516 0:f6b9d13870f2 786
ser1516 0:f6b9d13870f2 787 1. Load clraux command into cmd array
ser1516 0:f6b9d13870f2 788 2. Calculate clraux cmd PEC and load pec into cmd array
ser1516 0:f6b9d13870f2 789 3. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
ser1516 0:f6b9d13870f2 790 4. send broadcast clraux command to LTC6804 daisy chain
ser1516 0:f6b9d13870f2 791 */
ser1516 0:f6b9d13870f2 792
ser1516 0:f6b9d13870f2 793
ser1516 0:f6b9d13870f2 794 /*****************************************************//**
ser1516 0:f6b9d13870f2 795 \brief Write the LTC6804 configuration register
ser1516 0:f6b9d13870f2 796
ser1516 0:f6b9d13870f2 797 This command will write the configuration registers of the LTC6804-1s
ser1516 0:f6b9d13870f2 798 connected in a daisy chain stack. The configuration is written in descending
ser1516 0:f6b9d13870f2 799 order so the last device's configuration is written first.
ser1516 0:f6b9d13870f2 800
ser1516 0:f6b9d13870f2 801 @param[in] uint8_t total_ic; The number of ICs being written to.
ser1516 0:f6b9d13870f2 802
ser1516 0:f6b9d13870f2 803 @param[in] uint8_t config[][6] is a two dimensional array of the configuration data that will be written, the array should contain the 6 bytes for each
ser1516 0:f6b9d13870f2 804 IC in the daisy chain. The lowest IC in the daisy chain should be the first 6 byte block in the array. The array should
ser1516 0:f6b9d13870f2 805 have the following format:
ser1516 0:f6b9d13870f2 806 | config[0][0]| config[0][1] | config[0][2]| config[0][3]| config[0][4]| config[0][5]| config[1][0] | config[1][1]| config[1][2]| ..... |
ser1516 0:f6b9d13870f2 807 |--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|-----------|
ser1516 0:f6b9d13870f2 808 |IC1 CFGR0 |IC1 CFGR1 |IC1 CFGR2 |IC1 CFGR3 |IC1 CFGR4 |IC1 CFGR5 |IC2 CFGR0 |IC2 CFGR1 | IC2 CFGR2 | ..... |
ser1516 0:f6b9d13870f2 809
ser1516 0:f6b9d13870f2 810 The function will calculate the needed PEC codes for the write data
ser1516 0:f6b9d13870f2 811 and then transmit data to the ICs on a daisy chain.
ser1516 0:f6b9d13870f2 812
ser1516 0:f6b9d13870f2 813
ser1516 0:f6b9d13870f2 814 Command Code:
ser1516 0:f6b9d13870f2 815 -------------
ser1516 0:f6b9d13870f2 816 | | CMD[0] | CMD[1] |
ser1516 0:f6b9d13870f2 817 |---------------|---------------------------------------------------------------|---------------------------------------------------------------|
ser1516 0:f6b9d13870f2 818 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 819 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 820 |WRCFG: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
ser1516 0:f6b9d13870f2 821 ********************************************************/
ser1516 0:f6b9d13870f2 822 void LTC6804_wrcfg(uint8_t total_ic, //The number of ICs being written to
ser1516 0:f6b9d13870f2 823 uint8_t config[][6] //A two dimensional array of the configuration data that will be written
ser1516 0:f6b9d13870f2 824 )
ser1516 0:f6b9d13870f2 825 {
ser1516 0:f6b9d13870f2 826 const uint8_t BYTES_IN_REG = 6;
ser1516 0:f6b9d13870f2 827 const uint8_t CMD_LEN = 4+(8*total_ic);
ser1516 0:f6b9d13870f2 828 uint8_t *cmd;
ser1516 0:f6b9d13870f2 829 uint16_t cfg_pec;
ser1516 0:f6b9d13870f2 830 uint8_t cmd_index; //command counter
ser1516 0:f6b9d13870f2 831
ser1516 0:f6b9d13870f2 832 cmd = (uint8_t *)malloc(CMD_LEN*sizeof(uint8_t));
ser1516 0:f6b9d13870f2 833
ser1516 0:f6b9d13870f2 834 //1
ser1516 0:f6b9d13870f2 835 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 836 cmd[1] = 0x01;
ser1516 0:f6b9d13870f2 837 cmd[2] = 0x3d;
ser1516 0:f6b9d13870f2 838 cmd[3] = 0x6e;
ser1516 0:f6b9d13870f2 839
ser1516 0:f6b9d13870f2 840 //2
ser1516 0:f6b9d13870f2 841 cmd_index = 4;
ser1516 0:f6b9d13870f2 842 for (uint8_t current_ic = total_ic; current_ic > 0; current_ic--) // executes for each LTC6804 in daisy chain, this loops starts with
ser1516 0:f6b9d13870f2 843 {
ser1516 0:f6b9d13870f2 844 // the last IC on the stack. The first configuration written is
ser1516 0:f6b9d13870f2 845 // received by the last IC in the daisy chain
ser1516 0:f6b9d13870f2 846
ser1516 0:f6b9d13870f2 847 for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++) // executes for each of the 6 bytes in the CFGR register
ser1516 0:f6b9d13870f2 848 {
ser1516 0:f6b9d13870f2 849 // current_byte is the byte counter
ser1516 0:f6b9d13870f2 850
ser1516 0:f6b9d13870f2 851 cmd[cmd_index] = config[current_ic-1][current_byte]; //adding the config data to the array to be sent
ser1516 0:f6b9d13870f2 852 cmd_index = cmd_index + 1;
ser1516 0:f6b9d13870f2 853 }
ser1516 0:f6b9d13870f2 854 //3
ser1516 0:f6b9d13870f2 855 cfg_pec = (uint16_t)pec15_calc(BYTES_IN_REG, &config[current_ic-1][0]); // calculating the PEC for each ICs configuration register data
ser1516 0:f6b9d13870f2 856 cmd[cmd_index] = (uint8_t)(cfg_pec >> 8);
ser1516 0:f6b9d13870f2 857 cmd[cmd_index + 1] = (uint8_t)cfg_pec;
ser1516 0:f6b9d13870f2 858 cmd_index = cmd_index + 2;
ser1516 0:f6b9d13870f2 859 }
ser1516 0:f6b9d13870f2 860
ser1516 0:f6b9d13870f2 861 //4
ser1516 0:f6b9d13870f2 862 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake.This command can be removed.
ser1516 0:f6b9d13870f2 863 //5
ser1516 0:f6b9d13870f2 864 spi_cs=0;
ser1516 0:f6b9d13870f2 865 spi_write_array(CMD_LEN, cmd);
ser1516 0:f6b9d13870f2 866 spi_cs=1;
ser1516 0:f6b9d13870f2 867 free(cmd);
ser1516 0:f6b9d13870f2 868 }
ser1516 0:f6b9d13870f2 869 /*
ser1516 0:f6b9d13870f2 870 WRCFG Sequence:
ser1516 0:f6b9d13870f2 871
ser1516 0:f6b9d13870f2 872 1. Load cmd array with the write configuration command and PEC
ser1516 0:f6b9d13870f2 873 2. Load the cmd with LTC6804 configuration data
ser1516 0:f6b9d13870f2 874 3. Calculate the pec for the LTC6804 configuration data being transmitted
ser1516 0:f6b9d13870f2 875 4. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
ser1516 0:f6b9d13870f2 876 5. Write configuration data to the LTC6804 daisy chain
ser1516 0:f6b9d13870f2 877
ser1516 0:f6b9d13870f2 878 */
ser1516 0:f6b9d13870f2 879
ser1516 0:f6b9d13870f2 880 /*!******************************************************
ser1516 0:f6b9d13870f2 881 \brief Reads configuration registers of a LTC6804 daisy chain
ser1516 0:f6b9d13870f2 882
ser1516 0:f6b9d13870f2 883 @param[in] uint8_t total_ic: number of ICs in the daisy chain
ser1516 0:f6b9d13870f2 884
ser1516 0:f6b9d13870f2 885 @param[out] uint8_t r_config[][8] is a two dimensional array that the function stores the read configuration data. The configuration data for each IC
ser1516 0:f6b9d13870f2 886 is stored in blocks of 8 bytes with the configuration data of the lowest IC on the stack in the first 8 bytes
ser1516 0:f6b9d13870f2 887 block of the array, the second IC in the second 8 byte etc. Below is an table illustrating the array organization:
ser1516 0:f6b9d13870f2 888
ser1516 0:f6b9d13870f2 889 |r_config[0][0]|r_config[0][1]|r_config[0][2]|r_config[0][3]|r_config[0][4]|r_config[0][5]|r_config[0][6] |r_config[0][7] |r_config[1][0]|r_config[1][1]| ..... |
ser1516 0:f6b9d13870f2 890 |--------------|--------------|--------------|--------------|--------------|--------------|----------------|---------------|--------------|--------------|-----------|
ser1516 0:f6b9d13870f2 891 |IC1 CFGR0 |IC1 CFGR1 |IC1 CFGR2 |IC1 CFGR3 |IC1 CFGR4 |IC1 CFGR5 |IC1 PEC High |IC1 PEC Low |IC2 CFGR0 |IC2 CFGR1 | ..... |
ser1516 0:f6b9d13870f2 892
ser1516 0:f6b9d13870f2 893
ser1516 0:f6b9d13870f2 894 @return int8_t, PEC Status.
ser1516 0:f6b9d13870f2 895
ser1516 0:f6b9d13870f2 896 0: Data read back has matching PEC
ser1516 0:f6b9d13870f2 897
ser1516 0:f6b9d13870f2 898 -1: Data read back has incorrect PEC
ser1516 0:f6b9d13870f2 899
ser1516 0:f6b9d13870f2 900
ser1516 0:f6b9d13870f2 901 Command Code:
ser1516 0:f6b9d13870f2 902 -------------
ser1516 0:f6b9d13870f2 903
ser1516 0:f6b9d13870f2 904 |CMD[0:1] | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ser1516 0:f6b9d13870f2 905 |---------------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
ser1516 0:f6b9d13870f2 906 |RDCFG: | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
ser1516 0:f6b9d13870f2 907 ********************************************************/
ser1516 0:f6b9d13870f2 908 int8_t LTC6804_rdcfg(uint8_t total_ic, //Number of ICs in the system
ser1516 0:f6b9d13870f2 909 uint8_t r_config[][8] //A two dimensional array that the function stores the read configuration data.
ser1516 0:f6b9d13870f2 910 )
ser1516 0:f6b9d13870f2 911 {
ser1516 0:f6b9d13870f2 912 const uint8_t BYTES_IN_REG = 8;
ser1516 0:f6b9d13870f2 913
ser1516 0:f6b9d13870f2 914 uint8_t cmd[4];
ser1516 0:f6b9d13870f2 915 uint8_t *rx_data;
ser1516 0:f6b9d13870f2 916 int8_t pec_error = 0;
ser1516 0:f6b9d13870f2 917 uint16_t data_pec;
ser1516 0:f6b9d13870f2 918 uint16_t received_pec;
ser1516 0:f6b9d13870f2 919
ser1516 0:f6b9d13870f2 920 rx_data = (uint8_t *) malloc((8*total_ic)*sizeof(uint8_t));
ser1516 0:f6b9d13870f2 921
ser1516 0:f6b9d13870f2 922 //1
ser1516 0:f6b9d13870f2 923 cmd[0] = 0x00;
ser1516 0:f6b9d13870f2 924 cmd[1] = 0x02;
ser1516 0:f6b9d13870f2 925 cmd[2] = 0x2b;
ser1516 0:f6b9d13870f2 926 cmd[3] = 0x0A;
ser1516 0:f6b9d13870f2 927
ser1516 0:f6b9d13870f2 928 //2
ser1516 0:f6b9d13870f2 929 wakeup_idle (); //This will guarantee that the LTC6804 isoSPI port is awake. This command can be removed.
ser1516 0:f6b9d13870f2 930 //3
ser1516 0:f6b9d13870f2 931 spi_cs=0;
ser1516 0:f6b9d13870f2 932 spi_write_read(cmd, 4, rx_data, (BYTES_IN_REG*total_ic)); //Read the configuration data of all ICs on the daisy chain into
ser1516 0:f6b9d13870f2 933 spi_cs=1; //rx_data[] array
ser1516 0:f6b9d13870f2 934
ser1516 0:f6b9d13870f2 935 for (uint8_t current_ic = 0; current_ic < total_ic; current_ic++) //executes for each LTC6804 in the daisy chain and packs the data
ser1516 0:f6b9d13870f2 936 {
ser1516 0:f6b9d13870f2 937 //into the r_config array as well as check the received Config data
ser1516 0:f6b9d13870f2 938 //for any bit errors
ser1516 0:f6b9d13870f2 939 //4.a
ser1516 0:f6b9d13870f2 940 for (uint8_t current_byte = 0; current_byte < BYTES_IN_REG; current_byte++)
ser1516 0:f6b9d13870f2 941 {
ser1516 0:f6b9d13870f2 942 r_config[current_ic][current_byte] = rx_data[current_byte + (current_ic*BYTES_IN_REG)];
ser1516 0:f6b9d13870f2 943 }
ser1516 0:f6b9d13870f2 944 //4.b
ser1516 0:f6b9d13870f2 945 received_pec = (r_config[current_ic][6]<<8) + r_config[current_ic][7];
ser1516 0:f6b9d13870f2 946 data_pec = pec15_calc(6, &r_config[current_ic][0]);
ser1516 0:f6b9d13870f2 947 if (received_pec != data_pec)
ser1516 0:f6b9d13870f2 948 {
ser1516 0:f6b9d13870f2 949 pec_error = -1;
ser1516 0:f6b9d13870f2 950 }
ser1516 0:f6b9d13870f2 951 }
ser1516 0:f6b9d13870f2 952
ser1516 0:f6b9d13870f2 953 free(rx_data);
ser1516 0:f6b9d13870f2 954 //5
ser1516 0:f6b9d13870f2 955 return(pec_error);
ser1516 0:f6b9d13870f2 956 }
ser1516 0:f6b9d13870f2 957 /*
ser1516 0:f6b9d13870f2 958 RDCFG Sequence:
ser1516 0:f6b9d13870f2 959
ser1516 0:f6b9d13870f2 960 1. Load cmd array with the write configuration command and PEC
ser1516 0:f6b9d13870f2 961 2. wakeup isoSPI port, this step can be removed if isoSPI status is previously guaranteed
ser1516 0:f6b9d13870f2 962 3. Send command and read back configuration data
ser1516 0:f6b9d13870f2 963 4. For each LTC6804 in the daisy chain
ser1516 0:f6b9d13870f2 964 a. load configuration data into r_config array
ser1516 0:f6b9d13870f2 965 b. calculate PEC of received data and compare against calculated PEC
ser1516 0:f6b9d13870f2 966 5. Return PEC Error
ser1516 0:f6b9d13870f2 967
ser1516 0:f6b9d13870f2 968 */
ser1516 0:f6b9d13870f2 969
ser1516 0:f6b9d13870f2 970 /*!****************************************************
ser1516 0:f6b9d13870f2 971 \brief Wake isoSPI up from idle state
ser1516 0:f6b9d13870f2 972 Generic wakeup commannd to wake isoSPI up out of idle
ser1516 0:f6b9d13870f2 973 *****************************************************/
ser1516 0:f6b9d13870f2 974 void wakeup_idle()
ser1516 0:f6b9d13870f2 975 {
ser1516 0:f6b9d13870f2 976 spi_cs=0;
ser1516 0:f6b9d13870f2 977 wait_us(2); //Guarantees the isoSPI will be in ready mode
ser1516 0:f6b9d13870f2 978 spi_cs=1;
ser1516 0:f6b9d13870f2 979 }
ser1516 0:f6b9d13870f2 980
ser1516 0:f6b9d13870f2 981 /*!****************************************************
ser1516 0:f6b9d13870f2 982 \brief Wake the LTC6804 from the sleep state
ser1516 0:f6b9d13870f2 983
ser1516 0:f6b9d13870f2 984 Generic wakeup commannd to wake the LTC6804 from sleep
ser1516 0:f6b9d13870f2 985 *****************************************************/
ser1516 0:f6b9d13870f2 986 void wakeup_sleep()
ser1516 0:f6b9d13870f2 987 {
ser1516 0:f6b9d13870f2 988 spi_cs=0;
ser1516 0:f6b9d13870f2 989 spi_cs = 0;
ser1516 0:f6b9d13870f2 990 wait_ms(1); // Guarantees the LTC6804 will be in standby
ser1516 0:f6b9d13870f2 991 spi_cs=1;
ser1516 0:f6b9d13870f2 992 }
ser1516 0:f6b9d13870f2 993 /*!**********************************************************
ser1516 0:f6b9d13870f2 994 \brief calaculates and returns the CRC15
ser1516 0:f6b9d13870f2 995
ser1516 0:f6b9d13870f2 996 @param[in] uint8_t len: the length of the data array being passed to the function
ser1516 0:f6b9d13870f2 997
ser1516 0:f6b9d13870f2 998 @param[in] uint8_t data[] : the array of data that the PEC will be generated from
ser1516 0:f6b9d13870f2 999
ser1516 0:f6b9d13870f2 1000
ser1516 0:f6b9d13870f2 1001 @returns The calculated pec15 as an unsigned int
ser1516 0:f6b9d13870f2 1002 ***********************************************************/
ser1516 0:f6b9d13870f2 1003 uint16_t pec15_calc(uint8_t len, //Number of bytes that will be used to calculate a PEC
ser1516 0:f6b9d13870f2 1004 uint8_t *data //Array of data that will be used to calculate a PEC
ser1516 0:f6b9d13870f2 1005 )
ser1516 0:f6b9d13870f2 1006 {
ser1516 0:f6b9d13870f2 1007 uint16_t remainder,addr;
ser1516 0:f6b9d13870f2 1008
ser1516 0:f6b9d13870f2 1009 remainder = 16;//initialize the PEC
ser1516 0:f6b9d13870f2 1010 for (uint8_t i = 0; i<len; i++) // loops for each byte in data array
ser1516 0:f6b9d13870f2 1011 {
ser1516 0:f6b9d13870f2 1012 addr = ((remainder>>7)^data[i])&0xff;//calculate PEC table address
ser1516 0:f6b9d13870f2 1013 remainder = (remainder<<8)^crc15Table[addr];
ser1516 0:f6b9d13870f2 1014 }
ser1516 0:f6b9d13870f2 1015 return(remainder*2);//The CRC15 has a 0 in the LSB so the remainder must be multiplied by 2
ser1516 0:f6b9d13870f2 1016 }
ser1516 0:f6b9d13870f2 1017
ser1516 0:f6b9d13870f2 1018
ser1516 0:f6b9d13870f2 1019 /*!
ser1516 0:f6b9d13870f2 1020 \brief Writes an array of bytes out of the SPI port
ser1516 0:f6b9d13870f2 1021
ser1516 0:f6b9d13870f2 1022 @param[in] uint8_t len length of the data array being written on the SPI port
ser1516 0:f6b9d13870f2 1023 @param[in] uint8_t data[] the data array to be written on the SPI port
ser1516 0:f6b9d13870f2 1024
ser1516 0:f6b9d13870f2 1025 */
ser1516 0:f6b9d13870f2 1026 void spi_write_array(uint8_t len, // Option: Number of bytes to be written on the SPI port
ser1516 0:f6b9d13870f2 1027 uint8_t data[] //Array of bytes to be written on the SPI port
ser1516 0:f6b9d13870f2 1028 )
ser1516 0:f6b9d13870f2 1029 {
ser1516 0:f6b9d13870f2 1030 for (uint8_t i = 0; i < len; i++)
ser1516 0:f6b9d13870f2 1031 {
ser1516 0:f6b9d13870f2 1032 spi.write((int8_t)data[i]);
ser1516 0:f6b9d13870f2 1033 }
ser1516 0:f6b9d13870f2 1034 }
ser1516 0:f6b9d13870f2 1035
ser1516 0:f6b9d13870f2 1036 /*!
ser1516 0:f6b9d13870f2 1037 \brief Writes and read a set number of bytes using the SPI port.
ser1516 0:f6b9d13870f2 1038
ser1516 0:f6b9d13870f2 1039 @param[in] uint8_t tx_data[] array of data to be written on the SPI port
ser1516 0:f6b9d13870f2 1040 @param[in] uint8_t tx_len length of the tx_data array
ser1516 0:f6b9d13870f2 1041 @param[out] uint8_t rx_data array that read data will be written too.
ser1516 0:f6b9d13870f2 1042 @param[in] uint8_t rx_len number of bytes to be read from the SPI port.
ser1516 0:f6b9d13870f2 1043
ser1516 0:f6b9d13870f2 1044 */
ser1516 0:f6b9d13870f2 1045
ser1516 0:f6b9d13870f2 1046 void spi_write_read(uint8_t tx_Data[],//array of data to be written on SPI port
ser1516 0:f6b9d13870f2 1047 uint8_t tx_len, //length of the tx data arry
ser1516 0:f6b9d13870f2 1048 uint8_t *rx_data,//Input: array that will store the data read by the SPI port
ser1516 0:f6b9d13870f2 1049 uint8_t rx_len //Option: number of bytes to be read from the SPI port
ser1516 0:f6b9d13870f2 1050 )
ser1516 0:f6b9d13870f2 1051 {
ser1516 0:f6b9d13870f2 1052 for (uint8_t i = 0; i < tx_len; i++)
ser1516 0:f6b9d13870f2 1053 {
ser1516 0:f6b9d13870f2 1054 spi.write(tx_Data[i]);
ser1516 0:f6b9d13870f2 1055
ser1516 0:f6b9d13870f2 1056 }
ser1516 0:f6b9d13870f2 1057
ser1516 0:f6b9d13870f2 1058 for (uint8_t i = 0; i < rx_len; i++)
ser1516 0:f6b9d13870f2 1059 {
ser1516 0:f6b9d13870f2 1060 rx_data[i] = (uint8_t)spi.write(0xFF);
ser1516 0:f6b9d13870f2 1061 }
ser1516 0:f6b9d13870f2 1062
ser1516 0:f6b9d13870f2 1063 }
ser1516 0:f6b9d13870f2 1064
ser1516 0:f6b9d13870f2 1065
ser1516 0:f6b9d13870f2 1066