foxBMS  1.1.0
The foxBMS Battery Management System API Documentation
ltc_6806.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * We kindly request you to use one or more of the following phrases to refer to
34  * foxBMS in your hardware, software, documentation or advertising materials:
35  *
36  * - ″This product uses parts of foxBMS®″
37  * - ″This product includes parts of foxBMS®″
38  * - ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file ltc_6806.c
44  * @author foxBMS Team
45  * @date 2019-09-01 (date of creation)
46  * @updated 2021-07-14 (date of last update)
47  * @ingroup DRIVERS
48  * @prefix LTC
49  *
50  * @brief Driver for the LTC monitoring chip.
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 /* clang-format off */
56 #include "ltc.h"
57 #include "ltc_6806_cfg.h"
58 /* clang-format on */
59 
60 #include "HL_spi.h"
61 #include "HL_system.h"
62 
63 #include "database.h"
64 #include "diag.h"
65 #include "io.h"
66 #include "ltc_pec.h"
67 #include "os.h"
68 #include "mic_plausibility.h"
69 
70 /*========== Macros and Definitions =========================================*/
71 
72 /**
73  * LTC 6820 GPIO configuration
74  * @{
75  */
76 #define LTC_LTC6820CONTROL_GIODIR (hetREG1->DIR)
77 #define LTC_LTC6820CONTROL_GIOPORT (hetREG1->DOUT)
78 
79 #define LTC_LTC6820_FORWARD_ENABLE_PIN (22U)
80 #define LTC_LTC6820_FORWARD_SPI1_MASTER_PIN (24U)
81 
82 #define LTC_LTC6820_REVERSE_ENABLE_PIN (23U)
83 #define LTC_LTC6820_REVERSE_MASTER_PIN (25U)
84 /**@}*/
85 
86 /**
87  * TI port expander register addresses
88  * @{
89  */
90 #define LTC_PORT_EXPANDER_TI_INPUT_REG_ADR (0x00u)
91 #define LTC_PORT_EXPANDER_TI_OUTPUT_REG_ADR (0x01u)
92 #define LTC_PORT_EXPANDER_TI_CONFIG_REG_ADR (0x03u)
93 /**@}*/
94 
95 /**
96  * Value of the LSB in mV
97  */
98 #if LTC_HIRNG == 0u
99 #define LTC_FUEL_CELL_LSB_RESOLUTION_mV (1.5f)
100 #else
101 #define LTC_FUEL_CELL_LSB_RESOLUTION_mV (3.0f)
102 #endif
103 
104 /**
105  * Value for positive full scale measurement for fuel cell
106  */
107 #define LTC_FUELCELL_POSITIVE_FULLSCALE_RANGE_mV ((int16_t)((0x7FF * LTC_FUEL_CELL_LSB_RESOLUTION_mV)))
108 
109 /**
110  * Value for negative full scale measurement for fuel cell
111  */
112 #define LTC_FUELCELL_NEGATIVE_FULLSCALE_RANGE_mV \
113  ((int16_t)((((~0x001) + 1) & 0x7FF) * (-LTC_FUEL_CELL_LSB_RESOLUTION_mV)))
114 
115 /*========== Static Constant and Variable Definitions =======================*/
116 /**
117  * PEC buffer for RX and TX
118  * @{
119  */
120 #pragma SET_DATA_SECTION(".sharedRAM")
123 #pragma SET_DATA_SECTION()
124 /**@}*/
125 
126 /** index of used cells */
127 static uint16_t ltc_used_cells_index[BS_NR_OF_STRINGS] = {0};
128 /** local copies of database tables */
129 /**@{*/
134 /**@}*/
135 /** stores information on the detected open wires locally */
137 static LTC_ERRORTABLE_s ltc_errorTable = {0}; /*!< init in LTC_ResetErrorTable-function */
138 
139 /** local definition of plausible cell voltage values for the LTC 6806 */
142  .minimumPlausibleVoltage_mV = -5000,
143 };
144 
145 /*========== Extern Constant and Variable Definitions =======================*/
146 
148  .timer = 0,
149  .statereq = {.request = LTC_STATE_NO_REQUEST, .string = 0xFFu},
151  .substate = 0,
152  .laststate = LTC_STATEMACH_UNINITIALIZED,
153  .lastsubstate = 0,
154  .adcModereq = LTC_ADCMODE_FAST_DCP0,
155  .adcMode = LTC_ADCMODE_FAST_DCP0,
156  .adcMeasChreq = LTC_ADCMEAS_UNDEFINED,
157  .adcMeasCh = LTC_ADCMEAS_UNDEFINED,
158  .numberOfMeasuredMux = 32,
159  .triggerentry = 0,
160  .ErrRetryCounter = 0,
161  .ErrRequestCounter = 0,
162  .VoltageSampleTime = 0,
163  .muxSampleTime = 0,
164  .commandDataTransferTime = 3,
165  .commandTransferTime = 3,
166  .gpioClocksTransferTime = 3,
167  .muxmeas_seqptr = NULL_PTR,
168  .muxmeas_seqendptr = NULL_PTR,
169  .muxmeas_nr_end = 0,
170  .first_measurement_made = false,
171  .ltc_muxcycle_finished = STD_NOT_OK,
172  .check_spi_flag = STD_NOT_OK,
173  .balance_control_done = STD_NOT_OK,
174  .transmit_ongoing = false,
175  .dummyByte_ongoing = STD_NOT_OK,
176  .ltcData.pSpiInterface = spi_ltcInterface,
177  .ltcData.txBuffer = ltc_TxPecBuffer,
178  .ltcData.rxBuffer = ltc_RxPecBuffer,
179  .ltcData.frameLength = LTC_N_BYTES_FOR_DATA_TRANSMISSION,
180  .ltcData.cellVoltage = &ltc_cellvoltage,
181  .ltcData.cellTemperature = &ltc_celltemperature,
182  .ltcData.balancingFeedback = NULL_PTR,
183  .ltcData.balancingControl = NULL_PTR,
184  .ltcData.slaveControl = NULL_PTR,
185  .ltcData.openWireDetection = &ltc_openWireDetection,
186  .ltcData.errorTable = &ltc_errorTable,
187  .ltcData.allGpioVoltages = &ltc_allgpiovoltage,
188  .ltcData.openWire = &ltc_openwire,
189  .ltcData.usedCellIndex = ltc_used_cells_index,
190  .currentString = 0u,
191  .requestedString = 0u,
192 };
193 
194 static uint16_t ltc_cmdWRCFG[4] = {0x00, 0x01, 0x3D, 0x6E};
195 static uint16_t ltc_cmdRDCFG[4] = {0x00, 0x02, 0x2B, 0x0A};
196 
197 /* static uint16_t ltc_cmdRDAUXA[4] = {0x00, 0x0C, 0xEF, 0xCC};
198 static uint16_t ltc_cmdRDAUXB[4] = {0x00, 0x0E, 0x72, 0x9A};
199 static uint16_t ltc_cmdRDAUXC[4] = {0x00, 0x0D, 0x64, 0xFE};
200 static uint16_t ltc_cmdRDAUXD[4] = {0x00, 0x0F, 0xF9, 0xA8}; */
201 
202 static uint16_t ltc_cmdRDCVA_Fuelcell[4] = {0x00, 0x04, 0x07, 0xC2};
203 static uint16_t ltc_cmdRDCVB_Fuelcell[4] = {0x00, 0x05, 0x8C, 0xF0};
204 static uint16_t ltc_cmdRDCVC_Fuelcell[4] = {0x00, 0x06, 0x9A, 0x94};
205 static uint16_t ltc_cmdRDCVD_Fuelcell[4] = {0x00, 0x07, 0x11, 0xA6};
206 static uint16_t ltc_cmdRDCVE_Fuelcell[4] = {0x00, 0x08, 0x5E, 0x52};
207 static uint16_t ltc_cmdRDCVF_Fuelcell[4] = {0x00, 0x09, 0xD5, 0x60};
208 static uint16_t ltc_cmdRDCVG_Fuelcell[4] = {0x00, 0x0A, 0xC3, 0x04};
209 static uint16_t ltc_cmdRDCVH_Fuelcell[4] = {0x00, 0x0B, 0x48, 0x36};
210 static uint16_t ltc_cmdRDCVI_Fuelcell[4] = {0x00, 0x0C, 0xEF, 0xCC};
211 
212 /* static uint16_t ltc_cmdMUTE[4] = {0x00, 0x28, 0xE8, 0x0E}; !< MUTE discharging via S pins */
213 /* static uint16_t ltc_cmdUNMUTE[4] = {0x00, 0x29, 0x63, 0x3C}; !< UN-MUTE discharging via S pins */
214 
215 static uint16_t ltc_cmdADCV_normal_Fuelcell[4] = {0x04, 0x40, 0xED, 0xB0}; /*!< All cells, normal mode */
216 
217 /* GPIOs */
218 /* static uint16_t ltc_cmdADAX_normal_GPIO1[4] = {0x05, 0x61, 0x58, 0x92}; !< Single channel, GPIO 1, normal mode */
219 /* static uint16_t ltc_cmdADAX_filtered_GPIO1[4] = {0x05, 0xE1, 0x1C, 0xB4}; !< Single channel, GPIO 1, filtered mode */
220 /* static uint16_t ltc_cmdADAX_fast_GPIO1[4] = {0x04, 0xE1, 0x94, 0xF8}; !< Single channel, GPIO 1, fast mode */
221 /* static uint16_t ltc_cmdADAX_normal_GPIO2[4] = {0x05, 0x62, 0x4E, 0xF6}; !< Single channel, GPIO 2, normal mode */
222 /* static uint16_t ltc_cmdADAX_filtered_GPIO2[4] = {0x05, 0xE2, 0x0A, 0xD0}; !< Single channel, GPIO 2, filtered mode */
223 /* static uint16_t ltc_cmdADAX_fast_GPIO2[4] = {0x04, 0xE2, 0x82, 0x9C}; !< Single channel, GPIO 2, fast mode */
224 /* static uint16_t ltc_cmdADAX_normal_GPIO3[4] = {0x05, 0x63, 0xC5, 0xC4}; !< Single channel, GPIO 3, normal mode */
225 /* static uint16_t ltc_cmdADAX_filtered_GPIO3[4] = {0x05, 0xE3, 0x81, 0xE2}; !< Single channel, GPIO 3, filtered mode */
226 /* static uint16_t ltc_cmdADAX_fast_GPIO3[4] = {0x04, 0xE3, 0x09, 0xAE}; !< Single channel, GPIO 3, fast mode */
227 /* static uint16_t ltc_cmdADAX_normal_GPIO4[4] = {0x05, 0x64, 0x62, 0x3E}; !< Single channel, GPIO 4, normal mode */
228 /* static uint16_t ltc_cmdADAX_filtered_GPIO4[4] = {0x05, 0xE4, 0x26, 0x18}; !< Single channel, GPIO 4, filtered mode */
229 /* static uint16_t ltc_cmdADAX_fast_GPIO4[4] = {0x04, 0xE4, 0xAE, 0x54}; !< Single channel, GPIO 4, fast mode */
230 /* static uint16_t ltc_cmdADAX_normal_GPIO5[4] = {0x05, 0x65, 0xE9, 0x0C}; !< Single channel, GPIO 5, normal mode */
231 /* static uint16_t ltc_cmdADAX_filtered_GPIO5[4] = {0x05, 0xE5, 0xAD, 0x2A}; !< Single channel, GPIO 5, filtered mode */
232 /* static uint16_t ltc_cmdADAX_fast_GPIO5[4] = {0x04, 0xE5, 0x25, 0x66}; !< Single channel, GPIO 5, fast mode */
233 /* static uint16_t ltc_cmdADAX_normal_ALLGPIOS[4] = {0x05, 0x60, 0xD3, 0xA0}; !< All channels, normal mode */
234 /* static uint16_t ltc_cmdADAX_filtered_ALLGPIOS[4] =
235  {0x05, 0xE0, 0x97, 0x86}; !< All channels, filtered mode */
236 /* static uint16_t ltc_cmdADAX_fast_ALLGPIOS[4] = {0x04, 0xE0, 0x1F, 0xCA}; !< All channels, fast mode */
237 
238 /* Open-wire */
240  {0x07, 0xC0, 0xBA, 0x70}; /*!< Broadcast, Pull-up current, All cells, normal mode, 100ms */
242  {0x06, 0xC0, 0x32, 0x3C}; /*!< Broadcast, Pull-down current, All cells, normal mode, 100ms */
243 
244 /*========== Static Function Prototypes =====================================*/
245 static void LTC_SetFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state);
246 static void LTC_Initialize_Database(LTC_STATE_s *ltc_state);
247 static void LTC_SaveLastStates(LTC_STATE_s *ltc_state);
248 static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms);
249 static void LTC_CondBasedStateTransition(
250  LTC_STATE_s *ltc_state,
251  STD_RETURN_TYPE_e retVal,
252  DIAG_ID_e diagCode,
253  LTC_STATEMACH_e state_ok,
254  uint8_t substate_ok,
255  uint16_t timer_ms_ok,
256  LTC_STATEMACH_e state_nok,
257  uint8_t substate_nok,
258  uint16_t timer_ms_nok);
259 
260 static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state);
262  SPI_INTERFACE_CONFIG_s *pSpiInterface,
263  uint16_t *pTxBuff,
264  uint16_t *pRxBuff,
265  uint32_t frameLength);
266 
268  SPI_INTERFACE_CONFIG_s *pSpiInterface,
269  LTC_ADCMODE_e adcMode,
270  LTC_ADCMEAS_CHAN_e adcMeasCh);
272  SPI_INTERFACE_CONFIG_s *pSpiInterface,
273  LTC_ADCMODE_e adcMode,
274  uint8_t PUP);
275 
277  LTC_STATE_s *ltc_state,
278  uint16_t *pRxBuff,
279  uint8_t registerSet,
280  uint8_t stringNumber);
281 
283  LTC_STATE_s *ltc_state,
284  uint16_t *DataBufferSPI_RX_with_PEC,
285  uint8_t stringNumber);
287  uint16_t *Command,
288  SPI_INTERFACE_CONFIG_s *pSpiInterface,
289  uint16_t *pTxBuff,
290  uint16_t *pRxBuff,
291  uint32_t frameLength);
292 
293 static uint32_t LTC_GetSPIClock(SPI_INTERFACE_CONFIG_s *pSpiInterface);
294 static void LTC_SetTransferTimes(LTC_STATE_s *ltc_state);
295 
297 
298 /*========== Static Function Implementations ================================*/
299 /**
300  * @brief in the database, initializes the fields related to the LTC drivers.
301  *
302  * This function loops through all the LTC-related data fields in the database
303  * and sets them to 0. It should be called in the initialization or re-initialization
304  * routine of the LTC driver.
305  *
306  * @param ltc_state: state of the ltc state machine
307  *
308  */
309 static void LTC_Initialize_Database(LTC_STATE_s *ltc_state) {
310  uint16_t i = 0;
311 
312  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
313  ltc_state->ltcData.cellVoltage->state = 0;
314  for (i = 0; i < BS_NR_OF_BAT_CELLS; i++) {
315  ltc_state->ltcData.cellVoltage->cellVoltage_mV[stringNumber][i] = 0;
316  ltc_state->ltcData.openWireDetection->openWirePup[stringNumber][i] = 0;
317  ltc_state->ltcData.openWireDetection->openWirePdown[stringNumber][i] = 0;
318  ltc_state->ltcData.openWireDetection->openWireDelta[stringNumber][i] = 0;
319  }
320 
321  ltc_state->ltcData.cellTemperature->state = 0;
322  for (i = 0; i < BS_NR_OF_TEMP_SENSORS_PER_STRING; i++) {
323  ltc_state->ltcData.cellTemperature->cellTemperature_ddegC[stringNumber][i] = 0;
324  }
325 
326  ltc_state->ltcData.allGpioVoltages->state = 0;
327  for (i = 0; i < (BS_NR_OF_MODULES * BS_NR_OF_GPIOS_PER_MODULE); i++) {
328  ltc_state->ltcData.allGpioVoltages->gpioVoltages_mV[stringNumber][i] = 0;
329  }
330 
331  for (i = 0; i < (BS_NR_OF_MODULES * (BS_NR_OF_CELLS_PER_MODULE + 1)); i++) {
332  ltc_state->ltcData.openWire->openwire[stringNumber][i] = 0;
333  }
334  ltc_state->ltcData.openWire->state = 0;
335  }
336 
337  DATA_WRITE_DATA(ltc_state->ltcData.cellVoltage, ltc_state->ltcData.cellTemperature, ltc_state->ltcData.openWire);
338 }
339 
340 /**
341  * @brief Saves the last state and the last substate
342  *
343  * @param ltc_state: state of the ltc state machine
344  */
345 static void LTC_SaveLastStates(LTC_STATE_s *ltc_state) {
346  ltc_state->laststate = ltc_state->state;
347  ltc_state->lastsubstate = ltc_state->substate;
348 }
349 
350 /**
351  * @brief function for setting LTC_Trigger state transitions
352  *
353  * @param ltc_state: state of the ltc state machine
354  * @param state: state to transition into
355  * @param substate: substate to transition into
356  * @param timer_ms: transition into state, substate after timer elapsed
357  */
358 static void LTC_StateTransition(LTC_STATE_s *ltc_state, LTC_STATEMACH_e state, uint8_t substate, uint16_t timer_ms) {
359  ltc_state->state = state;
360  ltc_state->substate = substate;
361  ltc_state->timer = timer_ms;
362 }
363 
364 /**
365  * @brief condition-based state transition depending on retVal
366  *
367  * If retVal is #STD_OK, after timer_ms_ok is elapsed the LTC statemachine will
368  * transition into state_ok and substate_ok, otherwise after timer_ms_nok the
369  * statemachine will transition to state_nok and substate_nok. Depending on
370  * value of retVal the corresponding diagnosis entry will be called.
371  *
372  * @param ltc_state: state of the ltc state machine
373  * @param retVal: condition to determine if statemachine will transition into ok or nok states
374  * @param diagCode: symbolic IDs for diagnosis entry, called with #DIAG_EVENT_OK if retVal is #STD_OK, #DIAG_EVENT_NOT_OK otherwise
375  * @param state_ok state to transition into if retVal is #STD_OK
376  * @param substate_ok: substate to transition into if retVal is #STD_OK
377  * @param timer_ms_ok: transition into state_ok, substate_ok after timer_ms_ok elapsed
378  * @param state_nok: state to transition into if retVal is #STD_NOT_OK
379  * @param substate_nok: substate to transition into if retVal is #STD_NOT_OK
380  * @param timer_ms_nok: transition into state_nok, substate_nok after 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; m++) {
416  for (uint8_t c = 0u; c < BS_NR_OF_CELLS_PER_MODULE; c++) {
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->openwire[stringNumber][(m * (BS_NR_OF_CELLS_PER_MODULE + 1u)) + c] ==
424  0u) &&
425  (ltc_state->ltcData.openWire->openwire[stringNumber][(m * (BS_NR_OF_CELLS_PER_MODULE + 1u)) + c + 1u] ==
426  0u) &&
427  ((ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] & (0x01u << c)) == 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
433  ->cellVoltage_mV[stringNumber][(m * BS_NR_OF_CELLS_PER_MODULE) + c],
435  /* Cell voltage is valid -> calculate string voltage */
436  /* -------- 3. Calculate string values ------------- */
437  stringVoltage_mV += ltc_state->ltcData.cellVoltage
438  ->cellVoltage_mV[stringNumber][(m * BS_NR_OF_CELLS_PER_MODULE) + c];
439  numberValidMeasurements++;
440  } else {
441  /* Invalidate cell voltage measurement */
442  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] |= (0x01u << c);
443  cellVoltageMeasurementValid = STD_NOT_OK;
444  }
445  } else {
446  /* Set cell voltage measurement value invalid, if not already invalid because of PEC Error */
447  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][m] |= (0x01u << c);
448  cellVoltageMeasurementValid = STD_NOT_OK;
449  }
450  }
451  }
453  cellVoltageMeasurementValid, DIAG_ID_MEASUREMENT_IC_CELL_VOLTAGE_MEAS_ERROR, DIAG_STRING, stringNumber);
454  ltc_state->ltcData.cellVoltage->packVoltage_mV[stringNumber] = stringVoltage_mV;
455  ltc_state->ltcData.cellVoltage->nrValidCellVoltages[stringNumber] = numberValidMeasurements;
456 
457  /* Increment state variable each time new values are written into database */
458  ltc_state->ltcData.cellVoltage->state++;
459 
460  DATA_WRITE_DATA(ltc_state->ltcData.cellVoltage);
461 }
462 
463 extern void LTC_SaveTemperatures(LTC_STATE_s *ltc_state, uint8_t stringNumber) {
464  STD_RETURN_TYPE_e cellTemperatureMeasurementValid = STD_OK;
465  uint16_t numberValidMeasurements = 0;
466  for (uint8_t m = 0u; m < BS_NR_OF_MODULES; m++) {
467  for (uint8_t c = 0u; c < BS_NR_OF_TEMP_SENSORS_PER_MODULE; c++) {
468  /* ------- 1. Check valid flag -----------------
469  * Is cell temperature valid because of previous PEC error
470  * If so, everything okay, else set cell temperature measurement to invalid.
471  */
472  if ((ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][m] & (0x01u << c)) == 0u) {
473  /* Cell temperature is valid -> perform minimum/maximum plausibility check */
474 
475  /* ------- 2. Perform minimum/maximum measurement range check ---------- */
476  if (STD_OK ==
478  ltc_state->ltcData.cellTemperature
479  ->cellTemperature_ddegC[stringNumber][(m * BS_NR_OF_TEMP_SENSORS_PER_MODULE) + c])) {
480  numberValidMeasurements++;
481  } else {
482  /* Invalidate cell temperature measurement */
483  ltc_state->ltcData.cellTemperature->invalidCellTemperature[stringNumber][m] |= (0x01u << c);
484  cellTemperatureMeasurementValid = STD_NOT_OK;
485  }
486  } else {
487  /* Already invalid because of PEC Error */
488  cellTemperatureMeasurementValid = STD_NOT_OK;
489  }
490  }
491  }
493  cellTemperatureMeasurementValid, DIAG_ID_MEASUREMENT_IC_CELL_TEMPERATURE_MEAS_ERROR, DIAG_STRING, stringNumber);
494 
495  ltc_state->ltcData.cellTemperature->nrValidTemperatures[stringNumber] = numberValidMeasurements;
496  ltc_state->ltcData.cellTemperature->state++;
498 }
499 
500 /**
501  * @brief stores the measured GPIOs in the database.
502  *
503  * This function loops through the data of all modules in the LTC daisy-chain that are
504  * stored in the ltc_allgpiovoltage buffer and writes them in the database.
505  * At each write iteration, the variable named "state" and related to voltages in the
506  * database is incremented.
507  *
508  * @param ltc_state: state of the ltc state machine
509  *
510  */
511 extern void LTC_SaveAllGPIOMeasurement(LTC_STATE_s *ltc_state) {
512  ltc_state->ltcData.allGpioVoltages->state++;
514 }
515 
516 /**
517  * @brief re-entrance check of LTC state machine trigger function
518  *
519  * This function is not re-entrant and should only be called time- or event-triggered.
520  * It increments the triggerentry counter from the state variable ltc_state.
521  * It should never be called by two different processes, so if it is the case, triggerentry
522  * should never be higher than 0 when this function is called.
523  *
524  * @param ltc_state: state of the ltc state machine
525  *
526  * @return retval 0 if no further instance of the function is active, 0xff else
527  *
528  */
529 uint8_t LTC_CheckReEntrance(LTC_STATE_s *ltc_state) {
530  uint8_t retval = 0;
531 
533  if (!ltc_state->triggerentry) {
534  ltc_state->triggerentry++;
535  } else {
536  retval = 0xFF; /* multiple calls of function */
537  }
539 
540  return (retval);
541 }
542 
543 /**
544  * @brief gets the current state request.
545  *
546  * This function is used in the functioning of the LTC state machine.
547  *
548  * @param ltc_state: state of the ltc state machine
549  *
550  * @return retval current state request, taken from LTC_STATE_REQUEST_e
551  */
553  LTC_REQUEST_s retval = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
554 
556  retval.request = ltc_state->statereq.request;
557  retval.string = ltc_state->statereq.string;
559 
560  return (retval);
561 }
562 
563 /**
564  * @brief gets the current state.
565  *
566  * This function is used in the functioning of the LTC state machine.
567  *
568  * @param ltc_state: state of the ltc state machine
569  *
570  * @return current state, taken from LTC_STATEMACH_e
571  */
573  return ltc_state->state;
574 }
575 
576 /**
577  * @brief transfers the current state request to the state machine.
578  *
579  * This function takes the current state request from ltc_state and transfers it to the state machine.
580  * It resets the value from ltc_state to LTC_STATE_NO_REQUEST
581  *
582  * @param ltc_state state of the ltc state machine
583  * @param pBusIDptr bus ID, main or backup (deprecated)
584  * @param pAdcModeptr LTC ADCmeasurement mode (fast, normal or filtered)
585  * @param pAdcMeasChptr number of channels measured for GPIOS (one at a time for multiplexers or all five GPIOs)
586  *
587  * @return retVal current state request, taken from LTC_STATE_REQUEST_e
588  *
589  */
591  LTC_STATE_s *ltc_state,
592  uint8_t *pBusIDptr,
593  LTC_ADCMODE_e *pAdcModeptr,
594  LTC_ADCMEAS_CHAN_e *pAdcMeasChptr) {
595  LTC_REQUEST_s retval = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
596 
598  retval.request = ltc_state->statereq.request;
599  retval.string = ltc_state->statereq.string;
600  ltc_state->requestedString = ltc_state->statereq.string;
601  *pAdcModeptr = ltc_state->adcModereq;
602  *pAdcMeasChptr = ltc_state->adcMeasChreq;
604  ltc_state->statereq.string = 0x0u;
606 
607  return (retval);
608 }
609 
611  LTC_RETURN_TYPE_e retVal = LTC_ERROR;
612 
614  retVal = LTC_CheckStateRequest(ltc_state, statereq);
615 
616  if ((retVal == LTC_OK) || (retVal == LTC_BUSY_OK) || (retVal == LTC_OK_FROM_ERROR)) {
617  ltc_state->statereq.request = statereq.request;
618  ltc_state->statereq.string = statereq.string;
619  }
621 
622  return (retVal);
623 }
624 
625 void LTC_Trigger(LTC_STATE_s *ltc_state) {
626  STD_RETURN_TYPE_e retVal = STD_OK;
627  LTC_REQUEST_s statereq = {.request = LTC_STATE_NO_REQUEST, .string = 0x0u};
628  uint8_t tmpbusID = 0;
631  STD_RETURN_TYPE_e continueFunction = STD_OK;
632 
633  FAS_ASSERT(ltc_state != NULL_PTR);
634 
635  /* Check re-entrance of function */
636  if (LTC_CheckReEntrance(ltc_state) > 0u) {
637  continueFunction = STD_NOT_OK;
638  }
639 
640  if (ltc_state->check_spi_flag == STD_NOT_OK) {
641  if (ltc_state->timer > 0u) {
642  if ((--ltc_state->timer) > 0u) {
643  ltc_state->triggerentry--;
644  continueFunction = STD_NOT_OK; /* handle state machine only if timer has elapsed */
645  }
646  }
647  } else {
648  if (MIC_IsTransmitOngoing(ltc_state) == true) {
649  if (ltc_state->timer > 0u) {
650  if ((--ltc_state->timer) > 0u) {
651  ltc_state->triggerentry--;
652  continueFunction = STD_NOT_OK; /* handle state machine only if timer has elapsed */
653  }
654  }
655  }
656  }
657 
658  if (continueFunction == STD_OK) {
659  switch (ltc_state->state) {
660  /****************************UNINITIALIZED***********************************/
662  /* waiting for Initialization Request */
663  statereq = LTC_TransferStateRequest(ltc_state, &tmpbusID, &tmpadcMode, &tmpadcMeasCh);
664  if (statereq.request == LTC_STATE_INIT_REQUEST) {
665  LTC_SaveLastStates(ltc_state);
666  LTC_Initialize_Database(ltc_state);
667  LTC_ResetErrorTable(ltc_state);
670  ltc_state->adcMode = tmpadcMode;
671  ltc_state->adcMeasCh = tmpadcMeasCh;
672  } else if (statereq.request == LTC_STATE_NO_REQUEST) {
673  /* no actual request pending */
674  } else {
675  ltc_state->ErrRequestCounter++; /* illegal request pending */
676  }
677  break;
678 
679  /****************************INITIALIZATION**********************************/
681 
682  LTC_SetTransferTimes(ltc_state);
683  if (ltc_state->substate == LTC_INIT_STRING) {
684  LTC_SaveLastStates(ltc_state);
685  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface;
687  ltc_state->spiSeqEndPtr = ltc_state->ltcData.pSpiInterface + BS_NR_OF_STRINGS;
690  } else if (ltc_state->substate == LTC_ENTRY_INITIALIZATION) {
691  LTC_SaveLastStates(ltc_state);
692  retVal = LTC_TransmitWakeUp(ltc_state->spiSeqPtr); /* Send dummy byte to wake up the daisy chain */
694  ltc_state,
695  retVal,
703 
704  } else if (ltc_state->substate == LTC_RE_ENTRY_INITIALIZATION) {
705  LTC_SaveLastStates(ltc_state);
706  retVal =
707  LTC_TransmitWakeUp(ltc_state->spiSeqPtr); /* Send dummy byte again to wake up the daisy chain */
709  ltc_state,
710  retVal,
718 
719  } else if (ltc_state->substate == LTC_START_INIT_INITIALIZATION) {
720  LTC_SaveLastStates(ltc_state);
721  ltc_state->check_spi_flag = STD_OK;
722  MIC_SetTransmitOngoing(ltc_state);
723  retVal = LTC_Init(
724  ltc_state->spiSeqPtr,
725  ltc_state->ltcData.txBuffer,
726  ltc_state->ltcData.rxBuffer,
727  ltc_state->ltcData.frameLength); /* Initialize main LTC loop */
728  ltc_state->lastsubstate = ltc_state->substate;
731  ltc_state,
735 
736  } else if (ltc_state->substate == LTC_CHECK_INITIALIZATION) {
737  /* Read values written in config register, currently unused */
738  LTC_SaveLastStates(ltc_state);
739  MIC_SetTransmitOngoing(ltc_state);
740  retVal = LTC_RX(
741  ltc_cmdRDCFG,
742  ltc_state->spiSeqPtr,
743  ltc_state->ltcData.txBuffer,
744  ltc_state->ltcData.rxBuffer,
745  ltc_state->ltcData.frameLength); /* Read config register */
747  ltc_state,
751 
752  } else if (ltc_state->substate == LTC_EXIT_INITIALIZATION) {
753  LTC_SaveLastStates(ltc_state);
754  ++ltc_state->spiSeqPtr;
755  ++ltc_state->currentString;
756  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
759  } else {
762  }
763  }
764  break;
765 
766  /****************************INITIALIZED*************************************/
768  LTC_SaveLastStates(ltc_state);
770  break;
771 
772  /****************************START MEASUREMENT*******************************/
774 
776  ltc_state->adcMeasCh = LTC_ADCMEAS_ALLCHANNEL;
777 
778  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface;
780  ltc_state->spiSeqEndPtr = ltc_state->ltcData.pSpiInterface + BS_NR_OF_STRINGS;
781  ltc_state->currentString = 0u;
782 
783  ltc_state->check_spi_flag = STD_NOT_OK;
784  retVal = LTC_StartVoltageMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
785 
787  ltc_state,
788  retVal,
796 
797  break;
798 
799  /****************************START MEASUREMENT CONTINUE*******************************/
800  /* Do not reset SPI interface pointer */
802 
804  ltc_state->adcMeasCh = LTC_ADCMEAS_ALLCHANNEL;
805 
806  ltc_state->check_spi_flag = STD_NOT_OK;
807  retVal = LTC_StartVoltageMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, ltc_state->adcMeasCh);
808 
810  ltc_state,
811  retVal,
819 
820  break;
821 
822  /****************************READ VOLTAGE************************************/
824 
826  ltc_state->check_spi_flag = STD_OK;
827  MIC_SetTransmitOngoing(ltc_state);
828  retVal = LTC_RX(
830  ltc_state->spiSeqPtr,
831  ltc_state->ltcData.txBuffer,
832  ltc_state->ltcData.rxBuffer,
833  ltc_state->ltcData.frameLength);
835  ltc_state,
836  retVal,
844  break;
845 
846  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_B_RDCVB_READVOLTAGE) {
847  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
850  ltc_state, ltc_state->ltcData.rxBuffer, 0u, ltc_state->currentString);
851 
852  MIC_SetTransmitOngoing(ltc_state);
853  retVal = LTC_RX(
855  ltc_state->spiSeqPtr,
856  ltc_state->ltcData.txBuffer,
857  ltc_state->ltcData.rxBuffer,
858  ltc_state->ltcData.frameLength);
860  ltc_state,
861  retVal,
869  break;
870 
871  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_C_RDCVC_READVOLTAGE) {
872  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
875  ltc_state, ltc_state->ltcData.rxBuffer, 1u, ltc_state->currentString);
876 
877  MIC_SetTransmitOngoing(ltc_state);
878  retVal = LTC_RX(
880  ltc_state->spiSeqPtr,
881  ltc_state->ltcData.txBuffer,
882  ltc_state->ltcData.rxBuffer,
883  ltc_state->ltcData.frameLength);
885  ltc_state,
886  retVal,
894  break;
895 
896  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_D_RDCVD_READVOLTAGE) {
897  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
900  ltc_state, ltc_state->ltcData.rxBuffer, 2u, ltc_state->currentString);
901 
902  MIC_SetTransmitOngoing(ltc_state);
903  retVal = LTC_RX(
905  ltc_state->spiSeqPtr,
906  ltc_state->ltcData.txBuffer,
907  ltc_state->ltcData.rxBuffer,
908  ltc_state->ltcData.frameLength);
910  ltc_state,
911  retVal,
919  break;
920 
921  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_E_RDCVE_READVOLTAGE) {
922  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
925  ltc_state, ltc_state->ltcData.rxBuffer, 3u, ltc_state->currentString);
926 
927  MIC_SetTransmitOngoing(ltc_state);
928  retVal = LTC_RX(
930  ltc_state->spiSeqPtr,
931  ltc_state->ltcData.txBuffer,
932  ltc_state->ltcData.rxBuffer,
933  ltc_state->ltcData.frameLength);
935  ltc_state,
936  retVal,
944  break;
945 
946  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_F_RDCVF_READVOLTAGE) {
947  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
950  ltc_state, ltc_state->ltcData.rxBuffer, 4u, ltc_state->currentString);
951 
952  MIC_SetTransmitOngoing(ltc_state);
953  retVal = LTC_RX(
955  ltc_state->spiSeqPtr,
956  ltc_state->ltcData.txBuffer,
957  ltc_state->ltcData.rxBuffer,
958  ltc_state->ltcData.frameLength);
960  ltc_state,
961  retVal,
969  break;
970 
971  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_G_RDCVG_READVOLTAGE) {
972  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
975  ltc_state, ltc_state->ltcData.rxBuffer, 5u, ltc_state->currentString);
976 
977  MIC_SetTransmitOngoing(ltc_state);
978  retVal = LTC_RX(
980  ltc_state->spiSeqPtr,
981  ltc_state->ltcData.txBuffer,
982  ltc_state->ltcData.rxBuffer,
983  ltc_state->ltcData.frameLength);
985  ltc_state,
986  retVal,
994  break;
995 
996  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_H_RDCVH_READVOLTAGE) {
997  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1000  ltc_state, ltc_state->ltcData.rxBuffer, 6u, ltc_state->currentString);
1001 
1002  MIC_SetTransmitOngoing(ltc_state);
1003  retVal = LTC_RX(
1005  ltc_state->spiSeqPtr,
1006  ltc_state->ltcData.txBuffer,
1007  ltc_state->ltcData.rxBuffer,
1008  ltc_state->ltcData.frameLength);
1010  ltc_state,
1011  retVal,
1019  break;
1020 
1021  } else if (ltc_state->substate == LTC_READ_VOLTAGE_REGISTER_I_RDCVI_READVOLTAGE) {
1022  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1025  ltc_state, ltc_state->ltcData.rxBuffer, 7u, ltc_state->currentString);
1026 
1027  MIC_SetTransmitOngoing(ltc_state);
1028  retVal = LTC_RX(
1030  ltc_state->spiSeqPtr,
1031  ltc_state->ltcData.txBuffer,
1032  ltc_state->ltcData.rxBuffer,
1033  ltc_state->ltcData.frameLength);
1035  ltc_state,
1036  retVal,
1044  break;
1045 
1046  } else if (ltc_state->substate == LTC_EXIT_READVOLTAGE) {
1047  retVal = LTC_RX_PECCheck(ltc_state, ltc_state->ltcData.rxBuffer, ltc_state->currentString);
1050  ltc_state, ltc_state->ltcData.rxBuffer, 8u, ltc_state->currentString);
1051 
1052  /* Switch to different state if read voltage state is reused
1053  * e.g. open-wire check... */
1054  if (ltc_state->reusageMeasurementMode == LTC_NOT_REUSED) {
1055  LTC_SaveVoltages(ltc_state, ltc_state->currentString);
1056 
1057  ++ltc_state->spiSeqPtr;
1058  ++ltc_state->currentString;
1059  if (ltc_state->spiSeqPtr >= ltc_state->spiSeqEndPtr) {
1060  if (LTC_IsFirstMeasurementCycleFinished(ltc_state) == false) {
1062  }
1063  statereq = LTC_TransferStateRequest(ltc_state, &tmpbusID, &tmpadcMode, &tmpadcMeasCh);
1064  if (statereq.request == LTC_STATE_OPENWIRE_CHECK_REQUEST) {
1065  if (statereq.string < BS_NR_OF_STRINGS) {
1066  ltc_state->spiSeqPtr = ltc_state->ltcData.pSpiInterface + statereq.string;
1067  ltc_state->requestedString = statereq.string;
1068  /* This is necessary because the state machine will go through read voltage measurement registers */
1069  ltc_state->currentString = statereq.string;
1072  ltc_state,
1076  }
1077  } else {
1080  ltc_state->check_spi_flag = STD_NOT_OK;
1081  }
1082  } else {
1085  ltc_state->check_spi_flag = STD_NOT_OK;
1086  }
1087  } else if (ltc_state->reusageMeasurementMode == LTC_REUSE_READVOLT_FOR_ADOW_PUP) {
1089  ltc_state,
1093  } else if (ltc_state->reusageMeasurementMode == LTC_REUSE_READVOLT_FOR_ADOW_PDOWN) {
1095  ltc_state,
1099  }
1100  }
1101  break;
1102 
1103  /**************************OPEN-WIRE CHECK*******************************/
1106  /* Run ADOW command with PUP = 1 */
1107  ltc_state->adcMode = LTC_OW_MEASUREMENT_MODE;
1108  ltc_state->check_spi_flag = STD_NOT_OK;
1109 
1110  retVal = LTC_StartOpenWireMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, 1);
1111  if (retVal == STD_OK) {
1113 
1115  ltc_state,
1119 
1120  ltc_state->resendCommandCounter--;
1121 
1122  /* Check how many retries are left */
1123  if (ltc_state->resendCommandCounter == 0) {
1124  /* Switch to read voltage state to read cell voltages */
1125 
1127  ltc_state,
1131 
1132  /* Reuse read voltage register */
1134  }
1135  } else {
1139  }
1140  } else if (ltc_state->substate == LTC_READ_VOLTAGES_PULLUP_OPENWIRE_CHECK) {
1141  /* Previous state: Read voltage -> information stored in voltage buffer */
1143 
1144  /* Copy data from voltage struct into open-wire struct */
1145  for (uint16_t i = 0u; i < BS_NR_OF_BAT_CELLS; i++) {
1146  ltc_state->ltcData.openWireDetection->openWirePup[ltc_state->requestedString][i] =
1147  ltc_state->ltcData.cellVoltage->cellVoltage_mV[ltc_state->requestedString][i];
1148  }
1149 
1150  /* Set number of ADOW retries - send ADOW command with pull-down two times */
1153  ltc_state,
1157 
1158  } else if (ltc_state->substate == LTC_REQUEST_PULLDOWN_CURRENT_OPENWIRE_CHECK) {
1159  /* Run ADOW command with PUP = 0 */
1160  ltc_state->adcMode = LTC_OW_MEASUREMENT_MODE;
1161  ltc_state->check_spi_flag = STD_NOT_OK;
1162 
1163  retVal = LTC_StartOpenWireMeasurement(ltc_state->spiSeqPtr, ltc_state->adcMode, 0);
1164  if (retVal == STD_OK) {
1166 
1168  ltc_state,
1172 
1173  ltc_state->resendCommandCounter--;
1174 
1175  /* Check how many retries are left */
1176  if (ltc_state->resendCommandCounter == 0) {
1177  /* Switch to read voltage state to read cell voltages */
1178 
1180  ltc_state,
1184 
1185  /* Reuse read voltage register */
1187  }
1188  } else {
1192  }
1193  } else if (ltc_state->substate == LTC_READ_VOLTAGES_PULLDOWN_OPENWIRE_CHECK) {
1194  /* Previous state: Read voltage -> information stored in voltage buffer */
1196 
1197  /* Copy data from voltage struct into open-wire struct */
1198  for (uint16_t i = 0u; i < BS_NR_OF_BAT_CELLS; i++) {
1199  ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][i] =
1200  ltc_state->ltcData.cellVoltage->cellVoltage_mV[ltc_state->requestedString][i];
1201  }
1202 
1205 
1206  } else if (ltc_state->substate == LTC_PERFORM_OPENWIRE_CHECK) {
1207  /* Perform actual open-wire check */
1208 
1209  /* Take difference between pull-up and pull-down measurement */
1210  for (uint16_t i = 1u; i < BS_NR_OF_BAT_CELLS; i++) {
1211  ltc_state->ltcData.openWireDetection->openWireDelta[ltc_state->requestedString][i] = (int32_t)(
1212  ltc_state->ltcData.openWireDetection->openWirePup[ltc_state->requestedString][i] -
1213  ltc_state->ltcData.openWireDetection->openWirePdown[ltc_state->requestedString][i]);
1214  }
1215 
1216  /* PDOWN or PUP positive or negative full scale value: C(N) or C(N-1) open*/
1217  for (uint8_t m = 0u; m < BS_NR_OF_MODULES; m++) {
1218  /* PUP */
1219  for (uint8_t p = 0u; p < BS_NR_OF_CELLS_PER_MODULE; p++) {
1220  if ((ltc_state->ltcData.openWireDetection
1221  ->openWirePup[ltc_state->requestedString][p + (m * BS_NR_OF_CELLS_PER_MODULE)] ==
1223  (ltc_state->ltcData.openWireDetection
1224  ->openWirePup[ltc_state->requestedString][p + (m * BS_NR_OF_CELLS_PER_MODULE)] ==
1226  ltc_state->ltcData.openWire
1227  ->openwire[ltc_state->requestedString][p + (m * (BS_NR_OF_CELLS_PER_MODULE))] = 1;
1228  ltc_state->ltcData.openWire->openwire[ltc_state->requestedString]
1229  [(p + 1u) + (m * (BS_NR_OF_CELLS_PER_MODULE))] = 1;
1230  }
1231  if ((ltc_state->ltcData.openWireDetection
1232  ->openWirePdown[ltc_state->requestedString][p + (m * BS_NR_OF_CELLS_PER_MODULE)] ==
1234  (ltc_state->ltcData.openWireDetection
1235  ->openWirePdown[ltc_state->requestedString][p + (m * BS_NR_OF_CELLS_PER_MODULE)] ==
1237  ltc_state->ltcData.openWire
1238  ->openwire[ltc_state->requestedString][p + (m * (BS_NR_OF_CELLS_PER_MODULE))] = 1;
1239  ltc_state->ltcData.openWire->openwire[ltc_state->requestedString]
1240  [(p + 1u) + (m * (BS_NR_OF_CELLS_PER_MODULE))] = 1;
1241  }
1242  }
1243  }
1244 
1245  /* Datasheet page 28: "for all values of n from 1 to 36: If CELL Delta(n+1) < -200mV then C(n) is open" */
1246  for (uint8_t m = 0u; m < BS_NR_OF_MODULES; m++) {
1247  /* ltc_state->ltcData.openWireDelta parsed from 1 to (BS_NR_OF_CELLS_PER_MODULE-1) */
1248  for (uint8_t c = 1u; c < BS_NR_OF_CELLS_PER_MODULE; c++) {
1249  /* If delta cell(n+1) < -200mV: open-wire at C(n) */
1250  if (ltc_state->ltcData.openWireDetection
1251  ->openWireDelta[ltc_state->requestedString][c + (m * BS_NR_OF_CELLS_PER_MODULE)] <
1253  ltc_state->ltcData.openWire
1254  ->openwire[ltc_state->requestedString][c + (m * BS_NR_OF_CELLS_PER_MODULE)] = 1;
1255  }
1256  }
1257  }
1258 
1259  ltc_state->ltcData.openWire->nrOpenWires[ltc_state->requestedString] = 0;
1260  for (uint16_t c = 0u; c < (BS_NR_OF_MODULES * (BS_NR_OF_CELLS_PER_MODULE + 1)); c++) {
1261  if (ltc_state->ltcData.openWire->openwire[ltc_state->requestedString][c] == 1) {
1262  ltc_state->ltcData.openWire->nrOpenWires[ltc_state->requestedString]++;
1263  }
1264  }
1265 
1266  /* Write database entry */
1267  DATA_WRITE_DATA(ltc_state->ltcData.openWire);
1268  /* Start new measurement cycle */
1270  }
1271  break;
1272 
1273  /****************************DEFAULT**************************/
1274  default:
1275  /* invalid state */
1277  break;
1278  }
1279 
1280  ltc_state->triggerentry--; /* reentrance counter */
1281  } /* continueFunction */
1282 }
1283 
1284 /**
1285  * @brief saves the voltage values read from the LTC daisy-chain.
1286  *
1287  * After a voltage measurement was initiated to measure the voltages of the cells,
1288  * the result is read via SPI from the daisy-chain.
1289  * There are 6 register to read _(A,B,C,D,E,F,G,H,I) to get all cell voltages.
1290  * Only one register can be read at a time.
1291  * This function is called to store the result from the transmission in a buffer.
1292  *
1293  * @param ltc_state state of the ltc state machine
1294  * @param pRxBuff receive buffer
1295  * @param registerSet voltage register that was read (voltage register A,B,C,D,E,F,G,H or I)
1296  * @param stringNumber string addressed
1297  *
1298  */
1300  LTC_STATE_s *ltc_state,
1301  uint16_t *pRxBuff,
1302  uint8_t registerSet,
1303  uint8_t stringNumber) {
1304  uint16_t cellOffset = 0;
1305  uint16_t val_ui = 0;
1306  int16_t voltage = 0;
1307  uint64_t bitmask = 0;
1308  uint16_t buffer_LSB = 0;
1309  uint16_t buffer_MSB = 0;
1310 
1311  cellOffset = registerSet * 4u;
1312 
1313  /* Calculate bitmask for valid flags */
1314  bitmask |= 0x0Full << cellOffset; /* 0x0F: four voltages in each register */
1315 
1316  /* reinitialize index counter at begin of cycle */
1317  if (cellOffset == 0u) {
1318  (ltc_state->ltcData.usedCellIndex[stringNumber]) = 0u;
1319  }
1320 
1321  /* Retrieve data without command and CRC*/
1322  for (uint8_t m = 0u; m < LTC_N_LTC; m++) {
1323  uint8_t incrementations = 0u;
1324 
1325  /* parse all four voltages (4 * 12bits) contained in one register */
1326  for (uint8_t c = 0u; c < 4u; c++) {
1327  switch (c) {
1328  case 0u:
1329  buffer_MSB = pRxBuff[4u + (m * 8u)];
1330  buffer_LSB = (pRxBuff[4u + 1u + (m * 8u)]) >> 4u;
1331  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 4u));
1332  break;
1333  case 1u:
1334  buffer_MSB = pRxBuff[4u + 1u + (m * 8u)] & 0x0Fu;
1335  buffer_LSB = (pRxBuff[4u + 2u + (m * 8u)]);
1336  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 8u));
1337  break;
1338  case 2u:
1339  buffer_MSB = pRxBuff[4u + 3u + (m * 8u)];
1340  buffer_LSB = (pRxBuff[4u + 4u + (m * 8u)]) >> 4u;
1341  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 4u));
1342  break;
1343  case 3u:
1344  buffer_MSB = pRxBuff[4u + 4u + (m * 8u)] & 0x0Fu;
1345  buffer_LSB = (pRxBuff[4u + 5u + (m * 8u)]);
1346  val_ui = (uint16_t)(buffer_LSB | (buffer_MSB << 8u));
1347  break;
1348  default:
1349  break;
1350  }
1351 
1352  /* Check signed bit if measured value is negative or not */
1353  if ((val_ui & (1u << (12u - 1u))) == 0u) {
1354  voltage = (int16_t)(((val_ui & 0x7FFu)) * LTC_FUEL_CELL_LSB_RESOLUTION_mV); /* Unit mV */
1355  } else {
1356  voltage = (int16_t)(((((~val_ui) + 1) & 0x7FF)) * (-LTC_FUEL_CELL_LSB_RESOLUTION_mV)); /* Unit mV */
1357  }
1358 
1359  if (ltc_state->ltcData.errorTable->PEC_valid[stringNumber][m] == true) {
1360  ltc_state->ltcData.cellVoltage->cellVoltage_mV[stringNumber]
1361  [(ltc_state->ltcData.usedCellIndex[stringNumber]) +
1362  (m * BS_NR_OF_CELLS_PER_MODULE)] = voltage;
1363  bitmask = ~bitmask; /* negate bitmask to only validate flags of this voltage register */
1364  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][(m / LTC_NUMBER_OF_LTC_PER_MODULE)] &=
1365  bitmask;
1366  } else {
1367  /* PEC_valid == false: Invalidate only flags of this voltage register */
1368  ltc_state->ltcData.cellVoltage->invalidCellVoltage[stringNumber][(m / LTC_NUMBER_OF_LTC_PER_MODULE)] |=
1369  bitmask;
1370  }
1371 
1372  (ltc_state->ltcData.usedCellIndex[stringNumber])++;
1373  incrementations++;
1374 
1375  if ((ltc_state->ltcData.usedCellIndex[stringNumber]) > BS_NR_OF_CELLS_PER_MODULE) {
1376  break;
1377  }
1378  }
1379 
1380  /* Restore start value for next module in the daisy-chain. Only
1381  * decrement used cell index if current module is not the last
1382  * module in the daisy-chain. */
1383  if ((m + 1u) < LTC_N_LTC) {
1384  (ltc_state->ltcData.usedCellIndex[stringNumber]) -= incrementations;
1385  }
1386  }
1387 }
1388 
1389 /**
1390  * @brief initialize the daisy-chain.
1391  *
1392  * To initialize the LTC6804 daisy-chain, a dummy byte (0x00) is sent.
1393  *
1394  * @param pSpiInterface pointer to SPI configuration
1395  * @param pTxBuff transmit buffer
1396  * @param pRxBuff receive buffer
1397  * @param frameLength number of words to transmit
1398  *
1399  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
1400  *
1401  */
1403  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1404  uint16_t *pTxBuff,
1405  uint16_t *pRxBuff,
1406  uint32_t frameLength) {
1407  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
1408 
1409  uint8_t PEC_Check[6];
1410  uint16_t PEC_result = 0;
1411 
1412  /* now construct the message to be sent: it contains the wanted data, PLUS the needed PECs */
1413  pTxBuff[0] = ltc_cmdWRCFG[0];
1414  pTxBuff[1] = ltc_cmdWRCFG[1];
1415  pTxBuff[2] = ltc_cmdWRCFG[2];
1416  pTxBuff[3] = ltc_cmdWRCFG[3];
1417 
1418  /* set REFON bit to 1 */
1419  /* data for the configuration */
1420  for (uint16_t i = 0u; i < LTC_N_LTC; i++) {
1421  /* 3F = disable all pull-downs, 40: REFON = 1 */
1422  pTxBuff[4u + (i * 8u)] = 0x3F;
1423  pTxBuff[5u + (i * 8u)] = (LTC_HIRNG << 7u) | 0x40u;
1424  pTxBuff[6u + (i * 8u)] = 0x00;
1425  pTxBuff[7u + (i * 8u)] = 0x00;
1426  pTxBuff[8u + (i * 8u)] = 0x00;
1427  pTxBuff[9u + (i * 8u)] = 0x00;
1428 
1429  PEC_Check[0] = pTxBuff[4u + (i * 8u)];
1430  PEC_Check[1] = pTxBuff[5u + (i * 8u)];
1431  PEC_Check[2] = pTxBuff[6u + (i * 8u)];
1432  PEC_Check[3] = pTxBuff[7u + (i * 8u)];
1433  PEC_Check[4] = pTxBuff[8u + (i * 8u)];
1434  PEC_Check[5] = pTxBuff[9u + (i * 8u)];
1435 
1436  PEC_result = LTC_pec15_calc(6, PEC_Check);
1437  pTxBuff[10u + (i * 8u)] = (PEC_result >> 8u) & 0xFFu;
1438  pTxBuff[11u + (i * 8u)] = PEC_result & 0xFFu;
1439  } /* end for */
1440 
1441  retVal = LTC_TransmitReceiveData(pSpiInterface, pTxBuff, pRxBuff, frameLength);
1442 
1443  return retVal;
1444 }
1445 
1446 /**
1447  * @brief resets the error table.
1448  *
1449  * This function should be called during initialization or before starting a new measurement cycle
1450  *
1451  * @param ltc_state: state of the ltc state machine
1452  *
1453  */
1454 static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state) {
1455  uint16_t i = 0;
1456 
1457  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
1458  for (i = 0; i < LTC_N_LTC; i++) {
1459  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = false;
1460  ltc_state->ltcData.errorTable->mux0[stringNumber][i] = 0;
1461  ltc_state->ltcData.errorTable->mux1[stringNumber][i] = 0;
1462  ltc_state->ltcData.errorTable->mux2[stringNumber][i] = 0;
1463  ltc_state->ltcData.errorTable->mux3[stringNumber][i] = 0;
1464  }
1465  }
1466 }
1467 
1468 /**
1469  * @brief tells the LTC daisy-chain to start measuring the voltage on all cells.
1470  *
1471  * This function sends an instruction to the daisy-chain via SPI, in order to start voltage measurement for all cells.
1472  *
1473  * @param pSpiInterface pointer to SPI configuration
1474  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
1475  * @param adcMeasCh number of cell voltage measured (2 cells or all cells)
1476  *
1477  * @return retVal #STD_OK if dummy byte was sent correctly by SPI, #STD_NOT_OK otherwise
1478  *
1479  */
1481  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1482  LTC_ADCMODE_e adcMode,
1483  LTC_ADCMEAS_CHAN_e adcMeasCh) {
1484  STD_RETURN_TYPE_e retVal = STD_OK;
1485 
1486  retVal = LTC_TransmitCommand(pSpiInterface, ltc_cmdADCV_normal_Fuelcell);
1487 
1488  return retVal;
1489 }
1490 
1491 /**
1492  * @brief tells LTC daisy-chain to start measuring the voltage on GPIOS.
1493  *
1494  * This function sends an instruction to the daisy-chain via SPI to start the measurement.
1495  *
1496  * @param pSpiInterface pointer to SPI configuration
1497  * @param adcMode LTC ADCmeasurement mode (fast, normal or filtered)
1498  * @param PUP pull-up bit for pull-up or pull-down current (0: pull-down, 1: pull-up)
1499  *
1500  * @return retVal #STD_OK if command was sent correctly by SPI, #STD_NOT_OK otherwise
1501  *
1502  */
1504  SPI_INTERFACE_CONFIG_s *pSpiInterface,
1505  LTC_ADCMODE_e adcMode,
1506  uint8_t PUP) {
1507  STD_RETURN_TYPE_e retval = STD_NOT_OK;
1508 
1509  if (PUP == 0u) {
1510  /* pull-down current */
1512  } else if (PUP == 1u) {
1513  /* pull-up current */
1514  retval = LTC_TransmitCommand(pSpiInterface, ltc_BC_cmdADOW_PUP_100ms_fuelcell);
1515  }
1516 
1517  return retval;
1518 }
1519 
1520 /**
1521  * @brief checks if the data received from the daisy-chain is not corrupt.
1522  *
1523  * This function computes the PEC (CRC) from the data received by the daisy-chain.
1524  * It compares it with the PEC sent by the LTCs.
1525  * If there are errors, the array the error table is updated to locate the LTCs in daisy-chain
1526  * that transmitted corrupt data.
1527  *
1528  * @param ltc_state state of the ltc state machine
1529  * @param DataBufferSPI_RX_with_PEC data obtained from the SPI transmission
1530  * @param stringNumber string addressed
1531  *
1532  * @return retVal STD_OK if PEC check is OK, STD_NOT_OK otherwise
1533  *
1534  */
1536  LTC_STATE_s *ltc_state,
1537  uint16_t *DataBufferSPI_RX_with_PEC,
1538  uint8_t stringNumber) {
1539  uint16_t i = 0;
1540  STD_RETURN_TYPE_e retVal = STD_OK;
1541  uint8_t PEC_TX[2];
1542  uint16_t PEC_result = 0;
1543  uint8_t PEC_Check[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1544 
1545  /* check all PECs and put data without command and PEC in DataBufferSPI_RX (easier to use) */
1546  for (i = 0; i < LTC_N_LTC; i++) {
1547  PEC_Check[0] = DataBufferSPI_RX_with_PEC[4u + (i * 8u)];
1548  PEC_Check[1] = DataBufferSPI_RX_with_PEC[5u + (i * 8u)];
1549  PEC_Check[2] = DataBufferSPI_RX_with_PEC[6u + (i * 8u)];
1550  PEC_Check[3] = DataBufferSPI_RX_with_PEC[7u + (i * 8u)];
1551  PEC_Check[4] = DataBufferSPI_RX_with_PEC[8u + (i * 8u)];
1552  PEC_Check[5] = DataBufferSPI_RX_with_PEC[9u + (i * 8u)];
1553 
1554  PEC_result = LTC_pec15_calc(6, PEC_Check);
1555  PEC_TX[0] = (uint8_t)((PEC_result >> 8u) & 0xFFu);
1556  PEC_TX[1] = (uint8_t)(PEC_result & 0xFFu);
1557 
1558  /* if calculated PEC not equal to received PEC */
1559  if ((PEC_TX[0] != DataBufferSPI_RX_with_PEC[10u + (i * 8u)]) ||
1560  (PEC_TX[1] != DataBufferSPI_RX_with_PEC[11u + (i * 8u)])) {
1561  /* update error table of the corresponding LTC only if PEC check is activated */
1562  if (LTC_DISCARD_PEC == false) {
1563  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = false;
1564  retVal = STD_NOT_OK;
1565  } else {
1566  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = true;
1567  }
1568  } else {
1569  /* update error table of the corresponding LTC */
1570  ltc_state->ltcData.errorTable->PEC_valid[stringNumber][i] = true;
1571  }
1572  }
1573  return retVal;
1574 }
1575 
1576 /**
1577  * @brief send command to the LTC daisy-chain and receives data from the LTC daisy-chain.
1578  *
1579  * This is the core function to receive data from the LTC6804 daisy-chain.
1580  * A 2 byte command is sent with the corresponding PEC. Example: read configuration register (RDCFG).
1581  * Only command has to be set, the function calculates the PEC automatically.
1582  * The data send is:
1583  * 2 bytes (COMMAND) 2 bytes (PEC)
1584  * The data received is:
1585  * 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)
1586  *
1587  * The function does not check the PECs. This has to be done elsewhere.
1588  *
1589  * @param Command command sent to the daisy-chain
1590  * @param pSpiInterface pointer to SPI configuration
1591  * @param pTxBuff transmit buffer
1592  * @param pRxBuff receive buffer
1593  * @param frameLength number of words to transmit
1594  *
1595  * @return statusSPI #STD_OK if SPI transmission is OK, #STD_NOT_OK otherwise
1596  *
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_TransmitReceiveData(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_monitoringPinInit(void) {
1753  /* set HET Pins to output */
1758 
1759  /* set LTC6820 forward enable to 1 */
1761  /* set LTC6820 forward master to 1 */
1763 
1764  /* set LTC6820 reverse enable to 0 */
1766  /* set LTC6820 reverse master to 0 */
1768 }
1769 
1770 /*========== Externalized Static Function Implementations (Unit Test) =======*/
1771 #ifdef UNITY_UNIT_TEST
1772 uint8_t TEST_LTC_CheckReEntrance(LTC_STATE_s *ltc_state) {
1773  return LTC_CheckReEntrance(ltc_state);
1774 }
1775 
1776 extern void TEST_LTC_SetFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state) {
1778 }
1779 
1780 /** this define is used for creating the declaration of a function for variable extraction */
1781 #define TEST_LTC_DEFINE_GET(VARIABLE) \
1782  extern void TEST_LTC_Get_##VARIABLE(uint8_t data[4]) { \
1783  for (uint8_t i = 0u; i < 4u; i++) { \
1784  data[i] = (uint8_t)(VARIABLE)[i]; \
1785  } \
1786  }
1787 
1788 TEST_LTC_DEFINE_GET(ltc_cmdWRCFG);
1789 TEST_LTC_DEFINE_GET(ltc_cmdRDCFG);
1790 TEST_LTC_DEFINE_GET(ltc_cmdRDCVA_Fuelcell);
1791 TEST_LTC_DEFINE_GET(ltc_cmdRDCVB_Fuelcell);
1792 TEST_LTC_DEFINE_GET(ltc_cmdRDCVC_Fuelcell);
1793 TEST_LTC_DEFINE_GET(ltc_cmdRDCVD_Fuelcell);
1794 TEST_LTC_DEFINE_GET(ltc_cmdRDCVE_Fuelcell);
1795 TEST_LTC_DEFINE_GET(ltc_cmdRDCVF_Fuelcell);
1796 TEST_LTC_DEFINE_GET(ltc_cmdRDCVG_Fuelcell);
1797 TEST_LTC_DEFINE_GET(ltc_cmdRDCVH_Fuelcell);
1798 TEST_LTC_DEFINE_GET(ltc_cmdRDCVI_Fuelcell);
1799 TEST_LTC_DEFINE_GET(ltc_cmdADCV_normal_Fuelcell);
1800 TEST_LTC_DEFINE_GET(ltc_BC_cmdADOW_PUP_100ms_fuelcell);
1801 TEST_LTC_DEFINE_GET(ltc_BC_cmdADOW_PDOWN_100ms_fuelcell);
1802 #endif
#define BS_NR_OF_STRINGS
#define BS_NR_OF_CELLS_PER_MODULE
number of battery cells per battery module (parallel cells are counted as one)
#define BS_NR_OF_MODULES
number of modules in 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_TEMP_SENSORS_PER_STRING
#define BS_NR_OF_BAT_CELLS
Database module header.
#define DATA_WRITE_DATA(...)
Definition: database.h:86
@ DATA_BLOCK_ID_CELL_TEMPERATURE_BASE
Definition: database_cfg.h:95
@ DATA_BLOCK_ID_OPEN_WIRE_BASE
Definition: database_cfg.h:81
@ DATA_BLOCK_ID_CELL_VOLTAGE_BASE
Definition: database_cfg.h:94
@ DATA_BLOCK_ID_ALL_GPIO_VOLTAGES_BASE
Definition: database_cfg.h:82
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:226
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:353
Diagnosis driver header.
@ DIAG_STRING
Definition: diag_cfg.h:248
@ DIAG_EVENT_NOT_OK
Definition: diag_cfg.h:235
@ DIAG_EVENT_OK
Definition: diag_cfg.h:234
enum DIAG_ID DIAG_ID_e
@ DIAG_ID_LTC_PEC
Definition: diag_cfg.h:161
@ DIAG_ID_MEASUREMENT_IC_CELL_VOLTAGE_MEAS_ERROR
Definition: diag_cfg.h:170
@ DIAG_ID_LTC_SPI
Definition: diag_cfg.h:160
@ DIAG_ID_MEASUREMENT_IC_CELL_TEMPERATURE_MEAS_ERROR
Definition: diag_cfg.h:171
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:237
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:108
@ STD_NOT_OK
Definition: fstd_types.h:73
@ STD_OK
Definition: fstd_types.h:72
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:66
enum STD_RETURN_TYPE STD_RETURN_TYPE_e
#define SETBIT(register, bit)
sets a bit to 1u
Definition: general.h:80
void IO_PinSet(volatile uint32_t *pRegisterAddress, uint32_t pin)
Set pin by writing in pin output register.
Definition: io.c:70
void IO_PinReset(volatile uint32_t *pRegisterAddress, uint32_t pin)
Set pin by writing in pin output register.
Definition: io.c:77
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:210
uint16_t ltc_TxPecBuffer[LTC_N_BYTES_FOR_DATA_TRANSMISSION]
Definition: ltc_6806.c:122
#define LTC_LTC6820_REVERSE_MASTER_PIN
Definition: ltc_6806.c:83
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:1480
static DATA_BLOCK_ALL_GPIO_VOLTAGES_s ltc_allgpiovoltage
Definition: ltc_6806.c:132
static uint32_t LTC_GetSPIClock(SPI_INTERFACE_CONFIG_s *pSpiInterface)
gets the frequency of the SPI clock.
Definition: ltc_6806.c:1634
static DATA_BLOCK_CELL_VOLTAGE_s ltc_cellvoltage
Definition: ltc_6806.c:130
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:1503
static uint16_t ltc_cmdRDCVA_Fuelcell[4]
Definition: ltc_6806.c:202
LTC_STATEMACH_e LTC_GetState(LTC_STATE_s *ltc_state)
gets the current state.
Definition: ltc_6806.c:572
bool LTC_IsFirstMeasurementCycleFinished(LTC_STATE_s *ltc_state)
gets the measurement initialization status.
Definition: ltc_6806.c:1733
#define LTC_LTC6820_FORWARD_ENABLE_PIN
Definition: ltc_6806.c:79
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:358
void LTC_SaveAllGPIOMeasurement(LTC_STATE_s *ltc_state)
stores the measured GPIOs in the database.
Definition: ltc_6806.c:511
#define LTC_LTC6820CONTROL_GIOPORT
Definition: ltc_6806.c:77
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:610
static uint16_t ltc_cmdRDCVD_Fuelcell[4]
Definition: ltc_6806.c:205
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 uint16_t ltc_cmdRDCVG_Fuelcell[4]
Definition: ltc_6806.c:208
static uint16_t ltc_cmdRDCVH_Fuelcell[4]
Definition: ltc_6806.c:209
static uint16_t ltc_cmdRDCVE_Fuelcell[4]
Definition: ltc_6806.c:206
static const MIC_PLAUSIBILITY_VALUES_s ltc_plausibleCellVoltages6806
Definition: ltc_6806.c:140
static uint16_t ltc_cmdRDCFG[4]
Definition: ltc_6806.c:195
static void LTC_SaveLastStates(LTC_STATE_s *ltc_state)
Saves the last state and the last substate.
Definition: ltc_6806.c:345
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:590
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:463
static uint16_t ltc_used_cells_index[BS_NR_OF_STRINGS]
Definition: ltc_6806.c:127
#define LTC_FUEL_CELL_LSB_RESOLUTION_mV
Definition: ltc_6806.c:99
#define LTC_LTC6820_REVERSE_ENABLE_PIN
Definition: ltc_6806.c:82
#define LTC_LTC6820_FORWARD_SPI1_MASTER_PIN
Definition: ltc_6806.c:80
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:1299
LTC_REQUEST_s LTC_GetStateRequest(LTC_STATE_s *ltc_state)
gets the current state request.
Definition: ltc_6806.c:552
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:112
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:1402
static void LTC_ResetErrorTable(LTC_STATE_s *ltc_state)
resets the error table.
Definition: ltc_6806.c:1454
LTC_STATE_s ltc_stateBase
Definition: ltc_6806.c:147
static uint16_t ltc_cmdRDCVF_Fuelcell[4]
Definition: ltc_6806.c:207
static uint16_t ltc_cmdRDCVB_Fuelcell[4]
Definition: ltc_6806.c:203
static LTC_ERRORTABLE_s ltc_errorTable
Definition: ltc_6806.c:137
static void LTC_Initialize_Database(LTC_STATE_s *ltc_state)
in the database, initializes the fields related to the LTC drivers.
Definition: ltc_6806.c:309
void LTC_Trigger(LTC_STATE_s *ltc_state)
trigger function for the LTC driver state machine.
Definition: ltc_6806.c:625
uint8_t LTC_CheckReEntrance(LTC_STATE_s *ltc_state)
re-entrance check of LTC state machine trigger function
Definition: ltc_6806.c:529
#define LTC_FUELCELL_POSITIVE_FULLSCALE_RANGE_mV
Definition: ltc_6806.c:107
static DATA_BLOCK_OPEN_WIRE_s ltc_openwire
Definition: ltc_6806.c:133
uint16_t ltc_RxPecBuffer[LTC_N_BYTES_FOR_DATA_TRANSMISSION]
Definition: ltc_6806.c:121
void LTC_monitoringPinInit(void)
Sets the transceiver pins to enable LTC6820 IC.
Definition: ltc_6806.c:1752
static LTC_OPENWIRE_DETECTION_s ltc_openWireDetection
Definition: ltc_6806.c:136
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:241
static uint16_t ltc_cmdWRCFG[4]
Definition: ltc_6806.c:194
static STD_RETURN_TYPE_e LTC_RX_PECCheck(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:1535
static DATA_BLOCK_CELL_TEMPERATURE_s ltc_celltemperature
Definition: ltc_6806.c:131
static uint16_t ltc_BC_cmdADOW_PUP_100ms_fuelcell[4]
Definition: ltc_6806.c:239
static uint16_t ltc_cmdRDCVC_Fuelcell[4]
Definition: ltc_6806.c:204
#define LTC_LTC6820CONTROL_GIODIR
Definition: ltc_6806.c:76
static uint16_t ltc_cmdADCV_normal_Fuelcell[4]
Definition: ltc_6806.c:215
static STD_RETURN_TYPE_e LTC_RX(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
Header for the configuration for the LTC 6806 monitoring IC.
#define LTC_STATEMACH_DAISY_CHAIN_FIRST_INITIALIZATION_TIME
Definition: ltc_6806_cfg.h:176
#define LTC_TRANSMISSION_TIMEOUT
Definition: ltc_6806_cfg.h:145
#define LTC_FUELCELL_NORMAL_ALL_CELLS_MS
Definition: ltc_6806_cfg.h:167
#define LTC_TransmitCommand(spi_ltcInterface, command)
Definition: ltc_6806_cfg.h:298
#define LTC_STATEMACH_SHORTTIME
Definition: ltc_6806_cfg.h:170
#define LTC_DISCARD_PEC
Definition: ltc_6806_cfg.h:88
#define LTC_NUMBER_OF_LTC_PER_MODULE
Definition: ltc_6806_cfg.h:103
#define LTC_HIRNG
Definition: ltc_6806_cfg.h:110
#define LTC_VOLTAGE_MEASUREMENT_MODE
Definition: ltc_6806_cfg.h:124
#define LTC_ADOW_THRESHOLD
Definition: ltc_6806_cfg.h:116
#define LTC_FUEL_CELL_ADOW_TIME_MS
Definition: ltc_6806_cfg.h:113
#define LTC_TransmitReceiveData(spi_ltcInterface, txbuf, rxbuf, length)
Definition: ltc_6806_cfg.h:300
#define LTC_SPI_WAKEUP_WAIT_TIME_US
Definition: ltc_6806_cfg.h:164
#define LTC_TransmitWakeUp(spi_ltcInterface)
Definition: ltc_6806_cfg.h:295
#define LTC_NMBR_REQ_ADOW_COMMANDS
Definition: ltc_6806_cfg.h:289
#define LTC_OW_MEASUREMENT_MODE
Definition: ltc_6806_cfg.h:139
#define LTC_STATEMACH_DAISY_CHAIN_SECOND_INITIALIZATION_TIME
Definition: ltc_6806_cfg.h:181
#define LTC_N_BYTES_FOR_DATA_TRANSMISSION
Definition: ltc_cfg.h:77
#define LTC_N_LTC
Definition: ltc_cfg.h:66
@ LTC_RE_ENTRY_INITIALIZATION
Definition: ltc_defs.h:175
@ LTC_ENTRY_INITIALIZATION
Definition: ltc_defs.h:173
@ LTC_START_INIT_INITIALIZATION
Definition: ltc_defs.h:174
@ LTC_EXIT_INITIALIZATION
Definition: ltc_defs.h:178
@ LTC_CHECK_INITIALIZATION
Definition: ltc_defs.h:177
@ LTC_INIT_STRING
Definition: ltc_defs.h:172
@ LTC_STATE_INIT_REQUEST
Definition: ltc_defs.h:363
@ LTC_STATE_OPENWIRE_CHECK_REQUEST
Definition: ltc_defs.h:385
@ LTC_STATE_NO_REQUEST
Definition: ltc_defs.h:389
@ LTC_REQUEST_PULLDOWN_CURRENT_OPENWIRE_CHECK
Definition: ltc_defs.h:234
@ LTC_READ_VOLTAGES_PULLDOWN_OPENWIRE_CHECK
Definition: ltc_defs.h:235
@ LTC_READ_VOLTAGES_PULLUP_OPENWIRE_CHECK
Definition: ltc_defs.h:233
@ LTC_REQUEST_PULLUP_CURRENT_OPENWIRE_CHECK
Definition: ltc_defs.h:232
@ LTC_PERFORM_OPENWIRE_CHECK
Definition: ltc_defs.h:236
LTC_STATEMACH_e
Definition: ltc_defs.h:116
@ LTC_STATEMACH_INITIALIZATION
Definition: ltc_defs.h:119
@ LTC_STATEMACH_UNINITIALIZED
Definition: ltc_defs.h:118
@ LTC_STATEMACH_STARTMEAS_CONTINUE
Definition: ltc_defs.h:147
@ LTC_STATEMACH_OPENWIRE_CHECK
Definition: ltc_defs.h:139
@ LTC_STATEMACH_READVOLTAGE
Definition: ltc_defs.h:125
@ LTC_STATEMACH_INITIALIZED
Definition: ltc_defs.h:121
@ LTC_STATEMACH_STARTMEAS
Definition: ltc_defs.h:124
LTC_ADCMEAS_CHAN_e
Definition: ltc_defs.h:103
@ LTC_ADCMEAS_ALLCHANNEL
Definition: ltc_defs.h:105
@ LTC_ADCMEAS_UNDEFINED
Definition: ltc_defs.h:104
LTC_RETURN_TYPE_e
Definition: ltc_defs.h:395
@ LTC_BUSY_OK
Definition: ltc_defs.h:397
@ LTC_ILLEGAL_REQUEST
Definition: ltc_defs.h:399
@ LTC_ALREADY_INITIALIZED
Definition: ltc_defs.h:406
@ LTC_ERROR
Definition: ltc_defs.h:405
@ LTC_OK_FROM_ERROR
Definition: ltc_defs.h:404
@ LTC_REQUEST_PENDING
Definition: ltc_defs.h:398
@ LTC_OK
Definition: ltc_defs.h:396
@ LTC_READ_VOLTAGE_REGISTER_F_RDCVF_READVOLTAGE
Definition: ltc_defs.h:194
@ LTC_READ_VOLTAGE_REGISTER_A_RDCVA_READVOLTAGE
Definition: ltc_defs.h:189
@ LTC_READ_VOLTAGE_REGISTER_D_RDCVD_READVOLTAGE
Definition: ltc_defs.h:192
@ LTC_READ_VOLTAGE_REGISTER_G_RDCVG_READVOLTAGE
Definition: ltc_defs.h:195
@ LTC_READ_VOLTAGE_REGISTER_I_RDCVI_READVOLTAGE
Definition: ltc_defs.h:197
@ LTC_READ_VOLTAGE_REGISTER_B_RDCVB_READVOLTAGE
Definition: ltc_defs.h:190
@ LTC_EXIT_READVOLTAGE
Definition: ltc_defs.h:198
@ LTC_READ_VOLTAGE_REGISTER_H_RDCVH_READVOLTAGE
Definition: ltc_defs.h:196
@ LTC_READ_VOLTAGE_REGISTER_E_RDCVE_READVOLTAGE
Definition: ltc_defs.h:193
@ LTC_READ_VOLTAGE_REGISTER_C_RDCVC_READVOLTAGE
Definition: ltc_defs.h:191
@ LTC_REUSE_READVOLT_FOR_ADOW_PUP
Definition: ltc_defs.h:495
@ LTC_REUSE_READVOLT_FOR_ADOW_PDOWN
Definition: ltc_defs.h:496
@ LTC_NOT_REUSED
Definition: ltc_defs.h:494
LTC_ADCMODE_e
Definition: ltc_defs.h:92
@ LTC_ADCMODE_UNDEFINED
Definition: ltc_defs.h:93
@ LTC_ADCMODE_FAST_DCP0
Definition: ltc_defs.h:94
@ LTC_ENTRY
Definition: ltc_defs.h:159
bool MIC_IsTransmitOngoing(LTC_STATE_s *pLtcState)
gets the SPI transmit status.
Definition: ltc_mic_dma.c:73
void MIC_SetTransmitOngoing(LTC_STATE_s *pLtcState)
sets the SPI transmit status.
Definition: ltc_mic_dma.c:77
STD_RETURN_TYPE_e MIC_PlausibilityCheckVoltageMeasurementRange(const int16_t cellvoltage_mV, const MIC_PLAUSIBILITY_VALUES_s plausibleValues)
Cell voltage measurement range plausibility check.
STD_RETURN_TYPE_e MIC_PlausibilityCheckTempMinMax(const int16_t celltemperature_ddegC)
Cell temperature plausibility check.
plausibility checks for cell voltage and cell temperatures
void OS_ExitTaskCritical(void)
Exit Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os.c:178
void OS_EnterTaskCritical(void)
Enter Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os.c:174
Implementation of the tasks used by the system, headers.
SPI_INTERFACE_CONFIG_s spi_ltcInterface[BS_NR_OF_STRINGS]
Definition: spi_cfg.c:77
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:110
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:315
uint16_t gpioVoltages_mV[BS_NR_OF_STRINGS][BS_NR_OF_MODULES *BS_NR_OF_GPIOS_PER_MODULE]
Definition: database_cfg.h:317
int16_t cellTemperature_ddegC[BS_NR_OF_STRINGS][BS_NR_OF_TEMP_SENSORS_PER_STRING]
Definition: database_cfg.h:138
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:136
uint16_t invalidCellTemperature[BS_NR_OF_STRINGS][BS_NR_OF_MODULES]
Definition: database_cfg.h:140
uint16_t nrValidTemperatures[BS_NR_OF_STRINGS]
Definition: database_cfg.h:141
uint16_t nrValidCellVoltages[BS_NR_OF_STRINGS]
Definition: database_cfg.h:126
int16_t cellVoltage_mV[BS_NR_OF_STRINGS][BS_NR_OF_BAT_CELLS]
Definition: database_cfg.h:123
uint64_t invalidCellVoltage[BS_NR_OF_STRINGS][BS_NR_OF_MODULES]
Definition: database_cfg.h:125
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:120
int32_t packVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:122
uint16_t nrOpenWires[BS_NR_OF_STRINGS]
Definition: database_cfg.h:305
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:303
uint8_t openwire[BS_NR_OF_STRINGS][BS_NR_OF_MODULES *(BS_NR_OF_CELLS_PER_MODULE+1)]
Definition: database_cfg.h:307
LTC_OPENWIRE_DETECTION_s * openWireDetection
Definition: ltc_defs.h:445
DATA_BLOCK_ALL_GPIO_VOLTAGES_s * allGpioVoltages
Definition: ltc_defs.h:442
DATA_BLOCK_CELL_VOLTAGE_s * cellVoltage
Definition: ltc_defs.h:437
DATA_BLOCK_CELL_TEMPERATURE_s * cellTemperature
Definition: ltc_defs.h:438
uint16_t * txBuffer
Definition: ltc_defs.h:434
LTC_ERRORTABLE_s * errorTable
Definition: ltc_defs.h:446
SPI_INTERFACE_CONFIG_s * pSpiInterface
Definition: ltc_defs.h:433
uint16_t * rxBuffer
Definition: ltc_defs.h:435
uint16_t * usedCellIndex
Definition: ltc_defs.h:444
uint32_t frameLength
Definition: ltc_defs.h:436
DATA_BLOCK_OPEN_WIRE_s * openWire
Definition: ltc_defs.h:443
uint8_t PEC_valid[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:70
uint8_t mux3[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:74
uint8_t mux2[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:73
uint8_t mux0[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:71
uint8_t mux1[BS_NR_OF_STRINGS][LTC_N_LTC]
Definition: ltc_defs.h:72
int16_t openWirePup[BS_NR_OF_STRINGS][BS_NR_OF_BAT_CELLS]
Definition: ltc_defs.h:79
int32_t openWireDelta[BS_NR_OF_STRINGS][BS_NR_OF_BAT_CELLS]
Definition: ltc_defs.h:81
int16_t openWirePdown[BS_NR_OF_STRINGS][BS_NR_OF_BAT_CELLS]
Definition: ltc_defs.h:80
LTC_STATE_REQUEST_e request
Definition: ltc_defs.h:511
uint8_t string
Definition: ltc_defs.h:512
uint32_t commandDataTransferTime
Definition: ltc_defs.h:543
LTC_DATAPTR_s ltcData
Definition: ltc_defs.h:578
LTC_ADCMODE_e adcModereq
Definition: ltc_defs.h:530
LTC_REQUEST_s statereq
Definition: ltc_defs.h:522
uint8_t triggerentry
Definition: ltc_defs.h:541
SPI_INTERFACE_CONFIG_s * spiSeqPtr
Definition: ltc_defs.h:568
uint32_t commandTransferTime
Definition: ltc_defs.h:544
SPI_INTERFACE_CONFIG_s * spiSeqEndPtr
Definition: ltc_defs.h:569
uint8_t substate
Definition: ltc_defs.h:524
LTC_STATEMACH_e laststate
Definition: ltc_defs.h:525
uint8_t lastsubstate
Definition: ltc_defs.h:526
LTC_ADCMEAS_CHAN_e adcMeasCh
Definition: ltc_defs.h:532
LTC_REUSE_MODE_e reusageMeasurementMode
Definition: ltc_defs.h:558
uint32_t gpioClocksTransferTime
Definition: ltc_defs.h:546
uint16_t timer
Definition: ltc_defs.h:520
uint8_t resendCommandCounter
Definition: ltc_defs.h:565
LTC_STATEMACH_e state
Definition: ltc_defs.h:523
uint8_t spiNumberInterfaces
Definition: ltc_defs.h:570
LTC_ADCMODE_e adcMode
Definition: ltc_defs.h:527
uint8_t currentString
Definition: ltc_defs.h:571
uint32_t ErrRequestCounter
Definition: ltc_defs.h:540
STD_RETURN_TYPE_e check_spi_flag
Definition: ltc_defs.h:563
bool first_measurement_made
Definition: ltc_defs.h:560
uint8_t requestedString
Definition: ltc_defs.h:572
LTC_ADCMEAS_CHAN_e adcMeasChreq
Definition: ltc_defs.h:534
struct definition for plausibility values of a MIC
const int16_t maximumPlausibleVoltage_mV
spiBASE_t * pNode
Definition: spi_cfg.h:110