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