foxBMS - Unit Tests  1.2.1
The foxBMS Unit Tests API Documentation
ltc_6813-1.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * We kindly request you to use one or more of the following phrases to refer to
34  * foxBMS in your hardware, software, documentation or advertising materials:
35  *
36  * - ″This product uses parts of foxBMS®″
37  * - ″This product includes parts of foxBMS®″
38  * - ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file ltc_6813-1.c
44  * @author foxBMS Team
45  * @date 2019-09-01 (date of creation)
46  * @updated 2021-12-07 (date of last update)
47  * @ingroup DRIVERS
48  * @prefix LTC
49  *
50  * @brief Driver for the LTC monitoring chip.
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 /* clang-format off */
56 #include "ltc_6813-1_cfg.h"
57 #include "ltc.h"
58 /* clang-format on */
59 
60 #include "HL_spi.h"
61 #include "HL_system.h"
62 
63 #include "database.h"
64 #include "diag.h"
65 #include "io.h"
66 #include "ltc_pec.h"
67 #include "pex.h"
68 #include "os.h"
69 #include "afe_plausibility.h"
70 
71 /*========== Macros and Definitions =========================================*/
72 
73 /**
74  * TI port expander register addresses
75  * @{
76  */
77 #define LTC_PORT_EXPANDER_TI_INPUT_REG_ADR (0x00u)
78 #define LTC_PORT_EXPANDER_TI_OUTPUT_REG_ADR (0x01u)
79 #define LTC_PORT_EXPANDER_TI_CONFIG_REG_ADR (0x03u)
80 /**@}*/
81 
82 /**
83  * LTC COMM definitions
84  * @{
85  */
86 #define LTC_ICOM_START (0x60u)
87 #define LTC_ICOM_STOP (0x10u)
88 #define LTC_ICOM_BLANK (0x00u)
89 #define LTC_ICOM_NO_TRANSMIT (0x70u)
90 #define LTC_FCOM_MASTER_ACK (0x00u)
91 #define LTC_FCOM_MASTER_NACK (0x08u)
92 #define LTC_FCOM_MASTER_NACK_STOP (0x09u)
93 /**@}*/
94 
95 /** maximum number of supported cells */
96 #define LTC_MAX_SUPPORTED_CELLS (12u)
97 
98 /*========== Static Constant and Variable Definitions =======================*/
99 /**
100  * PEC buffer for RX and TX
101  * @{
102  */
103 #pragma SET_DATA_SECTION(".sharedRAM")
106 #pragma SET_DATA_SECTION()
107 /**@}*/
108 
109 /** index of used cells */
110 static uint16_t ltc_used_cells_index[BS_NR_OF_STRINGS] = {0};
111 /** local copies of database tables */
112 /**@{*/
121 /**@}*/
122 /** stores information on the detected open wires locally */
124 static LTC_ERRORTABLE_s ltc_errorTable = {0}; /*!< init in LTC_ResetErrorTable-function */
125 
126 /** local definition of plausible cell voltage values for the LTC6813 (and similar) */
129  .minimumPlausibleVoltage_mV = 0,
130 };
131 
132 /*========== Extern Constant and Variable Definitions =======================*/
133 
135  .timer = 0,
136  .statereq = {.request = LTC_STATE_NO_REQUEST, .string = 0xFFu},
138  .substate = 0,
139  .laststate = LTC_STATEMACH_UNINITIALIZED,
140  .lastsubstate = 0,
141  .adcModereq = LTC_ADCMODE_FAST_DCP0,
142  .adcMode = LTC_ADCMODE_FAST_DCP0,
143  .adcMeasChreq = LTC_ADCMEAS_UNDEFINED,
144  .adcMeasCh = LTC_ADCMEAS_UNDEFINED,
145  .numberOfMeasuredMux = 32,
146  .triggerentry = 0,
147  .ErrRetryCounter = 0,
148  .ErrRequestCounter = 0,
149  .VoltageSampleTime = 0,
150  .muxSampleTime = 0,
151  .commandDataTransferTime = 3,
152  .commandTransferTime = 3,
153  .gpioClocksTransferTime = 3,
154  .muxmeas_seqptr = {NULL_PTR},
155  .muxmeas_seqendptr = {NULL_PTR},
156  .muxmeas_nr_end = {0},
157  .first_measurement_made = false,
158  .ltc_muxcycle_finished = STD_NOT_OK,
159  .check_spi_flag = STD_NOT_OK,
160  .balance_control_done = STD_NOT_OK,
161  .transmit_ongoing = false,
162  .dummyByte_ongoing = STD_NOT_OK,
163  .spiDiagErrorEntry = DIAG_ID_LTC_SPI,
164  .pecDiagErrorEntry = DIAG_ID_LTC_PEC,
165  .muxDiagErrorEntry = DIAG_ID_LTC_MUX,
166  .voltMeasDiagErrorEntry = DIAG_ID_AFE_CELL_VOLTAGE_MEAS_ERROR,
167  .tempMeasDiagErrorEntry = DIAG_ID_AFE_CELL_TEMPERATURE_MEAS_ERROR,
168  .ltcData.pSpiInterface = spi_ltcInterface,
169  .ltcData.txBuffer = ltc_TxPecBuffer,
170  .ltcData.rxBuffer = ltc_RxPecBuffer,
171  .ltcData.frameLength = LTC_N_BYTES_FOR_DATA_TRANSMISSION,
172  .ltcData.cellVoltage = &ltc_cellvoltage,
173  .ltcData.cellTemperature = &ltc_celltemperature,
174  .ltcData.balancingFeedback = &ltc_balancing_feedback,
175  .ltcData.balancingControl = &ltc_balancing_control,
176  .ltcData.slaveControl = &ltc_slave_control,
177  .ltcData.openWireDetection = &ltc_openWireDetection,
178  .ltcData.errorTable = &ltc_errorTable,
179  .ltcData.allGpioVoltages = &ltc_allgpiovoltage,
180  .ltcData.openWire = &ltc_openwire,
181  .ltcData.usedCellIndex = ltc_used_cells_index,
182  .currentString = 0u,
183  .requestedString = 0u,
184 };
185 
186 static uint16_t ltc_cmdWRCFG[4] = {0x00, 0x01, 0x3D, 0x6E};
187 static uint16_t ltc_cmdWRCFG2[4] = {0x00, 0x24, 0xB1, 0x9E};
188 static uint16_t ltc_cmdRDCFG[4] = {0x00, 0x02, 0x2B, 0x0A};
189 
190 static uint16_t ltc_cmdRDCVA[4] = {0x00, 0x04, 0x07, 0xC2};
191 static uint16_t ltc_cmdRDCVB[4] = {0x00, 0x06, 0x9A, 0x94};
192 static uint16_t ltc_cmdRDCVC[4] = {0x00, 0x08, 0x5E, 0x52};
193 static uint16_t ltc_cmdRDCVD[4] = {0x00, 0x0A, 0xC3, 0x04};
194 static uint16_t ltc_cmdRDCVE[4] = {0x00, 0x09, 0xD5, 0x60};
195 static uint16_t ltc_cmdRDCVF[4] = {0x00, 0x0B, 0x48, 0x36};
196 static uint16_t ltc_cmdWRCOMM[4] = {0x07, 0x21, 0x24, 0xB2};
197 static uint16_t ltc_cmdSTCOMM[4] = {0x07, 0x23, 0xB9, 0xE4};
198 static uint16_t ltc_cmdRDCOMM[4] = {0x07, 0x22, 0x32, 0xD6};
199 static uint16_t ltc_cmdRDAUXA[4] = {0x00, 0x0C, 0xEF, 0xCC};
200 static uint16_t ltc_cmdRDAUXB[4] = {0x00, 0x0E, 0x72, 0x9A};
201 static uint16_t ltc_cmdRDAUXC[4] = {0x00, 0x0D, 0x64, 0xFE};
202 static uint16_t ltc_cmdRDAUXD[4] = {0x00, 0x0F, 0xF9, 0xA8};
203 
204 /* static uint16_t ltc_cmdMUTE[4] = {0x00, 0x28, 0xE8, 0x0E}; !< MUTE discharging via S pins */
205 /* static uint16_t ltc_cmdUNMUTE[4] = {0x00, 0x29, 0x63, 0x3C}; !< UN-MUTE discharging via S pins */
206 
207 /* LTC I2C commands */
208 /* static uint16_t ltc_I2CcmdDummy[6] = {0x7F, 0xF9, 0x7F, 0xF9, 0x7F, 0xF9}; !< dummy command (no transmit) */
209 
210 static uint16_t ltc_I2CcmdTempSens0[6] = {
211  0x69,
212  0x08,
213  0x00,
214  0x09,
215  0x7F,
216  0xF9}; /*!< sets the internal data pointer of the temperature sensor (address 0x48) to 0x00 */
217 static uint16_t ltc_I2CcmdTempSens1[6] =
218  {0x69, 0x18, 0x0F, 0xF0, 0x0F, 0xF9}; /*!< reads two data bytes from the temperature sensor */
219 
220 static uint16_t ltc_I2CcmdPortExpander1[6] =
221  {0x64, 0x18, 0x0F, 0xF9, 0x7F, 0xF9}; /*!< reads one data byte from the port expander */
222 
223 /* Cells */
224 static uint16_t ltc_cmdADCV_normal_DCP0[4] =
225  {0x03, 0x60, 0xF4, 0x6C}; /*!< All cells, normal mode, discharge not permitted (DCP=0) */
226 static uint16_t ltc_cmdADCV_normal_DCP1[4] =
227  {0x03, 0x70, 0xAF, 0x42}; /*!< All cells, normal mode, discharge permitted (DCP=1) */
228 static uint16_t ltc_cmdADCV_filtered_DCP0[4] =
229  {0x03, 0xE0, 0xB0, 0x4A}; /*!< All cells, filtered mode, discharge not permitted (DCP=0) */
230 static uint16_t ltc_cmdADCV_filtered_DCP1[4] =
231  {0x03, 0xF0, 0xEB, 0x64}; /*!< All cells, filtered mode, discharge permitted (DCP=1) */
232 static uint16_t ltc_cmdADCV_fast_DCP0[4] =
233  {0x02, 0xE0, 0x38, 0x06}; /*!< All cells, fast mode, discharge not permitted (DCP=0) */
234 static uint16_t ltc_cmdADCV_fast_DCP1[4] =
235  {0x02, 0xF0, 0x63, 0x28}; /*!< All cells, fast mode, discharge permitted (DCP=1) */
236 static uint16_t ltc_cmdADCV_fast_DCP0_twocells[4] =
237  {0x02, 0xE1, 0xb3, 0x34}; /*!< Two cells (1 and 7), fast mode, discharge not permitted (DCP=0) */
238 
239 /* GPIOs */
240 static uint16_t ltc_cmdADAX_normal_GPIO1[4] = {0x05, 0x61, 0x58, 0x92}; /*!< Single channel, GPIO 1, normal mode */
241 static uint16_t ltc_cmdADAX_filtered_GPIO1[4] = {0x05, 0xE1, 0x1C, 0xB4}; /*!< Single channel, GPIO 1, filtered mode */
242 static uint16_t ltc_cmdADAX_fast_GPIO1[4] = {0x04, 0xE1, 0x94, 0xF8}; /*!< Single channel, GPIO 1, fast mode */
243 static uint16_t ltc_cmdADAX_normal_GPIO2[4] = {0x05, 0x62, 0x4E, 0xF6}; /*!< Single channel, GPIO 2, normal mode */
244 static uint16_t ltc_cmdADAX_filtered_GPIO2[4] = {0x05, 0xE2, 0x0A, 0xD0}; /*!< Single channel, GPIO 2, filtered mode */
245 static uint16_t ltc_cmdADAX_fast_GPIO2[4] = {0x04, 0xE2, 0x82, 0x9C}; /*!< Single channel, GPIO 2, fast mode */
246 static uint16_t ltc_cmdADAX_normal_GPIO3[4] = {0x05, 0x63, 0xC5, 0xC4}; /*!< Single channel, GPIO 3, normal mode */
247 static uint16_t ltc_cmdADAX_filtered_GPIO3[4] = {0x05, 0xE3, 0x81, 0xE2}; /*!< Single channel, GPIO 3, filtered mode */
248 static uint16_t ltc_cmdADAX_fast_GPIO3[4] = {0x04, 0xE3, 0x09, 0xAE}; /*!< Single channel, GPIO 3, fast mode */
249 /* static uint16_t ltc_cmdADAX_normal_GPIO4[4] = {0x05, 0x64, 0x62, 0x3E}; !< Single channel, GPIO 4, normal mode */
250 /* static uint16_t ltc_cmdADAX_filtered_GPIO4[4] = {0x05, 0xE4, 0x26, 0x18}; !< Single channel, GPIO 4, filtered mode */
251 /* static uint16_t ltc_cmdADAX_fast_GPIO4[4] = {0x04, 0xE4, 0xAE, 0x54}; !< Single channel, GPIO 4, fast mode */
252 /* static uint16_t ltc_cmdADAX_normal_GPIO5[4] = {0x05, 0x65, 0xE9, 0x0C}; !< Single channel, GPIO 5, normal mode */
253 /* static uint16_t ltc_cmdADAX_filtered_GPIO5[4] = {0x05, 0xE5, 0xAD, 0x2A}; !< Single channel, GPIO 5, filtered mode */
254 /* static uint16_t ltc_cmdADAX_fast_GPIO5[4] = {0x04, 0xE5, 0x25, 0x66}; !< Single channel, GPIO 5, fast mode */
255 static uint16_t ltc_cmdADAX_normal_ALLGPIOS[4] = {0x05, 0x60, 0xD3, 0xA0}; /*!< All channels, normal mode */
256 static uint16_t ltc_cmdADAX_filtered_ALLGPIOS[4] =
257  {0x05, 0xE0, 0x97, 0x86}; /*!< All channels, filtered mode */
258 static uint16_t ltc_cmdADAX_fast_ALLGPIOS[4] = {0x04, 0xE0, 0x1F, 0xCA}; /*!< All channels, fast mode */
259 
260 /* Open-wire */
261 static uint16_t ltc_BC_cmdADOW_PUP_normal_DCP0[4] = {
262  0x03,
263  0x68,
264  0x1C,
265  0x62}; /*!< Broadcast, Pull-up current, All cells, normal mode, discharge not permitted (DCP=0) */
266 static uint16_t ltc_BC_cmdADOW_PDOWN_normal_DCP0[4] = {
267  0x03,
268  0x28,
269  0xFB,
270  0xE8}; /*!< Broadcast, Pull-down current, All cells, normal mode, discharge not permitted (DCP=0) */
271 static uint16_t ltc_BC_cmdADOW_PUP_filtered_DCP0[4] = {
272  0x03,
273  0xE8,
274  0x58,
275  0x44}; /*!< Broadcast, Pull-up current, All cells, filtered mode, discharge not permitted (DCP=0) */
277  0x03,
278  0xA8,
279  0xBF,
280  0xCE}; /*!< Broadcast, Pull-down current, All cells, filtered mode, discharge not permitted (DCP=0) */
281 
282 /*========== Static Function Prototypes =====================================*/
283 static void LTC_SetFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state);
284 static void LTC_Initialize_Database(LTC_STATE_s *ltc_state);
285 static void LTC_SaveBalancingFeedback(LTC_STATE_s *ltc_state, uint16_t *DataBufferSPI_RX, uint8_t stringNumber);
286 static void LTC_Get_BalancingControlValues(LTC_STATE_s *ltc_state);
287 static void LTC_SaveLastStates(LTC_STATE_s *ltc_state);
288 static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms);
289 static void LTC_CondBasedStateTransition(
290  LTC_STATE_s *ltc_state,
291  STD_RETURN_TYPE_e retVal,
292  DIAG_ID_e diagCode,
293  LTC_STATEMACH_e state_ok,
294  uint8_t substate_ok,
295  uint16_t timer_ms_ok,
296  LTC_STATEMACH_e state_nok,
297  uint8_t substate_nok,
298  uint16_t timer_ms_nok);
299 
301  LTC_STATE_s *ltc_state,
302  SPI_INTERFACE_CONFIG_s *pSpiInterface,
303  uint16_t *pTxBuff,
304  uint16_t *pRxBuff,
305  uint32_t frameLength,
306  uint8_t registerSet,
307  uint8_t stringNumber);
308 
309 static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state);
311  SPI_INTERFACE_CONFIG_s *pSpiInterface,
312  uint16_t *pTxBuff,
313  uint16_t *pRxBuff,
314  uint32_t frameLength);
315 
317  SPI_INTERFACE_CONFIG_s *pSpiInterface,
318  LTC_ADCMODE_e adcMode,
319  LTC_ADCMEAS_CHAN_e adcMeasCh);
321  SPI_INTERFACE_CONFIG_s *pSpiInterface,
322  LTC_ADCMODE_e adcMode,
323  LTC_ADCMEAS_CHAN_e adcMeasCh);
325  SPI_INTERFACE_CONFIG_s *pSpiInterface,
326  LTC_ADCMODE_e adcMode,
327  uint8_t PUP);
328 
329 static uint16_t LTC_Get_MeasurementTCycle(LTC_ADCMODE_e adcMode, LTC_ADCMEAS_CHAN_e adcMeasCh);
330 static void LTC_SaveRXtoVoltagebuffer(
331  LTC_STATE_s *ltc_state,
332  uint16_t *pRxBuff,
333  uint8_t registerSet,
334  uint8_t stringNumber);
335 static void LTC_SaveRXtoGPIOBuffer(
336  LTC_STATE_s *ltc_state,
337  uint16_t *pRxBuff,
338  uint8_t registerSet,
339  uint8_t stringNumber);
340 
342  LTC_STATE_s *ltc_state,
343  uint16_t *DataBufferSPI_RX_with_PEC,
344  uint8_t stringNumber);
346  uint16_t *Command,
347  SPI_INTERFACE_CONFIG_s *pSpiInterface,
348  uint16_t *pTxBuff,
349  uint16_t *pRxBuff,
350  uint32_t frameLength);
352  uint16_t *Command,
353  SPI_INTERFACE_CONFIG_s *pSpiInterface,
354  uint16_t *pTxBuff,
355  uint16_t *pRxBuff,
356  uint32_t frameLength);
357 static void LTC_SetMUXChCommand(uint16_t *pTxBuff, uint8_t mux, uint8_t channel);
359  LTC_STATE_s *ltc_state,
360  SPI_INTERFACE_CONFIG_s *pSpiInterface,
361  uint16_t *pTxBuff,
362  uint16_t *pRxBuff,
363  uint32_t frameLength,
364  uint8_t step);
365 static void LTC_SetEEPROMReadCommand(LTC_STATE_s *ltc_state, uint16_t *pTxBuff, uint8_t step);
366 static void LTC_EEPROMSaveReadValue(LTC_STATE_s *ltc_state, uint16_t *pRxBuff);
368  LTC_STATE_s *ltc_state,
369  SPI_INTERFACE_CONFIG_s *pSpiInterface,
370  uint16_t *pTxBuff,
371  uint16_t *pRxBuff,
372  uint32_t frameLength,
373  uint8_t step);
374 static void LTC_SetEEPROMWriteCommand(LTC_STATE_s *ltc_state, uint16_t *pTxBuff, uint8_t step);
376  SPI_INTERFACE_CONFIG_s *pSpiInterface,
377  uint16_t *pTxBuff,
378  uint16_t *pRxBuff,
379  uint32_t frameLength,
380  uint8_t mux,
381  uint8_t channel);
383  LTC_STATE_s *ltc_state,
384  SPI_INTERFACE_CONFIG_s *pSpiInterface,
385  uint16_t *pTxBuff,
386  uint16_t *pRxBuff,
387  uint32_t frameLength);
388 static void LTC_PortExpanderSaveValues(LTC_STATE_s *ltc_state, uint16_t *pRxBuff);
389 static void LTC_TempSensSaveTemp(LTC_STATE_s *ltc_state, uint16_t *pRxBuff);
391  LTC_STATE_s *ltc_state,
392  SPI_INTERFACE_CONFIG_s *pSpiInterface,
393  uint16_t *pTxBuff,
394  uint16_t *pRxBuff,
395  uint32_t frameLength,
398  LTC_STATE_s *ltc_state,
399  SPI_INTERFACE_CONFIG_s *pSpiInterface,
400  uint16_t *pTxBuff,
401  uint16_t *pRxBuff,
402  uint32_t frameLength);
404  LTC_STATE_s *ltc_state,
405  SPI_INTERFACE_CONFIG_s *pSpiInterface,
406  uint16_t *pTxBuff,
407  uint16_t *pRxBuff,
408  uint32_t frameLength,
409  uint8_t step);
410 static void LTC_PortExpanderSaveValues_TI(LTC_STATE_s *ltc_state, uint16_t *pTxBuff);
411 
414  SPI_INTERFACE_CONFIG_s *pSpiInterface,
415  uint16_t *pTxBuff,
416  uint16_t *pRxBuff,
417  uint32_t frameLength,
418  uint16_t *cmd_data);
419 
420 static STD_RETURN_TYPE_e LTC_I2CCheckACK(LTC_STATE_s *ltc_state, uint16_t *pRxBuff, uint8_t mux, uint8_t stringNumber);
421 
422 static void LTC_SaveMuxMeasurement(
423  LTC_STATE_s *ltc_state,
424  uint16_t *pRxBuff,
425  LTC_MUX_CH_CFG_s *muxseqptr,
426  uint8_t stringNumber);
427 
428 static uint32_t LTC_GetSPIClock(SPI_INTERFACE_CONFIG_s *pSpiInterface);
429 static void LTC_SetTransferTimes(LTC_STATE_s *ltc_state);
430 
432 
433 /*========== Static Function Implementations ================================*/
434 /**
435  * @brief in the database, initializes the fields related to the LTC drivers.
436  *
437  * This function loops through all the LTC-related data fields in the database
438  * and sets them to 0. It should be called in the initialization or re-initialization
439  * routine of the LTC driver.
440  *
441  * @param ltc_state: state of the ltc state machine
442  *
443  */
444 static void LTC_Initialize_Database(LTC_STATE_s *ltc_state) {
445  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
446  ltc_state->ltcData.cellVoltage->state = 0;
447  for (uint16_t i = 0; i < BS_NR_OF_BAT_CELLS; i++) {
448  ltc_state->ltcData.cellVoltage->cellVoltage_mV[stringNumber][i] = 0;
449  ltc_state->ltcData.openWireDetection->openWirePup[stringNumber][i] = 0;
450  ltc_state->ltcData.openWireDetection->openWirePdown[stringNumber][i] = 0;
451  ltc_state->ltcData.openWireDetection->openWireDelta[stringNumber][i] = 0;
452  }
453 
454  ltc_state->ltcData.cellTemperature->state = 0;
455  for (uint16_t i = 0; i < BS_NR_OF_TEMP_SENSORS_PER_STRING; i++) {
456  ltc_state->ltcData.cellTemperature->cellTemperature_ddegC[stringNumber][i] = 0;
457  }
458 
459  ltc_state->ltcData.balancingFeedback->state = 0;
460  for (uint16_t i = 0; i < BS_NR_OF_BAT_CELLS; i++) {
461  ltc_state->ltcData.balancingControl->balancingState[stringNumber][i] = 0;
462  }
463  ltc_state->ltcData.balancingControl->nrBalancedCells[stringNumber] = 0u;
464  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
465  ltc_state->ltcData.balancingFeedback->value[stringNumber][i] = 0;
466  }
467 
468  ltc_state->ltcData.slaveControl->state = 0;
469  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
470  ltc_state->ltcData.slaveControl->ioValueIn[i] = 0;
471  ltc_state->ltcData.slaveControl->ioValueOut[i] = 0;
473  ltc_state->ltcData.slaveControl->eepromValueRead[i] = 0;
474  ltc_state->ltcData.slaveControl->eepromValueWrite[i] = 0;
475  }
476  ltc_state->ltcData.slaveControl->eepromReadAddressLastUsed = 0xFFFFFFFF;
477  ltc_state->ltcData.slaveControl->eepromReadAddressToUse = 0xFFFFFFFF;
478  ltc_state->ltcData.slaveControl->eepromWriteAddressLastUsed = 0xFFFFFFFF;
479  ltc_state->ltcData.slaveControl->eepromWriteAddressToUse = 0xFFFFFFFF;
480 
481  ltc_state->ltcData.allGpioVoltages->state = 0;
482  for (uint16_t i = 0; i < (BS_NR_OF_MODULES * BS_NR_OF_GPIOS_PER_MODULE); i++) {
483  ltc_state->ltcData.allGpioVoltages->gpioVoltages_mV[stringNumber][i] = 0;
484  }
485 
486  for (uint16_t i = 0; i < (BS_NR_OF_MODULES * (BS_NR_OF_CELLS_PER_MODULE + 1)); i++) {
487  ltc_state->ltcData.openWire->openwire[stringNumber][i] = 0;
488  }
489  ltc_state->ltcData.openWire->state = 0;
490  }
491 
493  ltc_state->ltcData.cellVoltage,
494  ltc_state->ltcData.cellTemperature,
495  ltc_state->ltcData.balancingFeedback,
496  ltc_state->ltcData.openWire);
498 }
499 
500 /**
501  * @brief Saves the last state and the last substate
502  *
503  * @param ltc_state: state of the ltc state machine
504  */
505 static void LTC_SaveLastStates(LTC_STATE_s *ltc_state) {
506  ltc_state->laststate = ltc_state->state;
507  ltc_state->lastsubstate = ltc_state->substate;
508 }
509 
510 /**
511  * @brief function for setting LTC_Trigger state transitions
512  *
513  * @param ltc_state: state of the ltc state machine
514  * @param state: state to transition into
515  * @param substate: substate to transition into
516  * @param timer_ms: transition into state, substate after timer elapsed
517  */
518 static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms) {
519  ltc_state->state = state;
520  ltc_state->substate = substate;
521  ltc_state->timer = timer_ms;
522 }
523 
524 /**
525  * @brief condition-based state transition depending on retVal
526  *
527  * If retVal is #STD_OK, after timer_ms_ok is elapsed the LTC statemachine will
528  * transition into state_ok and substate_ok, otherwise after timer_ms_nok the
529  * statemachine will transition to state_nok and substate_nok. Depending on
530  * value of retVal the corresponding diagnosis entry will be called.
531  *
532  * @param ltc_state: state of the ltc state machine
533  * @param retVal: condition to determine if statemachine will transition into ok or nok states
534  * @param diagCode: symbolic IDs for diagnosis entry, called with #DIAG_EVENT_OK if retVal is #STD_OK, #DIAG_EVENT_NOT_OK otherwise
535  * @param state_ok state to transition into if retVal is #STD_OK
536  * @param substate_ok: substate to transition into if retVal is #STD_OK
537  * @param timer_ms_ok: transition into state_ok, substate_ok after timer_ms_ok elapsed
538  * @param state_nok: state to transition into if retVal is #STD_NOT_OK
539  * @param substate_nok: substate to transition into if retVal is #STD_NOT_OK
540  * @param timer_ms_nok: transition into state_nok, substate_nok after timer_ms_nok elapsed
541  */
543  LTC_STATE_s *ltc_state,
544  STD_RETURN_TYPE_e retVal,
545  DIAG_ID_e diagCode,
546  LTC_STATEMACH_e state_ok,
547  uint8_t substate_ok,
548  uint16_t timer_ms_ok,
549  LTC_STATEMACH_e state_nok,
550  uint8_t substate_nok,
551  uint16_t timer_ms_nok) {
552  if ((retVal != STD_OK)) {
554  LTC_StateTransition(ltc_state, state_nok, substate_nok, timer_ms_nok);
555  } else {
556  DIAG_Handler(diagCode, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
557  LTC_StateTransition(ltc_state, state_ok, substate_ok, timer_ms_ok);
558  }
559 }
560 
561 extern void LTC_SaveVoltages(LTC_STATE_s *ltc_state, uint8_t stringNumber) {
562  /* Pointer validity check */
563  FAS_ASSERT(ltc_state != NULL_PTR);
564  FAS_ASSERT(stringNumber < BS_NR_OF_STRINGS);
565 
566  /* Iterate over all cell to:
567  *
568  * 1. Check open-wires and set respective cell measurements to invalid
569  * 2. Perform minimum/maximum measurement value plausibility check
570  * 3. Calculate string values
571  */
572  STD_RETURN_TYPE_e cellVoltageMeasurementValid = STD_OK;
573  int32_t stringVoltage_mV = 0;
574  uint16_t numberValidMeasurements = 0;
575  for (uint8_t m = 0u; m < BS_NR_OF_MODULES; m++) {
576  for (uint8_t c = 0u; c < BS_NR_OF_CELLS_PER_MODULE; c++) {
577  /* ------- 1. Check open-wires -----------------
578  * Is cell N input not open wire &&
579  * Is cell N+1 input not open wire &&
580  * Is cell voltage valid because of previous PEC error
581  * If so, everything okay, else set cell voltage measurement to invalid.
582  */
583  if ((ltc_state->ltcData.openWire->openwire[stringNumber][(m * (BS_NR_OF_CELLS_PER_MODULE + 1u)) + c] ==
584  0u) &&
585  (ltc_state->ltcData.openWire->openwire[stringNumber][(m * (BS_NR_OF_CELLS_PER_MODULE + 1u)) + c + 1u] ==
586  0u) &&
587  ((ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] & (0x01u << c)) == 0u)) {
588  /* Cell voltage is valid -> perform minimum/maximum plausibility check */
589 
590  /* ------- 2. Perform minimum/maximum measurement range check ---------- */
592  ltc_state->ltcData.cellVoltage
593  ->cellVoltage_mV[stringNumber][(m * BS_NR_OF_CELLS_PER_MODULE) + c],
595  /* Cell voltage is valid -> calculate string voltage */
596  /* -------- 3. Calculate string values ------------- */
597  stringVoltage_mV += ltc_state->ltcData.cellVoltage
598  ->cellVoltage_mV[stringNumber][(m * BS_NR_OF_CELLS_PER_MODULE) + c];
599  numberValidMeasurements++;
600  } else {
601  /* Invalidate cell voltage measurement */
602  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] |= (0x01u << c);
603  cellVoltageMeasurementValid = STD_NOT_OK;
604  }
605  } else {
606  /* Set cell voltage measurement value invalid, if not already invalid because of PEC Error */
607  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] |= (0x01u << c);
608  cellVoltageMeasurementValid = STD_NOT_OK;
609  }
610  }
611  }
612  DIAG_CheckEvent(cellVoltageMeasurementValid, ltc_state->voltMeasDiagErrorEntry, DIAG_STRING, stringNumber);
613  ltc_state->ltcData.cellVoltage->packVoltage_mV[stringNumber] = stringVoltage_mV;
614  ltc_state->ltcData.cellVoltage->nrValidCellVoltages[stringNumber] = numberValidMeasurements;
615 
616  /* Increment state variable each time new values are written into database */
617  ltc_state->ltcData.cellVoltage->state++;
618 
619  DATA_WRITE_DATA(ltc_state->ltcData.cellVoltage);
620 }
621 
622 /*========== Extern Function Implementations ================================*/
623 extern void LTC_SaveTemperatures(LTC_STATE_s *ltc_state, uint8_t stringNumber) {
624  STD_RETURN_TYPE_e cellTemperatureMeasurementValid = STD_OK;
625  uint16_t numberValidMeasurements = 0;
626 
627  for (uint8_t m = 0u; m < BS_NR_OF_MODULES; m++) {
628  for (uint8_t c = 0u; c < BS_NR_OF_TEMP_SENSORS_PER_MODULE; c++) {
629  /* ------- 1. Check valid flag -----------------
630  * Is cell temperature valid because of previous PEC error
631  * If so, everything okay, else set cell temperature measurement to invalid.
632  */
633  if ((ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][m] & (0x01u << c)) == 0u) {
634  /* Cell temperature is valid -> perform minimum/maximum plausibility check */
635 
636  /* ------- 2. Perform minimum/maximum measurement range check ---------- */
637  if (STD_OK ==
639  ltc_state->ltcData.cellTemperature
640  ->cellTemperature_ddegC[stringNumber][(m * BS_NR_OF_TEMP_SENSORS_PER_MODULE) + c])) {
641  numberValidMeasurements++;
642  } else {
643  /* Invalidate cell temperature measurement */
644  ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][m] |= (0x01u << c);
645  cellTemperatureMeasurementValid = STD_NOT_OK;
646  }
647  } else {
648  /* Already invalid because of PEC Error */
649  cellTemperatureMeasurementValid = STD_NOT_OK;
650  }
651  }
652  }
653  DIAG_CheckEvent(cellTemperatureMeasurementValid, ltc_state->tempMeasDiagErrorEntry, DIAG_STRING, stringNumber);
654 
655  ltc_state->ltcData.cellTemperature->nrValidTemperatures[stringNumber] = numberValidMeasurements;
656 
657  ltc_state->ltcData.cellTemperature->state++;
659 }
660 
661 extern void LTC_SaveAllGPIOMeasurement(LTC_STATE_s *ltc_state) {
662  ltc_state->ltcData.allGpioVoltages->state++;
664 }
665 
666 /**
667  * @brief stores the measured balancing feedback values in the database.
668  *
669  * This function stores the global balancing feedback value measured on GPIO3 of the LTC into the database
670  *
671  * @param ltc_state state of the ltc state machine
672  * @param DataBufferSPI_RX receive buffer of the SPI interface
673  * @param stringNumber string addressed
674  *
675  */
676 static void LTC_SaveBalancingFeedback(LTC_STATE_s *ltc_state, uint16_t *DataBufferSPI_RX, uint8_t stringNumber) {
677  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
678  const uint16_t val_i = DataBufferSPI_RX[8u + (1u * i * 8u)] |
679  (DataBufferSPI_RX[8u + (1u * i * 8u) + 1u] << 8u); /* raw value, GPIO3 */
680 
681  ltc_state->ltcData.balancingFeedback->value[stringNumber][i] = val_i;
682  }
683 
684  ltc_state->ltcData.balancingFeedback->state++;
686 }
687 
688 /**
689  * @brief gets the balancing orders from the database.
690  *
691  * This function gets the balancing control from the database. Balancing control
692  * is set by the BMS. The LTC driver only executes the balancing orders.
693  *
694  * @param ltc_state: state of the ltc state machine
695  *
696  */
699 }
700 
701 /**
702  * @brief re-entrance check of LTC state machine trigger function
703  *
704  * This function is not re-entrant and should only be called time- or event-triggered.
705  * It increments the triggerentry counter from the state variable ltc_state.
706  * It should never be called by two different processes, so if it is the case, triggerentry
707  * should never be higher than 0 when this function is called.
708  *
709  * @param ltc_state: state of the ltc state machine
710  *
711  * @return retval 0 if no further instance of the function is active, 0xff else
712  *
713  */
714 uint8_t LTC_CheckReEntrance(LTC_STATE_s *ltc_state) {
715  uint8_t retval = 0;
716 
718  if (!ltc_state->triggerentry) {
719  ltc_state->triggerentry++;
720  } else {
721  retval = 0xFF; /* multiple calls of function */
722  }
724 
725  return (retval);
726 }
727 
729  LTC_REQUEST_s retval = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
730 
732  retval.request = ltc_state->statereq.request;
733  retval.string = ltc_state->statereq.string;
735 
736  return (retval);
737 }
738 
740  return ltc_state->state;
741 }
742 
743 /**
744  * @brief transfers the current state request to the state machine.
745  *
746  * This function takes the current state request from ltc_state and transfers it to the state machine.
747  * It resets the value from ltc_state to LTC_STATE_NO_REQUEST
748  *
749  * @param ltc_state: state of the ltc state machine
750  * @param pBusIDptr bus ID, main or backup (deprecated)
751  * @param pAdcModeptr LTC ADCmeasurement mode (fast, normal or filtered)
752  * @param pAdcMeasChptr number of channels measured for GPIOS (one at a time for multiplexers or all five GPIOs)
753  *
754  * @return retVal current state request, taken from LTC_STATE_REQUEST_e
755  *
756  */
758  LTC_STATE_s *ltc_state,
759  uint8_t *pBusIDptr,
760  LTC_ADCMODE_e *pAdcModeptr,
761  LTC_ADCMEAS_CHAN_e *pAdcMeasChptr) {
762  LTC_REQUEST_s retval = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
763 
765  retval.request = ltc_state->statereq.request;
766  retval.string = ltc_state->statereq.string;
767  ltc_state->requestedString = ltc_state->statereq.string;
768  *pAdcModeptr = ltc_state->adcModereq;
769  *pAdcMeasChptr = ltc_state->adcMeasChreq;
771  ltc_state->statereq.string = 0x0u;
773 
774  return (retval);
775 }
776 
778  LTC_RETURN_TYPE_e retVal = LTC_ERROR;
779 
781  retVal = LTC_CheckStateRequest(ltc_state, statereq);
782 
783  if ((retVal == LTC_OK) || (retVal == LTC_BUSY_OK) || (retVal == LTC_OK_FROM_ERROR)) {
784  ltc_state->statereq = statereq;
785  }
787 
788  return (retVal);
789 }
790 
791 void LTC_Trigger(LTC_STATE_s *ltc_state) {
792  STD_RETURN_TYPE_e retVal = STD_OK;
793  LTC_REQUEST_s statereq = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
794  uint8_t tmpbusID = 0;
797  STD_RETURN_TYPE_e continueFunction = STD_OK;
798 
799  FAS_ASSERT(ltc_state != NULL_PTR);
800 
801  /* Check re-entrance of function */
802  if (LTC_CheckReEntrance(ltc_state) > 0u) {
803  continueFunction = STD_NOT_OK;
804  }
805 
806  if (ltc_state->check_spi_flag == STD_NOT_OK) {
807  if (ltc_state->timer > 0u) {
808  if ((--ltc_state->timer) > 0u) {
809  ltc_state->triggerentry--;
810  continueFunction = STD_NOT_OK; /* handle state machine only if timer has elapsed */
811  }
812  }
813  } else {
814  if (AFE_IsTransmitOngoing(ltc_state) == true) {
815  if (ltc_state->timer > 0u) {
816  if ((--ltc_state->timer) > 0u) {
817  ltc_state->triggerentry--;
818  continueFunction = STD_NOT_OK; /* handle state machine only if timer has elapsed */
819  }
820  }
821  }
822  }
823 
824  if (continueFunction == STD_OK) {
825  switch (ltc_state->state) {
826  /****************************UNINITIALIZED***********************************/
828  /* waiting for Initialization Request */
829  statereq = LTC_TransferStateRequest(ltc_state, &tmpbusID, &tmpadcMode, &tmpadcMeasCh);
830  if (statereq.request == LTC_STATE_INIT_REQUEST) {
831  LTC_SaveLastStates(ltc_state);
832  LTC_Initialize_Database(ltc_state);
833  LTC_ResetErrorTable(ltc_state);
836  ltc_state->adcMode = tmpadcMode;
837  ltc_state->adcMeasCh = tmpadcMeasCh;
838  } else if (statereq.request == LTC_STATE_NO_REQUEST) {
839  /* no actual request pending */
840  } else {
841  ltc_state->ErrRequestCounter++; /* illegal request pending */
842  }
843  break;
844 
845  /****************************INITIALIZATION**********************************/
847 
848  LTC_SetTransferTimes(ltc_state);
849 
850  if (ltc_state->substate == LTC_INIT_STRING) {
851  LTC_SaveLastStates(ltc_state);
852  ltc_state->currentString = 0u;
853 
854  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface;
856  ltc_state->spiSeqEndPtr = ltc_state->ltcData.pSpiInterface + BS_NR_OF_STRINGS;
859  } else if (ltc_state->substate == LTC_ENTRY_INITIALIZATION) {
860  LTC_SaveLastStates(ltc_state);
861 
862  ltc_state->muxmeas_seqptr[ltc_state->currentString] = ltc_mux_seq.seqptr;
863  ltc_state->muxmeas_nr_end[ltc_state->currentString] = ltc_mux_seq.nr_of_steps;
864  ltc_state->muxmeas_seqendptr[ltc_state->currentString] =
865  ((LTC_MUX_CH_CFG_s *)ltc_mux_seq.seqptr) + ltc_mux_seq.nr_of_steps; /* last sequence + 1 */
866 
867  retVal = LTC_TransmitWakeUp(ltc_state->spiSeqPtr); /* Send dummy byte to wake up the daisy chain */
869  ltc_state,
870  retVal,
871  ltc_state->spiDiagErrorEntry,
878 
879  } else if (ltc_state->substate == LTC_RE_ENTRY_INITIALIZATION) {
880  LTC_SaveLastStates(ltc_state);
881  retVal =
882  LTC_TransmitWakeUp(ltc_state->spiSeqPtr); /* Send dummy byte again to wake up the daisy chain */
884  ltc_state,
885  retVal,
886  ltc_state->spiDiagErrorEntry,
893 
894  } else if (ltc_state->substate == LTC_START_INIT_INITIALIZATION) {
895  LTC_SaveLastStates(ltc_state);
896  ltc_state->check_spi_flag = STD_OK;
897  AFE_SetTransmitOngoing(ltc_state);
898  retVal = LTC_Init(
899  ltc_state->spiSeqPtr,
900  ltc_state->ltcData.txBuffer,
901  ltc_state->ltcData.rxBuffer,
902  ltc_state->ltcData.frameLength); /* Initialize main LTC loop */
903  ltc_state->lastsubstate = ltc_state->substate;
904  DIAG_CheckEvent(retVal, ltc_state->spiDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
906  ltc_state,
910 
911  } else if (ltc_state->substate == LTC_CHECK_INITIALIZATION) {
912  /* Read values written in config register, currently unused */
913  LTC_SaveLastStates(ltc_state);
914  AFE_SetTransmitOngoing(ltc_state);
915  retVal = LTC_RX(
916  ltc_cmdRDCFG,
917  ltc_state->spiSeqPtr,
918  ltc_state->ltcData.txBuffer,
919  ltc_state->ltcData.rxBuffer,
920  ltc_state->ltcData.frameLength); /* Read config register */
922  ltc_state,
926 
927  } else if (ltc_state->substate == LTC_EXIT_INITIALIZATION) {
928  LTC_SaveLastStates(ltc_state);
929  ++ltc_state->spiSeqPtr;
930  ++ltc_state->currentString;
931  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
934  } else {
937  }
938  }
939  break;
940 
941  /****************************INITIALIZED*************************************/
943  LTC_SaveLastStates(ltc_state);
945  break;
946 
947  /****************************START MEASUREMENT*******************************/
949 
952 
953  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface;
955  ltc_state->spiSeqEndPtr = ltc_state->ltcData.pSpiInterface + BS_NR_OF_STRINGS;
956  ltc_state->currentString = 0u;
957 
958  ltc_state->check_spi_flag = STD_NOT_OK;
959  retVal = LTC_StartVoltageMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
960 
962  ltc_state,
963  retVal,
964  ltc_state->spiDiagErrorEntry,
967  (ltc_state->commandTransferTime +
968  LTC_Get_MeasurementTCycle(ltc_state->adcMode, ltc_state->adcMeasCh)),
972 
973  break;
974 
975  /****************************START MEASUREMENT CONTINUE*******************************/
976  /* Do not reset SPI interface pointer */
978 
981 
982  ltc_state->check_spi_flag = STD_NOT_OK;
983  retVal = LTC_StartVoltageMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
984 
986  ltc_state,
987  retVal,
988  ltc_state->spiDiagErrorEntry,
991  (ltc_state->commandTransferTime +
992  LTC_Get_MeasurementTCycle(ltc_state->adcMode, ltc_state->adcMeasCh)),
996 
997  break;
998 
999  /****************************READ VOLTAGE************************************/
1001 
1003  ltc_state->check_spi_flag = STD_OK;
1004  AFE_SetTransmitOngoing(ltc_state);
1005  retVal = LTC_RX(
1006  ltc_cmdRDCVA,
1007  ltc_state->spiSeqPtr,
1008  ltc_state->ltcData.txBuffer,
1009  ltc_state->ltcData.rxBuffer,
1010  ltc_state->ltcData.frameLength);
1012  ltc_state,
1013  retVal,
1014  ltc_state->spiDiagErrorEntry,
1021  break;
1022 
1023  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_B_RDCVB_READVOLTAGE) {
1024  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1025  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1026  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 0, ltc_state->currentString);
1027 
1028  AFE_SetTransmitOngoing(ltc_state);
1029  retVal = LTC_RX(
1030  ltc_cmdRDCVB,
1031  ltc_state->spiSeqPtr,
1032  ltc_state->ltcData.txBuffer,
1033  ltc_state->ltcData.rxBuffer,
1034  ltc_state->ltcData.frameLength);
1036  ltc_state,
1037  retVal,
1038  ltc_state->spiDiagErrorEntry,
1045  break;
1046 
1047  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_C_RDCVC_READVOLTAGE) {
1048  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1049  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1050  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 1, ltc_state->currentString);
1051 
1052  AFE_SetTransmitOngoing(ltc_state);
1053  retVal = LTC_RX(
1054  ltc_cmdRDCVC,
1055  ltc_state->spiSeqPtr,
1056  ltc_state->ltcData.txBuffer,
1057  ltc_state->ltcData.rxBuffer,
1058  ltc_state->ltcData.frameLength);
1060  ltc_state,
1061  retVal,
1062  ltc_state->spiDiagErrorEntry,
1069  break;
1070 
1071  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_D_RDCVD_READVOLTAGE) {
1072  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1073  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1074  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 2, ltc_state->currentString);
1075 
1076  AFE_SetTransmitOngoing(ltc_state);
1077  retVal = LTC_RX(
1078  ltc_cmdRDCVD,
1079  ltc_state->spiSeqPtr,
1080  ltc_state->ltcData.txBuffer,
1081  ltc_state->ltcData.rxBuffer,
1082  ltc_state->ltcData.frameLength);
1083  if (BS_MAX_SUPPORTED_CELLS > 12) {
1085  ltc_state,
1086  retVal,
1087  ltc_state->spiDiagErrorEntry,
1094  } else {
1096  ltc_state,
1097  retVal,
1098  ltc_state->spiDiagErrorEntry,
1105  }
1106  break;
1107 
1108  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_E_RDCVE_READVOLTAGE) {
1109  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1110  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1111  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 3, ltc_state->currentString);
1112 
1113  AFE_SetTransmitOngoing(ltc_state);
1114  retVal = LTC_RX(
1115  ltc_cmdRDCVE,
1116  ltc_state->spiSeqPtr,
1117  ltc_state->ltcData.txBuffer,
1118  ltc_state->ltcData.rxBuffer,
1119  ltc_state->ltcData.frameLength);
1120  if (BS_MAX_SUPPORTED_CELLS > 15) {
1122  ltc_state,
1123  retVal,
1124  ltc_state->spiDiagErrorEntry,
1131  } else {
1133  ltc_state,
1134  retVal,
1135  ltc_state->spiDiagErrorEntry,
1142  }
1143  break;
1144 
1145  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_F_RDCVF_READVOLTAGE) {
1146  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1147  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1148  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 4, ltc_state->currentString);
1149 
1150  AFE_SetTransmitOngoing(ltc_state);
1151  retVal = LTC_RX(
1152  ltc_cmdRDCVF,
1153  ltc_state->spiSeqPtr,
1154  ltc_state->ltcData.txBuffer,
1155  ltc_state->ltcData.rxBuffer,
1156  ltc_state->ltcData.frameLength);
1158  ltc_state,
1159  retVal,
1160  ltc_state->spiDiagErrorEntry,
1167  break;
1168 
1169  } else if (ltc_state->substate == LTC_EXIT_READVOLTAGE) {
1170  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1171  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1172  if (BS_MAX_SUPPORTED_CELLS == 12) {
1173  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 3, ltc_state->currentString);
1174  } else if (BS_MAX_SUPPORTED_CELLS == 15) {
1175  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 4, ltc_state->currentString);
1176  } else if (BS_MAX_SUPPORTED_CELLS == 18) {
1177  LTC_SaveRXtoVoltagebuffer(ltc_state, ltc_state->ltcData.rxBuffer, 5, ltc_state->currentString);
1178  }
1179 
1180  /* Switch to different state if read voltage state is reused
1181  * e.g. open-wire check... */
1182  if (ltc_state->reusageMeasurementMode == LTC_NOT_REUSED) {
1183  LTC_SaveVoltages(ltc_state, ltc_state->currentString);
1185  ltc_state,
1189  } else if (ltc_state->reusageMeasurementMode == LTC_REUSE_READVOLT_FOR_ADOW_PUP) {
1191  ltc_state,
1195  } else if (ltc_state->reusageMeasurementMode == LTC_REUSE_READVOLT_FOR_ADOW_PDOWN) {
1197  ltc_state,
1201  }
1202  ltc_state->check_spi_flag = STD_NOT_OK;
1203  }
1204  break;
1205 
1206  /****************************MULTIPLEXED MEASUREMENT CONFIGURATION***********/
1208 
1211 
1212  if (ltc_state->substate == LTC_STATEMACH_MUXCONFIGURATION_INIT) {
1213  ltc_state->adcMode = LTC_GPIO_MEASUREMENT_MODE;
1215 
1216  if (ltc_state->muxmeas_seqptr[ltc_state->currentString] >=
1217  ltc_state->muxmeas_seqendptr[ltc_state->currentString]) {
1218  /* last step of sequence reached (or no sequence configured) */
1219 
1220  ltc_state->muxmeas_seqptr[ltc_state->currentString] = ltc_mux_seq.seqptr;
1221  ltc_state->muxmeas_nr_end[ltc_state->currentString] = ltc_mux_seq.nr_of_steps;
1222  ltc_state->muxmeas_seqendptr[ltc_state->currentString] =
1223  ((LTC_MUX_CH_CFG_s *)ltc_mux_seq.seqptr) + ltc_mux_seq.nr_of_steps; /* last sequence + 1 */
1224 
1225  LTC_SaveTemperatures(ltc_state, ltc_state->currentString);
1226  }
1227 
1228  ltc_state->check_spi_flag = STD_OK;
1229  AFE_SetTransmitOngoing(ltc_state);
1230  retVal = LTC_SetMuxChannel(
1231  ltc_state->spiSeqPtr,
1232  ltc_state->ltcData.txBuffer,
1233  ltc_state->ltcData.rxBuffer,
1234  ltc_state->ltcData.frameLength,
1235  ltc_state->muxmeas_seqptr[ltc_state->currentString]->muxID, /* mux */
1236  ltc_state->muxmeas_seqptr[ltc_state->currentString]->muxCh /* channel */);
1237  if (retVal != STD_OK) {
1238  DIAG_Handler(
1240  ++ltc_state->muxmeas_seqptr[ltc_state->currentString];
1242  ltc_state,
1246  } else {
1247  DIAG_Handler(
1248  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1250  ltc_state,
1254  }
1255  break;
1256 
1257  } else if (ltc_state->substate == LTC_SEND_CLOCK_STCOMM_MUXMEASUREMENT_CONFIG) {
1258  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1259  DIAG_Handler(
1261  } else {
1262  DIAG_Handler(
1263  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1264  }
1265 
1266  AFE_SetTransmitOngoing(ltc_state);
1267  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
1268  if (LTC_GOTO_MUX_CHECK == true) {
1270  ltc_state,
1271  retVal,
1272  ltc_state->spiDiagErrorEntry,
1279  ;
1280  } else {
1282  ltc_state,
1283  retVal,
1284  ltc_state->spiDiagErrorEntry,
1291  }
1292  break;
1293 
1295  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1296  DIAG_Handler(
1298  } else {
1299  DIAG_Handler(
1300  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1301  }
1302 
1303  AFE_SetTransmitOngoing(ltc_state);
1304  retVal = LTC_RX(
1305  ltc_cmdRDCOMM,
1306  ltc_state->spiSeqPtr,
1307  ltc_state->ltcData.txBuffer,
1308  ltc_state->ltcData.rxBuffer,
1309  ltc_state->ltcData.frameLength);
1311  ltc_state,
1312  retVal,
1313  ltc_state->spiDiagErrorEntry,
1320  break;
1321 
1323  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1324  DIAG_Handler(
1326  } else {
1327  DIAG_Handler(
1328  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1329  }
1330 
1331  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1332  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1333 
1334  /* if CRC OK: check multiplexer answer on i2C bus */
1335  retVal = LTC_I2CCheckACK(
1336  ltc_state,
1337  ltc_state->ltcData.rxBuffer,
1338  ltc_state->muxmeas_seqptr[ltc_state->currentString]->muxID,
1339  ltc_state->currentString);
1340  DIAG_CheckEvent(retVal, ltc_state->muxDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1343  break;
1344 
1345  } else if (ltc_state->substate == LTC_STATEMACH_MUXMEASUREMENT) {
1346  if (ltc_state->muxmeas_seqptr[ltc_state->currentString]->muxCh == 0xFF) {
1347  /* actual multiplexer is switched off, so do not make a measurement and follow up with next step (mux configuration) */
1348  ++ltc_state
1349  ->muxmeas_seqptr[ltc_state->currentString]; /* go further with next step of sequence
1350  ltc_state.numberOfMeasuredMux not decremented, this does not count as a measurement */
1352  break;
1353  } else {
1354  if (LTC_GOTO_MUX_CHECK == false) {
1355  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1356  DIAG_Handler(
1357  ltc_state->spiDiagErrorEntry,
1359  DIAG_STRING,
1360  ltc_state->currentString);
1361  } else {
1362  DIAG_Handler(
1363  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1364  }
1365  }
1366 
1367  ltc_state->check_spi_flag = STD_NOT_OK;
1368  /* user multiplexer type -> connected to GPIO2! */
1369  if ((ltc_state->muxmeas_seqptr[ltc_state->currentString]->muxID == 1) ||
1370  (ltc_state->muxmeas_seqptr[ltc_state->currentString]->muxID == 2)) {
1371  retVal = LTC_StartGPIOMeasurement(
1372  ltc_state->spiSeqPtr, ltc_state->adcMode, LTC_ADCMEAS_SINGLECHANNEL_GPIO2);
1373  } else {
1374  retVal = LTC_StartGPIOMeasurement(
1375  ltc_state->spiSeqPtr, ltc_state->adcMode, LTC_ADCMEAS_SINGLECHANNEL_GPIO1);
1376  }
1377  }
1379  ltc_state,
1380  retVal,
1381  ltc_state->spiDiagErrorEntry,
1384  (ltc_state->commandTransferTime +
1386  ltc_state->adcMode, LTC_ADCMEAS_SINGLECHANNEL_GPIO2)), /* wait, ADAX-Command */
1390  break;
1391 
1392  } else if (ltc_state->substate == LTC_STATEMACH_READMUXMEASUREMENT) {
1393  ltc_state->check_spi_flag = STD_OK;
1394 
1395  AFE_SetTransmitOngoing(ltc_state);
1396  retVal = LTC_RX(
1397  ltc_cmdRDAUXA,
1398  ltc_state->spiSeqPtr,
1399  ltc_state->ltcData.txBuffer,
1400  ltc_state->ltcData.rxBuffer,
1401  ltc_state->ltcData.frameLength);
1403  ltc_state,
1404  retVal,
1405  ltc_state->spiDiagErrorEntry,
1412  break;
1413 
1414  } else if (ltc_state->substate == LTC_STATEMACH_STOREMUXMEASUREMENT) {
1415  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1416  DIAG_Handler(
1418  } else {
1419  DIAG_Handler(
1420  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1421  }
1422 
1423  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1424  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1426  ltc_state,
1427  ltc_state->ltcData.rxBuffer,
1428  ltc_state->muxmeas_seqptr[ltc_state->currentString],
1429  ltc_state->currentString);
1430 
1431  ++ltc_state->muxmeas_seqptr[ltc_state->currentString];
1432 
1435  break;
1436  }
1437 
1438  break;
1439 
1440  /****************************END OF MEASUREMENT CYCLE************************/
1442 
1443  if (ltc_state->balance_control_done == STD_OK) {
1444  if (LTC_IsFirstMeasurementCycleFinished(ltc_state) == false) {
1446  }
1447  statereq = LTC_TransferStateRequest(ltc_state, &tmpbusID, &tmpadcMode, &tmpadcMeasCh);
1448  if (statereq.request == LTC_STATE_USER_IO_WRITE_REQUEST) {
1450  ltc_state,
1454  ltc_state->balance_control_done = STD_NOT_OK;
1455  } else if (statereq.request == LTC_STATE_USER_IO_READ_REQUEST) {
1457  ltc_state,
1461  ltc_state->balance_control_done = STD_NOT_OK;
1462  } else if (statereq.request == LTC_STATE_USER_IO_WRITE_REQUEST_TI) {
1464  ltc_state,
1468  ltc_state->balance_control_done = STD_NOT_OK;
1469  } else if (statereq.request == LTC_STATE_USER_IO_READ_REQUEST_TI) {
1471  ltc_state,
1475  ltc_state->balance_control_done = STD_NOT_OK;
1476  } else if (statereq.request == LTC_STATE_EEPROM_READ_REQUEST) {
1479  } else if (statereq.request == LTC_STATE_EEPROM_WRITE_REQUEST) {
1482  ltc_state->balance_control_done = STD_NOT_OK;
1483  } else if (statereq.request == LTC_STATE_TEMP_SENS_READ_REQUEST) {
1486  ltc_state->balance_control_done = STD_NOT_OK;
1487  } else if (statereq.request == LTC_STATEMACH_BALANCEFEEDBACK_REQUEST) {
1490  ltc_state->balance_control_done = STD_NOT_OK;
1491  } else if (statereq.request == LTC_STATE_OPENWIRE_CHECK_REQUEST) {
1493  ltc_state,
1497  /* Send ADOW command with PUP two times */
1499  ltc_state->balance_control_done = STD_NOT_OK;
1500  } else {
1502  ltc_state,
1506  ltc_state->balance_control_done = STD_NOT_OK;
1507  }
1508  } else {
1511  }
1512 
1513  break;
1514 
1515  /****************************BALANCE CONTROL*********************************/
1517 
1518  if (ltc_state->substate == LTC_CONFIG_BALANCECONTROL) {
1519  ltc_state->check_spi_flag = STD_OK;
1520  AFE_SetTransmitOngoing(ltc_state);
1521  retVal = LTC_BalanceControl(
1522  ltc_state,
1523  ltc_state->spiSeqPtr,
1524  ltc_state->ltcData.txBuffer,
1525  ltc_state->ltcData.rxBuffer,
1526  ltc_state->ltcData.frameLength,
1527  0u,
1528  ltc_state->currentString);
1530  ltc_state,
1531  retVal,
1532  ltc_state->spiDiagErrorEntry,
1539  break;
1540 
1541  } else if (ltc_state->substate == LTC_CONFIG2_BALANCECONTROL) {
1542  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1543  DIAG_Handler(
1545  } else {
1546  DIAG_Handler(
1547  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1548  }
1549 
1550  if (BS_NR_OF_CELLS_PER_MODULE > 12) {
1551  AFE_SetTransmitOngoing(ltc_state);
1552  retVal = LTC_BalanceControl(
1553  ltc_state,
1554  ltc_state->spiSeqPtr,
1555  ltc_state->ltcData.txBuffer,
1556  ltc_state->ltcData.rxBuffer,
1557  ltc_state->ltcData.frameLength,
1558  1u,
1559  ltc_state->currentString);
1561  ltc_state,
1562  retVal,
1563  ltc_state->spiDiagErrorEntry,
1570  } else {
1571  /* 12 cells, balancing control finished */
1572  ltc_state->check_spi_flag = STD_NOT_OK;
1573  ++ltc_state->spiSeqPtr;
1574  ++ltc_state->currentString;
1575  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
1576  ltc_state->balance_control_done = STD_OK;
1578  } else {
1581  }
1582  }
1583 
1584  break;
1585 
1586  } else if (ltc_state->substate == LTC_CONFIG2_BALANCECONTROL_END) {
1587  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1588  DIAG_Handler(
1590  } else {
1591  DIAG_Handler(
1592  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1593  }
1594  /* More than 12 cells, balancing control finished */
1595  ltc_state->check_spi_flag = STD_NOT_OK;
1596  ++ltc_state->spiSeqPtr;
1597  ++ltc_state->currentString;
1598  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
1599  ltc_state->balance_control_done = STD_OK;
1601  } else {
1604  }
1605 
1606  break;
1607  }
1608  break;
1609 
1610  /****************************START MEASUREMENT*******************************/
1612 
1613  ltc_state->adcMode = LTC_GPIO_MEASUREMENT_MODE;
1615 
1616  ltc_state->check_spi_flag = STD_NOT_OK;
1617  retVal = LTC_StartGPIOMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
1619  ltc_state,
1620  retVal,
1621  ltc_state->spiDiagErrorEntry,
1624  (ltc_state->commandTransferTime +
1625  LTC_Get_MeasurementTCycle(ltc_state->adcMode, ltc_state->adcMeasCh)),
1627  LTC_ENTRY,
1628  LTC_STATEMACH_SHORTTIME); /* TODO: @koffel here same state is kept if error occurs */
1629  break;
1630 
1631  /****************************READ ALL GPIO VOLTAGE************************************/
1633 
1634  if (ltc_state->substate == LTC_READ_AUXILIARY_REGISTER_A_RDAUXA) {
1635  ltc_state->check_spi_flag = STD_OK;
1636  AFE_SetTransmitOngoing(ltc_state);
1637  retVal = LTC_RX(
1638  ltc_cmdRDAUXA,
1639  ltc_state->spiSeqPtr,
1640  ltc_state->ltcData.txBuffer,
1641  ltc_state->ltcData.rxBuffer,
1642  ltc_state->ltcData.frameLength);
1644  ltc_state,
1645  retVal,
1646  ltc_state->spiDiagErrorEntry,
1653  break;
1654 
1655  } else if (ltc_state->substate == LTC_READ_AUXILIARY_REGISTER_B_RDAUXB) {
1656  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1657  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1658  LTC_SaveRXtoGPIOBuffer(ltc_state, ltc_state->ltcData.rxBuffer, 0, ltc_state->currentString);
1659 
1660  AFE_SetTransmitOngoing(ltc_state);
1661  retVal = LTC_RX(
1662  ltc_cmdRDAUXB,
1663  ltc_state->spiSeqPtr,
1664  ltc_state->ltcData.txBuffer,
1665  ltc_state->ltcData.rxBuffer,
1666  ltc_state->ltcData.frameLength);
1667 
1668  if (BS_MAX_SUPPORTED_CELLS > 12) {
1670  ltc_state,
1671  retVal,
1672  ltc_state->spiDiagErrorEntry,
1679  } else {
1681  ltc_state,
1682  retVal,
1683  ltc_state->spiDiagErrorEntry,
1690  }
1691  break;
1692 
1693  } else if (ltc_state->substate == LTC_READ_AUXILIARY_REGISTER_C_RDAUXC) {
1694  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1695  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1696  LTC_SaveRXtoGPIOBuffer(ltc_state, ltc_state->ltcData.rxBuffer, 1, ltc_state->currentString);
1697 
1698  AFE_SetTransmitOngoing(ltc_state);
1699  retVal = LTC_RX(
1700  ltc_cmdRDAUXC,
1701  ltc_state->spiSeqPtr,
1702  ltc_state->ltcData.txBuffer,
1703  ltc_state->ltcData.rxBuffer,
1704  ltc_state->ltcData.frameLength);
1706  ltc_state,
1707  retVal,
1708  ltc_state->spiDiagErrorEntry,
1715  break;
1716 
1717  } else if (ltc_state->substate == LTC_READ_AUXILIARY_REGISTER_D_RDAUXD) {
1718  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1719  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1720  LTC_SaveRXtoGPIOBuffer(ltc_state, ltc_state->ltcData.rxBuffer, 2, ltc_state->currentString);
1721 
1722  AFE_SetTransmitOngoing(ltc_state);
1723  retVal = LTC_RX(
1724  ltc_cmdRDAUXD,
1725  ltc_state->spiSeqPtr,
1726  ltc_state->ltcData.txBuffer,
1727  ltc_state->ltcData.rxBuffer,
1728  ltc_state->ltcData.frameLength);
1730  ltc_state,
1731  retVal,
1732  ltc_state->spiDiagErrorEntry,
1739  break;
1740 
1741  } else if (ltc_state->substate == LTC_EXIT_READAUXILIARY_ALLGPIOS) {
1742  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1743  DIAG_CheckEvent(retVal, ltc_state->pecDiagErrorEntry, DIAG_STRING, ltc_state->currentString);
1744 
1745  if (BS_MAX_SUPPORTED_CELLS == 12) {
1746  LTC_SaveRXtoGPIOBuffer(ltc_state, ltc_state->ltcData.rxBuffer, 1, ltc_state->currentString);
1747  } else if (BS_MAX_SUPPORTED_CELLS > 12) {
1748  LTC_SaveRXtoGPIOBuffer(ltc_state, ltc_state->ltcData.rxBuffer, 3, ltc_state->currentString);
1749  }
1750 
1751  LTC_SaveAllGPIOMeasurement(ltc_state);
1752 
1755  }
1756 
1757  break;
1758 
1759  /****************************BALANCE FEEDBACK*********************************/
1761 
1762  ltc_state->adcMode = LTC_GPIO_MEASUREMENT_MODE;
1764 
1765  if (ltc_state->substate == LTC_ENTRY) {
1766  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
1767  ltc_state->adcMode = LTC_ADCMODE_NORMAL_DCP0;
1769 
1770  ltc_state->check_spi_flag = STD_NOT_OK;
1771  retVal = LTC_StartGPIOMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
1773  ltc_state,
1774  retVal,
1775  ltc_state->spiDiagErrorEntry,
1778  (ltc_state->commandDataTransferTime +
1779  LTC_Get_MeasurementTCycle(ltc_state->adcMode, ltc_state->adcMeasCh)),
1783  break;
1784 
1785  } else if (ltc_state->substate == LTC_READ_FEEDBACK_BALANCECONTROL) {
1786  ltc_state->check_spi_flag = STD_OK;
1787  AFE_SetTransmitOngoing(ltc_state);
1788  retVal = LTC_RX(
1789  ltc_cmdRDAUXA,
1790  ltc_state->spiSeqPtr,
1791  ltc_state->ltcData.txBuffer,
1792  ltc_state->ltcData.rxBuffer,
1793  ltc_state->ltcData.frameLength); /* read AUXA register */
1795  ltc_state,
1796  retVal,
1797  ltc_state->spiDiagErrorEntry,
1804 
1805  } else if (ltc_state->substate == LTC_SAVE_FEEDBACK_BALANCECONTROL) {
1806  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1807  DIAG_Handler(
1810  break;
1811  } else {
1812  DIAG_Handler(
1813  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1814  }
1815 
1816  if (LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString) != STD_OK) {
1817  DIAG_Handler(
1819  } else {
1820  DIAG_Handler(
1821  ltc_state->pecDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1822  LTC_SaveBalancingFeedback(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1823  }
1825  break;
1826  }
1827  break;
1828 
1829  /****************************BOARD TEMPERATURE SENSOR*********************************/
1831 
1832  if (ltc_state->substate == LTC_TEMP_SENS_SEND_DATA1) {
1833  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
1834  ltc_state->check_spi_flag = STD_OK;
1835  AFE_SetTransmitOngoing(ltc_state);
1836  retVal = LTC_Send_I2C_Command(
1837  ltc_state->spiSeqPtr,
1838  ltc_state->ltcData.txBuffer,
1839  ltc_state->ltcData.rxBuffer,
1840  ltc_state->ltcData.frameLength,
1842 
1843  if (retVal != STD_OK) {
1844  DIAG_Handler(
1846  ++ltc_state->muxmeas_seqptr[ltc_state->requestedString];
1848  } else {
1849  DIAG_Handler(
1850  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1852  ltc_state,
1856  }
1857 
1858  break;
1859 
1860  } else if (ltc_state->substate == LTC_TEMP_SENS_SEND_CLOCK_STCOMM1) {
1861  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1862  DIAG_Handler(
1865  break;
1866  } else {
1867  DIAG_Handler(
1868  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1869  }
1870 
1871  AFE_SetTransmitOngoing(ltc_state);
1872  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
1874  ltc_state,
1875  retVal,
1876  ltc_state->spiDiagErrorEntry,
1883  break;
1884 
1885  } else if (ltc_state->substate == LTC_TEMP_SENS_READ_DATA1) {
1886  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1887  DIAG_Handler(
1890  break;
1891  } else {
1892  DIAG_Handler(
1893  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1894  }
1895 
1896  AFE_SetTransmitOngoing(ltc_state);
1897  retVal = LTC_Send_I2C_Command(
1898  ltc_state->spiSeqPtr,
1899  ltc_state->ltcData.txBuffer,
1900  ltc_state->ltcData.rxBuffer,
1901  ltc_state->ltcData.frameLength,
1903 
1904  if (retVal != STD_OK) {
1905  DIAG_Handler(
1907  ++ltc_state->muxmeas_seqptr[ltc_state->requestedString];
1909  } else {
1910  DIAG_Handler(
1911  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1913  ltc_state,
1917  }
1918 
1919  break;
1920 
1921  } else if (ltc_state->substate == LTC_TEMP_SENS_SEND_CLOCK_STCOMM2) {
1922  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1923  DIAG_Handler(
1926  break;
1927  } else {
1928  DIAG_Handler(
1929  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1930  }
1931 
1932  AFE_SetTransmitOngoing(ltc_state);
1933  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
1935  ltc_state,
1936  retVal,
1937  ltc_state->spiDiagErrorEntry,
1944  break;
1946  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1947  DIAG_Handler(
1950  break;
1951  } else {
1952  DIAG_Handler(
1953  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1954  }
1955 
1956  AFE_SetTransmitOngoing(ltc_state);
1957  retVal = LTC_RX(
1958  ltc_cmdRDCOMM,
1959  ltc_state->spiSeqPtr,
1960  ltc_state->ltcData.txBuffer,
1961  ltc_state->ltcData.rxBuffer,
1962  ltc_state->ltcData.frameLength);
1964  ltc_state,
1965  retVal,
1966  ltc_state->spiDiagErrorEntry,
1973  break;
1974 
1975  } else if (ltc_state->substate == LTC_TEMP_SENS_SAVE_TEMP) {
1976  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
1977  DIAG_Handler(
1980  break;
1981  } else {
1982  DIAG_Handler(
1983  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1984  }
1985 
1986  if (LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString) != STD_OK) {
1987  DIAG_Handler(
1989  } else {
1990  DIAG_Handler(
1991  ltc_state->pecDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
1992  LTC_TempSensSaveTemp(ltc_state, ltc_state->ltcData.rxBuffer);
1993  }
1994 
1996  break;
1997  }
1998  break;
1999 
2000  /****************************WRITE TO PORT EXPANDER IO***********/
2002 
2003  if (ltc_state->substate == LTC_USER_IO_SET_OUTPUT_REGISTER) {
2004  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2005  ltc_state->check_spi_flag = STD_OK;
2006  AFE_SetTransmitOngoing(ltc_state);
2007  retVal = LTC_SetPortExpander(
2008  ltc_state,
2009  ltc_state->spiSeqPtr,
2010  ltc_state->ltcData.txBuffer,
2011  ltc_state->ltcData.rxBuffer,
2012  ltc_state->ltcData.frameLength);
2013 
2014  if (retVal != STD_OK) {
2015  DIAG_Handler(
2017  ++ltc_state->muxmeas_seqptr[ltc_state->requestedString];
2019  } else {
2020  DIAG_Handler(
2021  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2023  ltc_state,
2027  }
2028  break;
2029 
2030  } else if (ltc_state->substate == LTC_SEND_CLOCK_STCOMM_MUXMEASUREMENT_CONFIG) {
2031  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2032  DIAG_Handler(
2035  break;
2036  } else {
2037  DIAG_Handler(
2038  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2039  }
2040 
2041  ltc_state->check_spi_flag = STD_NOT_OK;
2042  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2044  ltc_state,
2045  retVal,
2046  ltc_state->spiDiagErrorEntry,
2048  LTC_ENTRY,
2049  ltc_state->gpioClocksTransferTime,
2051  LTC_ENTRY,
2053  break;
2054  }
2055  break;
2056 
2057  /****************************READ FROM PORT EXPANDER IO***********/
2059 
2060  if (ltc_state->substate == LTC_USER_IO_READ_INPUT_REGISTER) {
2061  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2062  ltc_state->check_spi_flag = STD_OK;
2063  AFE_SetTransmitOngoing(ltc_state);
2064  retVal = LTC_Send_I2C_Command(
2065  ltc_state->spiSeqPtr,
2066  ltc_state->ltcData.txBuffer,
2067  ltc_state->ltcData.rxBuffer,
2068  ltc_state->ltcData.frameLength,
2070 
2071  if (retVal != STD_OK) {
2072  DIAG_Handler(
2074  ++ltc_state->muxmeas_seqptr[ltc_state->requestedString];
2076  } else {
2077  DIAG_Handler(
2078  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2080  ltc_state,
2084  }
2085 
2086  break;
2087 
2088  } else if (ltc_state->substate == LTC_USER_IO_SEND_CLOCK_STCOMM) {
2089  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2090  DIAG_Handler(
2093  break;
2094  } else {
2095  DIAG_Handler(
2096  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2097  }
2098 
2099  ltc_state->check_spi_flag = STD_NOT_OK;
2100  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2102  ltc_state,
2103  retVal,
2104  ltc_state->spiDiagErrorEntry,
2107  ltc_state->gpioClocksTransferTime,
2111  break;
2112 
2113  } else if (ltc_state->substate == LTC_USER_IO_READ_I2C_TRANSMISSION_RESULT_RDCOMM) {
2114  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2115  DIAG_Handler(
2118  break;
2119  } else {
2120  DIAG_Handler(
2121  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2122  }
2123 
2124  AFE_SetTransmitOngoing(ltc_state);
2125  retVal = LTC_RX(
2126  ltc_cmdRDCOMM,
2127  ltc_state->spiSeqPtr,
2128  ltc_state->ltcData.txBuffer,
2129  ltc_state->ltcData.rxBuffer,
2130  ltc_state->ltcData.frameLength);
2132  ltc_state,
2133  retVal,
2134  ltc_state->spiDiagErrorEntry,
2141  break;
2142 
2143  } else if (ltc_state->substate == LTC_USER_IO_SAVE_DATA) {
2144  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2145  DIAG_Handler(
2148  break;
2149  } else {
2150  DIAG_Handler(
2151  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2152  }
2153 
2154  if (LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString) != STD_OK) {
2155  DIAG_Handler(
2157  } else {
2158  DIAG_Handler(
2159  ltc_state->pecDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2160  LTC_PortExpanderSaveValues(ltc_state, ltc_state->ltcData.rxBuffer);
2161  }
2162 
2164  break;
2165  }
2166 
2167  break;
2168 
2169  /****************************WRITE TO TI PORT EXPANDER IO***********/
2171 
2172  if (ltc_state->substate == LTC_USER_IO_SET_DIRECTION_REGISTER_TI) {
2173  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2174  ltc_state->check_spi_flag = STD_OK;
2175  AFE_SetTransmitOngoing(ltc_state);
2177  ltc_state,
2178  ltc_state->spiSeqPtr,
2179  ltc_state->ltcData.txBuffer,
2180  ltc_state->ltcData.rxBuffer,
2181  ltc_state->ltcData.frameLength,
2184  ltc_state,
2185  retVal,
2186  ltc_state->spiDiagErrorEntry,
2191  LTC_ENTRY,
2193  break;
2194 
2195  } else if (ltc_state->substate == LTC_USER_IO_SEND_CLOCK_STCOMM_TI) {
2196  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2197  DIAG_Handler(
2200  break;
2201 
2202  } else {
2203  DIAG_Handler(
2204  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2205  }
2206 
2207  ltc_state->check_spi_flag = STD_NOT_OK;
2208  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2210  ltc_state,
2211  retVal,
2212  ltc_state->spiDiagErrorEntry,
2215  ltc_state->gpioClocksTransferTime,
2217  LTC_ENTRY,
2219  break;
2220 
2221  } else if (ltc_state->substate == LTC_USER_IO_SET_OUTPUT_REGISTER_TI) {
2222  ltc_state->check_spi_flag = STD_OK;
2223  AFE_SetTransmitOngoing(ltc_state);
2225  ltc_state,
2226  ltc_state->spiSeqPtr,
2227  ltc_state->ltcData.txBuffer,
2228  ltc_state->ltcData.rxBuffer,
2229  ltc_state->ltcData.frameLength);
2231  ltc_state,
2232  retVal,
2233  ltc_state->spiDiagErrorEntry,
2238  LTC_ENTRY,
2240  break;
2241 
2243  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2244  DIAG_Handler(
2247  break;
2248  } else {
2249  DIAG_Handler(
2250  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2251  }
2252 
2253  ltc_state->check_spi_flag = STD_NOT_OK;
2254  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2256  ltc_state,
2257  retVal,
2258  ltc_state->spiDiagErrorEntry,
2260  LTC_ENTRY,
2261  ltc_state->gpioClocksTransferTime,
2263  LTC_ENTRY,
2265  break;
2266  }
2267  break;
2268 
2269  /****************************READ TI PORT EXPANDER IO***********/
2271 
2272  if (ltc_state->substate == LTC_USER_IO_SET_DIRECTION_REGISTER_TI) {
2273  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2274  ltc_state->check_spi_flag = STD_OK;
2275  AFE_SetTransmitOngoing(ltc_state);
2277  ltc_state,
2278  ltc_state->spiSeqPtr,
2279  ltc_state->ltcData.txBuffer,
2280  ltc_state->ltcData.rxBuffer,
2281  ltc_state->ltcData.frameLength,
2284  ltc_state,
2285  retVal,
2286  ltc_state->spiDiagErrorEntry,
2291  LTC_ENTRY,
2293  break;
2294 
2295  } else if (ltc_state->substate == LTC_USER_IO_SEND_CLOCK_STCOMM_TI) {
2296  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2297  DIAG_Handler(
2300  break;
2301 
2302  } else {
2303  DIAG_Handler(
2304  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2305  }
2306 
2307  ltc_state->check_spi_flag = STD_NOT_OK;
2308  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2310  ltc_state,
2311  retVal,
2312  ltc_state->spiDiagErrorEntry,
2315  ltc_state->gpioClocksTransferTime,
2317  LTC_ENTRY,
2319  break;
2320 
2321  } else if (ltc_state->substate == LTC_USER_IO_READ_INPUT_REGISTER_TI_FIRST) {
2322  ltc_state->check_spi_flag = STD_OK;
2323  AFE_SetTransmitOngoing(ltc_state);
2325  ltc_state,
2326  ltc_state->spiSeqPtr,
2327  ltc_state->ltcData.txBuffer,
2328  ltc_state->ltcData.rxBuffer,
2329  ltc_state->ltcData.frameLength,
2330  0);
2332  ltc_state,
2333  retVal,
2334  ltc_state->spiDiagErrorEntry,
2339  LTC_ENTRY,
2341  break;
2342 
2344  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2345  DIAG_Handler(
2348  break;
2349  } else {
2350  DIAG_Handler(
2351  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2352  }
2353 
2354  ltc_state->check_spi_flag = STD_NOT_OK;
2355  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2357  ltc_state,
2358  retVal,
2359  ltc_state->spiDiagErrorEntry,
2362  ltc_state->gpioClocksTransferTime,
2364  LTC_ENTRY,
2366  break;
2367  } else if (ltc_state->substate == LTC_USER_IO_READ_INPUT_REGISTER_TI_SECOND) {
2368  ltc_state->check_spi_flag = STD_OK;
2369  AFE_SetTransmitOngoing(ltc_state);
2371  ltc_state,
2372  ltc_state->spiSeqPtr,
2373  ltc_state->ltcData.txBuffer,
2374  ltc_state->ltcData.rxBuffer,
2375  ltc_state->ltcData.frameLength,
2376  1);
2378  ltc_state,
2379  retVal,
2380  ltc_state->spiDiagErrorEntry,
2385  LTC_ENTRY,
2387  break;
2388 
2390  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2391  DIAG_Handler(
2394  break;
2395  } else {
2396  DIAG_Handler(
2397  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2398  }
2399 
2400  ltc_state->check_spi_flag = STD_NOT_OK;
2401  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2403  ltc_state,
2404  retVal,
2405  ltc_state->spiDiagErrorEntry,
2408  ltc_state->gpioClocksTransferTime,
2410  LTC_ENTRY,
2412  break;
2414  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2415  DIAG_Handler(
2418  break;
2419  } else {
2420  DIAG_Handler(
2421  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2422  }
2423 
2424  AFE_SetTransmitOngoing(ltc_state);
2425  retVal = LTC_RX(
2426  ltc_cmdRDCOMM,
2427  ltc_state->spiSeqPtr,
2428  ltc_state->ltcData.txBuffer,
2429  ltc_state->ltcData.rxBuffer,
2430  ltc_state->ltcData.frameLength);
2432  ltc_state,
2433  retVal,
2434  ltc_state->spiDiagErrorEntry,
2441  break;
2442 
2443  } else if (ltc_state->substate == LTC_USER_IO_SAVE_DATA_TI) {
2444  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2445  DIAG_Handler(
2448  break;
2449  } else {
2450  DIAG_Handler(
2451  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2452  }
2453 
2454  if (LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString) != STD_OK) {
2455  DIAG_Handler(
2457  } else {
2458  DIAG_Handler(
2459  ltc_state->pecDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2460  LTC_PortExpanderSaveValues_TI(ltc_state, ltc_state->ltcData.txBuffer);
2461  }
2462 
2464  break;
2465  }
2466 
2467  break;
2468 
2469  /****************************EEPROM READ*********************************/
2471 
2472  if (ltc_state->substate == LTC_EEPROM_READ_DATA1) {
2473  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2474  ltc_state->check_spi_flag = STD_OK;
2475  AFE_SetTransmitOngoing(ltc_state);
2476  retVal = LTC_SendEEPROMReadCommand(
2477  ltc_state,
2478  ltc_state->spiSeqPtr,
2479  ltc_state->ltcData.txBuffer,
2480  ltc_state->ltcData.rxBuffer,
2481  ltc_state->ltcData.frameLength,
2482  0);
2483 
2484  if (retVal != STD_OK) {
2485  DIAG_Handler(
2487  ++ltc_state->muxmeas_seqptr[ltc_state->requestedString];
2489  } else {
2490  DIAG_Handler(
2491  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2493  ltc_state,
2497  }
2498 
2499  break;
2500 
2501  } else if (ltc_state->substate == LTC_EEPROM_SEND_CLOCK_STCOMM1) {
2502  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2503  DIAG_Handler(
2506  break;
2507  } else {
2508  DIAG_Handler(
2509  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2510  }
2511 
2512  AFE_SetTransmitOngoing(ltc_state);
2513  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2515  ltc_state,
2516  retVal,
2517  ltc_state->spiDiagErrorEntry,
2524  break;
2525 
2526  } else if (ltc_state->substate == LTC_EEPROM_READ_DATA2) {
2527  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2528  DIAG_Handler(
2531  break;
2532  } else {
2533  DIAG_Handler(
2534  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2535  }
2536 
2537  AFE_SetTransmitOngoing(ltc_state);
2538  retVal = LTC_SendEEPROMReadCommand(
2539  ltc_state,
2540  ltc_state->spiSeqPtr,
2541  ltc_state->ltcData.txBuffer,
2542  ltc_state->ltcData.rxBuffer,
2543  ltc_state->ltcData.frameLength,
2544  1);
2546  ltc_state,
2547  retVal,
2548  ltc_state->spiDiagErrorEntry,
2555  break;
2556 
2557  } else if (ltc_state->substate == LTC_EEPROM_SEND_CLOCK_STCOMM2) {
2558  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2559  DIAG_Handler(
2562  break;
2563  } else {
2564  DIAG_Handler(
2565  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2566  }
2567 
2568  AFE_SetTransmitOngoing(ltc_state);
2569  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2571  ltc_state,
2572  retVal,
2573  ltc_state->spiDiagErrorEntry,
2580  break;
2581  } else if (ltc_state->substate == LTC_EEPROM_READ_I2C_TRANSMISSION_RESULT_RDCOMM) {
2582  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2583  DIAG_Handler(
2586  break;
2587  } else {
2588  DIAG_Handler(
2589  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2590  }
2591 
2592  AFE_SetTransmitOngoing(ltc_state);
2593  retVal = LTC_RX(
2594  ltc_cmdRDCOMM,
2595  ltc_state->spiSeqPtr,
2596  ltc_state->ltcData.txBuffer,
2597  ltc_state->ltcData.rxBuffer,
2598  ltc_state->ltcData.frameLength);
2600  ltc_state,
2601  retVal,
2602  ltc_state->spiDiagErrorEntry,
2609  break;
2610 
2611  } else if (ltc_state->substate == LTC_EEPROM_SAVE_READ) {
2612  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2613  DIAG_Handler(
2616  break;
2617  } else {
2618  DIAG_Handler(
2619  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2620  }
2621 
2622  if (LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString) != STD_OK) {
2623  DIAG_Handler(
2625  } else {
2626  DIAG_Handler(
2627  ltc_state->pecDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2628  LTC_EEPROMSaveReadValue(ltc_state, ltc_state->ltcData.rxBuffer);
2629  }
2631  break;
2632  }
2633 
2634  break;
2635 
2636  /****************************EEPROM READ*********************************/
2638 
2639  if (ltc_state->substate == LTC_EEPROM_WRITE_DATA1) {
2640  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2641  ltc_state->check_spi_flag = STD_OK;
2642  AFE_SetTransmitOngoing(ltc_state);
2643  retVal = LTC_SendEEPROMWriteCommand(
2644  ltc_state,
2645  ltc_state->spiSeqPtr,
2646  ltc_state->ltcData.txBuffer,
2647  ltc_state->ltcData.rxBuffer,
2648  ltc_state->ltcData.frameLength,
2649  0);
2650 
2651  if (retVal != STD_OK) {
2652  DIAG_Handler(
2654  ++ltc_state->muxmeas_seqptr[ltc_state->requestedString];
2656  } else {
2657  DIAG_Handler(
2658  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2660  ltc_state,
2664  }
2665 
2666  break;
2667 
2668  } else if (ltc_state->substate == LTC_EEPROM_SEND_CLOCK_STCOMM3) {
2669  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2670  DIAG_Handler(
2673  break;
2674  } else {
2675  DIAG_Handler(
2676  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2677  }
2678 
2679  AFE_SetTransmitOngoing(ltc_state);
2680  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2682  ltc_state,
2683  retVal,
2684  ltc_state->spiDiagErrorEntry,
2691  break;
2692 
2693  } else if (ltc_state->substate == LTC_EEPROM_WRITE_DATA2) {
2694  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2695  DIAG_Handler(
2698  break;
2699  } else {
2700  DIAG_Handler(
2701  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2702  }
2703 
2704  AFE_SetTransmitOngoing(ltc_state);
2705  retVal = LTC_SendEEPROMWriteCommand(
2706  ltc_state,
2707  ltc_state->spiSeqPtr,
2708  ltc_state->ltcData.txBuffer,
2709  ltc_state->ltcData.rxBuffer,
2710  ltc_state->ltcData.frameLength,
2711  1);
2713  ltc_state,
2714  retVal,
2715  ltc_state->spiDiagErrorEntry,
2722  break;
2723 
2724  } else if (ltc_state->substate == LTC_EEPROM_SEND_CLOCK_STCOMM4) {
2725  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2726  DIAG_Handler(
2729  break;
2730  } else {
2731  DIAG_Handler(
2732  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2733  }
2734 
2735  AFE_SetTransmitOngoing(ltc_state);
2736  retVal = LTC_I2CClock(ltc_state->spiSeqPtr);
2738  ltc_state,
2739  retVal,
2740  ltc_state->spiDiagErrorEntry,
2747  break;
2748  } else if (ltc_state->substate == LTC_EEPROM_FINISHED) {
2749  if ((ltc_state->timer == 0) && (AFE_IsTransmitOngoing(ltc_state) == true)) {
2750  DIAG_Handler(
2753  break;
2754  } else {
2755  DIAG_Handler(
2756  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2757  }
2759  break;
2760  }
2761 
2762  break;
2763 
2764  /**************************OPEN-WIRE CHECK*******************************/
2766  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + ltc_state->requestedString;
2767  /* This is necessary because the state machine will go through read voltage measurement registers */
2768  ltc_state->currentString = ltc_state->requestedString;
2770  /* Run ADOW command with PUP = 1 */
2771  ltc_state->adcMode = LTC_OW_MEASUREMENT_MODE;
2772  ltc_state->check_spi_flag = STD_NOT_OK;
2773 
2774  retVal = LTC_StartOpenWireMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, 1);
2775  if (retVal == STD_OK) {
2776  DIAG_Handler(
2777  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2779  ltc_state,
2782  (ltc_state->commandDataTransferTime +
2784  ltc_state->resendCommandCounter--;
2785 
2786  /* Check how many retries are left */
2787  if (ltc_state->resendCommandCounter == 0) {
2788  /* Switch to read voltage state to read cell voltages */
2790  ltc_state,
2793  (ltc_state->commandDataTransferTime +
2795  /* Reuse read voltage register */
2797  }
2798  } else {
2799  DIAG_Handler(
2803  }
2804  } else if (ltc_state->substate == LTC_READ_VOLTAGES_PULLUP_OPENWIRE_CHECK) {
2805  /* Previous state: Read voltage -> information stored in voltage buffer */
2807 
2808  /* Copy data from voltage struct into open-wire struct */
2809  for (uint16_t i = 0u; i < BS_NR_OF_BAT_CELLS; i++) {
2810  ltc_state->ltcData.openWireDetection->openWirePup[ltc_state->requestedString][i] =
2811  ltc_state->ltcData.cellVoltage->cellVoltage_mV[ltc_state->requestedString][i];
2812  }
2813 
2814  /* Set number of ADOW retries - send ADOW command with pull-down two times */
2817  ltc_state,
2821 
2822  } else if (ltc_state->substate == LTC_REQUEST_PULLDOWN_CURRENT_OPENWIRE_CHECK) {
2823  /* Run ADOW command with PUP = 0 */
2824  ltc_state->adcMode = LTC_OW_MEASUREMENT_MODE;
2825  ltc_state->check_spi_flag = STD_NOT_OK;
2826 
2827  retVal = LTC_StartOpenWireMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, 0);
2828  if (retVal == STD_OK) {
2829  DIAG_Handler(
2830  ltc_state->spiDiagErrorEntry, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
2832  ltc_state,
2835  (ltc_state->commandDataTransferTime +
2837  ltc_state->resendCommandCounter--;
2838 
2839  /* Check how many retries are left */
2840  if (ltc_state->resendCommandCounter == 0) {
2841  /* Switch to read voltage state to read cell voltages */
2843  ltc_state,
2846  (ltc_state->commandDataTransferTime +
2848  /* Reuse read voltage register */
2850  }
2851  } else {
2852  DIAG_Handler(
2856  }
2857  } else if (ltc_state->substate == LTC_READ_VOLTAGES_PULLDOWN_OPENWIRE_CHECK) {
2858  /* Previous state: Read voltage -> information stored in voltage buffer */
2860 
2861  /* Copy data from voltage struct into open-wire struct */
2862  for (uint16_t i = 0u; i < BS_NR_OF_BAT_CELLS; i++) {
2863  ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][i] =
2864  ltc_state->ltcData.cellVoltage->cellVoltage_mV[ltc_state->requestedString][i];
2865  }
2868 
2869  } else if (ltc_state->substate == LTC_PERFORM_OPENWIRE_CHECK) {
2870  /* Perform actual open-wire check */
2871  for (uint8_t m = 0; m < BS_NR_OF_MODULES; m++) {
2872  /* Open-wire at C0: cell_pup(0) == 0 */
2873  if (ltc_state->ltcData.openWireDetection
2874  ->openWirePup[ltc_state->requestedString][0 + (m * BS_NR_OF_CELLS_PER_MODULE)] == 0u) {
2875  ltc_state->ltcData.openWire
2876  ->openwire[ltc_state->requestedString][0 + (m * (BS_NR_OF_CELLS_PER_MODULE))] = 1u;
2877  }
2878  /* Open-wire at Cmax: cell_pdown(BS_NR_OF_CELLS_PER_MODULE-1) == 0 */
2879  if (ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][(
2880  (BS_NR_OF_CELLS_PER_MODULE - 1) + (m * BS_NR_OF_CELLS_PER_MODULE))] == 0u) {
2881  ltc_state->ltcData.openWire
2882  ->openwire[ltc_state->requestedString]
2884  }
2885  }
2886 
2887  /* Take difference between pull-up and pull-down measurement */
2888  for (uint16_t i = 1u; i < BS_NR_OF_BAT_CELLS; i++) {
2889  ltc_state->ltcData.openWireDetection->openWireDelta[ltc_state->requestedString][i] =
2890  ltc_state->ltcData.openWireDetection->openWirePup[ltc_state->requestedString][i] -
2891  ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][i];
2892  }
2893 
2894  /* Open-wire at C(N): delta cell(n+1) < -400mV */
2895  for (uint8_t m = 0u; m < BS_NR_OF_MODULES; m++) {
2896  for (uint8_t c = 1u; c < (BS_NR_OF_CELLS_PER_MODULE - 1); c++) {
2897  if (ltc_state->ltcData.openWireDetection
2898  ->openWireDelta[ltc_state->requestedString][c + (m * BS_NR_OF_CELLS_PER_MODULE)] <
2900  ltc_state->ltcData.openWire
2901  ->openwire[ltc_state->requestedString][c + (m * BS_NR_OF_CELLS_PER_MODULE)] = 1;
2902  }
2903  }
2904  }
2905 
2906  /* Write database entry */
2907  DATA_WRITE_DATA(ltc_state->ltcData.openWire);
2908  /* Start new measurement cycle */
2910  }
2911  break;
2912 
2913  /****************************DEFAULT**************************/
2914  default:
2915  /* invalid state */
2917  break;
2918  }
2919 
2920  ltc_state->triggerentry--; /* reentrance counter */
2921  } /* continueFunction */
2922 }
2923 
2924 /**
2925  * @brief saves the multiplexer values read from the LTC daisy-chain.
2926  *
2927  * After a voltage measurement was initiated on GPIO 1 to read the currently selected
2928  * multiplexer voltage, the results is read via SPI from the daisy-chain.
2929  * This function is called to store the result from the transmission in a buffer.
2930  *
2931  * @param ltc_state state of the ltc state machine
2932  * @param pRxBuff receive buffer
2933  * @param muxseqptr pointer to the multiplexer sequence, which configures the currently selected multiplexer ID and channel
2934  * @param stringNumber string addressed
2935  *
2936  */
2938  LTC_STATE_s *ltc_state,
2939  uint16_t *pRxBuff,
2940  LTC_MUX_CH_CFG_s *muxseqptr,
2941  uint8_t stringNumber) {
2942  uint16_t val_ui = 0;
2943  int16_t temperature_ddegC = 0;
2944  uint8_t sensor_idx = 0;
2945  uint8_t ch_idx = 0;
2946  uint16_t buffer_LSB = 0;
2947  uint16_t buffer_MSB = 0;
2948 
2949  /* pointer to measurement Sequence of Mux- and Channel-Configurations (1,0xFF)...(3,0xFF),(0,1),...(0,7)) */
2950  /* Channel 0xFF means that the multiplexer is deactivated, therefore no measurement will be made and saved*/
2951  if (muxseqptr->muxCh != 0xFF) {
2952  /* user multiplexer type -> connected to GPIO2! */
2953  if ((muxseqptr->muxID == 1) || (muxseqptr->muxID == 2)) {
2954  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
2955  if (muxseqptr->muxID == 1) {
2956  ch_idx = 0 + muxseqptr->muxCh; /* channel index 0..7 */
2957  } else {
2958  ch_idx = 8 + muxseqptr->muxCh; /* channel index 8..15 */
2959  }
2960 
2961  if (ch_idx < (2u * 8u)) {
2962  val_ui = *((uint16_t *)(&pRxBuff[6u + (1u * i * 8u)])); /* raw values, all mux on all LTCs */
2963  /* ltc_user_mux.value[i*8*2+ch_idx] = (uint16_t)(((float)(val_ui))*100e-6f*1000.0f); */ /* Unit -> in V -> in mV */
2964  }
2965  }
2966  } else {
2967  /* temperature multiplexer type -> connected to GPIO1! */
2968  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
2969  buffer_MSB = pRxBuff[4u + (i * 8u) + 1u];
2970  buffer_LSB = pRxBuff[4u + (i * 8u)];
2971  val_ui = buffer_LSB | (buffer_MSB << 8);
2972  /* val_ui = *((uint16_t *)(&pRxBuff[4+i*8])); */
2973  /* GPIO voltage in 100uV -> * 0.1 ---- conversion to mV */
2974  temperature_ddegC = LTC_Convert_MuxVoltages_to_Temperatures(val_ui / 10u); /* unit: deci &deg;C */
2975  sensor_idx = ltc_muxsensortemperatur_cfg[muxseqptr->muxCh];
2976  /* wrong configuration! */
2977  if (sensor_idx >= BS_NR_OF_TEMP_SENSORS_PER_MODULE) {
2979  }
2980  /* Set bitmask for valid flags */
2981 
2982  /* Check LTC PEC error */
2983  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] == true) {
2984  /* Reset invalid flag */
2985  ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][i] =
2986  ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][i] &
2987  (~(1u << sensor_idx));
2988 
2989  ltc_state->ltcData.cellTemperature
2990  ->cellTemperature_ddegC[stringNumber][(i * (BS_NR_OF_TEMP_SENSORS_PER_MODULE)) + sensor_idx] =
2991  temperature_ddegC;
2992  } else {
2993  /* Set invalid flag */
2994  ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][i] |= (1u << sensor_idx);
2995  }
2996  }
2997  }
2998  }
2999 }
3000 
3001 /**
3002  * @brief saves the voltage values read from the LTC daisy-chain.
3003  *
3004  * After a voltage measurement was initiated to measure the voltages of the cells,
3005  * the result is read via SPI from the daisy-chain.
3006  * There are 6 register to read _(A,B,C,D,E,F) to get all cell voltages.
3007  * Only one register can be read at a time.
3008  * This function is called to store the result from the transmission in a buffer.
3009  *
3010  * @param ltc_state state of the ltc state machine
3011  * @param pRxBuff receive buffer
3012  * @param registerSet voltage register that was read (voltage register A,B,C,D,E or F)
3013  * @param stringNumber string addressed
3014  *
3015  */
3017  LTC_STATE_s *ltc_state,
3018  uint16_t *pRxBuff,
3019  uint8_t registerSet,
3020  uint8_t stringNumber) {
3021  uint16_t cellOffset = 0;
3022  uint16_t voltage_index = 0;
3023  uint16_t val_ui = 0;
3024  uint16_t voltage = 0;
3025  uint32_t bitmask = 0;
3026  uint16_t buffer_LSB = 0;
3027  uint16_t buffer_MSB = 0;
3028  bool continueFunction = true;
3029 
3030  if (registerSet == 0u) {
3031  /* RDCVA command -> voltage register group A */
3032  cellOffset = 0;
3033  } else if (registerSet == 1u) {
3034  /* RDCVB command -> voltage register group B */
3035  cellOffset = 3;
3036  } else if (registerSet == 2u) {
3037  /* RDCVC command -> voltage register group C */
3038  cellOffset = 6;
3039  } else if (registerSet == 3u) {
3040  /* RDCVD command -> voltage register group D */
3041  cellOffset = 9;
3042  } else if (registerSet == 4u) {
3043  /* RDCVD command -> voltage register group E (only for 15 and 18 cell version) */
3044  cellOffset = 12;
3045  } else if (registerSet == 5u) {
3046  /* RDCVD command -> voltage register group F (only for 18 cell version) */
3047  cellOffset = 15;
3048  } else {
3049  continueFunction = false;
3050  }
3051 
3052  if (continueFunction == true) {
3053  /* Calculate bitmask for valid flags */
3054  bitmask |= 0x07u << cellOffset; /* 0x07: three voltages in each register */
3055 
3056  /* reinitialize index counter at begin of cycle */
3057  if (cellOffset == 0u) {
3058  (ltc_state->ltcData.usedCellIndex[stringNumber]) = 0;
3059  }
3060 
3061  /* Retrieve data without command and CRC*/
3062  for (uint16_t m = 0u; m < LTC_N_LTC; m++) {
3063  uint16_t incrementations = 0u;
3064 
3065  /* parse all three voltages (3 * 2bytes) contained in one register */
3066  for (uint8_t c = 0u; c < 3u; c++) {
3067  /* index considering maximum number of cells */
3068  voltage_index = c + cellOffset;
3069 
3070  if (ltc_voltage_input_used[voltage_index] == 1u) {
3071  buffer_MSB = pRxBuff[4u + (2u * c) + (m * 8u) + 1u];
3072  buffer_LSB = pRxBuff[4u + (2u * c) + (m * 8u)];
3073  val_ui = buffer_LSB | (buffer_MSB << 8u);
3074  /* val_ui = *((uint16_t *)(&pRxBuff[4+2*j+i*8])); */
3075  voltage = ((val_ui)) * 100e-6f * 1000.0f; /* Unit V -> in mV */
3076 
3077  /* Check PEC for every LTC in the daisy-chain */
3078  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][m] == true) {
3079  ltc_state->ltcData.cellVoltage
3080  ->cellVoltage_mV[stringNumber]
3081  [(ltc_state->ltcData.usedCellIndex[stringNumber]) +
3082  (m * BS_NR_OF_CELLS_PER_MODULE)] = voltage;
3083  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
3084  ltc_state->ltcData.cellVoltage
3085  ->invalidCellVoltage[stringNumber][(m / LTC_NUMBER_OF_LTC_PER_MODULE)] &= bitmask;
3086  } else {
3087  /* PEC_valid == false: Invalidate only flags of this voltage register */
3088  ltc_state->ltcData.cellVoltage
3089  ->invalidCellVoltage[stringNumber][(m / LTC_NUMBER_OF_LTC_PER_MODULE)] |= bitmask;
3090  }
3091 
3092  (ltc_state->ltcData.usedCellIndex[stringNumber])++;
3093  incrementations++;
3094 
3095  if ((ltc_state->ltcData.usedCellIndex[stringNumber]) > BS_NR_OF_CELLS_PER_MODULE) {
3096  break;
3097  }
3098  }
3099  }
3100 
3101  /* Restore start value for next module in the daisy-chain. Only
3102  * decrement used cell index if current module is not the last
3103  * module in the daisy-chain. */
3104  if ((m + 1u) < LTC_N_LTC) {
3105  (ltc_state->ltcData.usedCellIndex[stringNumber]) -= incrementations;
3106  }
3107  }
3108  }
3109 }
3110 
3111 /**
3112  * @brief saves the GPIO voltage values read from the LTC daisy-chain.
3113  *
3114  * After a voltage measurement was initiated to measure the voltages on all GPIOs,
3115  * the result is read via SPI from the daisy-chain. In order to read the result of all GPIO measurements,
3116  * it is necessary to read auxiliary register A and B.
3117  * Only one register can be read at a time.
3118  * This function is called to store the result from the transmission in a buffer.
3119  *
3120  * @param ltc_state state of the ltc state machine
3121  * @param pRxBuff receive buffer
3122  * @param registerSet voltage register that was read (auxiliary register A, B, C or D)
3123  * @param stringNumber string addressed
3124  *
3125  */
3127  LTC_STATE_s *ltc_state,
3128  uint16_t *pRxBuff,
3129  uint8_t registerSet,
3130  uint8_t stringNumber) {
3131  uint8_t i_offset = 0;
3132  uint32_t bitmask = 0;
3133  uint16_t buffer_LSB = 0;
3134  uint16_t buffer_MSB = 0;
3135 
3136  if (registerSet == 0u) {
3137  /* RDAUXA command -> GPIO register group A */
3138  i_offset = 0;
3139  bitmask = 0x07u << i_offset; /* 0x07: three temperatures in this register */
3140  /* Retrieve data without command and CRC*/
3141  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3142  /* Check if PEC is valid */
3143  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] == true) {
3144  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
3145  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] &= bitmask;
3146  /* values received in 100uV -> divide by 10 to convert to mV */
3147  buffer_MSB = pRxBuff[4u + (i * 8u) + 1u];
3148  buffer_LSB = pRxBuff[4u + (i * 8u)];
3149  ltc_state->ltcData.allGpioVoltages
3150  ->gpioVoltages_mV[stringNumber][0u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3151  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3152  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][0 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[4+i*8]))/10; */
3153  buffer_MSB = pRxBuff[6u + (i * 8u) + 1u];
3154  buffer_LSB = pRxBuff[6u + (i * 8u)];
3155  ltc_state->ltcData.allGpioVoltages
3156  ->gpioVoltages_mV[stringNumber][1u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3157  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3158  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][1 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[6+i*8]))/10; */
3159  buffer_MSB = pRxBuff[8u + (i * 8u) + 1u];
3160  buffer_LSB = pRxBuff[8u + (i * 8u)];
3161  ltc_state->ltcData.allGpioVoltages
3162  ->gpioVoltages_mV[stringNumber][2u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3163  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3164  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][2 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[8+i*8]))/10; */
3165  } else {
3166  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] |= bitmask;
3167  }
3168  }
3169  } else if (registerSet == 1u) {
3170  /* RDAUXB command -> GPIO register group B */
3171  i_offset = 3;
3172  bitmask = 0x03u << i_offset; /* 0x03: two temperatures in this register */
3173  /* Retrieve data without command and CRC*/
3174  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3175  /* Check if PEC is valid */
3176  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] == true) {
3177  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
3178  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] &= bitmask;
3179  /* values received in 100uV -> divide by 10 to convert to mV */
3180  buffer_MSB = pRxBuff[4u + (i * 8u) + 1u];
3181  buffer_LSB = pRxBuff[4u + (i * 8u)];
3182  ltc_state->ltcData.allGpioVoltages
3183  ->gpioVoltages_mV[stringNumber][0u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3184  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3185  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][0 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[4+i*8]))/10; */
3186  buffer_MSB = pRxBuff[6u + (i * 8u) + 1u];
3187  buffer_LSB = pRxBuff[6u + (i * 8u)];
3188  ltc_state->ltcData.allGpioVoltages
3189  ->gpioVoltages_mV[stringNumber][1u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3190  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3191  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][1 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[6+i*8]))/10; */
3192  } else {
3193  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] |= bitmask;
3194  }
3195  }
3196  } else if (registerSet == 2u) {
3197  /* RDAUXC command -> GPIO register group C, for 18 cell version */
3198  i_offset = 5;
3199  bitmask = 0x07u << i_offset; /* 0x07: three temperatures in this register */
3200  /* Retrieve data without command and CRC*/
3201  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3202  /* Check if PEC is valid */
3203  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] == true) {
3204  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
3205  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] &= bitmask;
3206  /* values received in 100uV -> divide by 10 to convert to mV */
3207  buffer_MSB = pRxBuff[4u + (i * 8u) + 1u];
3208  buffer_LSB = pRxBuff[4u + (i * 8u)];
3209  ltc_state->ltcData.allGpioVoltages
3210  ->gpioVoltages_mV[stringNumber][0u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3211  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3212  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][0 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[4+i*8]))/10; */
3213  buffer_MSB = pRxBuff[6u + (i * 8u) + 1u];
3214  buffer_LSB = pRxBuff[6u + (i * 8u)];
3215  ltc_state->ltcData.allGpioVoltages
3216  ->gpioVoltages_mV[stringNumber][1u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3217  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3218  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][1 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[6+i*8]))/10; */
3219  buffer_MSB = pRxBuff[8u + (i * 8u) + 1u];
3220  buffer_LSB = pRxBuff[8u + (i * 8u)];
3221  ltc_state->ltcData.allGpioVoltages
3222  ->gpioVoltages_mV[stringNumber][2u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3223  ((buffer_LSB | (buffer_MSB << 8u))) / 10u;
3224  /* ltc_state->ltcData.allGpioVoltages->gpiovoltage[stringNumber][2 + i_offset + BS_NR_OF_GPIOS_PER_MODULE*i]= *((uint16_t *)(&pRxBuff[8+i*8]))/10; */
3225  } else {
3226  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] |= bitmask;
3227  }
3228  }
3229  } else if (registerSet == 3u) {
3230  /* RDAUXD command -> GPIO register group D, for 18 cell version */
3231  i_offset = 8;
3232  bitmask = 0x01u << i_offset; /* 0x01: one temperature in this register */
3233  /* Retrieve data without command and CRC*/
3234  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3235  /* Check if PEC is valid */
3236  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] == true) {
3237  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
3238  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] &= bitmask;
3239  /* values received in 100uV -> divide by 10 to convert to mV */
3240  ltc_state->ltcData.allGpioVoltages
3241  ->gpioVoltages_mV[stringNumber][0u + i_offset + (BS_NR_OF_GPIOS_PER_MODULE * i)] =
3242  *((uint16_t *)(&pRxBuff[4u + (i * 8u)])) / 10u;
3243  } else {
3244  ltc_state->ltcData.allGpioVoltages->invalidGpioVoltages[stringNumber][i] |= bitmask;
3245  }
3246  }
3247  } else {
3248  ; /* Nothing to do */
3249  }
3250 }
3251 
3252 /**
3253  * @brief checks if the multiplexers acknowledged transmission.
3254  *
3255  * The RDCOMM command can be used to read the answer of the multiplexers to a
3256  * I2C transmission.
3257  * This function determines if the communication with the multiplexers was
3258  * successful or not.
3259  * The array error table is updated to locate the multiplexers that did not
3260  * acknowledge transmission.
3261  *
3262  * @param ltc_state state of the ltc state machine
3263  * @param pRxBuff receive buffer
3264  * @param mux multiplexer to be addressed (multiplexer ID)
3265  * @param stringNumber string addressed
3266  *
3267  * @return muxError STD_OK is there was no error, STD_NOT_OK if there was errors
3268  */
3269 static STD_RETURN_TYPE_e LTC_I2CCheckACK(LTC_STATE_s *ltc_state, uint16_t *pRxBuff, uint8_t mux, uint8_t stringNumber) {
3270  STD_RETURN_TYPE_e muxError = STD_OK;
3271 
3272  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
3273  if ((pRxBuff[4u + 1u + (LTC_NUMBER_OF_LTC_PER_MODULE * i * 8u)] & 0x0Fu) != 0x07u) { /* ACK = 0xX7 */
3274  if (LTC_DISCARD_MUX_CHECK == false) {
3275  if (mux == 0u) {
3276  ltc_state->ltcData.errorTable->mux0[stringNumber][i] = 1;
3277  }
3278  if (mux == 1u) {
3279  ltc_state->ltcData.errorTable->mux1[stringNumber][i] = 1;
3280  }
3281  if (mux == 2u) {
3282  ltc_state->ltcData.errorTable->mux2[stringNumber][i] = 1;
3283  }
3284  if (mux == 3u) {
3285  ltc_state->ltcData.errorTable->mux3[stringNumber][i] = 1;
3286  }
3287  }
3288  muxError = STD_NOT_OK;
3289  } else {
3290  if (mux == 0u) {
3291  ltc_state->ltcData.errorTable->mux0[stringNumber][i] = 0;
3292  }
3293  if (mux == 1u) {
3294  ltc_state->ltcData.errorTable->mux1[stringNumber][i] = 0;
3295  }
3296  if (mux == 2u) {
3297  ltc_state->ltcData.errorTable->mux2[stringNumber][i] = 0;
3298  }
3299  if (mux == 3u) {
3300  ltc_state->ltcData.errorTable->mux3[stringNumber][i] = 0;
3301  }
3302  }
3303  }
3304 
3305  if (LTC_DISCARD_MUX_CHECK == true) {
3306  muxError = STD_OK;
3307  }
3308  return muxError;
3309 }
3310 
3311 /**
3312  * @brief initialize the daisy-chain.
3313  *
3314  * To initialize the LTC6804 daisy-chain, a dummy byte (0x00) is sent.
3315  *
3316  * @param pSpiInterface pointer to SPI configuration
3317  * @param pTxBuff transmit buffer
3318  * @param pRxBuff receive buffer
3319  * @param frameLength number of words to transmit
3320  *
3321  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
3322  *
3323  */
3325  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3326  uint16_t *pTxBuff,
3327  uint16_t *pRxBuff,
3328  uint32_t frameLength) {
3329  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
3330 
3331  uint8_t PEC_Check[6];
3332  uint16_t PEC_result = 0;
3333 
3334  /* now construct the message to be sent: it contains the wanted data, PLUS the needed PECs */
3335  pTxBuff[0] = ltc_cmdWRCFG[0];
3336  pTxBuff[1] = ltc_cmdWRCFG[1];
3337  pTxBuff[2] = ltc_cmdWRCFG[2];
3338  pTxBuff[3] = ltc_cmdWRCFG[3];
3339 
3340  /* set REFON bit to 1 */
3341  /* data for the configuration */
3342  for (uint16_t i = 0u; i < LTC_N_LTC; i++) {
3343  /* FC = disable all pull-downs, REFON = 1, DTEN = 0, ADCOPT = 0 */
3344  pTxBuff[4u + (i * 8u)] = 0xFC;
3345  pTxBuff[5u + (i * 8u)] = 0x00;
3346  pTxBuff[6u + (i * 8u)] = 0x00;
3347  pTxBuff[7u + (i * 8u)] = 0x00;
3348  pTxBuff[8u + (i * 8u)] = 0x00;
3349  pTxBuff[9u + (i * 8u)] = 0x00;
3350 
3351  PEC_Check[0] = pTxBuff[4u + (i * 8u)];
3352  PEC_Check[1] = pTxBuff[5u + (i * 8u)];
3353  PEC_Check[2] = pTxBuff[6u + (i * 8u)];
3354  PEC_Check[3] = pTxBuff[7u + (i * 8u)];
3355  PEC_Check[4] = pTxBuff[8u + (i * 8u)];
3356  PEC_Check[5] = pTxBuff[9u + (i * 8u)];
3357 
3358  PEC_result = LTC_pec15_calc(6, PEC_Check);
3359  pTxBuff[10u + (i * 8u)] = (PEC_result >> 8u) & 0xFFu;
3360  pTxBuff[11u + (i * 8u)] = PEC_result & 0xFFu;
3361  } /* end for */
3362 
3363  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
3364 
3365  return retVal;
3366 }
3367 
3368 /**
3369  * @brief sets the balancing according to the control values read in the database.
3370  *
3371  * To set balancing for the cells, the corresponding bits have to be written in the configuration register.
3372  * The LTC driver only executes the balancing orders written by the BMS in the database.
3373  *
3374  * @param ltc_state state of the ltc state machine
3375  * @param pSpiInterface pointer to SPI configuration
3376  * @param pTxBuff transmit buffer
3377  * @param pRxBuff receive buffer
3378  * @param frameLength number of words to transmit
3379  * @param registerSet register Set, 0: cells 1 to 12 (WRCFG), 1: cells 13 to 15/18 (WRCFG2)
3380  * @param stringNumber string addressed
3381  *
3382  * @return STD_OK if dummy byte was sent correctly by SPI, STD_NOT_OK otherwise
3383  *
3384  */
3386  LTC_STATE_s *ltc_state,
3387  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3388  uint16_t *pTxBuff,
3389  uint16_t *pRxBuff,
3390  uint32_t frameLength,
3391  uint8_t registerSet,
3392  uint8_t stringNumber) {
3393  STD_RETURN_TYPE_e retVal = STD_OK;
3394 
3395  uint8_t PEC_Check[6];
3396  uint16_t PEC_result = 0;
3397 
3398  LTC_Get_BalancingControlValues(ltc_state);
3399 
3400  if (registerSet == 0u) { /* cells 1 to 12, WRCFG */
3401  pTxBuff[0] = ltc_cmdWRCFG[0];
3402  pTxBuff[1] = ltc_cmdWRCFG[1];
3403  pTxBuff[2] = ltc_cmdWRCFG[2];
3404  pTxBuff[3] = ltc_cmdWRCFG[3];
3405  for (uint16_t j = 0; j < BS_NR_OF_MODULES; j++) {
3406  const uint16_t i = BS_NR_OF_MODULES - j - 1u;
3407 
3408  /* FC = disable all pull-downs, REFON = 1 (reference always on), DTEN off, ADCOPT = 0 */
3409  pTxBuff[4u + (i * 8u)] = 0xFC;
3410  pTxBuff[5u + (i * 8u)] = 0x00;
3411  pTxBuff[6u + (i * 8u)] = 0x00;
3412  pTxBuff[7u + (i * 8u)] = 0x00;
3413  pTxBuff[8u + (i * 8u)] = 0x00;
3414  pTxBuff[9u + (i * 8u)] = 0x00;
3415 
3416  if (ltc_state->ltcData.balancingControl
3417  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 0u] == 1u) {
3418  pTxBuff[8u + (i * 8u)] |= 0x01u;
3419  }
3420  if (ltc_state->ltcData.balancingControl
3421  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 1u] == 1u) {
3422  pTxBuff[8u + (i * 8u)] |= 0x02u;
3423  }
3424  if (ltc_state->ltcData.balancingControl
3425  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 2u] == 1u) {
3426  pTxBuff[8u + (i * 8u)] |= 0x04u;
3427  }
3428  if (ltc_state->ltcData.balancingControl
3429  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 3u] == 1u) {
3430  pTxBuff[8u + (i * 8u)] |= 0x08u;
3431  }
3432  if (ltc_state->ltcData.balancingControl
3433  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 4u] == 1u) {
3434  pTxBuff[8u + (i * 8u)] |= 0x10u;
3435  }
3436  if (ltc_state->ltcData.balancingControl
3437  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 5u] == 1u) {
3438  pTxBuff[8u + (i * 8u)] |= 0x20u;
3439  }
3440  if (ltc_state->ltcData.balancingControl
3441  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 6u] == 1u) {
3442  pTxBuff[8u + (i * 8u)] |= 0x40u;
3443  }
3444  if (ltc_state->ltcData.balancingControl
3445  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 7u] == 1u) {
3446  pTxBuff[8u + (i * 8u)] |= 0x80u;
3447  }
3448  if (ltc_state->ltcData.balancingControl
3449  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 8u] == 1u) {
3450  pTxBuff[9u + (i * 8u)] |= 0x01u;
3451  }
3452  if (ltc_state->ltcData.balancingControl
3453  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 9u] == 1u) {
3454  pTxBuff[9u + (i * 8u)] |= 0x02u;
3455  }
3456  if (ltc_state->ltcData.balancingControl
3457  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 10u] == 1u) {
3458  pTxBuff[9u + (i * 8u)] |= 0x04u;
3459  }
3460  if (ltc_state->ltcData.balancingControl
3461  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 11u] == 1u) {
3462  pTxBuff[9u + (i * 8u)] |= 0x08u;
3463  }
3464 
3465  PEC_Check[0] = pTxBuff[4u + (i * 8u)];
3466  PEC_Check[1] = pTxBuff[5u + (i * 8u)];
3467  PEC_Check[2] = pTxBuff[6u + (i * 8u)];
3468  PEC_Check[3] = pTxBuff[7u + (i * 8u)];
3469  PEC_Check[4] = pTxBuff[8u + (i * 8u)];
3470  PEC_Check[5] = pTxBuff[9u + (i * 8u)];
3471 
3472  PEC_result = LTC_pec15_calc(6, PEC_Check);
3473  pTxBuff[10u + (i * 8u)] = (PEC_result >> 8u) & 0xFFu;
3474  pTxBuff[11u + (i * 8u)] = PEC_result & 0xFFu;
3475  }
3476  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
3477  } else if (registerSet == 1u) { /* cells 13 to 15/18 WRCFG2 */
3478  pTxBuff[0] = ltc_cmdWRCFG2[0];
3479  pTxBuff[1] = ltc_cmdWRCFG2[1];
3480  pTxBuff[2] = ltc_cmdWRCFG2[2];
3481  pTxBuff[3] = ltc_cmdWRCFG2[3];
3482  for (uint16_t j = 0; j < BS_NR_OF_MODULES; j++) {
3483  const uint16_t i = BS_NR_OF_MODULES - j - 1;
3484 
3485  /* 0x0F = disable pull-downs on GPIO6-9 */
3486  pTxBuff[4u + (i * 8u)] = 0x0F;
3487  pTxBuff[5u + (i * 8u)] = 0x00;
3488  pTxBuff[6u + (i * 8u)] = 0x00;
3489  pTxBuff[7u + (i * 8u)] = 0x00;
3490  pTxBuff[8u + (i * 8u)] = 0x00;
3491  pTxBuff[9u + (i * 8u)] = 0x00;
3492 
3493  if (ltc_state->ltcData.balancingControl
3494  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 12u] == 1u) {
3495  pTxBuff[4u + (i * 8u)] |= 0x10u;
3496  }
3497  if (ltc_state->ltcData.balancingControl
3498  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 13u] == 1u) {
3499  pTxBuff[4u + (i * 8u)] |= 0x20u;
3500  }
3501  if (ltc_state->ltcData.balancingControl
3502  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 14u] == 1u) {
3503  pTxBuff[4u + (i * 8u)] |= 0x40u;
3504  }
3505  if (BS_NR_OF_CELLS_PER_MODULE > 15u) {
3506  if (ltc_state->ltcData.balancingControl
3507  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 15u] == 1u) {
3508  pTxBuff[4u + (i * 8u)] |= 0x80u;
3509  }
3510  if (ltc_state->ltcData.balancingControl
3511  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 16u] == 1u) {
3512  pTxBuff[5u + (i * 8u)] |= 0x01u;
3513  }
3514  if (ltc_state->ltcData.balancingControl
3515  ->balancingState[stringNumber][(j * (BS_NR_OF_CELLS_PER_MODULE)) + 17u] == 1u) {
3516  pTxBuff[5u + (i * 8u)] |= 0x02u;
3517  }
3518  }
3519 
3520  PEC_Check[0] = pTxBuff[4u + (i * 8u)];
3521  PEC_Check[1] = pTxBuff[5u + (i * 8u)];
3522  PEC_Check[2] = pTxBuff[6u + (i * 8u)];
3523  PEC_Check[3] = pTxBuff[7u + (i * 8u)];
3524  PEC_Check[4] = pTxBuff[8u + (i * 8u)];
3525  PEC_Check[5] = pTxBuff[9u + (i * 8u)];
3526 
3527  PEC_result = LTC_pec15_calc(6, PEC_Check);
3528  pTxBuff[10u + (i * 8u)] = (PEC_result >> 8u) & 0xFFu;
3529  pTxBuff[11u + (i * 8u)] = PEC_result & 0xFFu;
3530  }
3531  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
3532  } else {
3533  retVal = STD_NOT_OK;
3534  }
3535  return retVal;
3536 }
3537 
3538 /**
3539  * @brief resets the error table.
3540  *
3541  * This function should be called during initialization or before starting a new measurement cycle
3542  *
3543  * @param ltc_state: state of the ltc state machine
3544  *
3545  */
3546 static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state) {
3547  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
3548  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3549  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = false;
3550  ltc_state->ltcData.errorTable->mux0[stringNumber][i] = 0;
3551  ltc_state->ltcData.errorTable->mux1[stringNumber][i] = 0;
3552  ltc_state->ltcData.errorTable->mux2[stringNumber][i] = 0;
3553  ltc_state->ltcData.errorTable->mux3[stringNumber][i] = 0;
3554  }
3555  }
3556 }
3557 
3558 /**
3559  * @brief brief missing
3560  *
3561  * Gets the measurement time needed by the LTC chip, depending on the measurement mode and the number of channels.
3562  * For all cell voltages or all 5 GPIOS, the measurement time is the same.
3563  * For 2 cell voltages or 1 GPIO, the measurement time is the same.
3564  * As a consequence, this function is used for cell voltage and for GPIO measurement.
3565  *
3566  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
3567  * @param adcMeasCh number of channels measured for GPIOS (one at a time for multiplexers or all five GPIOs)
3568  * or number of cell voltage measured (2 cells or all cells)
3569  *
3570  * @return retVal measurement time in ms
3571  */
3572 static uint16_t LTC_Get_MeasurementTCycle(LTC_ADCMODE_e adcMode, LTC_ADCMEAS_CHAN_e adcMeasCh) {
3573  uint16_t retVal = LTC_ADCMEAS_UNDEFINED; /* default */
3574 
3575  if (adcMeasCh == LTC_ADCMEAS_ALLCHANNEL_CELLS) {
3576  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3578  } else if ((adcMode == LTC_ADCMODE_NORMAL_DCP0) || (adcMode == LTC_ADCMODE_NORMAL_DCP1)) {
3580  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3582  }
3583  } else if (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_TWOCELLS) {
3584  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3586  } else if ((adcMode == LTC_ADCMODE_NORMAL_DCP0) || (adcMode == LTC_ADCMODE_NORMAL_DCP1)) {
3588  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3590  }
3591  } else if (adcMeasCh == LTC_ADCMEAS_ALLCHANNEL_GPIOS) {
3592  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3594  } else if ((adcMode == LTC_ADCMODE_NORMAL_DCP0) || (adcMode == LTC_ADCMODE_NORMAL_DCP1)) {
3596  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3598  }
3599  } else if (
3600  (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO1) || (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO2) ||
3601  (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO3) || (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO4) ||
3602  (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO5)) {
3603  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3605  } else if ((adcMode == LTC_ADCMODE_NORMAL_DCP0) || (adcMode == LTC_ADCMODE_NORMAL_DCP1)) {
3607  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3609  }
3610  } else {
3611  retVal = LTC_ADCMEAS_UNDEFINED;
3612  }
3613 
3614  return retVal;
3615 }
3616 
3617 /**
3618  * @brief tells the LTC daisy-chain to start measuring the voltage on all cells.
3619  *
3620  * This function sends an instruction to the daisy-chain via SPI, in order to start voltage measurement for all cells.
3621  *
3622  * @param pSpiInterface pointer to SPI configuration
3623  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
3624  * @param adcMeasCh number of cell voltage measured (2 cells or all cells)
3625  *
3626  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
3627  *
3628  */
3630  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3631  LTC_ADCMODE_e adcMode,
3632  LTC_ADCMEAS_CHAN_e adcMeasCh) {
3633  STD_RETURN_TYPE_e retVal = STD_OK;
3634 
3635  if (adcMeasCh == LTC_ADCMEAS_ALLCHANNEL_CELLS) {
3636  if (adcMode == LTC_ADCMODE_FAST_DCP0) {
3637  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_fast_DCP0);
3638  } else if (adcMode == LTC_ADCMODE_NORMAL_DCP0) {
3639  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_normal_DCP0);
3640  } else if (adcMode == LTC_ADCMODE_FILTERED_DCP0) {
3641  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_filtered_DCP0);
3642  } else if (adcMode == LTC_ADCMODE_FAST_DCP1) {
3643  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_fast_DCP1);
3644  } else if (adcMode == LTC_ADCMODE_NORMAL_DCP1) {
3645  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_normal_DCP1);
3646  } else if (adcMode == LTC_ADCMODE_FILTERED_DCP1) {
3647  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_filtered_DCP1);
3648  } else {
3649  retVal = STD_NOT_OK;
3650  }
3651  } else if (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_TWOCELLS) {
3652  if (adcMode == LTC_ADCMODE_FAST_DCP0) {
3653  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_fast_DCP0_twocells);
3654  } else {
3655  retVal = STD_NOT_OK;
3656  }
3657  } else {
3658  retVal = STD_NOT_OK;
3659  }
3660  return retVal;
3661 }
3662 
3663 /**
3664  * @brief tells LTC daisy-chain to start measuring the voltage on GPIOS.
3665  *
3666  * This function sends an instruction to the daisy-chain via SPI to start the measurement.
3667  *
3668  * @param pSpiInterface pointer to SPI configuration
3669  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
3670  * @param adcMeasCh number of channels measured for GPIOS (one at a time, typically when multiplexers are used, or all five GPIOs)
3671  *
3672  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
3673  *
3674  */
3676  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3677  LTC_ADCMODE_e adcMode,
3678  LTC_ADCMEAS_CHAN_e adcMeasCh) {
3679  STD_RETURN_TYPE_e retVal;
3680 
3681  if (adcMeasCh == LTC_ADCMEAS_ALLCHANNEL_GPIOS) {
3682  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3683  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_fast_ALLGPIOS);
3684  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3685  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_filtered_ALLGPIOS);
3686  } else {
3687  /*if (adcMode == LTC_ADCMODE_NORMAL_DCP0 || adcMode == LTC_ADCMODE_NORMAL_DCP1)*/
3688  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_normal_ALLGPIOS);
3689  }
3690  } else if (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO1) {
3691  /* Single Channel */
3692  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3693  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_fast_GPIO1);
3694  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3695  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_filtered_GPIO1);
3696  } else {
3697  /*if (adcMode == LTC_ADCMODE_NORMAL_DCP0 || adcMode == LTC_ADCMODE_NORMAL_DCP1)*/
3698 
3699  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_normal_GPIO1);
3700  }
3701  } else if (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO2) {
3702  /* Single Channel */
3703  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3704  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_fast_GPIO2);
3705  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3706  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_filtered_GPIO2);
3707  } else {
3708  /*if (adcMode == LTC_ADCMODE_NORMAL_DCP0 || adcMode == LTC_ADCMODE_NORMAL_DCP1)*/
3709 
3710  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_normal_GPIO2);
3711  }
3712  } else if (adcMeasCh == LTC_ADCMEAS_SINGLECHANNEL_GPIO3) {
3713  /* Single Channel */
3714  if ((adcMode == LTC_ADCMODE_FAST_DCP0) || (adcMode == LTC_ADCMODE_FAST_DCP1)) {
3715  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_fast_GPIO3);
3716  } else if ((adcMode == LTC_ADCMODE_FILTERED_DCP0) || (adcMode == LTC_ADCMODE_FILTERED_DCP1)) {
3717  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_filtered_GPIO3);
3718  } else {
3719  /*if (adcMode == LTC_ADCMODE_NORMAL_DCP0 || adcMode == LTC_ADCMODE_NORMAL_DCP1)*/
3720 
3721  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADAX_normal_GPIO3);
3722  }
3723  } else {
3724  retVal = STD_NOT_OK;
3725  }
3726 
3727  return retVal;
3728 }
3729 
3730 /**
3731  * @brief tells LTC daisy-chain to start measuring the voltage on GPIOS.
3732  *
3733  * This function sends an instruction to the daisy-chain via SPI to start the measurement.
3734  *
3735  * @param pSpiInterface pointer to SPI configuration
3736  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
3737  * @param PUP pull-up bit for pull-up or pull-down current (0: pull-down, 1: pull-up)
3738  *
3739  * @return retVal #STD_OK if command was sent correctly by SPI, #STD_NOT_OK otherwise
3740  *
3741  */
3743  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3744  LTC_ADCMODE_e adcMode,
3745  uint8_t PUP) {
3746  STD_RETURN_TYPE_e retval = STD_NOT_OK;
3747  if (PUP == 0u) {
3748  /* pull-down current */
3749  if (adcMode == LTC_ADCMODE_NORMAL_DCP0) {
3750  retval = LTC_TransmitCommand(pSpiInterface, ltc_BC_cmdADOW_PDOWN_normal_DCP0);
3751  } else if (adcMode == LTC_ADCMODE_FILTERED_DCP0) {
3753  } else {
3754  retval = STD_NOT_OK;
3755  }
3756  } else if (PUP == 1u) {
3757  /* pull-up current */
3758  if (adcMode == LTC_ADCMODE_NORMAL_DCP0) {
3759  retval = LTC_TransmitCommand(pSpiInterface, ltc_BC_cmdADOW_PUP_normal_DCP0);
3760  } else if (adcMode == LTC_ADCMODE_FILTERED_DCP0) {
3761  retval = LTC_TransmitCommand(pSpiInterface, ltc_BC_cmdADOW_PUP_filtered_DCP0);
3762  } else {
3763  retval = STD_NOT_OK;
3764  }
3765  }
3766  return retval;
3767 }
3768 
3769 /**
3770  * @brief checks if the data received from the daisy-chain is not corrupt.
3771  *
3772  * This function computes the PEC (CRC) from the data received by the daisy-chain.
3773  * It compares it with the PEC sent by the LTCs.
3774  * If there are errors, the array LTC_ErrorTable is updated to locate the LTCs in daisy-chain
3775  * that transmitted corrupt data.
3776  *
3777  * @param ltc_state state of the ltc state machine
3778  * @param DataBufferSPI_RX_with_PEC data obtained from the SPI transmission
3779  * @param stringNumber string addressed
3780  *
3781  * @return retVal STD_OK if PEC check is OK, STD_NOT_OK otherwise
3782  *
3783  */
3785  LTC_STATE_s *ltc_state,
3786  uint16_t *DataBufferSPI_RX_with_PEC,
3787  uint8_t stringNumber) {
3788  STD_RETURN_TYPE_e retVal = STD_OK;
3789  uint8_t PEC_TX[2];
3790  uint16_t PEC_result = 0;
3791  uint8_t PEC_Check[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3792 
3793  /* check all PECs and put data without command and PEC in DataBufferSPI_RX (easier to use) */
3794  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3795  PEC_Check[0] = DataBufferSPI_RX_with_PEC[4u + (i * 8u)];
3796  PEC_Check[1] = DataBufferSPI_RX_with_PEC[5u + (i * 8u)];
3797  PEC_Check[2] = DataBufferSPI_RX_with_PEC[6u + (i * 8u)];
3798  PEC_Check[3] = DataBufferSPI_RX_with_PEC[7u + (i * 8u)];
3799  PEC_Check[4] = DataBufferSPI_RX_with_PEC[8u + (i * 8u)];
3800  PEC_Check[5] = DataBufferSPI_RX_with_PEC[9u + (i * 8u)];
3801 
3802  PEC_result = LTC_pec15_calc(6, PEC_Check);
3803  PEC_TX[0] = (uint8_t)((PEC_result >> 8u) & 0xFFu);
3804  PEC_TX[1] = (uint8_t)(PEC_result & 0xFFu);
3805 
3806  /* if calculated PEC not equal to received PEC */
3807  if ((PEC_TX[0] != DataBufferSPI_RX_with_PEC[10u + (i * 8u)]) ||
3808  (PEC_TX[1] != DataBufferSPI_RX_with_PEC[11u + (i * 8u)])) {
3809  /* update error table of the corresponding LTC only if PEC check is activated */
3810  if (LTC_DISCARD_PEC == false) {
3811  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = false;
3812  retVal = STD_NOT_OK;
3813  } else {
3814  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = true;
3815  }
3816  } else {
3817  /* update error table of the corresponding LTC */
3818  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = true;
3819  }
3820  }
3821  return retVal;
3822 }
3823 
3824 /**
3825  * @brief send command to the LTC daisy-chain and receives data from the LTC daisy-chain.
3826  *
3827  * This is the core function to receive data from the LTC6804 daisy-chain.
3828  * A 2 byte command is sent with the corresponding PEC. Example: read configuration register (RDCFG).
3829  * Only command has to be set, the function calculates the PEC automatically.
3830  * The data send is:
3831  * 2 bytes (COMMAND) 2 bytes (PEC)
3832  * The data received is:
3833  * 6 bytes (LTC1) 2 bytes (PEC) + 6 bytes (LTC2) 2 bytes (PEC) + 6 bytes (LTC3) 2 bytes (PEC) + ... + 6 bytes (LTC{LTC_N_LTC}) 2 bytes (PEC)
3834  *
3835  * The function does not check the PECs. This has to be done elsewhere.
3836  *
3837  * @param Command command sent to the daisy-chain
3838  * @param pSpiInterface pointer to SPI configuration
3839  * @param pTxBuff transmit buffer
3840  * @param pRxBuff receive buffer
3841  * @param frameLength number of words to transmit
3842  *
3843  * @return statusSPI #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
3844  *
3845  */
3847  uint16_t *Command,
3848  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3849  uint16_t *pTxBuff,
3850  uint16_t *pRxBuff,
3851  uint32_t frameLength) {
3852  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
3853 
3854  /* DataBufferSPI_RX_with_PEC contains the data to receive.
3855  The transmission function checks the PECs.
3856  It constructs DataBufferSPI_RX, which contains the received data without PEC (easier to use). */
3857 
3858  for (uint16_t i = 0; i < LTC_N_BYTES_FOR_DATA_TRANSMISSION; i++) {
3859  pTxBuff[i] = 0x00;
3860  }
3861 
3862  pTxBuff[0] = Command[0];
3863  pTxBuff[1] = Command[1];
3864  pTxBuff[2] = Command[2];
3865  pTxBuff[3] = Command[3];
3866 
3867  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
3868 
3869  return retVal;
3870 }
3871 
3872 /**
3873  * @brief sends command and data to the LTC daisy-chain.
3874  *
3875  * This is the core function to transmit data to the LTC6804 daisy-chain.
3876  * The data sent is:
3877  * COMMAND + 6 bytes (LTC1) + 6 bytes (LTC2) + 6 bytes (LTC3) + ... + 6 bytes (LTC{LTC_N_LTC})
3878  * A 2 byte command is sent with the corresponding PEC. Example: write configuration register (WRCFG).
3879  * THe command has to be set and then the function calculates the PEC automatically.
3880  * The function calculates the needed PEC to send the data to the daisy-chain. The sent data has the format:
3881  * 2 byte-COMMAND (2 bytes PEC) + 6 bytes (LTC1) (2 bytes PEC) + 6 bytes (LTC2) (2 bytes PEC) + 6 bytes (LTC3) (2 bytes PEC) + ... + 6 bytes (LTC{LTC_N_LTC}) (2 bytes PEC)
3882  *
3883  * The function returns 0. The only way to check if the transmission was successful is to read the results of the write operation.
3884  * (example: read configuration register after writing to it)
3885  *
3886  * @param Command command sent to the daisy-chain
3887  * @param pSpiInterface pointer to SPI configuration
3888  * @param pTxBuff transmit buffer
3889  * @param pRxBuff receive buffer
3890  * @param frameLength number of words to transmit
3891  *
3892  * @return STD_OK if SPI transmission is OK, STD_NOT_OK otherwise
3893  *
3894  */
3896  uint16_t *Command,
3897  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3898  uint16_t *pTxBuff,
3899  uint16_t *pRxBuff,
3900  uint32_t frameLength) {
3901  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
3902 
3903  uint16_t PEC_result = 0;
3904  uint8_t PEC_Check[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
3905 
3906  pTxBuff[0] = Command[0];
3907  pTxBuff[1] = Command[1];
3908  pTxBuff[2] = Command[2];
3909  pTxBuff[3] = Command[3];
3910 
3911  /* Calculate PEC of all data (1 PEC value for 6 bytes) */
3912  for (uint16_t i = 0u; i < LTC_N_LTC; i++) {
3913  PEC_Check[0] = pTxBuff[4u + (i * 8u)];
3914  PEC_Check[1] = pTxBuff[5u + (i * 8u)];
3915  PEC_Check[2] = pTxBuff[6u + (i * 8u)];
3916  PEC_Check[3] = pTxBuff[7u + (i * 8u)];
3917  PEC_Check[4] = pTxBuff[8u + (i * 8u)];
3918  PEC_Check[5] = pTxBuff[9u + (i * 8u)];
3919 
3920  PEC_result = LTC_pec15_calc(6, PEC_Check);
3921  pTxBuff[10u + (i * 8u)] = (PEC_result >> 8u) & 0xFFu;
3922  pTxBuff[11u + (i * 8u)] = PEC_result & 0xFFu;
3923  }
3924 
3925  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
3926 
3927  return retVal;
3928 }
3929 
3930 /**
3931  * @brief configures the data that will be sent to the LTC daisy-chain to configure multiplexer channels.
3932  *
3933  * This function does not sent the data to the multiplexer daisy-chain. This is done
3934  * by the function LTC_SetMuxChannel(), which calls LTC_SetMUXChCommand()..
3935  *
3936  * @param pTxBuff transmit buffer
3937  * @param mux multiplexer ID to be configured (0,1,2 or 3)
3938  * @param channel multiplexer channel to be configured (0 to 7)
3939  *
3940  */
3941 static void LTC_SetMUXChCommand(uint16_t *pTxBuff, uint8_t mux, uint8_t channel) {
3942  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
3943 #if SLAVE_BOARD_VERSION == 2u
3944 
3945  /* using ADG728 */
3946  uint8_t address = 0x98u | ((mux % 4u) << 1u);
3947  uint8_t data = 1u << (channel % 8u);
3948  if (channel == 0xFFu) { /* no channel selected, output of multiplexer is high impedance */
3949  data = 0x00;
3950  }
3951 
3952 #else
3953 
3954  /* using LTC1380 */
3955  uint8_t address = 0x90u | ((mux % 4u) << 1u);
3956  uint8_t data = 0x08u | (channel % 8u);
3957  if (channel == 0xFFu) { /* no channel selected, output of multiplexer is high impedance */
3958  data = 0x00;
3959  }
3960 
3961 #endif
3962 
3963  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | ((address >> 4u) & 0x0Fu); /* 0x6 : LTC6804: ICOM START from Master */
3964  pTxBuff[5u + (i * 8u)] = LTC_FCOM_MASTER_NACK | ((address << 4u) & 0xF0u);
3965  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | ((data >> 4u) & 0x0Fu);
3966  pTxBuff[7u + (i * 8u)] = LTC_FCOM_MASTER_NACK_STOP | ((data << 4u) & 0xF0u);
3967  pTxBuff[8u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT; /* 0x1 : ICOM-STOP */
3968  pTxBuff[9u + (i * 8u)] = 0x00; /* 0x0 : dummy (Dn) */
3969  /* 9: MASTER NACK + STOP (FCOM) */
3970  }
3971 }
3972 
3973 /**
3974  * @brief sends data to the LTC daisy-chain to read EEPROM on slaves.
3975  *
3976  * @param ltc_state state of the ltc state machine
3977  * @param pSpiInterface pointer to SPI configuration
3978  * @param pTxBuff transmit buffer
3979  * @param pRxBuff receive buffer
3980  * @param frameLength number of words to transmit
3981  * @param step first or second stage of read process (0 or 1)
3982  *
3983  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
3984  */
3986  LTC_STATE_s *ltc_state,
3987  SPI_INTERFACE_CONFIG_s *pSpiInterface,
3988  uint16_t *pTxBuff,
3989  uint16_t *pRxBuff,
3990  uint32_t frameLength,
3991  uint8_t step) {
3992  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
3993 
3994  /* send WRCOMM to send I2C message to choose channel */
3995  LTC_SetEEPROMReadCommand(ltc_state, pTxBuff, step);
3996  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
3997 
3998  return statusSPI;
3999 }
4000 
4001 /**
4002  * @brief configures the data that will be sent to the LTC daisy-chain to read EEPROM on slaves.
4003  *
4004  * @param ltc_state state of the ltc state machine
4005  * @param pTxBuff transmit buffer
4006  * @param step first or second stage of read process (0 or 1)
4007  *
4008  */
4009 static void LTC_SetEEPROMReadCommand(LTC_STATE_s *ltc_state, uint16_t *pTxBuff, uint8_t step) {
4010  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4011 
4012  uint32_t address = ltc_state->ltcData.slaveControl->eepromReadAddressToUse;
4013 
4014  address &= 0x3FFFFu;
4015  const uint8_t address0 = address >> 16u;
4016  const uint8_t address1 = (address & 0xFFFFu) >> 8u;
4017  const uint8_t address2 = address & 0xFFu;
4018 
4019  if (step == 0u) {
4020  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4021  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | (0x0Au); /* 0x6 : LTC6804: ICOM START from Master */
4022  pTxBuff[5u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (((address0 & 0x03u) << 5u) | 0x00u);
4023  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | (address1 >> 4u);
4024  pTxBuff[7u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (address1 << 4u);
4025  pTxBuff[8u + (i * 8u)] = LTC_ICOM_BLANK | (address2 >> 4u);
4026  pTxBuff[9u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (address2 << 4u);
4027  }
4028 
4029  } else { /* step == 1 */
4030  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4031  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | (0x0Au); /* 0x6 : LTC6804: ICOM START from Master */
4032  pTxBuff[5u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (((address0 & 0x03u) << 5u) | 0x10u);
4033  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | 0x0Fu;
4034  pTxBuff[7u + (i * 8u)] = LTC_FCOM_MASTER_NACK_STOP | 0xF0u;
4035  pTxBuff[8u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT | 0x00u;
4036  pTxBuff[9u + (i * 8u)] = LTC_FCOM_MASTER_NACK_STOP | 0x00u;
4037  }
4038  }
4039 }
4040 
4041 /**
4042  * @brief saves the read values of the external EEPROMs read from the LTC daisy-chain.
4043  *
4044  * @param ltc_state state of the ltc state machine
4045  * @param pRxBuff receive buffer
4046  *
4047  */
4048 static void LTC_EEPROMSaveReadValue(LTC_STATE_s *ltc_state, uint16_t *pRxBuff) {
4049  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4050 
4051  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4052  ltc_state->ltcData.slaveControl->eepromValueRead[i] = (pRxBuff[6u + (i * 8u)] << 4u) |
4053  ((pRxBuff[7u + (i * 8u)] >> 4u));
4054  }
4055 
4058  ltc_state->ltcData.slaveControl->eepromReadAddressToUse = 0xFFFFFFFF;
4059 
4060  DATA_WRITE_DATA(ltc_state->ltcData.slaveControl);
4061 }
4062 
4063 /**
4064  * @brief sends data to the LTC daisy-chain to write EEPROM on slaves.
4065  *
4066  * @param ltc_state state of the ltc state machine
4067  * @param pSpiInterface pointer to SPI configuration
4068  * @param pTxBuff transmit buffer
4069  * @param pRxBuff receive buffer
4070  * @param frameLength number of words to transmit
4071  * @param step first or second stage of read process (0 or 1)
4072  *
4073  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4074  */
4076  LTC_STATE_s *ltc_state,
4077  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4078  uint16_t *pTxBuff,
4079  uint16_t *pRxBuff,
4080  uint32_t frameLength,
4081  uint8_t step) {
4082  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4083 
4084  /* send WRCOMM to send I2C message to write EEPROM */
4085  LTC_SetEEPROMWriteCommand(ltc_state, pTxBuff, step);
4086  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4087 
4088  return statusSPI;
4089 }
4090 
4091 /**
4092  * @brief configures the data that will be sent to the LTC daisy-chain to write EEPROM on slaves.
4093  *
4094  * @param ltc_state state of the ltc state machine
4095  * @param pTxBuff transmit buffer
4096  * @param step first or second stage of read process (0 or 1)
4097  *
4098  */
4099 static void LTC_SetEEPROMWriteCommand(LTC_STATE_s *ltc_state, uint16_t *pTxBuff, uint8_t step) {
4100  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4101 
4102  uint32_t address = ltc_state->ltcData.slaveControl->eepromWriteAddressToUse;
4103 
4104  address &= 0x3FFFFu;
4105  const uint8_t address0 = address >> 16u;
4106  const uint8_t address1 = (address & 0xFFFFu) >> 8u;
4107  const uint8_t address2 = address & 0xFFu;
4108 
4109  if (step == 0u) {
4110  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4111  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | (0x0Au); /* 0x6 : LTC6804: ICOM START from Master */
4112  pTxBuff[5u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (((address0 & 0x03u) << 5u) | 0x00u);
4113  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | (address1 >> 4u);
4114  pTxBuff[7u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (address1 << 4u);
4115  pTxBuff[8u + (i * 8u)] = LTC_ICOM_BLANK | (address2 >> 4u);
4116  pTxBuff[9u + (i * 8u)] = LTC_FCOM_MASTER_NACK | (address2 << 4u);
4117  }
4118 
4119  } else { /* step == 1 */
4120  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4121  const uint8_t data = ltc_state->ltcData.slaveControl->eepromValueWrite[i];
4122 
4123  pTxBuff[4u + (i * 8u)] = LTC_ICOM_BLANK | (data >> 4u); /* 0x6 : LTC6804: ICOM START from Master */
4124  pTxBuff[5u + (i * 8u)] = LTC_FCOM_MASTER_NACK_STOP | (data << 4u);
4125  pTxBuff[6u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT | 0x00u;
4126  pTxBuff[7u + (i * 8u)] = LTC_FCOM_MASTER_NACK_STOP | 0x00u;
4127  pTxBuff[8u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT | 0x00u;
4128  pTxBuff[9u + (i * 8u)] = LTC_FCOM_MASTER_NACK_STOP | 0x00u;
4129  }
4130 
4133  ltc_state->ltcData.slaveControl->eepromWriteAddressToUse = 0xFFFFFFFF;
4134 
4135  DATA_WRITE_DATA(ltc_state->ltcData.slaveControl);
4136  }
4137 }
4138 
4139 /**
4140  * @brief sends data to the LTC daisy-chain to configure multiplexer channels.
4141  *
4142  * This function calls the function LTC_SetMUXChCommand() to set the data.
4143  *
4144  * @param pSpiInterface pointer to SPI configuration
4145  * @param pTxBuff transmit buffer
4146  * @param pRxBuff receive buffer
4147  * @param frameLength number of words to transmit
4148  * @param mux multiplexer ID to be configured (0,1,2 or 3)
4149  * @param channel multiplexer channel to be configured (0 to 7)
4150  *
4151  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4152  */
4154  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4155  uint16_t *pTxBuff,
4156  uint16_t *pRxBuff,
4157  uint32_t frameLength,
4158  uint8_t mux,
4159  uint8_t channel) {
4160  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4161 
4162  /* send WRCOMM to send I2C message to choose channel */
4163  LTC_SetMUXChCommand(pTxBuff, mux, channel);
4164  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4165 
4166  return statusSPI;
4167 }
4168 
4169 /**
4170  * @brief sends data to the LTC daisy-chain to communicate via I2C
4171  *
4172  * This function initiates an I2C signal sent by the LTC6804 on the slave boards
4173  *
4174  * @param pSpiInterface pointer to SPI configuration
4175  * @param pTxBuff transmit buffer
4176  * @param pRxBuff receive buffer
4177  * @param frameLength number of words to transmit
4178  * @param cmd_data command data to be sent
4179  *
4180  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4181  */
4183  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4184  uint16_t *pTxBuff,
4185  uint16_t *pRxBuff,
4186  uint32_t frameLength,
4187  uint16_t *cmd_data) {
4188  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4189 
4190  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
4191  pTxBuff[4u + (i * 6u)] = cmd_data[0];
4192  pTxBuff[5u + (i * 6u)] = cmd_data[1];
4193 
4194  pTxBuff[6u + (i * 6u)] = cmd_data[2];
4195  pTxBuff[7u + (i * 6u)] = cmd_data[3];
4196 
4197  pTxBuff[8u + (i * 6u)] = cmd_data[4];
4198  pTxBuff[9u + (i * 6u)] = cmd_data[5];
4199  }
4200 
4201  /* send WRCOMM to send I2C message */
4202  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4203 
4204  return statusSPI;
4205 }
4206 
4207 /**
4208  * @brief saves the temperature value of the external temperature sensors read from the LTC daisy-chain.
4209  *
4210  * This function saves the temperature value received from the external temperature sensors
4211  *
4212  * @param ltc_state state of the ltc state machine
4213  * @param pRxBuff receive buffer
4214  *
4215  */
4216 static void LTC_TempSensSaveTemp(LTC_STATE_s *ltc_state, uint16_t *pRxBuff) {
4217  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4218 
4219  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4220  uint8_t temp_tmp[2];
4221  temp_tmp[0] = (pRxBuff[6u + (i * 8u)] << 4u) | ((pRxBuff[7u + (i * 8u)] >> 4u));
4222  temp_tmp[1] = (pRxBuff[8u + (i * 8u)] << 4u) | ((pRxBuff[9u + (i * 8u)] >> 4u));
4223  uint16_t val_i = (temp_tmp[0] << 8u) | (temp_tmp[1]);
4224  val_i = val_i >> 8u;
4225  ltc_state->ltcData.slaveControl->externalTemperatureSensor[i] = val_i;
4226  }
4227 
4228  DATA_WRITE_DATA(ltc_state->ltcData.slaveControl);
4229 }
4230 
4231 /**
4232  * @brief sends data to the LTC daisy-chain to control the user port expander
4233  *
4234  * This function sends a control byte to the register of the user port expander
4235  *
4236  * @param ltc_state state of the ltc state machine
4237  * @param pSpiInterface pointer to SPI configuration
4238  * @param pTxBuff transmit buffer
4239  * @param pRxBuff receive buffer
4240  * @param frameLength number of words to transmit
4241  *
4242  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4243  */
4245  LTC_STATE_s *ltc_state,
4246  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4247  uint16_t *pTxBuff,
4248  uint16_t *pRxBuff,
4249  uint32_t frameLength) {
4250  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4251 
4252  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4253 
4254  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
4255  const uint8_t output_data = ltc_state->ltcData.slaveControl->ioValueOut[BS_NR_OF_MODULES - 1 - i];
4256 
4257  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START |
4258  0x04u; /* 6: ICOM0 start condition, 4: upper nibble of PCA8574 address */
4259  pTxBuff[5u + (i * 8u)] =
4260  0u | LTC_FCOM_MASTER_NACK; /* 0: lower nibble of PCA8574 address + R/W bit, 8: FCOM0 master NACK */
4261 
4262  pTxBuff[6u + (i * 8u)] =
4263  LTC_ICOM_BLANK |
4264  (output_data >> 4u); /* 0: ICOM1 blank, x: upper nibble of PCA8574 data register (0 == pin low) */
4265  pTxBuff[7u + (i * 8u)] =
4266  (uint8_t)(output_data << 4u) |
4267  LTC_FCOM_MASTER_NACK_STOP; /* x: lower nibble of PCA8574 data register, 9: FCOM1 master NACK + STOP */
4268 
4269  pTxBuff[8u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT; /* 7: no transmission, F: dummy data */
4270  pTxBuff[9u + (i * 8u)] = 0; /* F: dummy data, 9: FCOM2 master NACK + STOP */
4271  }
4272 
4273  /* send WRCOMM to send I2C message */
4274  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4275 
4276  return statusSPI;
4277 }
4278 
4279 /**
4280  * @brief saves the received values of the external port expander read from the LTC daisy-chain.
4281  *
4282  * This function saves the received data byte from the external port expander
4283  *
4284  * @param ltc_state state of the ltc state machine
4285  * @param pRxBuff receive buffer
4286  *
4287  */
4288 static void LTC_PortExpanderSaveValues(LTC_STATE_s *ltc_state, uint16_t *pRxBuff) {
4289  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4290 
4291  /* extract data */
4292  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4293  const uint8_t val_i = (pRxBuff[6u + (i * 8u)] << 4u) | ((pRxBuff[7u + (i * 8u)] >> 4u));
4294  ltc_state->ltcData.slaveControl->ioValueIn[i] = val_i;
4295  }
4296 
4297  DATA_WRITE_DATA(ltc_state->ltcData.slaveControl);
4298 }
4299 
4300 /**
4301  * @brief sends data to the LTC daisy-chain to control the user port expander from TI
4302  *
4303  * This function sends a control byte to the register of the user port expander from TI
4304  *
4305  * @param ltc_state state of the ltc state machine
4306  * @param pSpiInterface pointer to SPI configuration
4307  * @param pTxBuff transmit buffer
4308  * @param pRxBuff receive buffer
4309  * @param frameLength number of words to transmit
4310  * @param direction use port expander pin as input or output
4311  *
4312  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4313  */
4315  LTC_STATE_s *ltc_state,
4316  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4317  uint16_t *pTxBuff,
4318  uint16_t *pRxBuff,
4319  uint32_t frameLength,
4321  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4322 
4323  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4324 
4325  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
4326  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | 0x4u; /*upper nibble of TCA6408A address */
4327  pTxBuff[5u + (i * 8u)] = (uint8_t)((LTC_PORTEXPANDER_ADR_TI << 1u) << 4u) |
4328  LTC_FCOM_MASTER_NACK; /* 0: lower nibble of TCA6408A address + R/W bit */
4329 
4330  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | (LTC_PORT_EXPANDER_TI_CONFIG_REG_ADR >>
4331  4u); /* upper nibble of TCA6408A configuration register address */
4332  pTxBuff[7u + (i * 8u)] = (uint8_t)(LTC_PORT_EXPANDER_TI_CONFIG_REG_ADR << 4u) |
4333  LTC_FCOM_MASTER_NACK; /* lower nibble of TCA6408A configuration register address */
4334 
4335  pTxBuff[8u + (i * 8u)] = LTC_ICOM_BLANK |
4336  (direction >> 4u); /* upper nibble of TCA6408A configuration register data */
4337  pTxBuff[9u + (i * 8u)] = (uint8_t)(direction << 4u) |
4338  LTC_FCOM_MASTER_NACK_STOP; /* lower nibble of TCA6408A configuration register data */
4339  }
4340 
4341  /* send WRCOMM to send I2C message */
4342  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4343 
4344  return statusSPI;
4345 }
4346 
4347 /**
4348  * @brief sends data to the LTC daisy-chain to control the user port expander from TI
4349  *
4350  * This function sends a control byte to the register of the user port expander from TI
4351  *
4352  * @param ltc_state state of the ltc state machine
4353  * @param pSpiInterface pointer to SPI configuration
4354  * @param pTxBuff transmit buffer
4355  * @param pRxBuff receive buffer
4356  * @param frameLength number of words to transmit
4357  *
4358  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4359  */
4361  LTC_STATE_s *ltc_state,
4362  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4363  uint16_t *pTxBuff,
4364  uint16_t *pRxBuff,
4365  uint32_t frameLength) {
4366  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4367 
4368  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4369 
4370  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
4371  const uint8_t output_data = ltc_state->ltcData.slaveControl->ioValueOut[BS_NR_OF_MODULES - 1 - i];
4372 
4373  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | 0x4u; /* upper nibble of TCA6408A address */
4374  pTxBuff[5u + (i * 8u)] = (uint8_t)((LTC_PORTEXPANDER_ADR_TI << 1u) << 4u) |
4375  LTC_FCOM_MASTER_NACK; /* 0: lower nibble of TCA6408A address + R/W bit */
4376 
4377  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | (LTC_PORT_EXPANDER_TI_OUTPUT_REG_ADR >>
4378  4u); /* upper nibble of TCA6408A output register address */
4379  pTxBuff[7u + (i * 8u)] = (uint8_t)(LTC_PORT_EXPANDER_TI_OUTPUT_REG_ADR << 4u) |
4380  LTC_FCOM_MASTER_NACK; /* lower nibble of TCA6408A output register address */
4381 
4382  pTxBuff[8u + (i * 8u)] = LTC_ICOM_BLANK | (output_data >> 4u); /* upper nibble of TCA6408A output register */
4383  pTxBuff[9u + (i * 8u)] = (uint8_t)(output_data << 4u) |
4384  LTC_FCOM_MASTER_NACK_STOP; /* lower nibble of TCA6408A output register */
4385  }
4386 
4387  /* send WRCOMM to send I2C message */
4388  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4389 
4390  return statusSPI;
4391 }
4392 
4393 /**
4394  * @brief sends data to the LTC daisy-chain to control the user port expander from TI
4395  *
4396  * @details This function sends a control byte to the register of the user port expander from TI
4397  *
4398  * @param ltc_state state of the ltc state machine
4399  * @param pSpiInterface pointer to SPI configuration
4400  * @param pTxBuff transmit buffer
4401  * @param pRxBuff receive buffer
4402  * @param frameLength number of words to transmit
4403  * @param step first or second stage of read process (0 or 1)
4404  *
4405  * @return #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
4406  */
4408  LTC_STATE_s *ltc_state,
4409  SPI_INTERFACE_CONFIG_s *pSpiInterface,
4410  uint16_t *pTxBuff,
4411  uint16_t *pRxBuff,
4412  uint32_t frameLength,
4413  uint8_t step) {
4414  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4415 
4416  if (step == 0u) {
4417  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
4418  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | 0x4u; /* upper nibble of TCA6408A address */
4419  pTxBuff[5u + (i * 8u)] = (uint8_t)((LTC_PORTEXPANDER_ADR_TI << 1u) << 4u) |
4420  LTC_FCOM_MASTER_NACK; /* lower nibble of TCA6408A address + R/W bit */
4421 
4422  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | (LTC_PORT_EXPANDER_TI_INPUT_REG_ADR >>
4423  4u); /* upper nibble of TCA6408A input register address */
4424  pTxBuff[7u + (i * 8u)] = (uint8_t)(LTC_PORT_EXPANDER_TI_INPUT_REG_ADR << 4u) |
4425  LTC_FCOM_MASTER_NACK; /* x: lower nibble of TCA6408A input register address */
4426 
4427  pTxBuff[8u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT; /* no transmission */
4428  pTxBuff[9u + (i * 8u)] = 0; /* dummy data */
4429  }
4430 
4431  } else {
4432  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4433 
4434  for (uint16_t i = 0; i < BS_NR_OF_MODULES; i++) {
4435  pTxBuff[4u + (i * 8u)] = LTC_ICOM_START | 0x4u; /* upper nibble of TCA6408A address */
4436  pTxBuff[5u + (i * 8u)] = (uint8_t)(((LTC_PORTEXPANDER_ADR_TI << 1u) | 1u) << 4u) |
4437  LTC_FCOM_MASTER_NACK; /* lower nibble of TCA6408A address + R/W bit */
4438 
4439  pTxBuff[6u + (i * 8u)] = LTC_ICOM_BLANK | 0x0Fu; /* upper nibble slave data, master pulls bus high */
4440  pTxBuff[7u + (i * 8u)] = LTC_FCOM_MASTER_NACK | 0xF0u; /* lower nibble slave data, master pulls bus high */
4441 
4442  pTxBuff[8u + (i * 8u)] = LTC_ICOM_NO_TRANSMIT; /* no transmission */
4443  pTxBuff[9u + (i * 8u)] = 0; /* dummy data */
4444  }
4445  }
4446 
4447  /* send WRCOMM to send I2C message */
4448  statusSPI = LTC_TX(ltc_cmdWRCOMM, pSpiInterface, pTxBuff, pRxBuff, frameLength);
4449 
4450  return statusSPI;
4451 }
4452 
4453 /**
4454  * @brief saves the received values of the external port expander from TI read from the LTC daisy-chain.
4455  * @details This function saves the received data byte from the external port expander from TI
4456  * @param ltc_state state of the ltc state machine
4457  * @param pTxBuff transmit buffer
4458  */
4459 static void LTC_PortExpanderSaveValues_TI(LTC_STATE_s *ltc_state, uint16_t *pTxBuff) {
4460  DATA_READ_DATA(ltc_state->ltcData.slaveControl);
4461 
4462  /* extract data */
4463  for (uint16_t i = 0; i < LTC_N_LTC; i++) {
4464  const uint8_t val_i = (pTxBuff[6u + (i * 8u)] << 4u) | ((pTxBuff[7u + (i * 8u)] >> 4u));
4465  ltc_state->ltcData.slaveControl->ioValueIn[i] = val_i;
4466  }
4467 
4468  DATA_WRITE_DATA(ltc_state->ltcData.slaveControl);
4469 }
4470 
4471 /**
4472  * @brief sends 72 clock pulses to the LTC daisy-chain.
4473  *
4474  * This function is used for the communication with the multiplexers via I2C on the GPIOs.
4475  * It send the command STCOMM to the LTC daisy-chain.
4476  *
4477  * @param pSpiInterface pointer to SPI configuration
4478  *
4479  * @return statusSPI #STD_OK if clock pulses were sent correctly by SPI, #STD_NOT_OK otherwise
4480  *
4481  */
4483  STD_RETURN_TYPE_e statusSPI = STD_NOT_OK;
4484  uint16_t ltc_TXBufferClock[4u + 9u];
4485 
4486  for (uint16_t i = 0; i < (4u + 9u); i++) {
4487  ltc_TXBufferClock[i] = 0xFF;
4488  }
4489 
4490  ltc_TXBufferClock[0] = ltc_cmdSTCOMM[0];
4491  ltc_TXBufferClock[1] = ltc_cmdSTCOMM[1];
4492  ltc_TXBufferClock[2] = ltc_cmdSTCOMM[2];
4493  ltc_TXBufferClock[3] = ltc_cmdSTCOMM[3];
4494 
4495  statusSPI = LTC_TransmitI2cCommand(pSpiInterface, ltc_TXBufferClock);
4496 
4497  return statusSPI;
4498 }
4499 
4500 /**
4501  * @brief gets the frequency of the SPI clock.
4502  *
4503  * This function reads the configuration from the SPI handle directly.
4504  *
4505  * @param pSpiInterface pointer to SPI configuration
4506  *
4507  * @return frequency of the SPI clock
4508  */
4509 static uint32_t LTC_GetSPIClock(SPI_INTERFACE_CONFIG_s *pSpiInterface) {
4510  uint32_t SPI_Clock = 0;
4511  uint32_t prescaler = 0;
4512 
4513  /* if (LTC_SPI_INSTANCE == SPI2 || LTC_SPI_INSTANCE == SPI3) { */
4514  /* SPI2 and SPI3 are connected to APB1 (PCLK1) */
4515  /* The prescaler setup bits LTC_SPI_PRESCALER corresponds to the bits 5:3 in the SPI_CR1 register */
4516  /* Reference manual p.909 */
4517  /* The shift by 3 puts the bits 5:3 to the first position */
4518  /* Division are made by powers of 2 which corresponds to shifting to the right */
4519  /* Then 0 corresponds to divide by 2, 1 corresponds to divide by 4... so 1 has to be added to the value of the configuration bits */
4520 
4521  /* SPI_Clock = HAL_RCC_GetPCLK1Freq()>>((LTC_SPI_PRESCALER>>3)+1);
4522  } */
4523 
4524  /* if (LTC_SPI_INSTANCE == SPI1 || LTC_SPI_INSTANCE == SPI4 || LTC_SPI_INSTANCE == SPI5 || LTC_SPI_INSTANCE == SPI6) { */
4525  /* SPI1, SPI4, SPI5 and SPI6 are connected to APB2 (PCLK2) */
4526  /* The prescaler setup bits LTC_SPI_PRESCALER corresponds to the bits 5:3 in the SPI_CR1 register */
4527  /* Reference manual p.909 */
4528  /* The shift by 3 puts the bits 5:3 to the first position */
4529  /* Division are made by powers of 2 which corresponds to shifting to the right */
4530  /* Then 0 corresponds to divide by 2, 1 corresponds to divide by 4... so 1 has to be added to the value of the configuration bits */
4531 
4532  /* SPI_Clock = HAL_RCC_GetPCLK2Freq()>>((LTC_SPI_PRESCALER>>3)+1);
4533  } */
4534 
4535  /* Get SPI prescaler */
4536  prescaler = ((pSpiInterface->pNode->FMT0) >> 8u) & 0xFFu;
4537  SPI_Clock = (uint32_t)(AVCLK1_FREQ * 1000000u) / (prescaler + 1u);
4538 
4539  return SPI_Clock;
4540 }
4541 
4542 /**
4543  * @brief sets the transfer time needed to receive/send data with the LTC daisy-chain.
4544  *
4545  * This function gets the clock frequency and uses the number of LTCs in the daisy-chain.
4546  *
4547  * @param ltc_state: state of the ltc state machine
4548  *
4549  */
4550 static void LTC_SetTransferTimes(LTC_STATE_s *ltc_state) {
4551  uint32_t transferTime_us = 0;
4552  uint32_t SPI_Clock = 0;
4553 
4554  SPI_Clock = LTC_GetSPIClock(ltc_state->ltcData.pSpiInterface);
4555 
4556  /* Transmission of a command and data */
4557  /* Multiplication by 1000*1000 to get us */
4558  transferTime_us = (8u * 1000u * 1000u) / (SPI_Clock);
4559  transferTime_us *= LTC_N_BYTES_FOR_DATA_TRANSMISSION;
4560  transferTime_us = transferTime_us + LTC_SPI_WAKEUP_WAIT_TIME_US;
4561  ltc_state->commandDataTransferTime = (transferTime_us / 1000u) + 1u;
4562 
4563  /* Transmission of a command */
4564  /* Multiplication by 1000*1000 to get us */
4565  transferTime_us = ((4u) * 8u * 1000u * 1000u) / (SPI_Clock);
4566  transferTime_us = transferTime_us + LTC_SPI_WAKEUP_WAIT_TIME_US;
4567  ltc_state->commandTransferTime = (transferTime_us / 1000u) + 1u;
4568 
4569  /* Transmission of a command + 9 clocks */
4570  /* Multiplication by 1000*1000 to get us */
4571  transferTime_us = ((4u + 9u) * 8u * 1000u * 1000u) / (SPI_Clock);
4572  transferTime_us = transferTime_us + LTC_SPI_WAKEUP_WAIT_TIME_US;
4573  ltc_state->gpioClocksTransferTime = (transferTime_us / 1000u) + 1u;
4574 }
4575 
4576 /**
4577  * @brief checks the state requests that are made.
4578  *
4579  * This function checks the validity of the state requests.
4580  * The results of the checked is returned immediately.
4581  *
4582  * @param ltc_state: state of the ltc state machine
4583  * @param statereq state request to be checked
4584  *
4585  * @return result of the state request that was made, taken from LTC_RETURN_TYPE_e
4586  */
4588  LTC_RETURN_TYPE_e retVal = LTC_OK;
4589  if (statereq.string >= BS_NR_OF_STRINGS) {
4590  retVal = LTC_ILLEGAL_REQUEST;
4591  } else if (ltc_state->statereq.request == LTC_STATE_NO_REQUEST) {
4592  /* init only allowed from the uninitialized state */
4593  if (statereq.request == LTC_STATE_INIT_REQUEST) {
4594  if (ltc_state->state == LTC_STATEMACH_UNINITIALIZED) {
4595  retVal = LTC_OK;
4596  } else {
4597  retVal = LTC_ALREADY_INITIALIZED;
4598  }
4599  } else {
4600  retVal = LTC_OK;
4601  }
4602  } else {
4603  retVal = LTC_REQUEST_PENDING;
4604  }
4605 
4606  return retVal;
4607 }
4608 
4610  bool retval = false;
4611 
4613  retval = ltc_state->first_measurement_made;
4615 
4616  return (retval);
4617 }
4618 
4619 /**