TLMoto

Dependents:   BMS_2 BMS_4 BMS_8

Committer:
ser1516
Date:
Sat Oct 22 16:33:51 2016 +0000
Revision:
1:c55c4c93681f
Parent:
0:f6b9d13870f2
comit antes de gerardo mexer

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