TLMoto
LTC68041.cpp@1:c55c4c93681f, 2016-10-22 (annotated)
- 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?
User | Revision | Line number | New 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 |