foxBMS  1.6.0
The foxBMS Battery Management System API Documentation
adi_ades183x_helpers.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 adi_ades183x_helpers.c
44  * @author foxBMS Team
45  * @date 2022-12-06 (date of creation)
46  * @updated 2023-10-12 (date of last update)
47  * @version v1.6.0
48  * @ingroup DRIVERS
49  * @prefix ADI
50  *
51  * @brief Helper functionalities specific to the driver for the ADI ades183x
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 /* clang-format off */
57 #include "adi_ades183x.h"
58 /* clang-format on */
59 
60 #include "adi_ades183x_helpers.h"
61 
62 #include "adi_ades183x_buffers.h"
63 #include "adi_ades183x_commands.h"
64 #include "adi_ades183x_pec.h"
65 
66 #include <stdbool.h>
67 #include <stdint.h>
68 
69 /*========== Macros and Definitions =========================================*/
70 
71 /*========== Static Constant and Variable Definitions =======================*/
72 
73 /*========== Extern Constant and Variable Definitions =======================*/
74 
75 /*========== Static Function Prototypes =====================================*/
76 
77 /**
78  * @brief Increment command counter of AFE driver.
79  * @param adiState state of the driver
80  */
81 static void ADI_IncrementCommandCounter(ADI_STATE_s *adiState);
82 
83 /**
84  * @brief Writes data in the configuration stored in AFE driver,
85  * for a specific AFE.
86  * @details The driver stores the AFE configuration to write to the AFEs.
87  * This function sets the data for a specific register for a specific
88  * AFE in the daisy chain. The parameter registerSet selects one
89  * configuration register (A or B). Offset corresponds to one of the
90  * bytes in the selected register.
91  * @param module module number
92  * @param registerSet configuration register to address
93  * @param registerOffset position of byte to address in configuration register
94  * @param data data to write to byte in register
95  * @param position position where to store the data in byte
96  * @param mask mask corresponding to data to store
97  * @param adiState state of the driver
98  */
100  uint8_t module,
101  ADI_CFG_REGISTER_SET_e registerSet,
102  uint8_t registerOffset,
103  uint8_t data,
104  uint8_t position,
105  uint8_t mask,
106  ADI_STATE_s *adiState);
107 
108 /*========== Static Function Implementations ================================*/
110  uint8_t module,
111  ADI_CFG_REGISTER_SET_e registerSet,
112  uint8_t registerOffset,
113  uint8_t data,
114  uint8_t position,
115  uint8_t mask,
116  ADI_STATE_s *adiState) {
117  /* AXIVION Routine Generic-MissingParameterAssert: module: parameter accepts whole range */
118  /* AXIVION Routine Generic-MissingParameterAssert: data: parameter accepts whole range */
119  FAS_ASSERT(adiState != NULL_PTR);
120  FAS_ASSERT(registerSet <= ADI_CFG_REGISTER_SET_B);
121  /* Only 8 bit in a register part */
123  /* All 0s mask would mean do nothing */
124  FAS_ASSERT(mask > 0u);
125  FAS_ASSERT(registerOffset <= ADI_REGISTER_OFFSET5);
126 
127  if (registerSet == ADI_CFG_REGISTER_SET_A) {
129  &adi_configurationRegisterAgroup[adiState->currentString][(module * ADI_WRCFGA_LEN) + registerOffset],
130  data,
131  position,
132  mask);
133  } else if (registerSet == ADI_CFG_REGISTER_SET_B) {
135  &adi_configurationRegisterBgroup[adiState->currentString][(module * ADI_WRCFGB_LEN) + registerOffset],
136  data,
137  position,
138  mask);
139  } else { /* invalid register set */
140  FAS_ASSERT(FAS_TRAP); /* LCOV_EXCL_LINE */
141  }
142 }
143 
144 static void ADI_IncrementCommandCounter(ADI_STATE_s *adiState) {
145  FAS_ASSERT(adiState != NULL_PTR);
146 
147  /**
148  * SM_SPI_CNT: SPI Frame Counter
149  * Increment driver stored value of command counter if command causes increase.
150  */
151  for (uint16_t i = 0u; i < ADI_N_ADI; i++) {
152  if (adiState->data.commandCounter[adiState->currentString][i] < ADI_COMMAND_COUNTER_MAX_VALUE) {
153  adiState->data.commandCounter[adiState->currentString][i]++;
154  } else {
156  }
157  }
158 }
159 
160 /*========== Extern Function Implementations ================================*/
162  FAS_ASSERT(adiState != NULL_PTR);
163  FAS_ASSERT(registerSet <= ADI_CFG_REGISTER_SET_B);
164 
165  STD_RETURN_TYPE_e returnValue = STD_OK;
166  bool configurationAIsOk = true;
167  bool configurationBIsOk = true;
168 
169  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
170  /* Test configuration register A */
171  for (uint8_t byte = 0; byte < ADI_WRCFGA_LEN; byte++) {
172  if (adi_configurationRegisterAgroup[adiState->currentString][byte + (m * ADI_WRCFGA_LEN)] !=
174  configurationAIsOk = false;
175  returnValue = STD_NOT_OK;
176  break;
177  }
178  }
179  if (configurationAIsOk == false) {
180  adiState->data.errorTable->configurationAIsOk[adiState->currentString][m] = false;
181  } else {
182  adiState->data.errorTable->configurationAIsOk[adiState->currentString][m] = true;
183  }
184  configurationAIsOk = true;
185  /* Test configuration register B */
186  for (uint8_t byte = 0; byte < ADI_WRCFGA_LEN; byte++) {
187  if (adi_configurationRegisterBgroup[adiState->currentString][byte + (m * ADI_WRCFGB_LEN)] !=
189  configurationBIsOk = false;
190  returnValue = STD_NOT_OK;
191  break;
192  }
193  }
194  if (configurationBIsOk == false) {
195  adiState->data.errorTable->configurationBIsOk[adiState->currentString][m] = false;
196  } else {
197  adiState->data.errorTable->configurationBIsOk[adiState->currentString][m] = true;
198  }
199  configurationBIsOk = true;
200  }
201  return returnValue;
202 }
203 
205  uint16_t *configuredCommand,
206  uint8_t position,
207  uint8_t length,
208  uint16_t configuration) {
209  FAS_ASSERT(configuredCommand != NULL_PTR);
210  FAS_ASSERT(length > 0u);
212  FAS_ASSERT(position <= (ADI_COMMAND_CODE_LENGTH - 1u));
213  FAS_ASSERT(configuration <= (~(ADI_DATA_MASK_SEED << length)));
214 
215  uint16_t command = (((uint16_t)configuredCommand[ADI_COMMAND_FIRST_BYTE_POSITION]) << ADI_BYTE_SHIFT) |
216  configuredCommand[ADI_COMMAND_SECOND_BYTE_POSITION];
217  uint16_t mask = (~(ADI_COMMAND_MASK_SEED << length)) << position;
218  /* Set bits to modify to 0 */
219  command &= ~mask;
220  /* Now set bits, works if 0 or not */
221  command |= (configuration << position) & mask;
222  configuredCommand[ADI_COMMAND_FIRST_BYTE_POSITION] = (command >> ADI_BYTE_SHIFT) & ADI_ONE_BYTE_MASK;
223  configuredCommand[ADI_COMMAND_SECOND_BYTE_POSITION] = command & ADI_ONE_BYTE_MASK;
224 }
225 
227  FAS_ASSERT(adiState != NULL_PTR);
228  FAS_ASSERT(registerSet <= ADI_CFG_REGISTER_SET_B);
229  STD_RETURN_TYPE_e returnValueA = STD_OK;
230  STD_RETURN_TYPE_e returnValueB = STD_OK;
231  STD_RETURN_TYPE_e returnValue = STD_OK;
232 
233  if (registerSet == ADI_CFG_REGISTER_SET_A) {
238  adiState);
241  returnValueA = ADI_CheckConfigurationRegister(ADI_CFG_REGISTER_SET_A, adiState);
242  } else if (registerSet == ADI_CFG_REGISTER_SET_B) {
247  adiState);
250  returnValueB = ADI_CheckConfigurationRegister(ADI_CFG_REGISTER_SET_B, adiState);
251  } else { /* invalid register set */
252  FAS_ASSERT(FAS_TRAP); /* LCOV_EXCL_LINE */
253  }
254  if ((returnValueA == STD_NOT_OK) || (returnValueB == STD_NOT_OK)) {
255  returnValue = STD_NOT_OK;
256  }
257  return returnValue;
258 }
259 
260 extern void ADI_CopyCommandBits(const uint16_t *sourceCommand, uint16_t *destinationCommand) {
261  FAS_ASSERT(sourceCommand != NULL_PTR);
262  FAS_ASSERT(destinationCommand != NULL_PTR);
263  for (uint8_t i = 0u; i < ADI_COMMAND_DEFINITION_LENGTH; i++) {
264  destinationCommand[i] = sourceCommand[i];
265  }
266 }
267 
268 extern void ADI_ReadDataBits(uint8_t receivedData, uint8_t *pDataToRead, uint8_t position, uint8_t mask) {
269  /* AXIVION Routine Generic-MissingParameterAssert: receivedData: parameter accepts whole range */
270  FAS_ASSERT(pDataToRead != NULL_PTR);
271  /* Only 8 bit in a register part */
273  /* All 0s mask would mean do nothing */
274  FAS_ASSERT(mask > 0u);
275 
276  *pDataToRead = (receivedData & mask) >> position;
277 }
278 
279 /* RequirementId: D7.1 V0R4 FUN-0.0.01.01 */
280 /* RequirementId: D7.1 V0R4 SIF-4.10.01.01 */
281 /* RequirementId: D7.1 V0R4 SIF-4.10.02.01 */
282 /* RequirementId: D7.1 V0R4 SIF-4.10.11.02 */
283 /* RequirementId: D7.1 V0R4 SIF-4.10.12.01 */
284 extern void ADI_ReadRegister(uint16_t *registerToRead, uint8_t *data, ADI_STATE_s *adiState) {
285  FAS_ASSERT(registerToRead != NULL_PTR);
286  FAS_ASSERT(data != NULL_PTR);
287  FAS_ASSERT(adiState != NULL_PTR);
288 
289  uint8_t PEC_Check[ADI_SIZE_OF_DATA_FOR_PEC_COMPUTATION_WITH_COUNTER] = {0};
290  uint16_t PEC_result = 0u;
291  uint8_t PEC_RX[ADI_PEC_SIZE_IN_BYTES] = {0};
292  uint8_t afeCommandCounter = 0u;
293  uint16_t registerLengthInBytes = registerToRead[ADI_COMMAND_DATA_LENGTH_POSITION];
294  uint16_t byte = 0u; /* variable to parse data bytes */
295 
296  /* One frame = data + 2 bytes PEC */
297  /* + 2u: the two additional bytes corresponding to the PEC */
298  uint16_t spiFrameLength = registerLengthInBytes + ADI_PEC_SIZE_IN_BYTES;
299  uint16_t dataLength = registerLengthInBytes;
300 
301  for (uint16_t i = 0; i < ADI_N_BYTES_FOR_DATA_TRANSMISSION; i++) {
302  adiState->data.txBuffer[i] = 0x0;
303  }
304 
305  /**
306  * SM_SPI_PEC: SPI Packet Error Code
307  * Calculate PEC for command.
308  */
309  /* Compute PEC of the two command bytes */
310  PEC_Check[ADI_COMMAND_FIRST_BYTE_POSITION] = (uint8_t)registerToRead[ADI_COMMAND_FIRST_BYTE_POSITION];
311  PEC_Check[ADI_COMMAND_SECOND_BYTE_POSITION] = (uint8_t)registerToRead[ADI_COMMAND_SECOND_BYTE_POSITION];
312  PEC_result = ADI_Pec15(ADI_COMMAND_SIZE_IN_BYTES, PEC_Check);
313 
317  (uint8_t)((PEC_result >> ADI_BYTE_SHIFT) & ADI_ONE_BYTE_MASK);
318  adiState->data.txBuffer[ADI_COMMAND_PEC_SECOND_BYTE_POSITION] = (uint8_t)(PEC_result & ADI_ONE_BYTE_MASK);
319 
320  /* 4u: two bytes command + two bytes command PEC */
321  /* Register length + 2u: The two additional bytes correspond to the PEC */
322  uint16_t frameLength = ADI_COMMAND_AND_PEC_SIZE_IN_BYTES +
323  ((registerLengthInBytes + ADI_PEC_SIZE_IN_BYTES) * ADI_N_ADI);
324  ADI_SpiTransmitReceiveData(adiState, adiState->data.txBuffer, adiState->data.rxBuffer, (uint32_t)frameLength);
325 
326  for (uint16_t i = 0; i < ADI_N_ADI; i++) {
327  /* Put received messages in data buffer, used outside function to access data */
328  for (byte = 0u; byte < registerLengthInBytes; byte++) {
329  data[byte + (i * dataLength)] =
330  (uint8_t)(adiState->data.rxBuffer
331  [(ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + byte) + (i * spiFrameLength)]);
332  }
333  /* PEC_Check is a local variable holding read data and used to compute the PEC */
334  for (byte = 0u; byte < registerLengthInBytes; byte++) {
335  PEC_Check[byte] =
336  (uint8_t)(adiState->data.rxBuffer
337  [(ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + byte) + (i * spiFrameLength)]);
338  }
339  /* Data PEC is also computed on command counter, so one byte with command counter is added */
340  PEC_Check[byte] =
341  (uint8_t)(adiState->data.rxBuffer
342  [(ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + byte) + (i * spiFrameLength)]) &
344 
345  PEC_result =
346  ADI_Pec10((uint8_t)(registerToRead[ADI_COMMAND_DATA_LENGTH_POSITION] & ADI_ONE_BYTE_MASK), PEC_Check, true);
347  PEC_RX[ADI_DATA_PEC_FIRST_BYTE_POSITION] = (uint8_t)((PEC_result >> ADI_BYTE_SHIFT) & ADI_ONE_BYTE_MASK);
348  PEC_RX[ADI_DATA_PEC_SECOND_BYTE_POSITION] = (uint8_t)(PEC_result & ADI_ONE_BYTE_MASK);
349 
350  /* Position of the PEC (two bytes) in the first read frame */
351  /* 4u: two bytes command + two bytes command PEC, followed by number of bytes in register */
352  uint16_t crcByte0Position = registerLengthInBytes + ADI_COMMAND_AND_PEC_SIZE_IN_BYTES;
353  uint16_t crcByte1Position = registerLengthInBytes + ADI_COMMAND_AND_PEC_SIZE_IN_BYTES + 1u;
354 
355  /**
356  * SM_SPI_PEC: SPI Packet Error Code
357  * PEC check on read value.
358  */
359  /* if calculated PEC not equal to received PEC */
360  if ((PEC_RX[ADI_DATA_PEC_FIRST_BYTE_POSITION] !=
361  (adiState->data.rxBuffer[crcByte0Position + (i * spiFrameLength)] &
364  (adiState->data.rxBuffer[crcByte1Position + (i * spiFrameLength)] & ADI_ONE_BYTE_MASK))) {
365 /* update error table of the corresponding ades183x only if PEC check is activated */
366 #if (ADI_DISCARD_PEC == false)
367  adiState->data.errorTable->crcIsOk[adiState->currentString][i] = false;
368 #else
369  adiState->data.errorTable->crcIsOk[adiState->currentString][i] = true;
370 #endif
371  } else {
372  /* update error table of the corresponding ades183x */
373  adiState->data.errorTable->crcIsOk[adiState->currentString][i] = true;
374  }
375 
376  /* CRC is placed after the data bytes */
377  uint16_t crcFirstBytePosition = ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + registerLengthInBytes;
378  /**
379  * SM_SPI_CNT: SPI Frame Counter
380  * Compare driver stored value of command counter with values sent by the AFEs.
381  */
382  /* Retrieve command counter value sent by the AFE, included in first CRC byte of answer frame */
383  uint16_t commandCounterData = adiState->data.rxBuffer[crcFirstBytePosition + (i * spiFrameLength)] &
385  afeCommandCounter = (uint8_t)((commandCounterData >> ADI_COMMAND_COUNTER_POSITION) & ADI_ONE_BYTE_MASK);
386 
387  if (afeCommandCounter != adiState->data.commandCounter[adiState->currentString][i]) {
388  /**
389  * command counter flag stays set as soon as an error was detected
390  * it can only be reset within the reset function
391  */
392  adiState->data.errorTable->commandCounterIsOk[adiState->currentString][i] = false;
393  }
394  }
395 }
396 
397 /* RequirementId: D7.1 V0R4 FUN-0.0.01.04 */
399  ADI_STATE_s *adiState,
400  uint16_t *pTxBuff,
401  uint16_t *pRxBuff,
402  uint32_t frameLength) {
403  /* AXIVION Routine Generic-MissingParameterAssert: frameLength: parameter accepts whole range */
404  /* AXIVION Routine Generic-MissingParameterAssert: pRxBuff: parameter accepts whole range */
405  FAS_ASSERT(adiState != NULL_PTR);
406  FAS_ASSERT(pTxBuff != NULL_PTR);
407 
408  STD_RETURN_TYPE_e retValDummy = STD_OK;
409  STD_RETURN_TYPE_e retVal = STD_OK;
410  if (frameLength == 0u) {
411  /* Length = 0: only transmit dummy byte */
412  /* START SPI function to adapt for different environment */
413  /* No DMA, blocking */
414  retVal = SPI_TransmitDummyByte(&spi_adiInterface[adiState->currentString], 0u);
415  /* END SPI function to adapt for different environment */
416  } else {
417  if (pRxBuff == NULL_PTR) {
418  /* Transmit only (receive discarded) */
419  /* START SPI function to adapt for different environment */
420  /* No DMA, blocking */
421  retValDummy =
423  retVal = SPI_TransmitData(&spi_adiInterface[adiState->currentString], pTxBuff, frameLength);
424  /* END SPI function to adapt for different environment */
425  } else {
426  /* Transmit and receive */
427  /* START SPI function to adapt for different environment */
428  /* Uses DMA and notifications */
429  retValDummy =
431  retVal =
432  SPI_TransmitReceiveDataDma(&spi_adiInterface[adiState->currentString], pTxBuff, pRxBuff, frameLength);
433  /* Now wait for notification in DMA Rx finished interrupt */
434  uint32_t timeout = ADI_TRANSMISSION_TIMEOUT;
435  FAS_ASSERT(timeout > 0u);
436  uint32_t ulNotifiedValue = 0u;
437  /* Suspend task and wait for notification, clear notification value on entry and exit */
438  (void)OS_WaitForNotification(&ulNotifiedValue, timeout);
439  if (ulNotifiedValue != ADI_DMA_SPI_FINISHED_NOTIFICATION_VALUE) {
440  /* if ulNotifiedValue not written by xTaskNotify() in DMA interrupt: transmission timeout */
441  retVal = STD_NOT_OK;
442  }
443  /* END SPI function to adapt for different environment */
444  }
445  }
446 
447  if ((retVal == STD_NOT_OK) || (retValDummy == STD_NOT_OK)) {
448  adiState->data.errorTable->spiIsOk[adiState->currentString] = false;
449  } else if ((retVal == STD_OK) && (retValDummy == STD_OK)) {
450  adiState->data.errorTable->spiIsOk[adiState->currentString] = true;
451  } else {
452  FAS_ASSERT(FAS_TRAP); /* LCOV_EXCL_LINE */
453  }
454 }
455 
457  ADI_CFG_REGISTER_SET_e registerSet,
458  uint8_t registerOffset,
459  uint8_t data,
460  uint8_t position,
461  uint8_t mask,
462  ADI_STATE_s *adiState) {
463  /* AXIVION Routine Generic-MissingParameterAssert: data: parameter accepts whole range */
464  FAS_ASSERT(adiState != NULL_PTR);
465  FAS_ASSERT(registerSet <= ADI_CFG_REGISTER_SET_B);
466  /* Only 8 bit in a register part */
468  /* All 0s mask would mean do nothing */
469  FAS_ASSERT(mask > 0u);
470  FAS_ASSERT(registerOffset <= ADI_REGISTER_OFFSET5);
471 
472  for (uint8_t m = 0u; m < BS_NR_OF_MODULES_PER_STRING; m++) {
473  ADI_StoredConfigurationFillRegisterData(m, registerSet, registerOffset, data, position, mask, adiState);
474  }
475 }
476 
477 /* RequirementId: D7.1 V0R4 FUN-0.0.01.03 */
478 /* RequirementId: D7.1 V0R4 SIF-4.10.01.01 */
479 /* RequirementId: D7.1 V0R4 SIF-4.10.11.01 */
480 extern void ADI_TransmitCommand(uint16_t *command, ADI_STATE_s *adiState) {
481  FAS_ASSERT(command != NULL_PTR);
482  FAS_ASSERT(adiState != NULL_PTR);
483 
484  uint8_t PEC_Check[ADI_MAX_REGISTER_SIZE_IN_BYTES] = {0};
485  uint16_t PEC_result = 0u;
486 
487  /**
488  * SM_SPI_PEC: SPI Packet Error Code
489  * Calculate PEC for command.
490  */
491  PEC_Check[ADI_COMMAND_FIRST_BYTE_POSITION] = (uint8_t)command[ADI_COMMAND_BYTE0_POSITION];
492  PEC_Check[ADI_COMMAND_SECOND_BYTE_POSITION] = (uint8_t)command[ADI_COMMAND_BYTE1_POSITION];
493  PEC_result = ADI_Pec15(ADI_COMMAND_SIZE_IN_BYTES, PEC_Check);
494 
498  (uint8_t)((PEC_result >> ADI_BYTE_SHIFT) & ADI_ONE_BYTE_MASK);
499  adiState->data.txBuffer[ADI_COMMAND_PEC_SECOND_BYTE_POSITION] = (uint8_t)(PEC_result & ADI_ONE_BYTE_MASK);
500 
502 
503  /**
504  * SM_SPI_CNT: SPI Frame Counter
505  * Increment driver stored value of command counter if command causes increase.
506  */
507  /** If command increments AFE command counter, increment driver command counter */
508  if (command[ADI_COMMAND_INC_POSITION] == 1u) {
509  ADI_IncrementCommandCounter(adiState);
510  }
511 }
512 
514  const uint16_t *registerToWrite,
515  uint8_t *data,
516  ADI_PEC_FAULT_INJECTION_e pecFaultInjection,
517  ADI_STATE_s *adiState) {
518  FAS_ASSERT(registerToWrite != NULL_PTR);
519  FAS_ASSERT(data != NULL_PTR);
520  FAS_ASSERT(adiState != NULL_PTR);
521 
522  for (uint16_t i = 0u; i < ADI_N_ADI; i++) {
523  for (uint8_t byte = 0; byte < registerToWrite[ADI_COMMAND_DATA_LENGTH_POSITION]; byte++) {
524  adi_dataTransmit[byte + (i * registerToWrite[ADI_COMMAND_DATA_LENGTH_POSITION])] = data[byte];
525  }
526  }
527  ADI_WriteRegister(registerToWrite, adi_dataTransmit, pecFaultInjection, adiState);
528 }
529 
530 /* RequirementId: D7.1 V0R4 SIF-4.20.01.03 */
532  FAS_ASSERT(adiState != NULL_PTR);
533  STD_RETURN_TYPE_e returnValue = STD_OK;
534 
536  if (returnValue == STD_NOT_OK) {
537  /* If problem when writing configuration, retry once */
539  }
541  if (returnValue == STD_NOT_OK) {
542  /* If problem when writing configuration, retry once */
544  }
545 }
546 
547 extern void ADI_ClearCommandCounter(ADI_STATE_s *adiState) {
548  FAS_ASSERT(adiState != NULL_PTR);
549 
550  /**
551  * SM_SPI_CNT: SPI Frame Counter
552  * Reset driver stored value of command counter by sending RSTCC command.
553  */
554  /* Clear command counter */
556  ADI_TransmitCommand(adi_command, adiState);
557  for (uint16_t i = 0u; i < ADI_N_ADI; i++) {
558  adiState->data.errorTable->commandCounterIsOk[adiState->currentString][i] = true;
560  }
561 }
562 
563 extern void ADI_Wait(uint32_t waitTime) {
564  FAS_ASSERT(waitTime > 0u);
565 
566  uint32_t currentTime = OS_GetTickCount();
567  /* Block task without possibility to wake up */
568  /* +1: to wait at least waitTime*/
569  OS_DelayTaskUntil(&currentTime, waitTime + 1u);
570 }
571 
572 extern void ADI_WriteDataBits(uint8_t *pSentData, uint8_t dataToWrite, uint8_t position, uint8_t mask) {
573  FAS_ASSERT(pSentData != NULL_PTR);
574  /* AXIVION Routine Generic-MissingParameterAssert: dataToWrite: parameter accepts whole range */
575  /* Only 8 bit in a register part */
577  /* All 0s mask would mean do nothing */
578  FAS_ASSERT(mask > 0u);
579 
580  uint8_t tempData = (uint8_t)((((uint16_t)dataToWrite) << position) & ADI_DATA_MASK_SEED);
581  *pSentData &= ~mask;
582  *pSentData |= tempData & mask;
583 }
584 
585 /* RequirementId: D7.1 V0R4 FUN-0.0.01.02 */
586 /* RequirementId: D7.1 V0R4 SIF-4.10.01.01 */
587 /* RequirementId: D7.1 V0R4 SIF-4.10.11.01 */
588 extern void ADI_WriteRegister(
589  const uint16_t *registerToWrite,
590  uint8_t *data,
591  ADI_PEC_FAULT_INJECTION_e pecFaultInjection,
592  ADI_STATE_s *adiState) {
593  FAS_ASSERT(registerToWrite != NULL_PTR);
594  FAS_ASSERT(data != NULL_PTR);
595  FAS_ASSERT(adiState != NULL_PTR);
596 
597  uint16_t PEC_result = 0;
598  uint8_t PEC_Check[ADI_SIZE_OF_DATA_FOR_PEC_COMPUTATION] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
599  uint16_t registerLengthInBytes = registerToWrite[ADI_COMMAND_DATA_LENGTH_POSITION];
600  uint16_t spiFrameLength = registerLengthInBytes + 2u;
601  uint16_t dataLength = registerLengthInBytes;
602 
603  /**
604  * SM_SPI_PEC: SPI Packet Error Code
605  * Calculate PEC for command.
606  */
607  /* Compute PEC of the two command bytes */
608  PEC_Check[ADI_COMMAND_FIRST_BYTE_POSITION] = (uint8_t)registerToWrite[ADI_COMMAND_FIRST_BYTE_POSITION];
609  PEC_Check[ADI_COMMAND_SECOND_BYTE_POSITION] = (uint8_t)registerToWrite[ADI_COMMAND_SECOND_BYTE_POSITION];
610  PEC_result = ADI_Pec15(ADI_COMMAND_SIZE_IN_BYTES, PEC_Check);
611 
614  if (pecFaultInjection == ADI_COMMAND_PEC_FAULT_INJECTION) {
615  adiState->data.txBuffer[ADI_COMMAND_PEC_FIRST_BYTE_POSITION] = (PEC_result >> ADI_BYTE_SHIFT) &
617  adiState->data.txBuffer[ADI_COMMAND_PEC_SECOND_BYTE_POSITION] = (PEC_result & ADI_ONE_BYTE_MASK) + 1u;
618  } else {
619  adiState->data.txBuffer[ADI_COMMAND_PEC_FIRST_BYTE_POSITION] = (PEC_result >> ADI_BYTE_SHIFT) &
622  }
623 
624  for (uint16_t i = 0u; i < ADI_N_ADI; i++) {
625  /* data[] contains the data to write to the daisy-chain, it is used outside of the function */
626  for (uint16_t byte = 0; byte < registerLengthInBytes; byte++) {
627  adiState->data
628  .txBuffer[(ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + byte) + (i * spiFrameLength)] =
629  data[byte + (i * dataLength)];
630  }
631  /**
632  * SM_SPI_PEC: SPI Packet Error Code
633  * Calculate PEC for values to be sent to the daisy-chain.
634  */
635  /* Calculate PEC of all data (1 PEC value for 6 bytes) */
636  /* PEC_Check is a local variable holding data to write and used to compute the PEC */
637  for (uint16_t byte = 0; byte < registerLengthInBytes; byte++) {
638  uint16_t bufferData =
639  adiState->data
640  .txBuffer[(ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + byte) + (i * spiFrameLength)];
641  PEC_Check[byte] = (uint8_t)((bufferData)&ADI_ONE_BYTE_MASK);
642  }
643 
644  PEC_result = ADI_Pec10((uint8_t)(registerLengthInBytes & ADI_ONE_BYTE_MASK), PEC_Check, false);
645 
646  /* CRC is placed after the data bytes */
647  uint16_t crcFirstBytePosition = ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME + registerLengthInBytes;
648  if (pecFaultInjection == ADI_DATA_PEC_FAULT_INJECTION) {
649  adiState->data.txBuffer[crcFirstBytePosition + (i * spiFrameLength)] =
651  adiState->data.txBuffer[crcFirstBytePosition + 1u + (i * spiFrameLength)] =
652  (PEC_result & ADI_ONE_BYTE_MASK) + 1u;
653  } else {
654  adiState->data.txBuffer[crcFirstBytePosition + (i * spiFrameLength)] =
656  adiState->data.txBuffer[crcFirstBytePosition + 1u + (i * spiFrameLength)] = PEC_result & ADI_ONE_BYTE_MASK;
657  }
658  }
659 
660  uint16_t frameLength = ADI_COMMAND_AND_PEC_SIZE_IN_BYTES +
661  ((registerLengthInBytes + ADI_PEC_SIZE_IN_BYTES) * ADI_N_ADI);
662  ADI_SpiTransmitReceiveData(adiState, adiState->data.txBuffer, adiState->data.rxBuffer, (uint32_t)frameLength);
663 
664  /**
665  * SM_SPI_CNT: SPI Frame Counter
666  * Increment driver stored value of command counter if command causes increase.
667  */
668  /* If command increments AFE command counter, increment driver command counter */
669  /* Do not increment if a PEC error was injected */
670  if ((registerToWrite[ADI_COMMAND_INC_POSITION] == 1u) && (pecFaultInjection == ADI_PEC_NO_FAULT_INJECTION)) {
671  ADI_IncrementCommandCounter(adiState);
672  }
673 }
674 
675 /*========== Externalized Static Function Implementations (Unit Test) =======*/
676 #ifdef UNITY_UNIT_TEST
677 extern void TEST_ADI_StoredConfigurationFillRegisterData(
678  uint8_t module,
679  ADI_CFG_REGISTER_SET_e registerSet,
680  uint8_t registerOffset,
681  uint8_t data,
682  uint8_t position,
683  uint8_t mask,
684  ADI_STATE_s *adiState) {
685  ADI_StoredConfigurationFillRegisterData(module, registerSet, registerOffset, data, position, mask, adiState);
686 }
687 extern void TEST_ADI_IncrementCommandCounter(ADI_STATE_s *adiState) {
688  ADI_IncrementCommandCounter(adiState);
689 }
690 
691 #endif
Headers for the driver for the ADI analog front-end.
#define ADI_DMA_SPI_FINISHED_NOTIFICATION_VALUE
Definition: adi_ades183x.h:74
uint8_t adi_configurationRegisterBgroup[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *ADI_MAX_REGISTER_SIZE_IN_BYTES]
uint16_t adi_command[ADI_COMMAND_DEFINITION_LENGTH]
uint8_t adi_readConfigurationRegisterBgroup[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *ADI_MAX_REGISTER_SIZE_IN_BYTES]
uint8_t adi_configurationRegisterAgroup[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *ADI_MAX_REGISTER_SIZE_IN_BYTES]
uint8_t adi_dataTransmit[BS_NR_OF_MODULES_PER_STRING *ADI_MAX_REGISTER_SIZE_IN_BYTES]
uint8_t adi_readConfigurationRegisterAgroup[BS_NR_OF_STRINGS][BS_NR_OF_MODULES_PER_STRING *ADI_MAX_REGISTER_SIZE_IN_BYTES]
Header for the buffers used by the driver for the ADI analog front-end.
const uint16_t adi_cmdRdcfga[ADI_COMMAND_DEFINITION_LENGTH]
const uint16_t adi_cmdRstcc[ADI_COMMAND_DEFINITION_LENGTH]
const uint16_t adi_cmdWrcfgb[ADI_COMMAND_DEFINITION_LENGTH]
const uint16_t adi_cmdRdcfgb[ADI_COMMAND_DEFINITION_LENGTH]
const uint16_t adi_cmdWrcfga[ADI_COMMAND_DEFINITION_LENGTH]
Header file of some software.
#define ADI_COMMAND_CODE_LENGTH
#define ADI_COMMAND_PEC_SECOND_BYTE_POSITION
#define ADI_COMMAND_AND_PEC_SIZE_IN_BYTES
#define ADI_BYTE_SHIFT
#define ADI_COMMAND_COUNTER_POSITION
#define ADI_COMMAND_INC_POSITION
#define ADI_PEC10_FULL_EXCLUDE_COMMAND_COUNTER
#define ADI_COMMAND_COUNTER_MASK
#define ADI_COMMAND_COUNTER_MAX_VALUE
#define ADI_PEC10_MSB_EXCLUDE_COMMAND_COUNTER
#define ADI_N_ADI
#define ADI_FIRST_DATA_BYTE_POSITION_IN_TRANSMISSION_FRAME
#define ADI_COMMAND_SECOND_BYTE_POSITION
#define ADI_COMMAND_SIZE_IN_BYTES
#define ADI_REGISTER_OFFSET5
#define ADI_SPI_WAKEUP_WAIT_TIME_US
#define ADI_DATA_PEC_FIRST_BYTE_POSITION
#define ADI_ONE_BYTE_MASK
#define ADI_COMMAND_BYTE0_POSITION
#define ADI_MAX_REGISTER_SIZE_IN_BYTES
#define ADI_WRCFGA_LEN
ADI_CFG_REGISTER_SET_e
@ ADI_CFG_REGISTER_SET_B
@ ADI_CFG_REGISTER_SET_A
#define ADI_COMMAND_COUNTER_RESTART_VALUE
#define ADI_COMMAND_PEC_FIRST_BYTE_POSITION
#define ADI_N_BYTES_FOR_DATA_TRANSMISSION
#define ADI_COMMAND_BYTE1_POSITION
#define ADI_TRANSMISSION_TIMEOUT
#define ADI_COMMAND_FIRST_BYTE_POSITION
#define ADI_SIZE_OF_DATA_FOR_PEC_COMPUTATION
#define ADI_COMMAND_MASK_SEED
#define ADI_COMMAND_COUNTER_RESET_VALUE
#define ADI_DATA_MASK_SEED
#define ADI_COMMAND_DATA_LENGTH_POSITION
ADI_PEC_FAULT_INJECTION_e
@ ADI_PEC_NO_FAULT_INJECTION
@ ADI_COMMAND_PEC_FAULT_INJECTION
@ ADI_DATA_PEC_FAULT_INJECTION
#define ADI_SIZE_OF_DATA_FOR_PEC_COMPUTATION_WITH_COUNTER
#define ADI_PEC_SIZE_IN_BYTES
#define ADI_DATA_PEC_SECOND_BYTE_POSITION
#define ADI_WRCFGB_LEN
#define ADI_COMMAND_DEFINITION_LENGTH
#define ADI_MAX_BIT_POSITION_IN_BYTE
void ADI_WriteCommandConfigurationBits(uint16_t *configuredCommand, uint8_t position, uint8_t length, uint16_t configuration)
write configuration bits in commands (e.g., channel in ADAX command).
void ADI_WriteDataBits(uint8_t *pSentData, uint8_t dataToWrite, uint8_t position, uint8_t mask)
Helper function to write specific bits in data to be sent.
void ADI_ReadDataBits(uint8_t receivedData, uint8_t *pDataToRead, uint8_t position, uint8_t mask)
Helper function to read specific bits from received data.
void ADI_ReadRegister(uint16_t *registerToRead, uint8_t *data, ADI_STATE_s *adiState)
send command to the ades183x daisy-chain to read a register.
void ADI_ClearCommandCounter(ADI_STATE_s *adiState)
Send RSTCC to AFEs in daisy-chain and clear command counter of AFE driver.
void ADI_WriteRegister(const uint16_t *registerToWrite, uint8_t *data, ADI_PEC_FAULT_INJECTION_e pecFaultInjection, ADI_STATE_s *adiState)
sends command to the ades183x daisy-chain to write data.
STD_RETURN_TYPE_e ADI_CheckConfigurationRegister(ADI_CFG_REGISTER_SET_e registerSet, ADI_STATE_s *adiState)
Compares the configuration stored in the AFE driver with the configuration read from the AFEs.
void ADI_StoredConfigurationWriteToAfeGlobal(ADI_STATE_s *adiState)
Sends data in the configuration stored in driver to all AFEs in the daisy chain, for all configuratio...
void ADI_StoredConfigurationFillRegisterDataGlobal(ADI_CFG_REGISTER_SET_e registerSet, uint8_t registerOffset, uint8_t data, uint8_t position, uint8_t mask, ADI_STATE_s *adiState)
Writes data in the configuration stored in AFE driver, for all AFEs in the daisy-chain.
void ADI_SpiTransmitReceiveData(ADI_STATE_s *adiState, uint16_t *pTxBuff, uint16_t *pRxBuff, uint32_t frameLength)
Transmits and receives data on SPI.
void ADI_WriteRegisterGlobal(const uint16_t *registerToWrite, uint8_t *data, ADI_PEC_FAULT_INJECTION_e pecFaultInjection, ADI_STATE_s *adiState)
Write the same 6 bytes to all devices in the daisy-chain.
static void ADI_IncrementCommandCounter(ADI_STATE_s *adiState)
Increment command counter of AFE driver.
STD_RETURN_TYPE_e ADI_StoredConfigurationWriteToAfe(ADI_CFG_REGISTER_SET_e registerSet, ADI_STATE_s *adiState)
Sends data in the configuration stored in driver to all AFEs in the daisy chain, for a specific confi...
void ADI_TransmitCommand(uint16_t *command, ADI_STATE_s *adiState)
send command to the ades183x daisy-chain (e.g., start voltage measurement).
void ADI_Wait(uint32_t waitTime)
wait for a certain number of milliseconds
void ADI_CopyCommandBits(const uint16_t *sourceCommand, uint16_t *destinationCommand)
copy command bits in variables.
static void ADI_StoredConfigurationFillRegisterData(uint8_t module, ADI_CFG_REGISTER_SET_e registerSet, uint8_t registerOffset, uint8_t data, uint8_t position, uint8_t mask, ADI_STATE_s *adiState)
Writes data in the configuration stored in AFE driver, for a specific AFE.
Headers for the diagnostic driver for the ADI analog front-end.
uint16_t ADI_Pec10(uint8_t length, uint8_t *data, bool receive)
calculates the PEC10 K
uint16_t ADI_Pec15(uint8_t length, uint8_t *data)
calculates the PEC15
Headers for the PEC computations.
#define BS_NR_OF_MODULES_PER_STRING
number of modules in a string
#define FAS_ASSERT(x)
Assertion macro that asserts that x is true.
Definition: fassert.h:255
#define FAS_TRAP
Define that evaluates to essential boolean false thus tripping an assert.
Definition: fassert.h:129
STD_RETURN_TYPE_e
Definition: fstd_types.h:82
@ STD_NOT_OK
Definition: fstd_types.h:84
@ STD_OK
Definition: fstd_types.h:83
#define NULL_PTR
Null pointer.
Definition: fstd_types.h:77
OS_STD_RETURN_e OS_WaitForNotification(uint32_t *pNotifiedValue, uint32_t timeout)
Wait for a notification.
Definition: os_freertos.c:176
void OS_DelayTaskUntil(uint32_t *pPreviousWakeTime, uint32_t milliseconds)
Delay a task until a specified time.
Definition: os_freertos.c:162
uint32_t OS_GetTickCount(void)
Returns OS based system tick value.
Definition: os_freertos.c:158
STD_RETURN_TYPE_e SPI_TransmitReceiveDataDma(SPI_INTERFACE_CONFIG_s *pSpiInterface, uint16_t *pTxBuff, uint16_t *pRxBuff, uint32_t frameLength)
Transmits and receives data on SPI with DMA.
Definition: spi.c:292
STD_RETURN_TYPE_e SPI_TransmitDummyByte(SPI_INTERFACE_CONFIG_s *pSpiInterface, uint32_t delay)
Sends a dummy byte to wake up the SPI interface.
Definition: spi.c:159
STD_RETURN_TYPE_e SPI_TransmitData(SPI_INTERFACE_CONFIG_s *pSpiInterface, uint16 *pTxBuff, uint32 frameLength)
Transmits data on SPI without DMA.
Definition: spi.c:169
SPI_INTERFACE_CONFIG_s spi_adiInterface[BS_NR_OF_STRINGS]
Definition: spi_cfg.c:181
uint16_t * rxBuffer
uint8_t commandCounter[BS_NR_OF_STRINGS][ADI_N_ADI]
ADI_ERROR_TABLE_s * errorTable
uint16_t * txBuffer
bool crcIsOk[BS_NR_OF_STRINGS][ADI_N_ADI]
bool commandCounterIsOk[BS_NR_OF_STRINGS][ADI_N_ADI]
bool spiIsOk[BS_NR_OF_STRINGS]
bool configurationAIsOk[BS_NR_OF_STRINGS][ADI_N_ADI]
bool configurationBIsOk[BS_NR_OF_STRINGS][ADI_N_ADI]