foxBMS  1.3.0
The foxBMS Battery Management System API Documentation
ltc_6806.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2022, 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_6806.c
44  * @author foxBMS Team
45  * @date 2019-09-01 (date of creation)
46  * @updated 2022-05-30 (date of last update)
47  * @version v1.3.0
48  * @ingroup DRIVERS
49  * @prefix LTC
50  *
51  * @brief Driver for the LTC monitoring chip.
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 /* clang-format off */
57 #include "ltc.h"
58 #include "ltc_6806_cfg.h"
59 /* clang-format on */
60 
61 #include "HL_spi.h"
62 #include "HL_system.h"
63 
64 #include "afe_plausibility.h"
65 #include "database.h"
66 #include "diag.h"
67 #include "io.h"
68 #include "ltc_pec.h"
69 #include "os.h"
70 #include "pex.h"
71 
72 /*========== Macros and Definitions =========================================*/
73 
74 /**
75  * TI port expander register addresses
76  * @{
77  */
78 #define LTC_PORT_EXPANDER_TI_INPUT_REG_ADR (0x00u)
79 #define LTC_PORT_EXPANDER_TI_OUTPUT_REG_ADR (0x01u)
80 #define LTC_PORT_EXPANDER_TI_CONFIG_REG_ADR (0x03u)
81 /**@}*/
82 
83 /**
84  * Value of the LSB in mV
85  */
86 #if LTC_HIRNG == 0u
87 #define LTC_FUEL_CELL_LSB_RESOLUTION_mV (1.5f)
88 #else
89 #define LTC_FUEL_CELL_LSB_RESOLUTION_mV (3.0f)
90 #endif
91 
92 /**
93  * Value for positive full scale measurement for fuel cell
94  */
95 #define LTC_FUELCELL_POSITIVE_FULLSCALE_RANGE_mV ((int16_t)((0x7FF * LTC_FUEL_CELL_LSB_RESOLUTION_mV)))
96 
97 /**
98  * Value for negative full scale measurement for fuel cell
99  */
100 #define LTC_FUELCELL_NEGATIVE_FULLSCALE_RANGE_mV \
101  ((int16_t)((((~0x001) + 1) & 0x7FF) * (-LTC_FUEL_CELL_LSB_RESOLUTION_mV)))
102 
103 /*========== Static Constant and Variable Definitions =======================*/
104 /**
105  * PEC buffer for RX and TX
106  * @{
107  */
108 /* AXIVION Disable Style MisraC2012-1.2: The Pec buffer must be put in the shared RAM section for performance reasons */
109 #pragma SET_DATA_SECTION(".sharedRAM")
112 #pragma SET_DATA_SECTION()
113 /* AXIVION Enable Style MisraC2012-1.2: only Pec buffer needed to be in the shared RAM setcion */
114 /**@}*/
115 
116 /** index of used cells */
117 static uint16_t ltc_used_cells_index[BS_NR_OF_STRINGS] = {0};
118 /** local copies of database tables */
119 /**@{*/
124 /**@}*/
125 /** stores information on the detected open wires locally */
127 static LTC_ERRORTABLE_s ltc_errorTable = {0}; /*!< init in LTC_ResetErrorTable-function */
128 
129 /** local definition of plausible cell voltage values for the LTC 6806 */
132  .minimumPlausibleVoltage_mV = -5000,
133 };
134 
135 /*========== Extern Constant and Variable Definitions =======================*/
136 
138  .timer = 0,
139  .statereq = {.request = LTC_STATE_NO_REQUEST, .string = 0xFFu},
141  .substate = 0,
142  .laststate = LTC_STATEMACH_UNINITIALIZED,
143  .lastsubstate = 0,
144  .adcModereq = LTC_ADCMODE_FAST_DCP0,
145  .adcMode = LTC_ADCMODE_FAST_DCP0,
146  .adcMeasChreq = LTC_ADCMEAS_UNDEFINED,
147  .adcMeasCh = LTC_ADCMEAS_UNDEFINED,
148  .numberOfMeasuredMux = 32,
149  .triggerentry = 0,
150  .ErrRetryCounter = 0,
151  .ErrRequestCounter = 0,
152  .VoltageSampleTime = 0,
153  .muxSampleTime = 0,
154  .commandDataTransferTime = 3,
155  .commandTransferTime = 3,
156  .gpioClocksTransferTime = 3,
157  .muxmeas_seqptr = NULL_PTR,
158  .muxmeas_seqendptr = NULL_PTR,
159  .muxmeas_nr_end = 0,
160  .first_measurement_made = false,
161  .ltc_muxcycle_finished = STD_NOT_OK,
162  .check_spi_flag = STD_NOT_OK,
163  .balance_control_done = STD_NOT_OK,
164  .transmit_ongoing = false,
165  .dummyByte_ongoing = STD_NOT_OK,
166  .ltcData.pSpiInterface = spi_ltcInterface,
167  .ltcData.txBuffer = ltc_TxPecBuffer,
168  .ltcData.rxBuffer = ltc_RxPecBuffer,
169  .ltcData.frameLength = LTC_N_BYTES_FOR_DATA_TRANSMISSION,
170  .ltcData.cellVoltage = &ltc_cellvoltage,
171  .ltcData.cellTemperature = &ltc_celltemperature,
172  .ltcData.balancingFeedback = NULL_PTR,
173  .ltcData.balancingControl = NULL_PTR,
174  .ltcData.slaveControl = NULL_PTR,
175  .ltcData.openWireDetection = &ltc_openWireDetection,
176  .ltcData.errorTable = &ltc_errorTable,
177  .ltcData.allGpioVoltages = &ltc_allgpiovoltage,
178  .ltcData.openWire = &ltc_openwire,
179  .ltcData.usedCellIndex = ltc_used_cells_index,
180  .currentString = 0u,
181  .requestedString = 0u,
182 };
183 
184 static uint16_t ltc_cmdWRCFG[4] = {0x00, 0x01, 0x3D, 0x6E};
185 static uint16_t ltc_cmdRDCFG[4] = {0x00, 0x02, 0x2B, 0x0A};
186 
187 /* static uint16_t ltc_cmdRDAUXA[4] = {0x00, 0x0C, 0xEF, 0xCC};
188 static uint16_t ltc_cmdRDAUXB[4] = {0x00, 0x0E, 0x72, 0x9A};
189 static uint16_t ltc_cmdRDAUXC[4] = {0x00, 0x0D, 0x64, 0xFE};
190 static uint16_t ltc_cmdRDAUXD[4] = {0x00, 0x0F, 0xF9, 0xA8}; */
191 
192 static uint16_t ltc_cmdRDCVA_Fuelcell[4] = {0x00, 0x04, 0x07, 0xC2};
193 static uint16_t ltc_cmdRDCVB_Fuelcell[4] = {0x00, 0x05, 0x8C, 0xF0};
194 static uint16_t ltc_cmdRDCVC_Fuelcell[4] = {0x00, 0x06, 0x9A, 0x94};
195 static uint16_t ltc_cmdRDCVD_Fuelcell[4] = {0x00, 0x07, 0x11, 0xA6};
196 static uint16_t ltc_cmdRDCVE_Fuelcell[4] = {0x00, 0x08, 0x5E, 0x52};
197 static uint16_t ltc_cmdRDCVF_Fuelcell[4] = {0x00, 0x09, 0xD5, 0x60};
198 static uint16_t ltc_cmdRDCVG_Fuelcell[4] = {0x00, 0x0A, 0xC3, 0x04};
199 static uint16_t ltc_cmdRDCVH_Fuelcell[4] = {0x00, 0x0B, 0x48, 0x36};
200 static uint16_t ltc_cmdRDCVI_Fuelcell[4] = {0x00, 0x0C, 0xEF, 0xCC};
201 
202 /* static uint16_t ltc_cmdMUTE[4] = {0x00, 0x28, 0xE8, 0x0E}; !< MUTE discharging via S pins */
203 /* static uint16_t ltc_cmdUNMUTE[4] = {0x00, 0x29, 0x63, 0x3C}; !< UN-MUTE discharging via S pins */
204 
205 static uint16_t ltc_cmdADCV_normal_Fuelcell[4] = {0x04, 0x40, 0xED, 0xB0}; /*!< All cells, normal mode */
206 
207 /* GPIOs */
208 /* static uint16_t ltc_cmdADAX_normal_GPIO1[4] = {0x05, 0x61, 0x58, 0x92}; !< Single channel, GPIO 1, normal mode */
209 /* static uint16_t ltc_cmdADAX_filtered_GPIO1[4] = {0x05, 0xE1, 0x1C, 0xB4}; !< Single channel, GPIO 1, filtered mode */
210 /* static uint16_t ltc_cmdADAX_fast_GPIO1[4] = {0x04, 0xE1, 0x94, 0xF8}; !< Single channel, GPIO 1, fast mode */
211 /* static uint16_t ltc_cmdADAX_normal_GPIO2[4] = {0x05, 0x62, 0x4E, 0xF6}; !< Single channel, GPIO 2, normal mode */
212 /* static uint16_t ltc_cmdADAX_filtered_GPIO2[4] = {0x05, 0xE2, 0x0A, 0xD0}; !< Single channel, GPIO 2, filtered mode */
213 /* static uint16_t ltc_cmdADAX_fast_GPIO2[4] = {0x04, 0xE2, 0x82, 0x9C}; !< Single channel, GPIO 2, fast mode */
214 /* static uint16_t ltc_cmdADAX_normal_GPIO3[4] = {0x05, 0x63, 0xC5, 0xC4}; !< Single channel, GPIO 3, normal mode */
215 /* static uint16_t ltc_cmdADAX_filtered_GPIO3[4] = {0x05, 0xE3, 0x81, 0xE2}; !< Single channel, GPIO 3, filtered mode */
216 /* static uint16_t ltc_cmdADAX_fast_GPIO3[4] = {0x04, 0xE3, 0x09, 0xAE}; !< Single channel, GPIO 3, fast mode */
217 /* static uint16_t ltc_cmdADAX_normal_GPIO4[4] = {0x05, 0x64, 0x62, 0x3E}; !< Single channel, GPIO 4, normal mode */
218 /* static uint16_t ltc_cmdADAX_filtered_GPIO4[4] = {0x05, 0xE4, 0x26, 0x18}; !< Single channel, GPIO 4, filtered mode */
219 /* static uint16_t ltc_cmdADAX_fast_GPIO4[4] = {0x04, 0xE4, 0xAE, 0x54}; !< Single channel, GPIO 4, fast mode */
220 /* static uint16_t ltc_cmdADAX_normal_GPIO5[4] = {0x05, 0x65, 0xE9, 0x0C}; !< Single channel, GPIO 5, normal mode */
221 /* static uint16_t ltc_cmdADAX_filtered_GPIO5[4] = {0x05, 0xE5, 0xAD, 0x2A}; !< Single channel, GPIO 5, filtered mode */
222 /* static uint16_t ltc_cmdADAX_fast_GPIO5[4] = {0x04, 0xE5, 0x25, 0x66}; !< Single channel, GPIO 5, fast mode */
223 /* static uint16_t ltc_cmdADAX_normal_ALLGPIOS[4] = {0x05, 0x60, 0xD3, 0xA0}; !< All channels, normal mode */
224 /* static uint16_t ltc_cmdADAX_filtered_ALLGPIOS[4] =
225  {0x05, 0xE0, 0x97, 0x86}; !< All channels, filtered mode */
226 /* static uint16_t ltc_cmdADAX_fast_ALLGPIOS[4] = {0x04, 0xE0, 0x1F, 0xCA}; !< All channels, fast mode */
227 
228 /* Open-wire */
230  {0x07, 0xC0, 0xBA, 0x70}; /*!< Broadcast, Pull-up current, All cells, normal mode, 100ms */
232  {0x06, 0xC0, 0x32, 0x3C}; /*!< Broadcast, Pull-down current, All cells, normal mode, 100ms */
233 
234 /*========== Static Function Prototypes =====================================*/
235 static void LTC_SetFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state);
236 static void LTC_InitializeDatabase(LTC_STATE_s *ltc_state);
237 static void LTC_SaveLastStates(LTC_STATE_s *ltc_state);
238 static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms);
239 static void LTC_CondBasedStateTransition(
240  LTC_STATE_s *ltc_state,
241  STD_RETURN_TYPE_e retVal,
242  DIAG_ID_e diagCode,
243  LTC_STATEMACH_e state_ok,
244  uint8_t substate_ok,
245  uint16_t timer_ms_ok,
246  LTC_STATEMACH_e state_nok,
247  uint8_t substate_nok,
248  uint16_t timer_ms_nok);
249 
250 static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state);
252  SPI_INTERFACE_CONFIG_s *pSpiInterface,
253  uint16_t *pTxBuff,
254  uint16_t *pRxBuff,
255  uint32_t frameLength);
256 
258  SPI_INTERFACE_CONFIG_s *pSpiInterface,
259  LTC_ADCMODE_e adcMode,
260  LTC_ADCMEAS_CHAN_e adcMeasCh);
262  SPI_INTERFACE_CONFIG_s *pSpiInterface,
263  LTC_ADCMODE_e adcMode,
264  uint8_t PUP);
265 
267  LTC_STATE_s *ltc_state,
268  uint16_t *pRxBuff,
269  uint8_t registerSet,
270  uint8_t stringNumber);
271 
273  LTC_STATE_s *ltc_state,
274  uint16_t *DataBufferSPI_RX_with_PEC,
275  uint8_t stringNumber);
277  uint16_t *Command,
278  SPI_INTERFACE_CONFIG_s *pSpiInterface,
279  uint16_t *pTxBuff,
280  uint16_t *pRxBuff,
281  uint32_t frameLength);
282 
283 static uint32_t LTC_GetSpiClock(SPI_INTERFACE_CONFIG_s *pSpiInterface);
284 static void LTC_SetTransferTimes(LTC_STATE_s *ltc_state);
285 
287 
288 /*========== Static Function Implementations ================================*/
289 /**
290  * @brief in the database, initializes the fields related to the LTC drivers.
291  *
292  * This function loops through all the LTC-related data fields in the database
293  * and sets them to 0. It should be called in the initialization or re-initialization
294  * routine of the LTC driver.
295  *
296  * @param ltc_state: state of the ltc state machine
297  *
298  */
299 static void LTC_InitializeDatabase(LTC_STATE_s *ltc_state) {
300  uint16_t i = 0;
301 
302  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
303  ltc_state->ltcData.cellVoltage->state = 0;
304  for (i = 0; i < BS_NR_OF_CELL_BLOCKS_PER_STRING; i++) {
305  ltc_state->ltcData.cellVoltage->cellVoltage_mV[s][i] = 0;
306  ltc_state->ltcData.openWireDetection->openWirePup[s][i] = 0;
307  ltc_state->ltcData.openWireDetection->openWirePdown[s][i] = 0;
308  ltc_state->ltcData.openWireDetection->openWireDelta[s][i] = 0;
309  }
310 
311  ltc_state->ltcData.cellTemperature->state = 0;
312  for (i = 0; i < BS_NR_OF_TEMP_SENSORS_PER_STRING; i++) {
313  ltc_state->ltcData.cellTemperature->cellTemperature_ddegC[s][i] = 0;
314  }
315 
316  ltc_state->ltcData.allGpioVoltages->state = 0;
317  for (i = 0; i < (BS_NR_OF_MODULES_PER_STRING * BS_NR_OF_GPIOS_PER_MODULE); i++) {
318  ltc_state->ltcData.allGpioVoltages->gpioVoltages_mV[s][i] = 0;
319  }
320 
321  for (i = 0; i < (BS_NR_OF_MODULES_PER_STRING * (BS_NR_OF_CELL_BLOCKS_PER_MODULE + 1)); i++) {
322  ltc_state->ltcData.openWire->openwire[s][i] = 0;
323  }
324  ltc_state->ltcData.openWire->state = 0;
325  }
326 
327  DATA_WRITE_DATA(ltc_state->ltcData.cellVoltage, ltc_state->ltcData.cellTemperature, ltc_state->ltcData.openWire);
328 }
329 
330 /**
331  * @brief Saves the last state and the last substate
332  *
333  * @param ltc_state: state of the ltc state machine
334  */
335 static void LTC_SaveLastStates(LTC_STATE_s *ltc_state) {
336  ltc_state->laststate = ltc_state->state;
337  ltc_state->lastsubstate = ltc_state->substate;
338 }
339 
340 /**
341  * @brief function for setting LTC_Trigger state transitions
342  *
343  * @param ltc_state: state of the ltc state machine
344  * @param state: state to transition into
345  * @param substate: substate to transition into
346  * @param timer_ms: transition into state, substate after timer elapsed
347  */
348 static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms) {
349  ltc_state->state = state;
350  ltc_state->substate = substate;
351  ltc_state->timer = timer_ms;
352 }
353 
354 /**
355  * @brief condition-based state transition depending on retVal
356  *
357  * If retVal is #STD_OK, after timer_ms_ok is elapsed the LTC statemachine will
358  * transition into state_ok and substate_ok, otherwise after timer_ms_nok the
359  * statemachine will transition to state_nok and substate_nok. Depending on
360  * value of retVal the corresponding diagnosis entry will be called.
361  *
362  * @param ltc_state: state of the ltc state machine
363  * @param retVal: condition to determine if statemachine will transition into ok or nok states
364  * @param diagCode: symbolic IDs for diagnosis entry, called with #DIAG_EVENT_OK if retVal is #STD_OK, #DIAG_EVENT_NOT_OK otherwise
365  * @param state_ok state to transition into if retVal is #STD_OK
366  * @param substate_ok: substate to transition into if retVal is #STD_OK
367  * @param timer_ms_ok: transition into state_ok, substate_ok after timer_ms_ok elapsed
368  * @param state_nok: state to transition into if retVal is #STD_NOT_OK
369  * @param substate_nok: substate to transition into if retVal is #STD_NOT_OK
370  * @param timer_ms_nok: transition into state_nok, substate_nok after timer_ms_nok elapsed
371  */
373  LTC_STATE_s *ltc_state,
374  STD_RETURN_TYPE_e retVal,
375  DIAG_ID_e diagCode,
376  LTC_STATEMACH_e state_ok,
377  uint8_t substate_ok,
378  uint16_t timer_ms_ok,
379  LTC_STATEMACH_e state_nok,
380  uint8_t substate_nok,
381  uint16_t timer_ms_nok) {
382  if ((retVal != STD_OK)) {
384  LTC_StateTransition(ltc_state, state_nok, substate_nok, timer_ms_nok);
385  } else {
386  DIAG_Handler(diagCode, DIAG_EVENT_OK, DIAG_STRING, ltc_state->currentString);
387  LTC_StateTransition(ltc_state, state_ok, substate_ok, timer_ms_ok);
388  }
389 }
390 
391 /*========== Extern Function Implementations ================================*/
392 extern void LTC_SaveVoltages(LTC_STATE_s *ltc_state, uint8_t stringNumber) {
393  /* Pointer validity check */
394  FAS_ASSERT(ltc_state != NULL_PTR);
395 
396  /* Iterate over all cell to:
397  *
398  * 1. Check open-wires and set respective cell measurements to invalid
399  * 2. Perform minimum/maximum measurement value plausibility check
400  * 3. Calculate string values
401  */
402  STD_RETURN_TYPE_e cellVoltageMeasurementValid = STD_OK;
403  int32_t stringVoltage_mV = 0;
404  uint16_t numberValidMeasurements = 0;
405  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
406  for (uint8_t c = 0u; c < BS_NR_OF_CELL_BLOCKS_PER_MODULE; c++) {
407  /* ------- 1. Check open-wires -----------------
408  * Is cell N input not open wire &&
409  * Is cell N+1 input not open wire &&
410  * Is cell voltage valid because of previous PEC error
411  * If so, everything okay, else set cell voltage measurement to invalid.
412  */
413  if ((ltc_state->ltcData.openWire
414  ->openwire[stringNumber][(m * (BS_NR_OF_CELL_BLOCKS_PER_MODULE + 1u)) + c] == 0u) &&
415  (ltc_state->ltcData.openWire
416  ->openwire[stringNumber][(m * (BS_NR_OF_CELL_BLOCKS_PER_MODULE + 1u)) + c + 1u] == 0u) &&
417  ((ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] & (0x01u << c)) == 0u)) {
418  /* Cell voltage is valid -> perform minimum/maximum plausibility check */
419 
420  /* ------- 2. Perform minimum/maximum measurement range check ---------- */
422  ltc_state->ltcData.cellVoltage
423  ->cellVoltage_mV[stringNumber][(m * BS_NR_OF_CELL_BLOCKS_PER_MODULE) + c],
425  /* Cell voltage is valid -> calculate string voltage */
426  /* -------- 3. Calculate string values ------------- */
427  stringVoltage_mV += ltc_state->ltcData.cellVoltage
428  ->cellVoltage_mV[stringNumber][(m * BS_NR_OF_CELL_BLOCKS_PER_MODULE) + c];
429  numberValidMeasurements++;
430  } else {
431  /* Invalidate cell voltage measurement */
432  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] |= (0x01u << c);
433  cellVoltageMeasurementValid = STD_NOT_OK;
434  }
435  } else {
436  /* Set cell voltage measurement value invalid, if not already invalid because of PEC Error */
437  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] |= (0x01u << c);
438  cellVoltageMeasurementValid = STD_NOT_OK;
439  }
440  }
441  }
442  DIAG_CheckEvent(cellVoltageMeasurementValid, DIAG_ID_AFE_CELL_VOLTAGE_MEAS_ERROR, DIAG_STRING, stringNumber);
443  ltc_state->ltcData.cellVoltage->packVoltage_mV[stringNumber] = stringVoltage_mV;
444  ltc_state->ltcData.cellVoltage->nrValidCellVoltages[stringNumber] = numberValidMeasurements;
445 
446  /* Increment state variable each time new values are written into database */
447  ltc_state->ltcData.cellVoltage->state++;
448 
449  DATA_WRITE_DATA(ltc_state->ltcData.cellVoltage);
450 }
451 
452 extern void LTC_SaveTemperatures(LTC_STATE_s *ltc_state, uint8_t stringNumber) {
453  STD_RETURN_TYPE_e cellTemperatureMeasurementValid = STD_OK;
454  uint16_t numberValidMeasurements = 0;
455  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
456  for (uint8_t c = 0u; c < BS_NR_OF_TEMP_SENSORS_PER_MODULE; c++) {
457  /* ------- 1. Check valid flag -----------------
458  * Is cell temperature valid because of previous PEC error
459  * If so, everything okay, else set cell temperature measurement to invalid.
460  */
461  if ((ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][m] & (0x01u << c)) == 0u) {
462  /* Cell temperature is valid -> perform minimum/maximum plausibility check */
463 
464  /* ------- 2. Perform minimum/maximum measurement range check ---------- */
465  if (STD_OK ==
467  ltc_state->ltcData.cellTemperature
468  ->cellTemperature_ddegC[stringNumber][(m * BS_NR_OF_TEMP_SENSORS_PER_MODULE) + c])) {
469  numberValidMeasurements++;
470  } else {
471  /* Invalidate cell temperature measurement */
472  ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][m] |= (0x01u << c);
473  cellTemperatureMeasurementValid = STD_NOT_OK;
474  }
475  } else {
476  /* Already invalid because of PEC Error */
477  cellTemperatureMeasurementValid = STD_NOT_OK;
478  }
479  }
480  }
482  cellTemperatureMeasurementValid, DIAG_ID_AFE_CELL_TEMPERATURE_MEAS_ERROR, DIAG_STRING, stringNumber);
483 
484  ltc_state->ltcData.cellTemperature->nrValidTemperatures[stringNumber] = numberValidMeasurements;
485  ltc_state->ltcData.cellTemperature->state++;
487 }
488 
489 /**
490  * @brief stores the measured GPIOs in the database.
491  *
492  * This function loops through the data of all modules in the LTC daisy-chain that are
493  * stored in the ltc_allgpiovoltage buffer and writes them in the database.
494  * At each write iteration, the variable named "state" and related to voltages in the
495  * database is incremented.
496  *
497  * @param ltc_state: state of the ltc state machine
498  *
499  */
500 extern void LTC_SaveAllGpioMeasurement(LTC_STATE_s *ltc_state) {
501  ltc_state->ltcData.allGpioVoltages->state++;
503 }
504 
505 /**
506  * @brief re-entrance check of LTC state machine trigger function
507  *
508  * This function is not re-entrant and should only be called time- or event-triggered.
509  * It increments the triggerentry counter from the state variable ltc_state.
510  * It should never be called by two different processes, so if it is the case, triggerentry
511  * should never be higher than 0 when this function is called.
512  *
513  * @param ltc_state: state of the ltc state machine
514  *
515  * @return retval 0 if no further instance of the function is active, 0xff else
516  *
517  */
518 uint8_t LTC_CheckReEntrance(LTC_STATE_s *ltc_state) {
519  uint8_t retval = 0;
520 
522  if (!ltc_state->triggerentry) {
523  ltc_state->triggerentry++;
524  } else {
525  retval = 0xFF; /* multiple calls of function */
526  }
528 
529  return (retval);
530 }
531 
532 /**
533  * @brief gets the current state request.
534  *
535  * This function is used in the functioning of the LTC state machine.
536  *
537  * @param ltc_state: state of the ltc state machine
538  *
539  * @return retval current state request, taken from LTC_STATE_REQUEST_e
540  */
542  LTC_REQUEST_s retval = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
543 
545  retval.request = ltc_state->statereq.request;
546  retval.string = ltc_state->statereq.string;
548 
549  return (retval);
550 }
551 
552 /**
553  * @brief gets the current state.
554  *
555  * This function is used in the functioning of the LTC state machine.
556  *
557  * @param ltc_state: state of the ltc state machine
558  *
559  * @return current state, taken from LTC_STATEMACH_e
560  */
562  return ltc_state->state;
563 }
564 
565 /**
566  * @brief transfers the current state request to the state machine.
567  *
568  * This function takes the current state request from ltc_state and transfers it to the state machine.
569  * It resets the value from ltc_state to LTC_STATE_NO_REQUEST
570  *
571  * @param ltc_state state of the ltc state machine
572  * @param pBusIDptr bus ID, main or backup (deprecated)
573  * @param pAdcModeptr LTC ADCmeasurement mode (fast, normal or filtered)
574  * @param pAdcMeasChptr number of channels measured for GPIOS (one at a time for multiplexers or all five GPIOs)
575  *
576  * @return retVal current state request, taken from LTC_STATE_REQUEST_e
577  *
578  */
580  LTC_STATE_s *ltc_state,
581  uint8_t *pBusIDptr,
582  LTC_ADCMODE_e *pAdcModeptr,
583  LTC_ADCMEAS_CHAN_e *pAdcMeasChptr) {
584  LTC_REQUEST_s retval = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
585 
587  retval.request = ltc_state->statereq.request;
588  retval.string = ltc_state->statereq.string;
589  ltc_state->requestedString = ltc_state->statereq.string;
590  *pAdcModeptr = ltc_state->adcModereq;
591  *pAdcMeasChptr = ltc_state->adcMeasChreq;
593  ltc_state->statereq.string = 0x0u;
595 
596  return (retval);
597 }
598 
600  LTC_RETURN_TYPE_e retVal = LTC_ERROR;
601 
603  retVal = LTC_CheckStateRequest(ltc_state, statereq);
604 
605  if ((retVal == LTC_OK) || (retVal == LTC_BUSY_OK) || (retVal == LTC_OK_FROM_ERROR)) {
606  ltc_state->statereq.request = statereq.request;
607  ltc_state->statereq.string = statereq.string;
608  }
610 
611  return (retVal);
612 }
613 
614 void LTC_Trigger(LTC_STATE_s *ltc_state) {
615  STD_RETURN_TYPE_e retVal = STD_OK;
616  LTC_REQUEST_s statereq = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
617  uint8_t tmpbusID = 0;
620  STD_RETURN_TYPE_e continueFunction = STD_OK;
621 
622  FAS_ASSERT(ltc_state != NULL_PTR);
623 
624  /* Check re-entrance of function */
625  if (LTC_CheckReEntrance(ltc_state) > 0u) {
626  continueFunction = STD_NOT_OK;
627  }
628 
629  if (ltc_state->check_spi_flag == STD_NOT_OK) {
630  if (ltc_state->timer > 0u) {
631  if ((--ltc_state->timer) > 0u) {
632  ltc_state->triggerentry--;
633  continueFunction = STD_NOT_OK; /* handle state machine only if timer has elapsed */
634  }
635  }
636  } else {
637  if (AFE_IsTransmitOngoing(ltc_state) == true) {
638  if (ltc_state->timer > 0u) {
639  if ((--ltc_state->timer) > 0u) {
640  ltc_state->triggerentry--;
641  continueFunction = STD_NOT_OK; /* handle state machine only if timer has elapsed */
642  }
643  }
644  }
645  }
646 
647  if (continueFunction == STD_OK) {
648  switch (ltc_state->state) {
649  /****************************UNINITIALIZED***********************************/
651  /* waiting for Initialization Request */
652  statereq = LTC_TransferStateRequest(ltc_state, &tmpbusID, &tmpadcMode, &tmpadcMeasCh);
653  if (statereq.request == LTC_STATE_INIT_REQUEST) {
654  LTC_SaveLastStates(ltc_state);
655  LTC_InitializeDatabase(ltc_state);
656  LTC_ResetErrorTable(ltc_state);
659  ltc_state->adcMode = tmpadcMode;
660  ltc_state->adcMeasCh = tmpadcMeasCh;
661  } else if (statereq.request == LTC_STATE_NO_REQUEST) {
662  /* no actual request pending */
663  } else {
664  ltc_state->ErrRequestCounter++; /* illegal request pending */
665  }
666  break;
667 
668  /****************************INITIALIZATION**********************************/
670 
671  LTC_SetTransferTimes(ltc_state);
672  if (ltc_state->substate == LTC_INIT_STRING) {
673  LTC_SaveLastStates(ltc_state);
674  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface;
676  ltc_state->spiSeqEndPtr = ltc_state->ltcData.pSpiInterface + BS_NR_OF_STRINGS;
679  } else if (ltc_state->substate == LTC_ENTRY_INITIALIZATION) {
680  LTC_SaveLastStates(ltc_state);
681  retVal = LTC_TransmitWakeUp(ltc_state->spiSeqPtr); /* Send dummy byte to wake up the daisy chain */
683  ltc_state,
684  retVal,
692 
693  } else if (ltc_state->substate == LTC_RE_ENTRY_INITIALIZATION) {
694  LTC_SaveLastStates(ltc_state);
695  retVal =
696  LTC_TransmitWakeUp(ltc_state->spiSeqPtr); /* Send dummy byte again to wake up the daisy chain */
698  ltc_state,
699  retVal,
707 
708  } else if (ltc_state->substate == LTC_START_INIT_INITIALIZATION) {
709  LTC_SaveLastStates(ltc_state);
710  ltc_state->check_spi_flag = STD_OK;
711  AFE_SetTransmitOngoing(ltc_state);
712  retVal = LTC_Init(
713  ltc_state->spiSeqPtr,
714  ltc_state->ltcData.txBuffer,
715  ltc_state->ltcData.rxBuffer,
716  ltc_state->ltcData.frameLength); /* Initialize main LTC loop */
717  ltc_state->lastsubstate = ltc_state->substate;
720  ltc_state,
724 
725  } else if (ltc_state->substate == LTC_CHECK_INITIALIZATION) {
726  /* Read values written in config register, currently unused */
727  LTC_SaveLastStates(ltc_state);
728  AFE_SetTransmitOngoing(ltc_state);
729  retVal = LTC_ReadRegister(
730  ltc_cmdRDCFG,
731  ltc_state->spiSeqPtr,
732  ltc_state->ltcData.txBuffer,
733  ltc_state->ltcData.rxBuffer,
734  ltc_state->ltcData.frameLength); /* Read config register */
736  ltc_state,
740 
741  } else if (ltc_state->substate == LTC_EXIT_INITIALIZATION) {
742  LTC_SaveLastStates(ltc_state);
743  ++ltc_state->spiSeqPtr;
744  ++ltc_state->currentString;
745  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
748  } else {
751  }
752  }
753  break;
754 
755  /****************************INITIALIZED*************************************/
757  LTC_SaveLastStates(ltc_state);
759  break;
760 
761  /****************************START MEASUREMENT*******************************/
763 
766 
767  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface;
769  ltc_state->spiSeqEndPtr = ltc_state->ltcData.pSpiInterface + BS_NR_OF_STRINGS;
770  ltc_state->currentString = 0u;
771 
772  ltc_state->check_spi_flag = STD_NOT_OK;
773  retVal = LTC_StartVoltageMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
774 
776  ltc_state,
777  retVal,
785 
786  break;
787 
788  /****************************START MEASUREMENT CONTINUE*******************************/
789  /* Do not reset SPI interface pointer */
791 
794 
795  ltc_state->check_spi_flag = STD_NOT_OK;
796  retVal = LTC_StartVoltageMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
797 
799  ltc_state,
800  retVal,
808 
809  break;
810 
811  /****************************READ VOLTAGE************************************/
813 
815  ltc_state->check_spi_flag = STD_OK;
816  AFE_SetTransmitOngoing(ltc_state);
817  retVal = LTC_ReadRegister(
819  ltc_state->spiSeqPtr,
820  ltc_state->ltcData.txBuffer,
821  ltc_state->ltcData.rxBuffer,
822  ltc_state->ltcData.frameLength);
824  ltc_state,
825  retVal,
833  break;
834 
835  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_B_RDCVB_READVOLTAGE) {
836  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
839  ltc_state, ltc_state->ltcData.rxBuffer, 0u, ltc_state->currentString);
840 
841  AFE_SetTransmitOngoing(ltc_state);
842  retVal = LTC_ReadRegister(
844  ltc_state->spiSeqPtr,
845  ltc_state->ltcData.txBuffer,
846  ltc_state->ltcData.rxBuffer,
847  ltc_state->ltcData.frameLength);
849  ltc_state,
850  retVal,
858  break;
859 
860  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_C_RDCVC_READVOLTAGE) {
861  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
864  ltc_state, ltc_state->ltcData.rxBuffer, 1u, ltc_state->currentString);
865 
866  AFE_SetTransmitOngoing(ltc_state);
867  retVal = LTC_ReadRegister(
869  ltc_state->spiSeqPtr,
870  ltc_state->ltcData.txBuffer,
871  ltc_state->ltcData.rxBuffer,
872  ltc_state->ltcData.frameLength);
874  ltc_state,
875  retVal,
883  break;
884 
885  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_D_RDCVD_READVOLTAGE) {
886  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
889  ltc_state, ltc_state->ltcData.rxBuffer, 2u, ltc_state->currentString);
890 
891  AFE_SetTransmitOngoing(ltc_state);
892  retVal = LTC_ReadRegister(
894  ltc_state->spiSeqPtr,
895  ltc_state->ltcData.txBuffer,
896  ltc_state->ltcData.rxBuffer,
897  ltc_state->ltcData.frameLength);
899  ltc_state,
900  retVal,
908  break;
909 
910  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_E_RDCVE_READVOLTAGE) {
911  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
914  ltc_state, ltc_state->ltcData.rxBuffer, 3u, ltc_state->currentString);
915 
916  AFE_SetTransmitOngoing(ltc_state);
917  retVal = LTC_ReadRegister(
919  ltc_state->spiSeqPtr,
920  ltc_state->ltcData.txBuffer,
921  ltc_state->ltcData.rxBuffer,
922  ltc_state->ltcData.frameLength);
924  ltc_state,
925  retVal,
933  break;
934 
935  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_F_RDCVF_READVOLTAGE) {
936  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
939  ltc_state, ltc_state->ltcData.rxBuffer, 4u, ltc_state->currentString);
940 
941  AFE_SetTransmitOngoing(ltc_state);
942  retVal = LTC_ReadRegister(
944  ltc_state->spiSeqPtr,
945  ltc_state->ltcData.txBuffer,
946  ltc_state->ltcData.rxBuffer,
947  ltc_state->ltcData.frameLength);
949  ltc_state,
950  retVal,
958  break;
959 
960  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_G_RDCVG_READVOLTAGE) {
961  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
964  ltc_state, ltc_state->ltcData.rxBuffer, 5u, ltc_state->currentString);
965 
966  AFE_SetTransmitOngoing(ltc_state);
967  retVal = LTC_ReadRegister(
969  ltc_state->spiSeqPtr,
970  ltc_state->ltcData.txBuffer,
971  ltc_state->ltcData.rxBuffer,
972  ltc_state->ltcData.frameLength);
974  ltc_state,
975  retVal,
983  break;
984 
985  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_H_RDCVH_READVOLTAGE) {
986  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
989  ltc_state, ltc_state->ltcData.rxBuffer, 6u, ltc_state->currentString);
990 
991  AFE_SetTransmitOngoing(ltc_state);
992  retVal = LTC_ReadRegister(
994  ltc_state->spiSeqPtr,
995  ltc_state->ltcData.txBuffer,
996  ltc_state->ltcData.rxBuffer,
997  ltc_state->ltcData.frameLength);
999  ltc_state,
1000  retVal,
1008  break;
1009 
1010  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_I_RDCVI_READVOLTAGE) {
1011  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1014  ltc_state, ltc_state->ltcData.rxBuffer, 7u, ltc_state->currentString);
1015 
1016  AFE_SetTransmitOngoing(ltc_state);
1017  retVal = LTC_ReadRegister(
1019  ltc_state->spiSeqPtr,
1020  ltc_state->ltcData.txBuffer,
1021  ltc_state->ltcData.rxBuffer,
1022  ltc_state->ltcData.frameLength);
1024  ltc_state,
1025  retVal,
1033  break;
1034 
1035  } else if (ltc_state->substate == LTC_EXIT_READVOLTAGE) {
1036  retVal = LTC_CheckPec(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1039  ltc_state, ltc_state->ltcData.rxBuffer, 8u, ltc_state->currentString);
1040 
1041  /* Switch to different state if read voltage state is reused
1042  * e.g. open-wire check... */
1043  if (ltc_state->reusageMeasurementMode == LTC_NOT_REUSED) {
1044  LTC_SaveVoltages(ltc_state, ltc_state->currentString);
1045 
1046  ++ltc_state->spiSeqPtr;
1047  ++ltc_state->currentString;
1048  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
1049  if (LTC_IsFirstMeasurementCycleFinished(ltc_state) == false) {
1051  }
1052  statereq = LTC_TransferStateRequest(ltc_state, &tmpbusID, &tmpadcMode, &tmpadcMeasCh);
1053  if (statereq.request == LTC_STATE_OPENWIRE_CHECK_REQUEST) {
1054  if (statereq.string < BS_NR_OF_STRINGS) {
1055  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + statereq.string;
1056  ltc_state->requestedString = statereq.string;
1057  /* This is necessary because the state machine will go through read voltage measurement registers */
1058  ltc_state->currentString = statereq.string;
1061  ltc_state,
1065  }
1066  } else {
1069  ltc_state->check_spi_flag = STD_NOT_OK;
1070  }
1071  } else {
1074  ltc_state->check_spi_flag = STD_NOT_OK;
1075  }
1076  } else if (ltc_state->reusageMeasurementMode == LTC_REUSE_READVOLT_FOR_ADOW_PUP) {
1078  ltc_state,
1082  } else if (ltc_state->reusageMeasurementMode == LTC_REUSE_READVOLT_FOR_ADOW_PDOWN) {
1084  ltc_state,
1088  }
1089  }
1090  break;
1091 
1092  /**************************OPEN-WIRE CHECK*******************************/
1095  /* Run ADOW command with PUP = 1 */
1096  ltc_state->adcMode = LTC_OW_MEASUREMENT_MODE;
1097  ltc_state->check_spi_flag = STD_NOT_OK;
1098 
1099  retVal = LTC_StartOpenWireMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, 1);
1100  if (retVal == STD_OK) {
1102 
1104  ltc_state,
1108 
1109  ltc_state->resendCommandCounter--;
1110 
1111  /* Check how many retries are left */
1112  if (ltc_state->resendCommandCounter == 0) {
1113  /* Switch to read voltage state to read cell voltages */
1114 
1116  ltc_state,
1120 
1121  /* Reuse read voltage register */
1123  }
1124  } else {
1128  }
1129  } else if (ltc_state->substate == LTC_READ_VOLTAGES_PULLUP_OPENWIRE_CHECK) {
1130  /* Previous state: Read voltage -> information stored in voltage buffer */
1132 
1133  /* Copy data from voltage struct into open-wire struct */
1134  for (uint16_t i = 0u; i < BS_NR_OF_CELL_BLOCKS_PER_STRING; i++) {
1135  ltc_state->ltcData.openWireDetection->openWirePup[ltc_state->requestedString][i] =
1136  ltc_state->ltcData.cellVoltage->cellVoltage_mV[ltc_state->requestedString][i];
1137  }
1138 
1139  /* Set number of ADOW retries - send ADOW command with pull-down two times */
1142  ltc_state,
1146 
1147  } else if (ltc_state->substate == LTC_REQUEST_PULLDOWN_CURRENT_OPENWIRE_CHECK) {
1148  /* Run ADOW command with PUP = 0 */
1149  ltc_state->adcMode = LTC_OW_MEASUREMENT_MODE;
1150  ltc_state->check_spi_flag = STD_NOT_OK;
1151 
1152  retVal = LTC_StartOpenWireMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, 0);
1153  if (retVal == STD_OK) {
1155 
1157  ltc_state,
1161 
1162  ltc_state->resendCommandCounter--;
1163 
1164  /* Check how many retries are left */
1165  if (ltc_state->resendCommandCounter == 0) {
1166  /* Switch to read voltage state to read cell voltages */
1167 
1169  ltc_state,
1173 
1174  /* Reuse read voltage register */
1176  }
1177  } else {
1181  }
1182  } else if (ltc_state->substate == LTC_READ_VOLTAGES_PULLDOWN_OPENWIRE_CHECK) {
1183  /* Previous state: Read voltage -> information stored in voltage buffer */
1185 
1186  /* Copy data from voltage struct into open-wire struct */
1187  for (uint16_t i = 0u; i < BS_NR_OF_CELL_BLOCKS_PER_STRING; i++) {
1188  ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][i] =
1189  ltc_state->ltcData.cellVoltage->cellVoltage_mV[ltc_state->requestedString][i];
1190  }
1191 
1194 
1195  } else if (ltc_state->substate == LTC_PERFORM_OPENWIRE_CHECK) {
1196  /* Perform actual open-wire check */
1197 
1198  /* Take difference between pull-up and pull-down measurement */
1199  for (uint16_t i = 1u; i < BS_NR_OF_CELL_BLOCKS_PER_STRING; i++) {
1200  ltc_state->ltcData.openWireDetection->openWireDelta[ltc_state->requestedString][i] = (int32_t)(
1201  ltc_state->ltcData.openWireDetection->openWirePup[ltc_state->requestedString][i] -
1202  ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][i]);
1203  }
1204 
1205  /* PDOWN or PUP positive or negative full scale value: C(N) or C(N-1) open*/
1206  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
1207  /* PUP */
1208  for (uint8_t p = 0u; p < BS_NR_OF_CELL_BLOCKS_PER_MODULE; p++) {
1209  if ((ltc_state->ltcData.openWireDetection
1210  ->openWirePup[ltc_state->requestedString]
1211  [p + (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] ==
1213  (ltc_state->ltcData.openWireDetection
1214  ->openWirePup[ltc_state->requestedString]
1215  [p + (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] ==
1217  ltc_state->ltcData.openWire->openwire[ltc_state->requestedString]
1218  [p + (m * (BS_NR_OF_CELL_BLOCKS_PER_MODULE))] = 1;
1219  ltc_state->ltcData.openWire
1220  ->openwire[ltc_state->requestedString]
1221  [(p + 1u) + (m * (BS_NR_OF_CELL_BLOCKS_PER_MODULE))] = 1;
1222  }
1223  if ((ltc_state->ltcData.openWireDetection
1224  ->openWirePdown[ltc_state->requestedString]
1225  [p + (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] ==
1227  (ltc_state->ltcData.openWireDetection
1228  ->openWirePdown[ltc_state->requestedString]
1229  [p + (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] ==
1231  ltc_state->ltcData.openWire->openwire[ltc_state->requestedString]
1232  [p + (m * (BS_NR_OF_CELL_BLOCKS_PER_MODULE))] = 1;
1233  ltc_state->ltcData.openWire
1234  ->openwire[ltc_state->requestedString]
1235  [(p + 1u) + (m * (BS_NR_OF_CELL_BLOCKS_PER_MODULE))] = 1;
1236  }
1237  }
1238  }
1239 
1240  /* data sheet page 28: "for all values of n from 1 to 36: If CELL Delta(n+1) < -200mV then C(n) is open" */
1241  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
1242  /* ltc_state->ltcData.openWireDelta parsed from 1 to (BS_NR_OF_CELL_BLOCKS_PER_MODULE-1) */
1243  for (uint8_t c = 1u; c < BS_NR_OF_CELL_BLOCKS_PER_MODULE; c++) {
1244  /* If delta cell(n+1) < -200mV: open-wire at C(n) */
1245  if (ltc_state->ltcData.openWireDetection
1246  ->openWireDelta[ltc_state->requestedString]
1248  ltc_state->ltcData.openWire->openwire[ltc_state->requestedString]
1249  [c + (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] = 1;
1250  }
1251  }
1252  }
1253 
1254  ltc_state->ltcData.openWire->nrOpenWires[ltc_state->requestedString] = 0;
1255  for (uint16_t c = 0u; c < (BS_NR_OF_MODULES_PER_STRING * (BS_NR_OF_CELL_BLOCKS_PER_MODULE + 1));
1256  c++) {
1257  if (ltc_state->ltcData.openWire->openwire[ltc_state->requestedString][c] == 1) {
1258  ltc_state->ltcData.openWire->nrOpenWires[ltc_state->requestedString]++;
1259  }
1260  }
1261 
1262  /* Write database entry */
1263  DATA_WRITE_DATA(ltc_state->ltcData.openWire);
1264  /* Start new measurement cycle */
1266  }
1267  break;
1268 
1269  /****************************DEFAULT**************************/
1270  default:
1271  /* invalid state */
1273  break;
1274  }
1275 
1276  ltc_state->triggerentry--; /* reentrance counter */
1277  } /* continueFunction */
1278 }
1279 
1280 /**
1281  * @brief saves the voltage values read from the LTC daisy-chain.
1282  *
1283  * After a voltage measurement was initiated to measure the voltages of the cells,
1284  * the result is read via SPI from the daisy-chain.
1285  * There are 6 register to read _(A,B,C,D,E,F,G,H,I) to get all cell voltages.
1286  * Only one register can be read at a time.
1287  * This function is called to store the result from the transmission in a buffer.
1288  *
1289  * @param ltc_state state of the ltc state machine
1290  * @param pRxBuff receive buffer
1291  * @param registerSet voltage register that was read (voltage register A,B,C,D,E,F,G,H or I)
1292  * @param stringNumber string addressed
1293  *
1294  */
1296  LTC_STATE_s *ltc_state,
1297  uint16_t *pRxBuff,
1298  uint8_t registerSet,
1299  uint8_t stringNumber) {
1300  uint16_t cellOffset = 0;
1301  uint16_t val_ui = 0;
1302  int16_t voltage = 0;
1303  uint64_t bitmask = 0;
1304  uint16_t buffer_LSB = 0;
1305  uint16_t buffer_MSB = 0;
1306 
1307  cellOffset = registerSet * 4u;
1308 
1309  /* Calculate bitmask for valid flags */
1310  bitmask |= 0x0Full << cellOffset; /* 0x0F: four voltages in each register */
1311 
1312  /* reinitialize index counter at begin of cycle */
1313  if (cellOffset == 0u) {
1314  (ltc_state->ltcData.usedCellIndex[stringNumber]) = 0u;
1315  }
1316 
1317  /* Retrieve data without command and CRC*/
1318  for (uint8_t m = 0u; m < LTC_N_LTC; m++) {
1319  uint8_t incrementations = 0u;
1320 
1321  /* parse all four voltages (4 * 12bits) contained in one register */
1322  for (uint8_t c = 0u; c < 4u; c++) {
1323  switch (c) {
1324  case 0u:
1325  buffer_MSB = pRxBuff[4u + (m * 8u)];
1326  buffer_LSB = (pRxBuff[4u + 1u + (m * 8u)]) >> 4u;
1327  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 4u));
1328  break;
1329  case 1u:
1330  buffer_MSB = pRxBuff[4u + 1u + (m * 8u)] & 0x0Fu;
1331  buffer_LSB = (pRxBuff[4u + 2u + (m * 8u)]);
1332  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 8u));
1333  break;
1334  case 2u:
1335  buffer_MSB = pRxBuff[4u + 3u + (m * 8u)];
1336  buffer_LSB = (pRxBuff[4u + 4u + (m * 8u)]) >> 4u;
1337  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 4u));
1338  break;
1339  case 3u:
1340  buffer_MSB = pRxBuff[4u + 4u + (m * 8u)] & 0x0Fu;
1341  buffer_LSB = (pRxBuff[4u + 5u + (m * 8u)]);
1342  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 8u));
1343  break;
1344  default:
1345  break;
1346  }
1347 
1348  /* Check signed bit if measured value is negative or not */
1349  if ((val_ui & (1u << (12u - 1u))) == 0u) {
1350  voltage = (int16_t)(((val_ui & 0x7FFu)) * LTC_FUEL_CELL_LSB_RESOLUTION_mV); /* Unit mV */
1351  } else {
1352  voltage = (int16_t)(((((~val_ui) + 1) & 0x7FF)) * (-LTC_FUEL_CELL_LSB_RESOLUTION_mV)); /* Unit mV */
1353  }
1354 
1355  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][m] == true) {
1356  ltc_state->ltcData.cellVoltage->cellVoltage_mV[stringNumber]
1357  [(ltc_state->ltcData.usedCellIndex[stringNumber]) +
1358  (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] = voltage;
1359  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
1360  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][(m / LTC_NUMBER_OF_LTC_PER_MODULE)] &=
1361  bitmask;
1362  } else {
1363  /* PEC_valid == false: Invalidate only flags of this voltage register */
1364  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][(m / LTC_NUMBER_OF_LTC_PER_MODULE)] |=
1365  bitmask;
1366  }
1367 
1368  (ltc_state->ltcData.usedCellIndex[stringNumber])++;
1369  incrementations++;
1370 
1371  if ((ltc_state->ltcData.usedCellIndex[stringNumber]) > BS_NR_OF_CELL_BLOCKS_PER_MODULE) {
1372  break;
1373  }
1374  }
1375 
1376  /* Restore start value for next module in the daisy-chain. Only
1377  * decrement used cell index if current module is not the last
1378  * module in the daisy-chain. */
1379  if ((m + 1u) < LTC_N_LTC) {
1380  (ltc_state->ltcData.usedCellIndex[stringNumber]) -= incrementations;
1381  }
1382  }
1383 }
1384 
1385 /**
1386  * @brief initialize the daisy-chain.
1387  *
1388  * To initialize the LTC6804 daisy-chain, a dummy byte (0x00) is sent.
1389  *
1390  * @param pSpiInterface pointer to SPI configuration
1391  * @param pTxBuff transmit buffer
1392  * @param pRxBuff receive buffer
1393  * @param frameLength number of words to transmit
1394  *
1395  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
1396  *
1397  */
1399  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1400  uint16_t *pTxBuff,
1401  uint16_t *pRxBuff,
1402  uint32_t frameLength) {
1403  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
1404 
1405  uint8_t PEC_Check[6];
1406  uint16_t PEC_result = 0;
1407 
1408  /* now construct the message to be sent: it contains the wanted data, PLUS the needed PECs */
1409  pTxBuff[0] = ltc_cmdWRCFG[0];
1410  pTxBuff[1] = ltc_cmdWRCFG[1];
1411  pTxBuff[2] = ltc_cmdWRCFG[2];
1412  pTxBuff[3] = ltc_cmdWRCFG[3];
1413 
1414  /* set REFON bit to 1 */
1415  /* data for the configuration */
1416  for (uint16_t i = 0u; i < LTC_N_LTC; i++) {
1417  /* 3F = disable all pull-downs, 40: REFON = 1 */
1418  pTxBuff[4u + (i * 8u)] = 0x3F;
1419  pTxBuff[5u + (i * 8u)] = (LTC_HIRNG << 7u) | 0x40u;
1420  pTxBuff[6u + (i * 8u)] = 0x00;
1421  pTxBuff[7u + (i * 8u)] = 0x00;
1422  pTxBuff[8u + (i * 8u)] = 0x00;
1423  pTxBuff[9u + (i * 8u)] = 0x00;
1424 
1425  PEC_Check[0] = pTxBuff[4u + (i * 8u)];
1426  PEC_Check[1] = pTxBuff[5u + (i * 8u)];
1427  PEC_Check[2] = pTxBuff[6u + (i * 8u)];
1428  PEC_Check[3] = pTxBuff[7u + (i * 8u)];
1429  PEC_Check[4] = pTxBuff[8u + (i * 8u)];
1430  PEC_Check[5] = pTxBuff[9u + (i * 8u)];
1431 
1432  PEC_result = LTC_pec15_calc(6, PEC_Check);
1433  pTxBuff[10u + (i * 8u)] = (PEC_result >> 8u) & 0xFFu;
1434  pTxBuff[11u + (i * 8u)] = PEC_result & 0xFFu;
1435  } /* end for */
1436 
1437  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
1438 
1439  return retVal;
1440 }
1441 
1442 /**
1443  * @brief resets the error table.
1444  *
1445  * This function should be called during initialization or before starting a new measurement cycle
1446  *
1447  * @param ltc_state: state of the ltc state machine
1448  *
1449  */
1450 static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state) {
1451  uint16_t i = 0;
1452 
1453  for (uint8_t s = 0u; s < BS_NR_OF_STRINGS; s++) {
1454  for (i = 0; i < LTC_N_LTC; i++) {
1455  ltc_state->ltcData.errorTable->PEC_valid[s][i] = false;
1456  ltc_state->ltcData.errorTable->mux0[s][i] = 0;
1457  ltc_state->ltcData.errorTable->mux1[s][i] = 0;
1458  ltc_state->ltcData.errorTable->mux2[s][i] = 0;
1459  ltc_state->ltcData.errorTable->mux3[s][i] = 0;
1460  }
1461  }
1462 }
1463 
1464 /**
1465  * @brief tells the LTC daisy-chain to start measuring the voltage on all cells.
1466  *
1467  * This function sends an instruction to the daisy-chain via SPI, in order to start voltage measurement for all cells.
1468  *
1469  * @param pSpiInterface pointer to SPI configuration
1470  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
1471  * @param adcMeasCh number of cell voltage measured (2 cells or all cells)
1472  *
1473  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
1474  *
1475  */
1477  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1478  LTC_ADCMODE_e adcMode,
1479  LTC_ADCMEAS_CHAN_e adcMeasCh) {
1480  STD_RETURN_TYPE_e retVal = STD_OK;
1481 
1482  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_normal_Fuelcell);
1483 
1484  return retVal;
1485 }
1486 
1487 /**
1488  * @brief tells LTC daisy-chain to start measuring the voltage on GPIOS.
1489  *
1490  * This function sends an instruction to the daisy-chain via SPI to start the measurement.
1491  *
1492  * @param pSpiInterface pointer to SPI configuration
1493  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
1494  * @param PUP pull-up bit for pull-up or pull-down current (0: pull-down, 1: pull-up)
1495  *
1496  * @return retVal #STD_OK if command was sent correctly by SPI, #STD_NOT_OK otherwise
1497  *
1498  */
1500  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1501  LTC_ADCMODE_e adcMode,
1502  uint8_t PUP) {
1503  STD_RETURN_TYPE_e retval = STD_NOT_OK;
1504 
1505  if (PUP == 0u) {
1506  /* pull-down current */
1508  } else if (PUP == 1u) {
1509  /* pull-up current */
1510  retval = LTC_TransmitCommand(pSpiInterface, ltc_BC_cmdADOW_PUP_100ms_fuelcell);
1511  }
1512 
1513  return retval;
1514 }
1515 
1516 /**
1517  * @brief checks if the data received from the daisy-chain is not corrupt.
1518  *
1519  * This function computes the PEC (CRC) from the data received by the daisy-chain.
1520  * It compares it with the PEC sent by the LTCs.
1521  * If there are errors, the array the error table is updated to locate the LTCs in daisy-chain
1522  * that transmitted corrupt data.
1523  *
1524  * @param ltc_state state of the ltc state machine
1525  * @param DataBufferSPI_RX_with_PEC data obtained from the SPI transmission
1526  * @param stringNumber string addressed
1527  *
1528  * @return retVal STD_OK if PEC check is OK, STD_NOT_OK otherwise
1529  *
1530  */
1532  LTC_STATE_s *ltc_state,
1533  uint16_t *DataBufferSPI_RX_with_PEC,
1534  uint8_t stringNumber) {
1535  uint16_t i = 0;
1536  STD_RETURN_TYPE_e retVal = STD_OK;
1537  uint8_t PEC_TX[2];
1538  uint16_t PEC_result = 0;
1539  uint8_t PEC_Check[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1540 
1541  /* check all PECs and put data without command and PEC in DataBufferSPI_RX (easier to use) */
1542  for (i = 0; i < LTC_N_LTC; i++) {
1543  PEC_Check[0] = DataBufferSPI_RX_with_PEC[4u + (i * 8u)];
1544  PEC_Check[1] = DataBufferSPI_RX_with_PEC[5u + (i * 8u)];
1545  PEC_Check[2] = DataBufferSPI_RX_with_PEC[6u + (i * 8u)];
1546  PEC_Check[3] = DataBufferSPI_RX_with_PEC[7u + (i * 8u)];
1547  PEC_Check[4] = DataBufferSPI_RX_with_PEC[8u + (i * 8u)];
1548  PEC_Check[5] = DataBufferSPI_RX_with_PEC[9u + (i * 8u)];
1549 
1550  PEC_result = LTC_pec15_calc(6, PEC_Check);
1551  PEC_TX[0] = (uint8_t)((PEC_result >> 8u) & 0xFFu);
1552  PEC_TX[1] = (uint8_t)(PEC_result & 0xFFu);
1553 
1554  /* if calculated PEC not equal to received PEC */
1555  if ((PEC_TX[0] != DataBufferSPI_RX_with_PEC[10u + (i * 8u)]) ||
1556  (PEC_TX[1] != DataBufferSPI_RX_with_PEC[11u + (i * 8u)])) {
1557  /* update error table of the corresponding LTC only if PEC check is activated */
1558  if (LTC_DISCARD_PEC == false) {
1559  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = false;
1560  retVal = STD_NOT_OK;
1561  } else {
1562  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = true;
1563  }
1564  } else {
1565  /* update error table of the corresponding LTC */
1566  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = true;
1567  }
1568  }
1569  return retVal;
1570 }
1571 
1572 /**
1573  * @brief send command to the LTC daisy-chain and receives data from the LTC daisy-chain.
1574  *
1575  * This is the core function to receive data from the LTC6804 daisy-chain.
1576  * A 2 byte command is sent with the corresponding PEC. Example: read configuration register (RDCFG).
1577  * Only command has to be set, the function calculates the PEC automatically.
1578  * The data send is:
1579  * 2 bytes (COMMAND) 2 bytes (PEC)
1580  * The data received is:
1581  * 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)
1582  *
1583  * The function does not check the PECs. This has to be done elsewhere.
1584  *
1585  * @param Command command sent to the daisy-chain
1586  * @param pSpiInterface pointer to SPI configuration
1587  * @param pTxBuff transmit buffer
1588  * @param pRxBuff receive buffer
1589  * @param frameLength number of words to transmit
1590  *
1591  * @return statusSPI #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
1592  *
1593  */
1595  uint16_t *Command,
1596  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1597  uint16_t *pTxBuff,
1598  uint16_t *pRxBuff,
1599  uint32_t frameLength) {
1600  STD_RETURN_TYPE_e statusSPI = STD_OK;
1601  uint16_t i = 0;
1602 
1603  /* DataBufferSPI_RX_with_PEC contains the data to receive.
1604  The transmission function checks the PECs.
1605  It constructs DataBufferSPI_RX, which contains the received data without PEC (easier to use). */
1606 
1607  for (i = 0; i < LTC_N_BYTES_FOR_DATA_TRANSMISSION; i++) {
1608  pTxBuff[i] = 0x00;
1609  }
1610 
1611  pTxBuff[0] = Command[0];
1612  pTxBuff[1] = Command[1];
1613  pTxBuff[2] = Command[2];
1614  pTxBuff[3] = Command[3];
1615 
1616  statusSPI = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
1617 
1618  return statusSPI;
1619 }
1620 
1621 /**
1622  * @brief gets the frequency of the SPI clock.
1623  *
1624  * This function reads the configuration from the SPI handle directly.
1625  *
1626  * @param pSpiInterface pointer to SPI configuration
1627  *
1628  * @return frequency of the SPI clock
1629  */
1630 static uint32_t LTC_GetSpiClock(SPI_INTERFACE_CONFIG_s *pSpiInterface) {
1631  uint32_t SPI_Clock = 0;
1632  uint32_t prescaler = 0;
1633 
1634  /* if (LTC_SPI_INSTANCE == SPI2 || LTC_SPI_INSTANCE == SPI3) { */
1635  /* SPI2 and SPI3 are connected to APB1 (PCLK1) */
1636  /* The prescaler setup bits LTC_SPI_PRESCALER corresponds to the bits 5:3 in the SPI_CR1 register */
1637  /* Reference manual p.909 */
1638  /* The shift by 3 puts the bits 5:3 to the first position */
1639  /* Division are made by powers of 2 which corresponds to shifting to the right */
1640  /* 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 */
1641 
1642  /* SPI_Clock = HAL_RCC_GetPCLK1Freq()>>((LTC_SPI_PRESCALER>>3)+1);
1643  } */
1644 
1645  /* if (LTC_SPI_INSTANCE == SPI1 || LTC_SPI_INSTANCE == SPI4 || LTC_SPI_INSTANCE == SPI5 || LTC_SPI_INSTANCE == SPI6) { */
1646  /* SPI1, SPI4, SPI5 and SPI6 are connected to APB2 (PCLK2) */
1647  /* The prescaler setup bits LTC_SPI_PRESCALER corresponds to the bits 5:3 in the SPI_CR1 register */
1648  /* Reference manual p.909 */
1649  /* The shift by 3 puts the bits 5:3 to the first position */
1650  /* Division are made by powers of 2 which corresponds to shifting to the right */
1651  /* 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 */
1652 
1653  /* SPI_Clock = HAL_RCC_GetPCLK2Freq()>>((LTC_SPI_PRESCALER>>3)+1);
1654  } */
1655 
1656  /* Get SPI prescaler */
1657  prescaler = ((pSpiInterface->pNode->FMT0) >> 8u) & 0xFFu;
1658  SPI_Clock = (uint32_t)(AVCLK1_FREQ * 1000000u) / (prescaler + 1u);
1659 
1660  return SPI_Clock;
1661 }
1662 
1663 /**
1664  * @brief sets the transfer time needed to receive/send data with the LTC daisy-chain.
1665  *
1666  * This function gets the clock frequency and uses the number of LTCs in the daisy-chain.
1667  *
1668  * @param ltc_state: state of the ltc state machine
1669  *
1670  */
1671 static void LTC_SetTransferTimes(LTC_STATE_s *ltc_state) {
1672  uint32_t transferTime_us = 0;
1673  uint32_t SPI_Clock = 0;
1674 
1675  SPI_Clock = LTC_GetSpiClock(ltc_state->ltcData.pSpiInterface);
1676 
1677  /* Transmission of a command and data */
1678  /* Multiplication by 1000*1000 to get us */
1679  transferTime_us = (8u * 1000u * 1000u) / (SPI_Clock);
1680  transferTime_us *= LTC_N_BYTES_FOR_DATA_TRANSMISSION;
1681  transferTime_us = transferTime_us + LTC_SPI_WAKEUP_WAIT_TIME_US;
1682  ltc_state->commandDataTransferTime = (transferTime_us / 1000u) + 1u;
1683 
1684  /* Transmission of a command */
1685  /* Multiplication by 1000*1000 to get us */
1686  transferTime_us = ((4u) * 8u * 1000u * 1000u) / (SPI_Clock);
1687  transferTime_us = transferTime_us + LTC_SPI_WAKEUP_WAIT_TIME_US;
1688  ltc_state->commandTransferTime = (transferTime_us / 1000u) + 1u;
1689 
1690  /* Transmission of a command + 9 clocks */
1691  /* Multiplication by 1000*1000 to get us */
1692  transferTime_us = ((4u + 9u) * 8u * 1000u * 1000u) / (SPI_Clock);
1693  transferTime_us = transferTime_us + LTC_SPI_WAKEUP_WAIT_TIME_US;
1694  ltc_state->gpioClocksTransferTime = (transferTime_us / 1000u) + 1u;
1695 }
1696 
1697 /**
1698  * @brief checks the state requests that are made.
1699  *
1700  * This function checks the validity of the state requests.
1701  * The results of the checked is returned immediately.
1702  *
1703  * @param ltc_state: state of the ltc state machine
1704  * @param statereq state request to be checked
1705  *
1706  * @return result of the state request that was made, taken from #LTC_RETURN_TYPE_e
1707  */
1709  LTC_RETURN_TYPE_e retVal = LTC_OK;
1710  if (statereq.string >= BS_NR_OF_STRINGS) {
1711  retVal = LTC_ILLEGAL_REQUEST;
1712  } else if (ltc_state->statereq.request == LTC_STATE_NO_REQUEST) {
1713  /* init only allowed from the uninitialized state */
1714  if (statereq.request == LTC_STATE_INIT_REQUEST) {
1715  if (ltc_state->state == LTC_STATEMACH_UNINITIALIZED) {
1716  retVal = LTC_OK;
1717  } else {
1718  retVal = LTC_ALREADY_INITIALIZED;
1719  }
1720  } else {
1721  retVal = LTC_OK;
1722  }
1723  } else {
1724  retVal = LTC_REQUEST_PENDING;
1725  }
1726  return retVal;
1727 }
1728 
1730  bool retval = false;
1731 
1733  retval = ltc_state->first_measurement_made;
1735 
1736  return retval;
1737 }
1738 
1739 /**
1740  * @brief sets the measurement initialization status.
1741  */
1744  ltc_state->first_measurement_made = true;
1746 }
1747 
1748 extern void LTC_InitializeMonitoringPin(void) {
1749  /* Set 3rd PE pins to enable daisy chains */
1766 }
1767 
1768 /*========== Externalized Static Function Implementations (Unit Test) =======*/
1769 #ifdef UNITY_UNIT_TEST
1770 uint8_t TEST_LTC_CheckReEntrance(LTC_STATE_s *ltc_state) {
1771  return LTC_CheckReEntrance(ltc_state);
1772 }
1773 
1774 extern void TEST_LTC_SetFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state) {
1776 }
1777 
1778 /** this define is used for creating the declaration of a function for variable extraction */
1779 #define TEST_LTC_DEFINE_GET(VARIABLE) \
1780  extern void TEST_LTC_Get_##VARIABLE(uint8_t data[4]) { \
1781  for (uint8_t i = 0u; i < 4u; i++) { \
1782  data[i] = (uint8_t)(VARIABLE)[i]; \
1783  } \
1784  }
1785 
1786 TEST_LTC_DEFINE_GET(ltc_cmdWRCFG);
1787 TEST_LTC_DEFINE_GET(ltc_cmdRDCFG);
1788 TEST_LTC_DEFINE_GET(ltc_cmdRDCVA_Fuelcell);
1789 TEST_LTC_DEFINE_GET(ltc_cmdRDCVB_Fuelcell);
1790 TEST_LTC_DEFINE_GET(ltc_cmdRDCVC_Fuelcell);
1791 TEST_LTC_DEFINE_GET(ltc_cmdRDCVD_Fuelcell);
1792 TEST_LTC_DEFINE_GET(ltc_cmdRDCVE_Fuelcell);
1793 TEST_LTC_DEFINE_GET(ltc_cmdRDCVF_Fuelcell);
1794 TEST_LTC_DEFINE_GET(ltc_cmdRDCVG_Fuelcell);
1795 TEST_LTC_DEFINE_GET(ltc_cmdRDCVH_Fuelcell);
1796 TEST_LTC_DEFINE_GET(ltc_cmdRDCVI_Fuelcell);
1797 TEST_LTC_DEFINE_GET(ltc_cmdADCV_normal_Fuelcell);
1798 TEST_LTC_DEFINE_GET(ltc_BC_cmdADOW_PUP_100ms_fuelcell);
1799 TEST_LTC_DEFINE_GET(ltc_BC_cmdADOW_PDOWN_100ms_fuelcell);
1800 #endif
STD_RETURN_TYPE_e AFE_PlausibilityCheckTempMinMax(const int16_t celltemperature_ddegC)
Cell temperature plausibility check.
STD_RETURN_TYPE_e AFE_PlausibilityCheckVoltageMeasurementRange(const int16_t cellvoltage_mV, const AFE_PLAUSIBILITY_VALUES_s plausibleValues)
Cell voltage measurement range plausibility check.
plausibility checks for cell voltage and cell temperatures
#define BS_NR_OF_CELL_BLOCKS_PER_MODULE
number of cells per module
#define BS_NR_OF_STRINGS
Number of parallel strings in the battery pack.
#define BS_NR_OF_TEMP_SENSORS_PER_MODULE
number of temperature sensors per battery module
#define BS_NR_OF_GPIOS_PER_MODULE
Number of GPIOs on the LTC IC.
#define BS_NR_OF_CELL_BLOCKS_PER_STRING
#define BS_NR_OF_MODULES_PER_STRING
number of modules in a string
#define BS_NR_OF_TEMP_SENSORS_PER_STRING
Database module header.
#define DATA_WRITE_DATA(...)
Definition: database.h:93
@ DATA_BLOCK_ID_CELL_TEMPERATURE_BASE
Definition: database_cfg.h:98
@ DATA_BLOCK_ID_OPEN_WIRE_BASE
Definition: database_cfg.h:84
@ DATA_BLOCK_ID_CELL_VOLTAGE_BASE
Definition: database_cfg.h:97
@ DATA_BLOCK_ID_ALL_GPIO_VOLTAGES_BASE
Definition: database_cfg.h:85
DIAG_RETURNTYPE_e DIAG_Handler(DIAG_ID_e diag_id, DIAG_EVENT_e event, DIAG_IMPACT_LEVEL_e impact, uint32_t data)
DIAG_Handler provides generic error handling, based on diagnosis group.
Definition: diag.c:229
STD_RETURN_TYPE_e DIAG_CheckEvent(STD_RETURN_TYPE_e cond, DIAG_ID_e diag_id, DIAG_IMPACT_LEVEL_e impact, uint32_t data)
DIAG_CheckEvent provides a simple interface to check an event for STD_OK.
Definition: diag.c:356
Diagnosis driver header.
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:239
@ DIAG_EVENT_OK
Definition: diag_cfg.h:238
@ DIAG_STRING
Definition: diag_cfg.h:252
DIAG_ID_e
Definition: diag_cfg.h:157
@ DIAG_ID_AFE_CELL_VOLTAGE_MEAS_ERROR
Definition: diag_cfg.h:171
@ DIAG_ID_AFE_CELL_TEMPERATURE_MEAS_ERROR
Definition: diag_cfg.h:172
@ DIAG_ID_AFE_COM_INTEGRITY
Definition: diag_cfg.h:162
@ DIAG_ID_AFE_SPI
Definition: diag_cfg.h:161
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:241
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:115
STD_RETURN_TYPE_e
Definition: fstd_types.h:81
@ STD_NOT_OK
Definition: fstd_types.h:83
@ STD_OK
Definition: fstd_types.h:82
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:76
Header for the driver for the IO module.
Headers for the driver for the LTC monitoring chip.
static uint16_t ltc_cmdRDCVI_Fuelcell[4]
Definition: ltc_6806.c:200
uint16_t ltc_TxPecBuffer[LTC_N_BYTES_FOR_DATA_TRANSMISSION]
Definition: ltc_6806.c:111
static STD_RETURN_TYPE_e LTC_StartVoltageMeasurement(SPI_INTERFACE_CONFIG_s *pSpiInterface, LTC_ADCMODE_e adcMode, LTC_ADCMEAS_CHAN_e adcMeasCh)
tells the LTC daisy-chain to start measuring the voltage on all cells.
Definition: ltc_6806.c:1476
static DATA_BLOCK_ALL_GPIO_VOLTAGES_s ltc_allgpiovoltage
Definition: ltc_6806.c:122
static DATA_BLOCK_CELL_VOLTAGE_s ltc_cellvoltage
Definition: ltc_6806.c:120
static STD_RETURN_TYPE_e LTC_StartOpenWireMeasurement(SPI_INTERFACE_CONFIG_s *pSpiInterface, LTC_ADCMODE_e adcMode, uint8_t PUP)
tells LTC daisy-chain to start measuring the voltage on GPIOS.
Definition: ltc_6806.c:1499
static uint16_t ltc_cmdRDCVA_Fuelcell[4]
Definition: ltc_6806.c:192
LTC_STATEMACH_e LTC_GetState(LTC_STATE_s *ltc_state)
gets the current state.
Definition: ltc_6806.c:561
static STD_RETURN_TYPE_e LTC_ReadRegister(uint16_t *Command, SPI_INTERFACE_CONFIG_s *pSpiInterface, uint16_t *pTxBuff, uint16_t *pRxBuff, uint32_t frameLength)
send command to the LTC daisy-chain and receives data from the LTC daisy-chain.
Definition: ltc_6806.c:1594
bool LTC_IsFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state)
gets the measurement initialization status.
Definition: ltc_6806.c:1729
static const AFE_PLAUSIBILITY_VALUES_s ltc_plausibleCellVoltages6806
Definition: ltc_6806.c:130
static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms)
function for setting LTC_Trigger state transitions
Definition: ltc_6806.c:348
static void LTC_SetFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state)
sets the measurement initialization status.
Definition: ltc_6806.c:1742
static LTC_RETURN_TYPE_e LTC_CheckStateRequest(LTC_STATE_s *ltc_state, LTC_REQUEST_s statereq)
checks the state requests that are made.
Definition: ltc_6806.c:1708
LTC_RETURN_TYPE_e LTC_SetStateRequest(LTC_STATE_s *ltc_state, LTC_REQUEST_s statereq)
sets the current state request of the state variable ltc_state.
Definition: ltc_6806.c:599
static uint16_t ltc_cmdRDCVD_Fuelcell[4]
Definition: ltc_6806.c:195
static void LTC_SetTransferTimes(LTC_STATE_s *ltc_state)
sets the transfer time needed to receive/send data with the LTC daisy-chain.
Definition: ltc_6806.c:1671
static uint32_t LTC_GetSpiClock(SPI_INTERFACE_CONFIG_s *pSpiInterface)
gets the frequency of the SPI clock.
Definition: ltc_6806.c:1630
static uint16_t ltc_cmdRDCVG_Fuelcell[4]
Definition: ltc_6806.c:198
static uint16_t ltc_cmdRDCVH_Fuelcell[4]
Definition: ltc_6806.c:199
static STD_RETURN_TYPE_e LTC_CheckPec(LTC_STATE_s *ltc_state, uint16_t *DataBufferSPI_RX_with_PEC, uint8_t stringNumber)
checks if the data received from the daisy-chain is not corrupt.
Definition: ltc_6806.c:1531
static uint16_t ltc_cmdRDCVE_Fuelcell[4]
Definition: ltc_6806.c:196
static uint16_t ltc_cmdRDCFG[4]
Definition: ltc_6806.c:185
static void LTC_SaveLastStates(LTC_STATE_s *ltc_state)
Saves the last state and the last substate.
Definition: ltc_6806.c:335
LTC_REQUEST_s LTC_TransferStateRequest(LTC_STATE_s *ltc_state, uint8_t *pBusIDptr, LTC_ADCMODE_e *pAdcModeptr, LTC_ADCMEAS_CHAN_e *pAdcMeasChptr)
transfers the current state request to the state machine.
Definition: ltc_6806.c:579
void LTC_SaveTemperatures(LTC_STATE_s *ltc_state, uint8_t stringNumber)
stores the measured temperatures and the measured multiplexer feedbacks in the database.
Definition: ltc_6806.c:452
static uint16_t ltc_used_cells_index[BS_NR_OF_STRINGS]
Definition: ltc_6806.c:117
#define LTC_FUEL_CELL_LSB_RESOLUTION_mV
Definition: ltc_6806.c:87
void LTC_InitializeMonitoringPin(void)
Sets the transceiver pins to enable LTC6820 IC.
Definition: ltc_6806.c:1748
static void LTC_SaveRXtoVoltagebuffer_Fuelcell(LTC_STATE_s *ltc_state, uint16_t *pRxBuff, uint8_t registerSet, uint8_t stringNumber)
saves the voltage values read from the LTC daisy-chain.
Definition: ltc_6806.c:1295
LTC_REQUEST_s LTC_GetStateRequest(LTC_STATE_s *ltc_state)
gets the current state request.
Definition: ltc_6806.c:541
void LTC_SaveVoltages(LTC_STATE_s *ltc_state, uint8_t stringNumber)
stores the measured voltages in the database.
Definition: ltc_6806.c:392
#define LTC_FUELCELL_NEGATIVE_FULLSCALE_RANGE_mV
Definition: ltc_6806.c:100
static STD_RETURN_TYPE_e LTC_Init(SPI_INTERFACE_CONFIG_s *pSpiInterface, uint16_t *pTxBuff, uint16_t *pRxBuff, uint32_t frameLength)
initialize the daisy-chain.
Definition: ltc_6806.c:1398
static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state)
resets the error table.
Definition: ltc_6806.c:1450
LTC_STATE_s ltc_stateBase
Definition: ltc_6806.c:137
static uint16_t ltc_cmdRDCVF_Fuelcell[4]
Definition: ltc_6806.c:197
static uint16_t ltc_cmdRDCVB_Fuelcell[4]
Definition: ltc_6806.c:193
void LTC_SaveAllGpioMeasurement(LTC_STATE_s *ltc_state)
stores the measured GPIOs in the database.
Definition: ltc_6806.c:500
static LTC_ERRORTABLE_s ltc_errorTable
Definition: ltc_6806.c:127
void LTC_Trigger(LTC_STATE_s *ltc_state)
trigger function for the LTC driver state machine.
Definition: ltc_6806.c:614
uint8_t LTC_CheckReEntrance(LTC_STATE_s *ltc_state)
re-entrance check of LTC state machine trigger function
Definition: ltc_6806.c:518
#define LTC_FUELCELL_POSITIVE_FULLSCALE_RANGE_mV
Definition: ltc_6806.c:95
static DATA_BLOCK_OPEN_WIRE_s ltc_openwire
Definition: ltc_6806.c:123
static void LTC_InitializeDatabase(LTC_STATE_s *ltc_state)
in the database, initializes the fields related to the LTC drivers.
Definition: ltc_6806.c:299
uint16_t ltc_RxPecBuffer[LTC_N_BYTES_FOR_DATA_TRANSMISSION]
Definition: ltc_6806.c:110
static LTC_OPENWIRE_DETECTION_s ltc_openWireDetection
Definition: ltc_6806.c:126
static void LTC_CondBasedStateTransition(LTC_STATE_s *ltc_state, STD_RETURN_TYPE_e retVal, DIAG_ID_e diagCode, LTC_STATEMACH_e state_ok, uint8_t substate_ok, uint16_t timer_ms_ok, LTC_STATEMACH_e state_nok, uint8_t substate_nok, uint16_t timer_ms_nok)
condition-based state transition depending on retVal
Definition: ltc_6806.c:372
static uint16_t ltc_BC_cmdADOW_PDOWN_100ms_fuelcell[4]
Definition: ltc_6806.c:231
static uint16_t ltc_cmdWRCFG[4]
Definition: ltc_6806.c:184
static DATA_BLOCK_CELL_TEMPERATURE_s ltc_celltemperature
Definition: ltc_6806.c:121
static uint16_t ltc_BC_cmdADOW_PUP_100ms_fuelcell[4]
Definition: ltc_6806.c:229
static uint16_t ltc_cmdRDCVC_Fuelcell[4]
Definition: ltc_6806.c:194
static uint16_t ltc_cmdADCV_normal_Fuelcell[4]
Definition: ltc_6806.c:205
Header for the configuration for the LTC 6806 monitoring IC.
#define LTC_STATEMACH_DAISY_CHAIN_FIRST_INITIALIZATION_TIME
Definition: ltc_6806_cfg.h:177
#define LTC_TRANSMISSION_TIMEOUT
Definition: ltc_6806_cfg.h:146
#define LTC_FUELCELL_NORMAL_ALL_CELLS_MS
Definition: ltc_6806_cfg.h:168
#define LTC_TransmitCommand(spi_ltcInterface, command)
Definition: ltc_6806_cfg.h:272
#define LTC_STATEMACH_SHORTTIME
Definition: ltc_6806_cfg.h:171
#define LTC_DISCARD_PEC
Definition: ltc_6806_cfg.h:89
#define LTC_NUMBER_OF_LTC_PER_MODULE
Definition: ltc_6806_cfg.h:104
#define LTC_HIRNG
Definition: ltc_6806_cfg.h:111
#define LTC_VOLTAGE_MEASUREMENT_MODE
Definition: ltc_6806_cfg.h:125
#define LTC_ADOW_THRESHOLD
Definition: ltc_6806_cfg.h:117
#define LTC_FUEL_CELL_ADOW_TIME_MS
Definition: ltc_6806_cfg.h:114
#define LTC_TransmitReceiveData(spi_ltcInterface, txbuf, rxbuf, length)
Definition: ltc_6806_cfg.h:275
#define LTC_SPI_WAKEUP_WAIT_TIME_US
Definition: ltc_6806_cfg.h:165
#define LTC_TransmitWakeUp(spi_ltcInterface)
Definition: ltc_6806_cfg.h:268
#define LTC_NMBR_REQ_ADOW_COMMANDS
Definition: ltc_6806_cfg.h:262
#define LTC_OW_MEASUREMENT_MODE
Definition: ltc_6806_cfg.h:140
#define LTC_STATEMACH_DAISY_CHAIN_SECOND_INITIALIZATION_TIME
Definition: ltc_6806_cfg.h:182
bool AFE_IsTransmitOngoing(LTC_STATE_s *pLtcState)
gets the SPI transmit status.
Definition: ltc_afe_dma.c:74
void AFE_SetTransmitOngoing(LTC_STATE_s *pLtcState)
sets the SPI transmit status.
Definition: ltc_afe_dma.c:78
#define LTC_N_BYTES_FOR_DATA_TRANSMISSION
Definition: ltc_cfg.h:78
#define LTC_N_LTC
Definition: ltc_cfg.h:67
@ LTC_RE_ENTRY_INITIALIZATION
Definition: ltc_defs.h:177
@ LTC_ENTRY_INITIALIZATION
Definition: ltc_defs.h:175
@ LTC_START_INIT_INITIALIZATION
Definition: ltc_defs.h:176
@ LTC_EXIT_INITIALIZATION
Definition: ltc_defs.h:180
@ LTC_CHECK_INITIALIZATION
Definition: ltc_defs.h:179
@ LTC_INIT_STRING
Definition: ltc_defs.h:174
@ LTC_STATE_INIT_REQUEST
Definition: ltc_defs.h:365
@ LTC_STATE_OPENWIRE_CHECK_REQUEST
Definition: ltc_defs.h:387
@ LTC_STATE_NO_REQUEST
Definition: ltc_defs.h:391
LTC_STATEMACH_e
Definition: ltc_defs.h:118
@ LTC_STATEMACH_INITIALIZATION
Definition: ltc_defs.h:121
@ LTC_STATEMACH_UNINITIALIZED
Definition: ltc_defs.h:120
@ LTC_STATEMACH_STARTMEAS_CONTINUE
Definition: ltc_defs.h:149
@ LTC_STATEMACH_OPENWIRE_CHECK
Definition: ltc_defs.h:141
@ LTC_STATEMACH_READVOLTAGE
Definition: ltc_defs.h:127
@ LTC_STATEMACH_INITIALIZED
Definition: ltc_defs.h:123
@ LTC_STATEMACH_STARTMEAS
Definition: ltc_defs.h:126
@ LTC_REQUEST_PULLDOWN_CURRENT_OPENWIRE_CHECK
Definition: ltc_defs.h:236
@ LTC_READ_VOLTAGES_PULLDOWN_OPENWIRE_CHECK
Definition: ltc_defs.h:237
@ LTC_READ_VOLTAGES_PULLUP_OPENWIRE_CHECK
Definition: ltc_defs.h:235
@ LTC_REQUEST_PULLUP_CURRENT_OPENWIRE_CHECK
Definition: ltc_defs.h:234
@ LTC_PERFORM_OPENWIRE_CHECK
Definition: ltc_defs.h:238
LTC_ADCMEAS_CHAN_e
Definition: ltc_defs.h:104
@ LTC_ADCMEAS_UNDEFINED
Definition: ltc_defs.h:105
@ LTC_ADCMEAS_ALLCHANNEL_CELLS
Definition: ltc_defs.h:106
LTC_RETURN_TYPE_e
Definition: ltc_defs.h:397
@ LTC_BUSY_OK
Definition: ltc_defs.h:399
@ LTC_ILLEGAL_REQUEST
Definition: ltc_defs.h:401
@ LTC_ALREADY_INITIALIZED
Definition: ltc_defs.h:408
@ LTC_ERROR
Definition: ltc_defs.h:407
@ LTC_OK_FROM_ERROR
Definition: ltc_defs.h:406
@ LTC_REQUEST_PENDING
Definition: ltc_defs.h:400
@ LTC_OK
Definition: ltc_defs.h:398
@ LTC_READ_VOLTAGE_REGISTER_F_RDCVF_READVOLTAGE
Definition: ltc_defs.h:196
@ LTC_READ_VOLTAGE_REGISTER_A_RDCVA_READVOLTAGE
Definition: ltc_defs.h:191
@ LTC_READ_VOLTAGE_REGISTER_D_RDCVD_READVOLTAGE
Definition: ltc_defs.h:194
@ LTC_READ_VOLTAGE_REGISTER_G_RDCVG_READVOLTAGE
Definition: ltc_defs.h:197
@ LTC_READ_VOLTAGE_REGISTER_I_RDCVI_READVOLTAGE
Definition: ltc_defs.h:199
@ LTC_READ_VOLTAGE_REGISTER_B_RDCVB_READVOLTAGE
Definition: ltc_defs.h:192
@ LTC_EXIT_READVOLTAGE
Definition: ltc_defs.h:200
@ LTC_READ_VOLTAGE_REGISTER_H_RDCVH_READVOLTAGE
Definition: ltc_defs.h:198
@ LTC_READ_VOLTAGE_REGISTER_E_RDCVE_READVOLTAGE
Definition: ltc_defs.h:195
@ LTC_READ_VOLTAGE_REGISTER_C_RDCVC_READVOLTAGE
Definition: ltc_defs.h:193
@ LTC_REUSE_READVOLT_FOR_ADOW_PUP
Definition: ltc_defs.h:497
@ LTC_REUSE_READVOLT_FOR_ADOW_PDOWN
Definition: ltc_defs.h:498
@ LTC_NOT_REUSED
Definition: ltc_defs.h:496
LTC_ADCMODE_e
Definition: ltc_defs.h:93
@ LTC_ADCMODE_UNDEFINED
Definition: ltc_defs.h:94
@ LTC_ADCMODE_FAST_DCP0
Definition: ltc_defs.h:95
@ LTC_ENTRY
Definition: ltc_defs.h:161
Declaration of the OS wrapper interface.
void OS_ExitTaskCritical(void)
Exit Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:135
void OS_EnterTaskCritical(void)
Enter Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:131
void PEX_SetPin(uint8_t portExpander, uint8_t pin)
sets pin to high.
Definition: pex.c:321
void PEX_SetPinDirectionOutput(uint8_t portExpander, uint8_t pin)
sets pin to input.
Definition: pex.c:394
Header for the driver for the NXP PCA9539 port expander module.
#define PEX_PIN16
Definition: pex_cfg.h:95
#define PEX_PIN13
Definition: pex_cfg.h:92
#define PEX_PIN10
Definition: pex_cfg.h:89
#define PEX_PORT_EXPANDER3
Definition: pex_cfg.h:76
#define PEX_PIN17
Definition: pex_cfg.h:96
#define PEX_PIN12
Definition: pex_cfg.h:91
#define PEX_PIN15
Definition: pex_cfg.h:94
#define PEX_PIN11
Definition: pex_cfg.h:90
#define PEX_PIN14
Definition: pex_cfg.h:93
SPI_INTERFACE_CONFIG_s spi_ltcInterface[BS_NR_OF_STRINGS]
Definition: spi_cfg.c:175
struct definition for plausibility values of an AFE
const int16_t maximumPlausibleVoltage_mV
uint16_t gpioVoltages_mV[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *BS_NR_OF_GPIOS_PER_MODULE]
Definition: database_cfg.h:318
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:315
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:146
int16_t cellTemperature_ddegC[BS_NR_OF_STRINGS][BS_NR_OF_TEMP_SENSORS_PER_STRING]
Definition: database_cfg.h:148
uint16_t nrValidTemperatures[BS_NR_OF_STRINGS]
Definition: database_cfg.h:151
uint16_t invalidCellTemperature[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
Definition: database_cfg.h:150
int32_t packVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:131
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:129
uint64_t invalidCellVoltage[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
Definition: database_cfg.h:135
uint16_t nrValidCellVoltages[BS_NR_OF_STRINGS]
Definition: database_cfg.h:136
int16_t cellVoltage_mV[BS_NR_OF_STRINGS][BS_NR_OF_CELL_BLOCKS_PER_STRING]
Definition: database_cfg.h:132
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:119
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:302
uint16_t nrOpenWires[BS_NR_OF_STRINGS]
Definition: database_cfg.h:304
uint8_t openwire[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *(BS_NR_OF_CELL_BLOCKS_PER_MODULE+1u)]
Definition: database_cfg.h:307
LTC_OPENWIRE_DETECTION_s * openWireDetection
Definition: ltc_defs.h:447
DATA_BLOCK_ALL_GPIO_VOLTAGES_s * allGpioVoltages
Definition: ltc_defs.h:444
DATA_BLOCK_CELL_VOLTAGE_s * cellVoltage
Definition: ltc_defs.h:439
DATA_BLOCK_CELL_TEMPERATURE_s * cellTemperature
Definition: ltc_defs.h:440
uint16_t * txBuffer
Definition: ltc_defs.h:436
LTC_ERRORTABLE_s * errorTable
Definition: ltc_defs.h:448
SPI_INTERFACE_CONFIG_s * pSpiInterface
Definition: ltc_defs.h:435
uint16_t * rxBuffer
Definition: ltc_defs.h:437
uint16_t * usedCellIndex
Definition: ltc_defs.h:446
uint32_t frameLength
Definition: ltc_defs.h:438
DATA_BLOCK_OPEN_WIRE_s * openWire
Definition: ltc_defs.h:445
uint8_t PEC_valid[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:71
uint8_t mux3[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:75
uint8_t mux2[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:74
uint8_t mux0[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:72
uint8_t mux1[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:73
int32_t openWireDelta[BS_NR_OF_STRINGS][BS_NR_OF_CELL_BLOCKS_PER_STRING]
Definition: ltc_defs.h:82
int16_t openWirePdown[BS_NR_OF_STRINGS][BS_NR_OF_CELL_BLOCKS_PER_STRING]
Definition: ltc_defs.h:81
int16_t openWirePup[BS_NR_OF_STRINGS][BS_NR_OF_CELL_BLOCKS_PER_STRING]
Definition: ltc_defs.h:80
LTC_STATE_REQUEST_e request
Definition: ltc_defs.h:513
uint8_t string
Definition: ltc_defs.h:514
uint32_t commandDataTransferTime
Definition: ltc_defs.h:545
LTC_DATAPTR_s ltcData
Definition: ltc_defs.h:580
LTC_ADCMODE_e adcModereq
Definition: ltc_defs.h:532
LTC_REQUEST_s statereq
Definition: ltc_defs.h:524
uint8_t triggerentry
Definition: ltc_defs.h:543
SPI_INTERFACE_CONFIG_s * spiSeqPtr
Definition: ltc_defs.h:570
uint32_t commandTransferTime
Definition: ltc_defs.h:546
SPI_INTERFACE_CONFIG_s * spiSeqEndPtr
Definition: ltc_defs.h:571
uint8_t substate
Definition: ltc_defs.h:526
LTC_STATEMACH_e laststate
Definition: ltc_defs.h:527
uint8_t lastsubstate
Definition: ltc_defs.h:528
LTC_ADCMEAS_CHAN_e adcMeasCh
Definition: ltc_defs.h:534
LTC_REUSE_MODE_e reusageMeasurementMode
Definition: ltc_defs.h:560
uint32_t gpioClocksTransferTime
Definition: ltc_defs.h:548
uint16_t timer
Definition: ltc_defs.h:522
uint8_t resendCommandCounter
Definition: ltc_defs.h:567
LTC_STATEMACH_e state
Definition: ltc_defs.h:525
uint8_t spiNumberInterfaces
Definition: ltc_defs.h:572
LTC_ADCMODE_e adcMode
Definition: ltc_defs.h:529
uint8_t currentString
Definition: ltc_defs.h:573
uint32_t ErrRequestCounter
Definition: ltc_defs.h:542
STD_RETURN_TYPE_e check_spi_flag
Definition: ltc_defs.h:565
bool first_measurement_made
Definition: ltc_defs.h:562
uint8_t requestedString
Definition: ltc_defs.h:574
LTC_ADCMEAS_CHAN_e adcMeasChreq
Definition: ltc_defs.h:536
spiBASE_t * pNode
Definition: spi_cfg.h:142