foxBMS  1.5.0
The foxBMS Battery Management System API Documentation
nxp_mc33775a.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 nxp_mc33775a.c
44  * @author foxBMS Team
45  * @date 2020-05-08 (date of creation)
46  * @updated 2023-02-03 (date of last update)
47  * @version v1.5.0
48  * @ingroup DRIVERS
49  * @prefix N775
50  *
51  * @brief Driver for the MC33775A analog front-end.
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "nxp_mc33775a.h"
57 /* clang-format off */
58 #include "nxp_mc33775a-ll.h"
59 /* clang-format on */
60 
61 #include "HL_gio.h"
62 #include "HL_system.h"
63 #pragma diag_push
64 #pragma diag_suppress 232
65 #include "MC33775A.h"
66 #pragma diag_pop
67 
68 #include "afe.h"
69 #include "afe_dma.h"
70 #include "database.h"
71 #include "diag.h"
72 #include "fassert.h"
73 #include "fstd_types.h"
74 #include "ftask.h"
75 #include "io.h"
76 #include "mcu.h"
77 #include "os.h"
78 #include "spi.h"
79 
80 #include <math.h>
81 #include <stdbool.h>
82 #include <stdint.h>
83 
84 /*========== Macros and Definitions =========================================*/
85 
86 /*========== Static Constant and Variable Definitions =======================*/
87 /** local copies of database tables */
88 /**@{*/
98 /**@}*/
101 
102 /*========== Extern Constant and Variable Definitions =======================*/
103 
105  .firstMeasurementMade = false,
106  .currentString = 0u,
107  .pSpiTxSequenceStart = NULL_PTR,
108  .pSpiTxSequence = NULL_PTR,
109  .pSpiRxSequenceStart = NULL_PTR,
110  .pSpiRxSequence = NULL_PTR,
111  .currentMux = {0},
112  .pMuxSequenceStart = {0},
113  .pMuxSequence = {0},
114  .n775Data.cellVoltage = &n775_cellVoltage,
115  .n775Data.cellTemperature = &n775_cellTemperature,
116  .n775Data.allGpioVoltage = &n775_allGpioVoltage,
117  .n775Data.minMax = &n775_minMax,
118  .n775Data.balancingFeedback = &n775_balancingFeedback,
119  .n775Data.balancingControl = &n775_balancingControl,
120  .n775Data.slaveControl = &n775_slaveControl,
121  .n775Data.openWire = &n775_openWire,
122  .n775Data.supplyCurrent = &n775_supplyCurrent,
123  .n775Data.errorTable = &n775_errorTable,
124 };
125 
126 /*========== Static Function Prototypes =====================================*/
127 static void N775_SetFirstMeasurementCycleFinished(N775_STATE_s *n775_state);
128 static void N775_InitializeDatabase(N775_STATE_s *n775_state);
129 static void N775_ResetStringSequence(N775_STATE_s *n775_state);
130 static void N775_IncrementStringSequence(N775_STATE_s *n775_state);
131 static void N775_ResetMuxIndex(N775_STATE_s *n775_state);
132 static void N775_IncrementMuxIndex(N775_STATE_s *n775_state);
133 static void N775_ErrorHandling(N775_STATE_s *n775_state, N775_COMMUNICATION_STATUS_e returnedValue, uint8_t module);
134 static void N775_Init(N775_STATE_s *n775_state);
135 static STD_RETURN_TYPE_e N775_Enumerate(N775_STATE_s *n775_state);
136 static void N775_I2cInit(N775_STATE_s *n775_state);
137 static void N775_StartMeasurement(N775_STATE_s *n775_state);
138 static void N775_CaptureMeasurement(N775_STATE_s *n775_state);
141 static void N775_BalanceSetup(N775_STATE_s *n775_state);
142 static void N775_BalanceControl(N775_STATE_s *n775_state);
143 static void N775_waitTime(uint32_t milliseconds);
144 
145 /*========== Static Function Implementations ================================*/
146 
147 /*========== Extern Function Implementations ================================*/
148 
149 /**
150  * @brief in the database, initializes the fields related to the N775 driver.
151  *
152  * This function loops through all the N775-related data fields in the database
153  * and sets them to 0. It should be called in the initialization or re-initialization
154  * routine of the N775 driver.
155  *
156  * @param n775_state state of the N775A driver
157  *
158  */
159 static void N775_InitializeDatabase(N775_STATE_s *n775_state) {
160  FAS_ASSERT(n775_state != NULL_PTR);
161  uint16_t iterator = 0;
162 
163  for (uint8_t stringNumber = 0u; stringNumber < BS_NR_OF_STRINGS; stringNumber++) {
164  n775_state->n775Data.cellVoltage->state = 0;
165  n775_state->n775Data.minMax->minimumCellVoltage_mV[stringNumber] = 0;
166  n775_state->n775Data.minMax->maximumCellVoltage_mV[stringNumber] = 0;
167  n775_state->n775Data.minMax->nrModuleMinimumCellVoltage[stringNumber] = 0;
168  n775_state->n775Data.minMax->nrModuleMaximumCellVoltage[stringNumber] = 0;
169  n775_state->n775Data.minMax->nrCellMinimumCellVoltage[stringNumber] = 0;
170  n775_state->n775Data.minMax->nrCellMaximumCellVoltage[stringNumber] = 0;
171  for (iterator = 0u; iterator < BS_NR_OF_CELL_BLOCKS_PER_STRING; iterator++) {
172  n775_state->n775Data.cellVoltage->cellVoltage_mV[stringNumber][iterator] = 0;
173  }
174 
175  n775_state->n775Data.cellTemperature->state = 0;
176  n775_state->n775Data.minMax->minimumTemperature_ddegC[stringNumber] = 0;
177  n775_state->n775Data.minMax->maximumTemperature_ddegC[stringNumber] = 0;
178  n775_state->n775Data.minMax->nrModuleMinimumTemperature[stringNumber] = 0;
179  n775_state->n775Data.minMax->nrModuleMaximumTemperature[stringNumber] = 0;
180  n775_state->n775Data.minMax->nrSensorMinimumTemperature[stringNumber] = 0;
181  n775_state->n775Data.minMax->nrSensorMaximumTemperature[stringNumber] = 0;
182  for (iterator = 0u; iterator < BS_NR_OF_TEMP_SENSORS_PER_STRING; iterator++) {
183  n775_state->n775Data.cellTemperature->cellTemperature_ddegC[stringNumber][iterator] = 0;
184  }
185 
186  for (iterator = 0u; iterator < BS_NR_OF_CELL_BLOCKS_PER_STRING; iterator++) {
187  n775_state->n775Data.balancingControl->balancingState[stringNumber][iterator] = 0;
188  }
189  for (iterator = 0u; iterator < BS_NR_OF_MODULES_PER_STRING; iterator++) {
190  n775_state->n775Data.errorTable->communicationOk[stringNumber][iterator] = false;
191  n775_state->n775Data.errorTable->noCommunicationTimeout[stringNumber][iterator] = false;
192  n775_state->n775Data.errorTable->crcIsValid[stringNumber][iterator] = false;
193  n775_state->n775Data.errorTable->mux0IsOk[stringNumber][iterator] = false;
194  n775_state->n775Data.errorTable->mux1IsOK[stringNumber][iterator] = false;
195  n775_state->n775Data.errorTable->mux2IsOK[stringNumber][iterator] = false;
196  n775_state->n775Data.errorTable->mux3IsOK[stringNumber][iterator] = false;
197  }
198  for (iterator = 0u; iterator < BS_NR_OF_MODULES_PER_STRING; iterator++) {
199  n775_state->n775Data.uid[stringNumber][iterator] = 0;
200  }
201  }
202 
203  DATA_WRITE_DATA(n775_state->n775Data.cellVoltage);
205  DATA_WRITE_DATA(n775_state->n775Data.minMax);
207 }
208 
209 void N775_Meas(N775_STATE_s *n775_state) {
210  FAS_ASSERT(n775_state != NULL_PTR);
211 
212  N775_InitializeDatabase(n775_state);
213  /* Initialize SPI sequence pointers */
216 
217  /* Initialize each string */
218  N775_ResetStringSequence(n775_state);
219  while (n775_state->currentString < BS_NR_OF_STRINGS) {
220  /* Initialize mux sequence pointers */
221  n775_state->pMuxSequenceStart[n775_state->currentString] = n775_muxSequence;
222  N775_Init(n775_state);
223  N775_IncrementStringSequence(n775_state);
224  }
225 
226  while (1) {
227  N775_ResetStringSequence(n775_state);
228 
229  while (n775_state->currentString < BS_NR_OF_STRINGS) {
230  if (N775_USE_MUX_FOR_TEMP == true) {
231  /* Set mux channel according to mux sequence */
232  N775_SetMuxChannel(n775_state);
233  }
234  N775_CaptureMeasurement(n775_state);
235  if (N775_USE_MUX_FOR_TEMP == true) {
236  /* Update index in mux sequence */
237  N775_IncrementMuxIndex(n775_state);
238  }
239  N775_BalanceControl(n775_state);
240 
241  N775_TransmitI2c(n775_state);
242 
243  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
244  if (N775_IsFirstMeasurementCycleFinished(n775_state) == true) {
245  if (n775_state->n775Data.errorTable->noCommunicationTimeout[n775_state->currentString][m] == 0u) {
246  /* Daisy-chain does not answer: initialize it again */
247  n775_state->pMuxSequenceStart[n775_state->currentString] = n775_muxSequence;
248  N775_Init(n775_state);
249  /* Daisy-chain re-initialized: no need to check further slaves */
250  break;
251  }
252  }
253  }
254 
255  N775_IncrementStringSequence(n775_state);
256  }
257 
258  /* Set flag when all strings have been measured */
259  if ((n775_state->currentString == BS_NR_OF_STRINGS) &&
260  (N775_IsFirstMeasurementCycleFinished(n775_state) == 0u)) {
262  }
263  }
264 }
265 
266 STD_RETURN_TYPE_e N775_I2cWrite(uint8_t module, uint8_t deviceAddress, uint8_t *pData, uint8_t dataLength) {
267  FAS_ASSERT(pData != NULL_PTR);
268  FAS_ASSERT((dataLength > 0u) && (dataLength <= 13u));
269  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
270  AFE_I2C_QUEUE_s transactionData;
271 
272  transactionData.module = module;
273  transactionData.deviceAddress = deviceAddress;
274  transactionData.writeDataLength = dataLength;
275  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_WRITE;
276  for (uint8_t i = 0u; i < dataLength; i++) {
277  transactionData.writeData[i] = pData[i];
278  }
279  if (OS_SendToBackOfQueue(ftsk_afeToI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
280  /* queue is not full */
281  /* wating for transfer to finish */
283  OS_SUCCESS) {
284  if (transactionData.transferType == AFE_I2C_TRANSFER_TYPE_WRITE_SUCCESS) {
285  retVal = STD_OK;
286  }
287  }
288  } else {
289  /* queue is full */
290  }
291 
292  return retVal;
293 }
294 
296  uint8_t module,
297  uint8_t deviceAddress,
298  uint8_t *pDataWrite,
299  uint8_t writeDataLength,
300  uint8_t *pDataRead,
301  uint8_t readDataLength) {
302  FAS_ASSERT(pDataWrite != NULL_PTR);
303  FAS_ASSERT(pDataRead != NULL_PTR);
304  FAS_ASSERT(writeDataLength > 0u);
305  FAS_ASSERT(readDataLength > 0u);
306  FAS_ASSERT((uint16_t)(writeDataLength + readDataLength) <= 12u);
307  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
308  AFE_I2C_QUEUE_s transactionData;
309 
310  transactionData.module = module;
311  transactionData.deviceAddress = deviceAddress;
312  transactionData.writeDataLength = writeDataLength;
313  transactionData.readDataLength = readDataLength;
315  for (uint8_t i = 0u; i < writeDataLength; i++) {
316  transactionData.writeData[i] = pDataWrite[i];
317  }
318  if (OS_SendToBackOfQueue(ftsk_afeToI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
319  /* queue is not full */
320  /* wating for transfer to finish */
322  OS_SUCCESS) {
323  if (transactionData.transferType == AFE_I2C_TRANSFER_TYPE_READ_SUCCESS) {
324  for (uint8_t i = 0u; i < readDataLength; i++) {
325  pDataRead[i] = transactionData.readData[i];
326  }
327  retVal = STD_OK;
328  }
329  }
330  } else {
331  /* queue is full */
332  }
333 
334  return retVal;
335 }
336 
337 STD_RETURN_TYPE_e N775_I2cRead(uint8_t module, uint8_t deviceAddress, uint8_t *pData, uint8_t dataLength) {
338  FAS_ASSERT(pData != NULL_PTR);
339  FAS_ASSERT((dataLength > 0u) && (dataLength <= 13u));
340  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
341  AFE_I2C_QUEUE_s transactionData;
342 
343  transactionData.module = module;
344  transactionData.deviceAddress = deviceAddress;
345  transactionData.readDataLength = dataLength;
346  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_READ;
347  if (OS_SendToBackOfQueue(ftsk_afeToI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
348  /* queue is not full */
349  /* wating for transfer to finish */
351  OS_SUCCESS) {
352  if (transactionData.transferType == AFE_I2C_TRANSFER_TYPE_READ_SUCCESS) {
353  for (uint8_t i = 0u; i < dataLength; i++) {
354  pData[i] = transactionData.readData[i];
355  }
356  retVal = STD_OK;
357  }
358  }
359  } else {
360  /* queue is full */
361  }
362 
363  return retVal;
364 }
365 
366 /**
367  * @brief reset index in string sequence.
368  *
369  * @param n775_state state of the N775A driver
370  *
371  */
372 static void N775_ResetStringSequence(N775_STATE_s *n775_state) {
373  FAS_ASSERT(n775_state != NULL_PTR);
374 
375  n775_state->currentString = 0u;
376  n775_state->pSpiTxSequence = n775_state->pSpiTxSequenceStart + n775_state->currentString;
377  n775_state->pSpiRxSequence = n775_state->pSpiRxSequenceStart + n775_state->currentString;
378 }
379 
380 /**
381  * @brief updates index in string sequence.
382  *
383  * @param n775_state state of the N775A driver
384  *
385  */
386 static void N775_IncrementStringSequence(N775_STATE_s *n775_state) {
387  FAS_ASSERT(n775_state != NULL_PTR);
388 
389  n775_state->currentString++;
390  n775_state->pSpiTxSequence = n775_state->pSpiTxSequenceStart + n775_state->currentString;
391  n775_state->pSpiRxSequence = n775_state->pSpiRxSequenceStart + n775_state->currentString;
392 }
393 
394 /**
395  * @brief resets index in mux sequence.
396  *
397  * @param n775_state state of the N775A driver
398  *
399  */
400 static void N775_ResetMuxIndex(N775_STATE_s *n775_state) {
401  FAS_ASSERT(n775_state != NULL_PTR);
402 
403  n775_state->currentMux[n775_state->currentString] = 0u;
404  n775_state->pMuxSequence[n775_state->currentString] = n775_state->pMuxSequenceStart[n775_state->currentString];
405 }
406 
407 /**
408  * @brief updates index in mux sequence.
409  *
410  * @param n775_state state of the N775A driver
411  *
412  */
413 static void N775_IncrementMuxIndex(N775_STATE_s *n775_state) {
414  FAS_ASSERT(n775_state != NULL_PTR);
415 
416  n775_state->currentMux[n775_state->currentString]++;
417  if (n775_state->currentMux[n775_state->currentString] >= N775_MUX_SEQUENCE_LENGTH) {
418  n775_state->currentMux[n775_state->currentString] = 0u;
419  }
420  n775_state->pMuxSequence[n775_state->currentString] = n775_state->pMuxSequenceStart[n775_state->currentString] +
421  n775_state->currentMux[n775_state->currentString];
422 }
423 
424 /**
425  * @brief handles error when doing measurements.
426  *
427  * This function is used in the measurement function. It sets the errors flags in
428  * the error table according to the value returned by the communication function.
429  *
430  * @param n775_state state of the N775A driver
431  * @param returnedValue status of the low-level communication
432  * @param module number of module addressed
433  *
434  */
435 static void N775_ErrorHandling(N775_STATE_s *n775_state, N775_COMMUNICATION_STATUS_e returnedValue, uint8_t module) {
436  FAS_ASSERT(n775_state != NULL_PTR);
437 
438  if (returnedValue == N775_COMMUNICATION_OK) {
439  n775_state->n775Data.errorTable->communicationOk[n775_state->currentString][module] = true;
440  n775_state->n775Data.errorTable->noCommunicationTimeout[n775_state->currentString][module] = true;
441  n775_state->n775Data.errorTable->crcIsValid[n775_state->currentString][module] = true;
442  } else {
443  n775_state->n775Data.errorTable->communicationOk[n775_state->currentString][module] = false;
444  switch (returnedValue) {
446  n775_state->n775Data.errorTable->noCommunicationTimeout[n775_state->currentString][module] = false;
447  break;
449  n775_state->n775Data.errorTable->crcIsValid[n775_state->currentString][module] = false;
450  break;
451  default:
452  n775_state->n775Data.errorTable->communicationOk[n775_state->currentString][module] = false;
453  break;
454  }
455  }
456 }
457 
458 /**
459  * @brief initializes the N775 driver.
460  *
461  * This function enumerates the slaves and starts the measurement.
462  *
463  * @param n775_state state of the N775A driver
464  *
465  */
466 static void N775_Init(N775_STATE_s *n775_state) {
467  FAS_ASSERT(n775_state != NULL_PTR);
468 
469  /* Reset mux sequence */
470  N775_ResetMuxIndex(n775_state);
471 
472  /* Initialize daisy-chain */
473  if (STD_OK != N775_Enumerate(n775_state)) {
474  /* error handling */}
475  N775_StartMeasurement(n775_state);
476  N775_I2cInit(n775_state);
477  N775_BalanceSetup(n775_state);
478 }
479 
480 /**
481  * @brief enumerates the N775 slaves.
482  *
483  * This function gives the slaves in the daisy-chain an address.
484  *
485  * @param n775_state state of the N775A driver
486  *
487  */
489  FAS_ASSERT(n775_state != NULL_PTR);
490  uint16_t readValue = 0u;
491  uint16_t uid[3u] = {0};
493  STD_RETURN_TYPE_e retVal = STD_NOT_OK;
494 
495  /** Parse all slaves in the daisy-chain */
496  for (uint8_t i = 1; i <= BS_NR_OF_MODULES_PER_STRING; i++) {
497  /* First send slave to deep sleep to reset message counter */
499  i,
500  MC33775_SYS_MODE_OFFSET,
501  (MC33775_SYS_MODE_TARGETMODE_DEEPSLEEP_ENUM_VAL << MC33775_SYS_MODE_TARGETMODE_POS),
502  n775_state->pSpiTxSequence);
503  N775_waitTime(1u);
504 
505  /* Wake up slave */
506  returnedValue = N775_CommunicationRead(i, MC33775_SYS_COM_CFG_OFFSET, &readValue, n775_state);
507  /* If slave is not enumerated */
508  if (returnedValue != N775_COMMUNICATION_OK) {
509  /* Wait until the slave has woken up */
511 
512  returnedValue = N775_CommunicationRead(i, MC33775_SYS_COM_CFG_OFFSET, &readValue, n775_state);
513  /* If slave is not enumerated */
514  if (returnedValue != N775_COMMUNICATION_OK) {
515  /* Enumerate slave */
517  (0u << 6u) + 0u,
518  MC33775_SYS_COM_CFG_OFFSET,
519  i + (N775_DEFAULT_CHAIN_ADDRESS << 6) +
520  (MC33775_SYS_COM_CFG_BUSFW_ENABLED_ENUM_VAL << MC33775_SYS_COM_CFG_BUSFW_POS),
521  n775_state->pSpiTxSequence);
522  }
523 
524  /* Reset the message counter of the driver */
526  /* Check that the device has been enumerated */
527  returnedValue = N775_CommunicationRead(i, MC33775_SYS_VERSION_OFFSET, &readValue, n775_state);
528  if (returnedValue == N775_COMMUNICATION_OK) {
529  retVal = STD_OK;
530  }
531  } else {
532  /* Slave already has an address */
533  retVal = STD_OK;
534  }
535 
536  /* Set timeout, enable/disable timeout */
538  i,
539  MC33775_SYS_COM_TO_CFG_OFFSET,
540  (N775_TIMEOUT_SWITCH << MC33775_SYS_COM_TO_CFG_COMTODISABLE_POS) |
541  (N775_TIMEOUT_TO_SLEEP_10MS << MC33775_SYS_COM_TO_CFG_COMTO_POS),
542  n775_state->pSpiTxSequence);
543 
544  /* read uid of each device */
545  returnedValue = N775_CommunicationReadMultiple(i, 3u, 3u, MC33775_SYS_UID_LOW_OFFSET, uid, n775_state);
546  if (returnedValue == N775_COMMUNICATION_OK) {
547  n775_state->n775Data.uid[n775_state->currentString][i - 1u] = 0u;
548  for (uint8_t j = 0u; j <= 3u; j++) {
549  n775_state->n775Data.uid[n775_state->currentString][i - 1u] |= ((uint64_t)uid[j]) << (16u * j);
550  }
551  }
552  }
553 
554  return retVal;
555 }
556 
557 /**
558  * @brief init I2C for the N775 slaves.
559  *
560  * This function makes slaves ready for I2C transactions with on-slave devices.
561  *
562  * @param n775_state state of the N775A driver
563  *
564  */
565 static void N775_I2cInit(N775_STATE_s *n775_state) {
566  FAS_ASSERT(n775_state != NULL_PTR);
567 
568  /* Enable the I2C module and select 400 kHz */
571  MC33775_I2C_CFG_OFFSET,
572  (MC33775_I2C_CFG_EN_ENABLED_ENUM_VAL << MC33775_I2C_CFG_EN_POS) +
573  (MC33775_I2C_CFG_CLKSEL_F_400K_ENUM_VAL << MC33775_I2C_CFG_CLKSEL_POS),
574  n775_state->pSpiTxSequence);
575 }
576 
577 /**
578  * @brief starts the measurement.
579  *
580  * The MC33775A measures continuously. This function
581  * starts the measurement.
582  *
583  * @param n775_state state of the N775A driver
584  *
585  */
586 static void N775_StartMeasurement(N775_STATE_s *n775_state) {
587  FAS_ASSERT(n775_state != NULL_PTR);
588 
589  /* Enable cell voltage measurements */
590  N775_CommunicationWrite(N775_BROADCAST_ADDRESS, MC33775_ALLM_VCVB_CFG_OFFSET, 0x3FFF, n775_state->pSpiTxSequence);
591  /* Enable analog inputs 0-3 and module voltage measurement */
592  N775_CommunicationWrite(N775_BROADCAST_ADDRESS, MC33775_PRMM_AIN_CFG_OFFSET, 0x1F, n775_state->pSpiTxSequence);
593  /* Enable analog inputs 4-7 measurement */
594  N775_CommunicationWrite(N775_BROADCAST_ADDRESS, MC33775_SECM_AIN_CFG_OFFSET, 0x0F, n775_state->pSpiTxSequence);
595  /* Set pause of balancing before measurement start, enable the measurement units simultaneously */
598  MC33775_ALLM_CFG_OFFSET,
599  (N775_BALPAUSELEN_10US << MC33775_ALLM_CFG_BALPAUSELEN_POS) | (1 << MC33775_ALLM_CFG_MEASEN_POS),
600  n775_state->pSpiTxSequence);
601 
603 }
604 
605 /**
606  * @brief captures the measurement.
607  *
608  * The MC33775A measures continuously.
609  * This function takes a snapshot on all slaves in the daisy-chain.
610  *
611  * @param n775_state state of the N775A driver
612  *
613  */
614 static void N775_CaptureMeasurement(N775_STATE_s *n775_state) {
615  FAS_ASSERT(n775_state != NULL_PTR);
616 
617  uint16_t primaryRawValues[20] = {0u};
618  uint16_t secondaryRawValues[4] = {0u};
619  uint16_t currentRawValue = 0u;
620  int16_t primaryValues[20] = {0u};
621  int16_t secondaryValues[4] = {0u};
622  int16_t currentValue = 0u;
626  uint16_t error = 0u;
627  bool gpio03Error = false;
628  bool gpio47Error = false;
629 
630  /* Send capture command. This ends the last cycle and starts a new one */
633  MC33775_ALLM_APP_CTRL_OFFSET,
634  (1u << MC33775_ALLM_APP_CTRL_PAUSEBAL_POS) | (0x3FFu << MC33775_PRMM_APP_CTRL_CAPVC_POS) |
635  (MC33775_PRMM_APP_CTRL_VCOLNUM_DISABLED_ENUM_VAL << MC33775_PRMM_APP_CTRL_VCOLNUM_POS),
636  n775_state->pSpiTxSequence);
637  /* Wait for measurements to take place */
639  /* Send capture command. This ends the last cycle and starts a new one */
642  MC33775_ALLM_APP_CTRL_OFFSET,
643  (0u << MC33775_ALLM_APP_CTRL_PAUSEBAL_POS) | (0x3FFu << MC33775_PRMM_APP_CTRL_CAPVC_POS) |
644  (MC33775_PRMM_APP_CTRL_VCOLNUM_DISABLED_ENUM_VAL << MC33775_PRMM_APP_CTRL_VCOLNUM_POS),
645  n775_state->pSpiTxSequence);
646  /* Wait for measurements to be ready */
648 
649  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
650  uint8_t deviceAddress = m + 1u;
651  retValPrimary = N775_CommunicationReadMultiple(
652  deviceAddress, 20, 4u, MC33775_PRMM_APP_VC_CNT_OFFSET, primaryRawValues, n775_state);
653  retValSecondary = N775_CommunicationReadMultiple(
654  deviceAddress, 4, 4u, MC33775_SECM_APP_AIN4_OFFSET, secondaryRawValues, n775_state);
655  if (N775_CHECK_SUPPLY_CURRENT == true) {
656  retValSupplyCurrent =
657  N775_CommunicationRead(deviceAddress, MC33775_SECM_PER_NPNISENSE_OFFSET, &currentRawValue, n775_state);
658  }
659 
660  N775_ErrorHandling(n775_state, retValPrimary, m);
661  if (retValPrimary == N775_COMMUNICATION_OK) {
662  for (uint8_t c = 0u; c < BS_NR_OF_CELL_BLOCKS_PER_MODULE; c++) {
663  /* Store cell voltages */
664  if (N775_INVALID_REGISTER_VALUE != primaryRawValues[c + 1u]) {
665  primaryValues[c + 1u] = (int16_t)primaryRawValues[c + 1u];
666  n775_state->n775Data.cellVoltage
668  (((float_t)primaryValues[c + 1u]) * 154.0e-6f * 1000.0f);
669  } else {
670  error++;
671  }
672  }
673  for (uint8_t g = 0u; g < 4u; g++) {
674  /* Store GPIO voltages */
675  if (N775_INVALID_REGISTER_VALUE != primaryRawValues[g + 16u]) {
676  primaryValues[g + 16u] = (int16_t)primaryRawValues[g + 16u];
677  n775_state->n775Data.allGpioVoltage
678  ->gpioVoltages_mV[n775_state->currentString][g + (m * BS_NR_OF_GPIOS_PER_MODULE)] =
679  (((float_t)primaryValues[g + 16u]) * 154.0e-6f * 1000.0f);
680  } else {
681  gpio03Error = true;
682  error++;
683  }
684  }
685  /* Store module voltage */
686  if (N775_INVALID_REGISTER_VALUE != primaryRawValues[15u]) {
687  primaryValues[15u] = (int16_t)primaryRawValues[15u];
688  n775_state->n775Data.cellVoltage->moduleVoltage_mV[n775_state->currentString][m] =
689  (((float_t)primaryValues[15u]) * 2.58e-3f * 1000.0f);
690  } else {
691  error++;
692  }
693  }
694 
695  N775_ErrorHandling(n775_state, retValSecondary, m);
696  if (retValSecondary == N775_COMMUNICATION_OK) {
697  for (uint8_t g = 4u; g < 8u; g++) {
698  if (N775_INVALID_REGISTER_VALUE != secondaryRawValues[g - 4u]) {
699  secondaryValues[g - 4u] = (int16_t)secondaryRawValues[g - 4u];
700  n775_state->n775Data.allGpioVoltage
701  ->gpioVoltages_mV[n775_state->currentString][g + (m * BS_NR_OF_GPIOS_PER_MODULE)] =
702  (((float_t)secondaryValues[g - 4u]) * 154.0e-6f * 1000.0f);
703  } else {
704  gpio47Error = true;
705  error++;
706  }
707  }
708  }
709 
710  /* Set temperature values */
711  if (N775_USE_MUX_FOR_TEMP == true) {
712  /* Mux case */
713  if (gpio03Error == false) {
714  n775_state->n775Data.cellTemperature
715  ->cellTemperature_ddegC[n775_state->currentString]
716  [n775_state->currentMux[n775_state->currentString] +
719  n775_state->n775Data.allGpioVoltage
720  ->gpioVoltages_mV[n775_state->currentString]
722  }
723  } else if (N775_USE_MUX_FOR_TEMP == false) {
724  /* No mux case */
725  if ((gpio03Error == false) && (gpio47Error == false)) {
726  for (uint16_t t = 0u; t < BS_NR_OF_TEMP_SENSORS_PER_MODULE; t++) {
727  n775_state->n775Data.cellTemperature
730  n775_state->n775Data.allGpioVoltage
731  ->gpioVoltages_mV[n775_state->currentString][t + (m * BS_NR_OF_GPIOS_PER_MODULE)]);
732  }
733  }
734  } else {
735  /* Invalid value for switch case */
737  }
738 
739  if (N775_CHECK_SUPPLY_CURRENT == true) {
740  N775_ErrorHandling(n775_state, retValSupplyCurrent, m);
741  if (retValSupplyCurrent == N775_COMMUNICATION_OK) {
742  if (N775_INVALID_REGISTER_VALUE != currentRawValue) {
743  currentValue = (int16_t)currentRawValue;
744  n775_state->n775Data.supplyCurrent->current[n775_state->currentString][m] =
745  (((float_t)currentValue) * 7.69e-6f * 1000.0f);
746  } else {
747  error++;
748  }
749  }
750  }
751  }
752 
754  n775_state->n775Data.cellVoltage, n775_state->n775Data.cellTemperature, n775_state->n775Data.allGpioVoltage);
755 }
756 
757 /**
758  * @brief tranmit over I2C on NXP slave.
759  *
760  * @param n775_state state of the N775A driver
761  *
762  */
764  FAS_ASSERT(n775_state != NULL_PTR);
765  uint8_t i2cAddressByte = 0u;
766  uint16_t readValue = 0u;
767  uint16_t tries = 0u;
768  STD_RETURN_TYPE_e retVal = STD_OK;
770  AFE_I2C_QUEUE_s transactionData;
771 
772  if (ftsk_allQueuesCreated == true) {
773  if (OS_ReceiveFromQueue(ftsk_afeToI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
774  /* Queue was not empty */
775  i2cAddressByte = (transactionData.deviceAddress << 1u) & 0xFEu; /* I2C address has only 7 bits */
776  uint8_t nack = 0u;
777  uint8_t registerIncrement = 0u;
778  uint16_t registerStartAddress = 0u;
779  uint16_t dataToWrite = 0u;
780  uint8_t byteIndex = 0u;
781  uint8_t bytesWritten = 0u;
782  uint8_t msbIndex = 1u;
783  uint8_t lsbIndex = 1u;
784 
785  switch (transactionData.transferType) {
787  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_WRITE_FAIL;
788  /* First prepare data to send on I2C bus in registers */
789  i2cAddressByte |= N775_I2C_WRITE;
790  /* Set I2C device address for write access followed by first byte of data */
792  transactionData.module + 1u,
793  MC33775_I2C_DATA0_OFFSET,
794  (i2cAddressByte << MC33775_I2C_DATA0_BYTE0_POS) |
795  (transactionData.writeData[0u] << MC33775_I2C_DATA0_BYTE1_POS),
796  n775_state->pSpiTxSequence);
797 
798  if (transactionData.writeDataLength > 1u) {
799  /* Now set data to be written to I2C device */
800  registerStartAddress = MC33775_I2C_DATA1_OFFSET;
801  registerIncrement = 0u;
802  byteIndex = 1u;
803  dataToWrite = 0u;
804  while (byteIndex < transactionData.writeDataLength) {
805  /* Each subsequent data register contains two bytes of read data */
806 
807  if ((byteIndex % 2u) != 0u) {
808  dataToWrite |= (uint16_t)(transactionData.writeData[byteIndex]) & 0xFFu;
809  bytesWritten++;
810  } else {
811  dataToWrite |= ((uint16_t)(transactionData.writeData[byteIndex]) << 8u) & 0xFF00u;
812  bytesWritten++;
813  }
814  byteIndex++;
815  if ((bytesWritten == 2u) || (byteIndex == transactionData.writeDataLength)) {
817  transactionData.module + 1u,
818  registerStartAddress + registerIncrement,
819  dataToWrite,
820  n775_state->pSpiTxSequence);
821  registerIncrement++;
822  bytesWritten = 0u;
823  dataToWrite = 0u;
824  }
825  }
826  }
827  /* Data to write ready, now start transmisison */
828  /* Write into the control register to start transaction */
830  transactionData.module + 1u,
831  MC33775_I2C_CTRL_OFFSET,
832  /* transactionData.writeDataLength + 1u: data + I2C device address byte */
833  ((transactionData.writeDataLength + 1u) << MC33775_I2C_CTRL_START_POS) |
834  ((MC33775_I2C_CTRL_STPAFTER_STOP_ENUM_VAL << MC33775_I2C_CTRL_STPAFTER_POS) +
835  (0u << MC33775_I2C_CTRL_RDAFTER_POS)),
836  n775_state->pSpiTxSequence);
837  /* Wait until transaction ends */
838  tries = N775_FLAG_READY_TRIES;
839  do {
840  returnedValue = N775_CommunicationRead(
841  transactionData.module + 1u, MC33775_I2C_STAT_OFFSET, &readValue, n775_state);
842  tries--;
843  N775_waitTime(2u);
844  } while ((readValue & MC33775_I2C_STAT_PENDING_MSK) && (returnedValue == N775_COMMUNICATION_OK) &&
845  (tries > 0u));
846 
847  if ((returnedValue == N775_COMMUNICATION_OK) && (tries > 0u)) {
848  retVal = STD_OK;
849  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_WRITE_SUCCESS;
850  }
851  if (OS_SendToBackOfQueue(ftsk_afeFromI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
852  /* Queue is not full */
853  } else {
854  /* Queue is full */
855  retVal = STD_NOT_OK;
856  }
857  break;
858 
860  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_READ_FAIL;
861  i2cAddressByte |= N775_I2C_READ;
862  /* First prepare address to send on I2C bus in registers */
864  transactionData.module + 1u,
865  MC33775_I2C_DATA0_OFFSET,
866  i2cAddressByte << MC33775_I2C_DATA0_BYTE0_POS,
867  n775_state->pSpiTxSequence);
868  /* Write into the control register to start transaction */
869  /* Stop condition after transfer, no repeated start */
871  transactionData.module + 1u,
872  MC33775_I2C_CTRL_OFFSET,
873  /* transactionData.dataLength + 1u: data + I2C device address byte */
874  ((transactionData.readDataLength + 1u) << MC33775_I2C_CTRL_START_POS) |
875  ((1u << MC33775_I2C_CTRL_STPAFTER_POS) + (0u << MC33775_I2C_CTRL_RDAFTER_POS)),
876  n775_state->pSpiTxSequence);
877  /* Wait until transaction ends */
878  tries = N775_FLAG_READY_TRIES;
879  do {
880  returnedValue = N775_CommunicationRead(
881  transactionData.module + 1u, MC33775_I2C_STAT_OFFSET, &readValue, n775_state);
882  tries--;
883  N775_waitTime(2u);
884  } while ((readValue & MC33775_I2C_STAT_PENDING_MSK) && (returnedValue == N775_COMMUNICATION_OK) &&
885  (tries > 0u));
886  /* Now retrieve read data */
887  nack = readValue & MC33775_I2C_STAT_NACKRCV_MSK;
888  if ((returnedValue == N775_COMMUNICATION_OK) && (tries > 0u) && (nack == 0u)) {
889  uint16_t readData[13u] = {0u};
890  /* In data registers, bytes0 contains the address, read data begins at byte1 */
891  /* First data register contains byte1, second data register byte2 and byte3, ... */
892  uint16_t nrOfRegisterToRead = (transactionData.readDataLength / 2u) + 1u;
893  returnedValue = N775_CommunicationReadMultiple(
894  transactionData.module + 1u,
895  nrOfRegisterToRead,
896  4u,
897  MC33775_I2C_DATA0_OFFSET,
898  readData,
899  n775_state);
900 
901  /* First data register only contains one byte of the read data */
902  transactionData.readData[0u] = (uint8_t)((readData[0u] & 0xFF00) >> 8u);
903  byteIndex = 1u;
904  msbIndex = 1u;
905  lsbIndex = 1u;
906  while (byteIndex < transactionData.readDataLength) {
907  /* Each subsequent data register contains two bytes of read data */
908  if ((byteIndex % 2u) != 0u) {
909  transactionData.readData[byteIndex] = (uint8_t)(readData[lsbIndex] & 0xFFu);
910  lsbIndex++;
911  } else {
912  transactionData.readData[byteIndex] = (uint8_t)((readData[msbIndex] & 0xFF00u) >> 8u);
913  msbIndex++;
914  }
915  byteIndex++;
916  }
917  retVal = STD_OK;
918  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_READ_SUCCESS;
919  }
920  if (OS_SendToBackOfQueue(ftsk_afeFromI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
921  /* Queue is not full */
922  } else {
923  /* Queue is full */
924  retVal = STD_NOT_OK;
925  }
926  break;
927 
929  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_READ_FAIL;
930  /* First prepare address to send on I2C bus in registers */
932  transactionData.module + 1u,
933  MC33775_I2C_DATA0_OFFSET,
934  ((i2cAddressByte | N775_I2C_WRITE) << MC33775_I2C_DATA0_BYTE0_POS) |
935  (transactionData.writeData[0u] << MC33775_I2C_DATA0_BYTE1_POS),
936  n775_state->pSpiTxSequence);
937 
938  if (transactionData.writeDataLength > 1u) {
939  /* Now set data to be written to I2C device */
940  registerStartAddress = MC33775_I2C_DATA1_OFFSET;
941  registerIncrement = 0u;
942  byteIndex = 1u;
943  dataToWrite = 0u;
944  transactionData.writeData[transactionData.writeDataLength] = i2cAddressByte | N775_I2C_READ;
945  while (byteIndex < (transactionData.writeDataLength + 1)) {
946  /* Each subsequent data register contains two bytes of read data */
947 
948  if ((byteIndex % 2u) != 0u) {
949  dataToWrite |= (uint16_t)(transactionData.writeData[byteIndex]) & 0xFFu;
950  bytesWritten++;
951  } else {
952  dataToWrite |= ((uint16_t)(transactionData.writeData[byteIndex]) << 8u) & 0xFF00u;
953  bytesWritten++;
954  }
955  byteIndex++;
956  if ((bytesWritten == 2u) || (byteIndex == (transactionData.writeDataLength + 1))) {
958  transactionData.module + 1u,
959  registerStartAddress + registerIncrement,
960  dataToWrite,
961  n775_state->pSpiTxSequence);
962  registerIncrement++;
963  bytesWritten = 0u;
964  dataToWrite = 0u;
965  }
966  }
967  } else {
969  transactionData.module + 1u,
970  MC33775_I2C_DATA1_OFFSET,
971  ((i2cAddressByte | N775_I2C_READ) << MC33775_I2C_DATA1_BYTE2_POS),
972  n775_state->pSpiTxSequence);
973  }
974 
975  /* Write into the control register to start transaction */
976  /* Stop condition after transfer, repeated start */
978  transactionData.module + 1u,
979  MC33775_I2C_CTRL_OFFSET,
980  /* transaction length: I2C device address byte for write + data to write
981  + I2C device address byte for read + data to read */
982  ((transactionData.writeDataLength + transactionData.readDataLength + 2u)
983  << MC33775_I2C_CTRL_START_POS) |
984  ((1u << MC33775_I2C_CTRL_STPAFTER_POS) +
985  ((1u + transactionData.writeDataLength) << MC33775_I2C_CTRL_RDAFTER_POS)),
986  n775_state->pSpiTxSequence);
987  /* Wait until transaction ends */
988  tries = N775_FLAG_READY_TRIES;
989  do {
990  returnedValue = N775_CommunicationRead(
991  transactionData.module + 1u, MC33775_I2C_STAT_OFFSET, &readValue, n775_state);
992  tries--;
993  N775_waitTime(2u);
994  } while ((readValue & MC33775_I2C_STAT_PENDING_MSK) && (returnedValue == N775_COMMUNICATION_OK) &&
995  (tries > 0u));
996  /* Now retrieve read data */
997  nack = readValue & MC33775_I2C_STAT_NACKRCV_MSK;
998  if ((returnedValue == N775_COMMUNICATION_OK) && (tries > 0u) && (nack == 0u)) {
999  uint16_t readData[13u] = {0u};
1000  /* First data to read is at least in this register */
1001  uint16_t registerOffset = MC33775_I2C_DATA0_OFFSET;
1002  /* Find offset of first register to read */
1003  registerOffset += (transactionData.writeDataLength + 2u) / 2u;
1004  /* In data registers, byte0 contains the device address, byte1 the first byte written */
1005  /* I2C device address byte for read is present before the first read byte */
1006  uint16_t nrOfRegisterToRead = 0u;
1007  if ((transactionData.writeDataLength % 2u) == 0u) {
1008  nrOfRegisterToRead = (transactionData.readDataLength + 1u) / 2u;
1009  } else {
1010  nrOfRegisterToRead = (transactionData.readDataLength / 2u) + 1u;
1011  }
1012 
1013  returnedValue = N775_CommunicationReadMultiple(
1014  transactionData.module + 1u, nrOfRegisterToRead, 4u, registerOffset, readData, n775_state);
1015 
1016  /* Second data register only contains one byte of the read data (byte3)
1017  Read data starts at second register because:
1018  byte0: I2C device address for write access
1019  byte1: first byte written
1020  I2C device address byte for read is present before the first read byte
1021  */
1022  if (((transactionData.writeDataLength + 1) % 2u) != 0u) {
1023  byteIndex = 0u;
1024  msbIndex = 0u;
1025  lsbIndex = 0u;
1026  while (byteIndex < transactionData.readDataLength) {
1027  /* Each subsequent data register contains two bytes of read data */
1028  if ((byteIndex % 2u) == 0u) {
1029  transactionData.readData[byteIndex] = (uint8_t)(readData[lsbIndex] & 0xFFu);
1030  lsbIndex++;
1031  } else {
1032  transactionData.readData[byteIndex] =
1033  (uint8_t)((readData[msbIndex] & 0xFF00u) >> 8u);
1034  msbIndex++;
1035  }
1036  byteIndex++;
1037  }
1038  } else {
1039  byteIndex = 0u;
1040  msbIndex = 0u;
1041  lsbIndex = 1u;
1042  while (byteIndex < transactionData.readDataLength) {
1043  /* Each subsequent data register contains two bytes of read data */
1044  if ((byteIndex % 2u) != 0u) {
1045  transactionData.readData[byteIndex] = (uint8_t)(readData[lsbIndex] & 0xFFu);
1046  lsbIndex++;
1047  } else {
1048  transactionData.readData[byteIndex] =
1049  (uint8_t)((readData[msbIndex] & 0xFF00u) >> 8u);
1050  msbIndex++;
1051  }
1052  byteIndex++;
1053  }
1054  }
1055  retVal = STD_OK;
1056  transactionData.transferType = AFE_I2C_TRANSFER_TYPE_READ_SUCCESS;
1057  }
1058  if (OS_SendToBackOfQueue(ftsk_afeFromI2cQueue, (void *)&transactionData, 0u) == OS_SUCCESS) {
1059  /* Queue is not full */
1060  } else {
1061  /* Queue is full */
1062  retVal = STD_NOT_OK;
1063  }
1064  break;
1065 
1066  default:
1067  /* Invalid value transfer type */
1069  break;
1070  }
1071  }
1072  }
1073 
1074  return retVal;
1075 }
1076 
1077 /**
1078  * @brief sets mux channel.
1079  *
1080  * This function uses I2C to set the mux channel.
1081  *
1082  * @param n775_state state of the N775A driver
1083  *
1084  */
1086  FAS_ASSERT(n775_state != NULL_PTR);
1087  FAS_ASSERT(n775_state->pMuxSequence[n775_state->currentString]->muxId < 4u);
1088  FAS_ASSERT(n775_state->pMuxSequence[n775_state->currentString]->muxChannel <= 0xFFu);
1089 
1090  uint16_t readValue = 0u;
1091  uint8_t dataI2c = 0u;
1092  uint8_t addressI2c_write = N775_ADG728_ADDRESS_UPPERBITS;
1093  uint8_t addressI2c_read = N775_ADG728_ADDRESS_UPPERBITS;
1094  uint16_t tries = 0u;
1095  STD_RETURN_TYPE_e retVAL = STD_OK;
1097 
1098  /* First set channel */
1099 
1100  /* Set bit1 and bit0 with mux address, write to mux */
1101  addressI2c_write |= ((n775_state->pMuxSequence[n775_state->currentString]->muxId) << 1u) | N775_I2C_WRITE;
1102  /* Set bit1 and bit0 with mux address, read from mux */
1103  addressI2c_read |= ((n775_state->pMuxSequence[n775_state->currentString]->muxId) << 1u) | N775_I2C_READ;
1104 
1105  /**
1106  * Set data to send, contains channel bit (8 channels)
1107  * 1 means channel active, 0 means channel inactive
1108  */
1109  if (n775_state->pMuxSequence[n775_state->currentString]->muxChannel == 0xFF) {
1110  /* 0xFF in mux sequence means disable all channels */
1111  dataI2c = 0u;
1112  } else {
1113  dataI2c = (uint8_t)(1u << (n775_state->pMuxSequence[n775_state->currentString]->muxChannel));
1114  }
1115 
1116  /* Write data to send on I2C bus in registers */
1119  MC33775_I2C_DATA0_OFFSET,
1120  (addressI2c_write << MC33775_I2C_DATA0_BYTE0_POS) | (dataI2c << MC33775_I2C_DATA0_BYTE1_POS),
1121  n775_state->pSpiTxSequence);
1122 
1123  /* Read with a repeated start directly after write */
1126  MC33775_I2C_DATA1_OFFSET,
1127  (addressI2c_read << MC33775_I2C_DATA1_BYTE2_POS) | (N775_I2C_DUMMY_BYTE << MC33775_I2C_DATA1_BYTE3_POS),
1128  n775_state->pSpiTxSequence);
1129 
1130  /* Write into the control register to start transaction */
1133  MC33775_I2C_CTRL_OFFSET,
1134  (N775_I2C_NR_BYTES_FOR_MUX_WRITE << MC33775_I2C_CTRL_START_POS) |
1135  ((MC33775_I2C_CTRL_STPAFTER_STOP_ENUM_VAL << MC33775_I2C_CTRL_STPAFTER_POS) +
1136  (N775_I2C_NR_BYTES_TO_SWITCH_TO_READ_FOR_UX_READ << MC33775_I2C_CTRL_RDAFTER_POS)),
1137  n775_state->pSpiTxSequence);
1138 
1139  /**
1140  * Wait util transaction ends, test on last device in daisy-chain
1141  * So device address = number of modules
1142  */
1143  tries = N775_FLAG_READY_TRIES;
1144  do {
1145  returnedValue =
1146  N775_CommunicationRead(BS_NR_OF_MODULES_PER_STRING, MC33775_I2C_STAT_OFFSET, &readValue, n775_state);
1147  tries--;
1148  N775_waitTime(2u);
1149  } while ((readValue & MC33775_I2C_STAT_PENDING_MSK) && (returnedValue == N775_COMMUNICATION_OK) && (tries > 0u));
1150 
1151  if ((returnedValue == N775_COMMUNICATION_OK) && (tries > 0u)) {
1152  /**
1153  * Get I2C read data, on last device in daisy-chain
1154  * Use result to set error state for all slaves to avoid
1155  * reading all slaves in daisy-chain.
1156  */
1157  returnedValue =
1158  N775_CommunicationRead(BS_NR_OF_MODULES_PER_STRING, MC33775_I2C_DATA1_OFFSET, &readValue, n775_state);
1159  readValue = readValue >> MC33775_I2C_DATA1_BYTE3_POS;
1160 
1161  if (returnedValue == N775_COMMUNICATION_OK) {
1162  if (N775_CHECK_MUX_STATE == true) {
1163  if (readValue == dataI2c) {
1164  /* OK */
1165  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
1166  n775_state->n775Data.errorTable->mux0IsOk[n775_state->currentString][m] = true;
1167  }
1168  } else {
1169  /* Not OK */
1170  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
1171  n775_state->n775Data.errorTable->mux0IsOk[n775_state->currentString][m] = false;
1172  }
1173  }
1174  } else {
1175  retVAL = STD_NOT_OK;
1176  }
1177  }
1178  } else {
1179  retVAL = STD_NOT_OK;
1180  }
1181 
1182  return retVAL;
1183 }
1184 
1185 /**
1186  * @brief setups balancing.
1187  *
1188  * Sets all balancing timer to max to allow for software balancing control.
1189  *
1190  * @param n775_state state of the N775A driver
1191  *
1192  */
1193 static void N775_BalanceSetup(N775_STATE_s *n775_state) {
1194  FAS_ASSERT(n775_state != NULL_PTR);
1195 
1196  /* Set global timeout counter to max value */
1199  MC33775_BAL_GLOB_TO_TMR_OFFSET,
1201  n775_state->pSpiTxSequence);
1202 
1203  /* Disable pre-balancing timer by setting it to zero */
1205  N775_BROADCAST_ADDRESS, MC33775_BAL_PRE_TMR_OFFSET, N775_PRE_BALANCING_TIMER, n775_state->pSpiTxSequence);
1206 
1207  /* Set PWM value for all channels to 100%, set balancing timer for all channels to maximum value */
1210  MC33775_BAL_TMR_CH_ALL_OFFSET,
1211  (MC33775_BAL_TMR_CH_ALL_PWM_PWM100_ENUM_VAL << MC33775_BAL_TMR_CH_ALL_PWM_POS) |
1212  (N775_ALL_CHANNEL_BALANCING_TIMER << MC33775_BAL_TMR_CH_ALL_BALTIME_POS),
1213  n775_state->pSpiTxSequence);
1214 
1215  /* Select timer based balancing and enable balancing */
1218  MC33775_BAL_GLOB_CFG_OFFSET,
1219  (MC33775_BAL_GLOB_CFG_BALEN_ENABLED_ENUM_VAL << MC33775_BAL_GLOB_CFG_BALEN_POS) |
1220  (MC33775_BAL_GLOB_CFG_TMRBALEN_STOP_ENUM_VAL << MC33775_BAL_GLOB_CFG_TMRBALEN_POS),
1221  n775_state->pSpiTxSequence);
1222 }
1223 
1224 /**
1225  * @brief manages balancing.
1226  *
1227  * Reads balancing order from database and balances the corresponding cells.
1228  *
1229  * @param n775_state state of the N775A driver
1230  *
1231  */
1232 static void N775_BalanceControl(N775_STATE_s *n775_state) {
1233  FAS_ASSERT(n775_state != NULL_PTR);
1234 
1235  N775_BalanceSetup(n775_state);
1236 
1238 
1239  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
1240  uint8_t deviceAddress = m + 1u;
1241  uint16_t balancingState = 0u;
1242  for (uint16_t c = 0u; c < BS_NR_OF_CELL_BLOCKS_PER_MODULE; c++) {
1243  if (n775_state->n775Data.balancingControl
1244  ->balancingState[n775_state->currentString][c + (m * BS_NR_OF_CELL_BLOCKS_PER_MODULE)] != 0u) {
1245  balancingState |= 1u << c;
1246  }
1247  }
1248  /* All channels active --> 14 bits set to 1 --> 0x3FFF */
1249  FAS_ASSERT(balancingState <= 0x3FFFu);
1250  /* Enable channels, one written to a channels means balancing active */
1251  N775_CommunicationWrite(deviceAddress, MC33775_BAL_CH_CFG_OFFSET, balancingState, n775_state->pSpiTxSequence);
1252  }
1253 }
1254 
1256  FAS_ASSERT(n775_state != NULL_PTR);
1257  bool retval = false;
1258 
1260  retval = n775_state->firstMeasurementMade;
1262 
1263  return retval;
1264 }
1265 
1266 /**
1267  * @brief sets the measurement initialization status.
1268  *
1269  * @param n775_state state of the N775A driver
1270  *
1271  */
1273  FAS_ASSERT(n775_state != NULL_PTR);
1274 
1276  n775_state->firstMeasurementMade = true;
1278 }
1279 
1282 }
1283 
1284 /**
1285  * @brief waits for a definite amount of time in ms.
1286  *
1287  * This function uses FreeRTOS. It blocks the tasks for
1288  * the given amount of milliseconds.
1289  *
1290  * @param milliseconds time to wait in ms
1291  *
1292  */
1293 void N775_waitTime(uint32_t milliseconds) {
1294  uint32_t current_time = OS_GetTickCount();
1295  /* Block task without possibility to wake up */
1296  OS_DelayTaskUntil(&current_time, milliseconds);
1297 }
1298 
1299 /*========== Externalized Static Function Implementations (Unit Test) =======*/
1300 #ifdef UNITY_UNIT_TEST
1301 #endif
AFE driver header.
@ AFE_I2C_TRANSFER_TYPE_WRITE
Definition: afe.h:82
@ AFE_I2C_TRANSFER_TYPE_WRITEREAD
Definition: afe.h:79
@ AFE_I2C_TRANSFER_TYPE_READ_SUCCESS
Definition: afe.h:80
@ AFE_I2C_TRANSFER_TYPE_WRITE_FAIL
Definition: afe.h:84
@ AFE_I2C_TRANSFER_TYPE_READ
Definition: afe.h:78
@ AFE_I2C_TRANSFER_TYPE_WRITE_SUCCESS
Definition: afe.h:83
@ AFE_I2C_TRANSFER_TYPE_READ_FAIL
Definition: afe.h:81
Headers for the driver for the general DMA module of monitoring ICs.
#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
#define BS_NR_OF_TEMP_SENSORS_PER_STRING
Database module header.
#define DATA_READ_DATA(...)
Definition: database.h:86
#define DATA_WRITE_DATA(...)
Definition: database.h:96
@ DATA_BLOCK_ID_BALANCING_CONTROL
Definition: database_cfg.h:83
@ DATA_BLOCK_ID_MIN_MAX
Definition: database_cfg.h:81
@ DATA_BLOCK_ID_CELL_TEMPERATURE_BASE
Definition: database_cfg.h:101
@ DATA_BLOCK_ID_OPEN_WIRE_BASE
Definition: database_cfg.h:87
@ DATA_BLOCK_ID_SLAVE_CONTROL
Definition: database_cfg.h:84
@ DATA_BLOCK_ID_CELL_VOLTAGE_BASE
Definition: database_cfg.h:100
@ DATA_BLOCK_ID_ALL_GPIO_VOLTAGES_BASE
Definition: database_cfg.h:88
@ DATA_BLOCK_ID_BALANCING_FEEDBACK_BASE
Definition: database_cfg.h:85
Diagnosis driver header.
Assert macro implementation.
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:254
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:129
Definition of foxBMS standard types.
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 of task driver implementation.
OS_QUEUE ftsk_afeFromI2cQueue
volatile bool ftsk_allQueuesCreated
OS_QUEUE ftsk_afeToI2cQueue
Header for the driver for the IO module.
Headers for the driver for the MCU module.
N775_COMMUNICATION_STATUS_e N775_CommunicationReadMultiple(uint16_t deviceAddress, uint16_t numberOfItems, uint16_t responseLength, uint16_t registerAddress, uint16_t *pValues, N775_STATE_s *n775_state)
Read multiple values from specific registers in a specific device.
void N775_ResetMessageCounter(uint16_t deviceAddress, uint8_t string)
Reset the message counter for one or all devices.
void N775_CommunicationWrite(uint16_t deviceAddress, uint16_t registerAddress, uint16_t value, SPI_INTERFACE_CONFIG_s *pSpiInterface)
Write a value into a specific register in a specific device.
N775_COMMUNICATION_STATUS_e N775_CommunicationRead(uint16_t deviceAddress, uint16_t registerAddress, uint16_t *pValue, N775_STATE_s *n775_state)
Read a value from a specific register in a specific device.
enum N775_COMMUNICATION_STATUS N775_COMMUNICATION_STATUS_e
@ N775_COMMUNICATION_OK
@ N775_COMMUNICATION_ERROR_WRONG_CRC
@ N775_COMMUNICATION_ERROR_TIMEOUT
static STD_RETURN_TYPE_e N775_Enumerate(N775_STATE_s *n775_state)
enumerates the N775 slaves.
Definition: nxp_mc33775a.c:488
static DATA_BLOCK_SLAVE_CONTROL_s n775_slaveControl
Definition: nxp_mc33775a.c:96
STD_RETURN_TYPE_e N775_I2cWriteRead(uint8_t module, uint8_t deviceAddress, uint8_t *pDataWrite, uint8_t writeDataLength, uint8_t *pDataRead, uint8_t readDataLength)
trigger a read on the I2C bus of the slave, first write address of register to read.
Definition: nxp_mc33775a.c:295
void TEST_N775_SetFirstMeasurementCycleFinished(N775_STATE_s *n775_state)
static N775_ERRORTABLE_s n775_errorTable
Definition: nxp_mc33775a.c:100
static void N775_Init(N775_STATE_s *n775_state)
initializes the N775 driver.
Definition: nxp_mc33775a.c:466
static void N775_I2cInit(N775_STATE_s *n775_state)
init I2C for the N775 slaves.
Definition: nxp_mc33775a.c:565
void N775_Meas(N775_STATE_s *n775_state)
trigger function for the N775 driver state machine.
Definition: nxp_mc33775a.c:209
N775_STATE_s n775_stateBase
Definition: nxp_mc33775a.c:104
static DATA_BLOCK_ALL_GPIO_VOLTAGES_s n775_allGpioVoltage
Definition: nxp_mc33775a.c:93
static DATA_BLOCK_MIN_MAX_s n775_minMax
Definition: nxp_mc33775a.c:91
static DATA_BLOCK_CELL_TEMPERATURE_s n775_cellTemperature
Definition: nxp_mc33775a.c:90
static STD_RETURN_TYPE_e N775_SetMuxChannel(N775_STATE_s *n775_state)
sets mux channel.
static void N775_StartMeasurement(N775_STATE_s *n775_state)
starts the measurement.
Definition: nxp_mc33775a.c:586
static void N775_SetFirstMeasurementCycleFinished(N775_STATE_s *n775_state)
sets the measurement initialization status.
static DATA_BLOCK_CELL_VOLTAGE_s n775_cellVoltage
Definition: nxp_mc33775a.c:89
static void N775_IncrementMuxIndex(N775_STATE_s *n775_state)
updates index in mux sequence.
Definition: nxp_mc33775a.c:413
static void N775_BalanceSetup(N775_STATE_s *n775_state)
setups balancing.
static STD_RETURN_TYPE_e N775_TransmitI2c(N775_STATE_s *n775_state)
tranmit over I2C on NXP slave.
Definition: nxp_mc33775a.c:763
static DATA_BLOCK_BALANCING_CONTROL_s n775_balancingControl
Definition: nxp_mc33775a.c:92
static DATA_BLOCK_OPEN_WIRE_s n775_openWire
Definition: nxp_mc33775a.c:97
static void N775_ResetMuxIndex(N775_STATE_s *n775_state)
resets index in mux sequence.
Definition: nxp_mc33775a.c:400
static N775_SUPPLY_CURRENT_s n775_supplyCurrent
Definition: nxp_mc33775a.c:99
static void N775_BalanceControl(N775_STATE_s *n775_state)
manages balancing.
STD_RETURN_TYPE_e N775_I2cRead(uint8_t module, uint8_t deviceAddress, uint8_t *pData, uint8_t dataLength)
trigger a read on the I2C bus of the slave.
Definition: nxp_mc33775a.c:337
static void N775_InitializeDatabase(N775_STATE_s *n775_state)
in the database, initializes the fields related to the N775 driver.
Definition: nxp_mc33775a.c:159
static void N775_ErrorHandling(N775_STATE_s *n775_state, N775_COMMUNICATION_STATUS_e returnedValue, uint8_t module)
handles error when doing measurements.
Definition: nxp_mc33775a.c:435
STD_RETURN_TYPE_e N775_I2cWrite(uint8_t module, uint8_t deviceAddress, uint8_t *pData, uint8_t dataLength)
trigger a write on the I2C bus of the slave.
Definition: nxp_mc33775a.c:266
static void N775_ResetStringSequence(N775_STATE_s *n775_state)
reset index in string sequence.
Definition: nxp_mc33775a.c:372
static void N775_IncrementStringSequence(N775_STATE_s *n775_state)
updates index in string sequence.
Definition: nxp_mc33775a.c:386
static DATA_BLOCK_BALANCING_FEEDBACK_s n775_balancingFeedback
Definition: nxp_mc33775a.c:94
static void N775_waitTime(uint32_t milliseconds)
waits for a definite amount of time in ms.
static void N775_CaptureMeasurement(N775_STATE_s *n775_state)
captures the measurement.
Definition: nxp_mc33775a.c:614
bool N775_IsFirstMeasurementCycleFinished(N775_STATE_s *n775_state)
gets the measurement initialization status.
Headers for the driver for the MC33775A analog front-end.
N775_MUX_CH_CFG_s n775_muxSequence[N775_MUX_SEQUENCE_LENGTH]
int16_t N775_ConvertVoltagesToTemperatures(uint16_t adcVoltage_mV)
converts a raw voltage from multiplexer to a temperature value in deci °C.
#define N775_I2C_NR_BYTES_FOR_MUX_WRITE
#define N775_I2C_NR_BYTES_TO_SWITCH_TO_READ_FOR_UX_READ
#define N775_MEASUREMENT_CAPTURE_TIME_MS
#define N775_INVALID_REGISTER_VALUE
#define N775_I2C_DUMMY_BYTE
#define N775_CHECK_SUPPLY_CURRENT
#define N775_TIMEOUT_SWITCH
#define N775_TIMEOUT_TO_SLEEP_10MS
#define N775_CHECK_MUX_STATE
#define N775_DEFAULT_CHAIN_ADDRESS
#define N775_I2C_READ
#define N775_MUXED_TEMP_GPIO_POSITION
#define N775_MEASUREMENT_READY_TIME_MS
#define N775_MUX_SEQUENCE_LENGTH
#define N775_I2C_WRITE
#define N775_I2C_FINISHED_TIMEOUT_ms
#define N775_ADG728_ADDRESS_UPPERBITS
#define N775_BROADCAST_ADDRESS
#define N775_USE_MUX_FOR_TEMP
#define N775_PRE_BALANCING_TIMER
#define N775_BALPAUSELEN_10US
#define N775_GLOBAL_BALANCING_TIMER
#define N775_WAKEUP_TIME_MS
#define N775_TIME_AFTER_MEASUREMENT_START_MS
#define N775_ALL_CHANNEL_BALANCING_TIMER
#define N775_FLAG_READY_TRIES
Declaration of the OS wrapper interface.
@ OS_SUCCESS
Definition: os.h:83
OS_STD_RETURN_e OS_ReceiveFromQueue(OS_QUEUE xQueue, void *const pvBuffer, uint32_t ticksToWait)
Receive an item from a queue.
Definition: os_freertos.c:248
void OS_DelayTaskUntil(uint32_t *pPreviousWakeTime, uint32_t milliseconds)
Delay a task until a specified time.
Definition: os_freertos.c:146
void OS_ExitTaskCritical(void)
Exit Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:138
void OS_EnterTaskCritical(void)
Enter Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:134
OS_STD_RETURN_e OS_SendToBackOfQueue(OS_QUEUE xQueue, const void *const pvItemToQueue, uint32_t ticksToWait)
Post an item to the back the provided queue.
Definition: os_freertos.c:261
uint32_t OS_GetTickCount(void)
Returns OS based system tick value.
Definition: os_freertos.c:142
Headers for the driver for the SPI module.
SPI_INTERFACE_CONFIG_s spi_nxp775InterfaceTx[BS_NR_OF_STRINGS]
Definition: spi_cfg.c:191
SPI_INTERFACE_CONFIG_s spi_nxp775InterfaceRx[BS_NR_OF_STRINGS]
Definition: spi_cfg.c:202
uint8_t module
Definition: afe.h:89
uint8_t writeData[13u]
Definition: afe.h:95
AFE_I2C_TRANSFER_TYPE_e transferType
Definition: afe.h:90
uint8_t deviceAddress
Definition: afe.h:91
uint8_t readDataLength
Definition: afe.h:94
uint8_t writeDataLength
Definition: afe.h:96
int16_t gpioVoltages_mV[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *BS_NR_OF_GPIOS_PER_MODULE]
Definition: database_cfg.h:320
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:318
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:250
uint8_t balancingState[BS_NR_OF_STRINGS][BS_NR_OF_CELL_BLOCKS_PER_STRING]
Definition: database_cfg.h:255
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:285
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:149
int16_t cellTemperature_ddegC[BS_NR_OF_STRINGS][BS_NR_OF_TEMP_SENSORS_PER_STRING]
Definition: database_cfg.h:151
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:132
uint32_t moduleVoltage_mV[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
Definition: database_cfg.h:140
int16_t cellVoltage_mV[BS_NR_OF_STRINGS][BS_NR_OF_CELL_BLOCKS_PER_STRING]
Definition: database_cfg.h:135
DATA_BLOCK_ID_e uniqueId
Definition: database_cfg.h:122
int16_t minimumTemperature_ddegC[BS_NR_OF_STRINGS]
Definition: database_cfg.h:175
uint16_t nrSensorMinimumTemperature[BS_NR_OF_STRINGS]
Definition: database_cfg.h:177
uint16_t nrModuleMinimumTemperature[BS_NR_OF_STRINGS]
Definition: database_cfg.h:176
uint16_t nrModuleMaximumTemperature[BS_NR_OF_STRINGS]
Definition: database_cfg.h:179
int16_t maximumTemperature_ddegC[BS_NR_OF_STRINGS]
Definition: database_cfg.h:178
uint16_t nrSensorMaximumTemperature[BS_NR_OF_STRINGS]
Definition: database_cfg.h:180
uint16_t nrCellMaximumCellVoltage[BS_NR_OF_STRINGS]
Definition: database_cfg.h:172
uint16_t nrCellMinimumCellVoltage[BS_NR_OF_STRINGS]
Definition: database_cfg.h:170
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:162
uint16_t nrModuleMinimumCellVoltage[BS_NR_OF_STRINGS]
Definition: database_cfg.h:169
uint16_t nrModuleMaximumCellVoltage[BS_NR_OF_STRINGS]
Definition: database_cfg.h:171
int16_t maximumCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:167
int16_t minimumCellVoltage_mV[BS_NR_OF_STRINGS]
Definition: database_cfg.h:165
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:305
DATA_BLOCK_HEADER_s header
Definition: database_cfg.h:266
N775_ERRORTABLE_s * errorTable
DATA_BLOCK_BALANCING_CONTROL_s * balancingControl
uint64_t uid[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
DATA_BLOCK_CELL_TEMPERATURE_s * cellTemperature
DATA_BLOCK_ALL_GPIO_VOLTAGES_s * allGpioVoltage
N775_SUPPLY_CURRENT_s * supplyCurrent
DATA_BLOCK_MIN_MAX_s * minMax
DATA_BLOCK_CELL_VOLTAGE_s * cellVoltage
bool mux3IsOK[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
bool communicationOk[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
bool noCommunicationTimeout[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
bool mux2IsOK[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
bool mux0IsOk[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
bool mux1IsOK[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
bool crcIsValid[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]
SPI_INTERFACE_CONFIG_s * pSpiRxSequenceStart
SPI_INTERFACE_CONFIG_s * pSpiTxSequenceStart
N775_MUX_CH_CFG_s * pMuxSequence[BS_NR_OF_STRINGS]
SPI_INTERFACE_CONFIG_s * pSpiTxSequence
SPI_INTERFACE_CONFIG_s * pSpiRxSequence
N775_DATAPTR_s n775Data
uint8_t currentMux[BS_NR_OF_STRINGS]
N775_MUX_CH_CFG_s * pMuxSequenceStart[BS_NR_OF_STRINGS]
uint16_t current[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING]