foxBMS  1.6.0
The foxBMS Battery Management System API Documentation
i2c.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 i2c.c
44  * @author foxBMS Team
45  * @date 2021-07-22 (date of creation)
46  * @updated 2023-10-12 (date of last update)
47  * @version v1.6.0
48  * @ingroup DRIVERS
49  * @prefix I2C
50  *
51  * @brief Driver for the I2C module
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "i2c.h"
57 
58 #include "HL_system.h"
59 
60 #include "database.h"
61 #include "diag.h"
62 #include "dma.h"
63 #include "fstd_types.h"
64 #include "fsystem.h"
65 #include "mcu.h"
66 #include "os.h"
67 
68 #include <stdbool.h>
69 #include <stdint.h>
70 
71 /*========== Macros and Definitions =========================================*/
72 
73 /*========== Static Constant and Variable Definitions =======================*/
74 /* Pointer to the last byte of the table where received bytes are written, pI2cInterface */
76 /* Pointer to the last byte of the table where received bytes are written, i2cREG2 */
78 
79 /*========== Extern Constant and Variable Definitions =======================*/
80 
81 /*========== Static Function Prototypes =====================================*/
82 /**
83  * @brief Return transmit time of a word in microseconds.
84  * @details The function uses the clock settings of the interface
85  * to determine the time needed to transmit one word.
86  * Word means one byte + the ACK bit.
87  * @param pI2cInterface I2C interface to use
88  * @return time in microseconds needed to transmit a byte on the I2C interface
89  */
90 static uint32_t I2C_GetWordTransmitTime(i2cBASE_t *pI2cInterface);
91 /**
92  * @brief Waits for the I2C Tx buffer to be empty.
93  * @details When the buffer is empty, the next byte can be sent.
94  * If the buffer is empty before timeout_us microseconds are elapsed,
95  * the function returns true, false otherwise.
96  * The function also returns false if a NACK condition
97  * is detected.
98  * @param pI2cInterface I2C interface to use
99  * @param timeout_us time in microseconds to wait until the buffer is empty
100  * @return true if buffer is empty within timeout, false otherwise
101  */
102 static bool I2C_WaitTransmit(i2cBASE_t *pI2cInterface, uint32_t timeout_us);
103 /**
104  * @brief Waits for a stop condition to be detected.
105  * @details When a stop condition is issued, this function waits until
106  * the stop condition is detected on the bus. This means that
107  * that transmission is finished. If stop is detected before
108  * timeout_us microseconds are elapsed, the function returns true,
109  * false otherwise.
110  * @param pI2cInterface I2C interface to use
111  * @param timeout_us time in microseconds to wait until stop is detected
112  * @return true if stop is detected within timeout, false otherwise
113  */
114 static bool I2C_WaitStop(i2cBASE_t *pI2cInterface, uint32_t timeout_us);
115 
116 /**
117  * @brief Wait for the I2C transmit communication to complete, using notifications
118  *
119  * @return I2C_TX_NOTIFIED_VALUE if notification received,
120  * I2C_NO_NOTIFIED_VALUE if timeout reached
121  */
122 static uint32_t I2C_WaitForTxCompletedNotification(void);
123 /**
124  * @brief Wait for the I2C receive communication to complete, using notifications
125  *
126  * @return I2C_RX_NOTIFIED_VALUE if notification received,
127  * I2C_NO_NOTIFIED_VALUE if timeout reached
128  */
129 static uint32_t I2C_WaitForRxCompletedNotification(void);
130 /**
131  * @brief Clear pending notifications
132  *
133  */
134 static void I2C_ClearNotifications(void);
135 
136 /*========== Static Function Implementations ================================*/
137 static uint32_t I2C_GetWordTransmitTime(i2cBASE_t *pI2cInterface) {
138  FAS_ASSERT(pI2cInterface != NULL_PTR);
139  uint32_t i2cClock_khz = 0;
140  uint32_t prescaler = 0;
141  uint32_t wordTransmitTime_us = 0u;
142  uint8_t dFactor = 0u;
143 
144  /* Get prescaler */
145  prescaler = pI2cInterface->PSC & I2C_PRESCALER_MASK;
146  if (prescaler == 0u) {
148  } else if (prescaler == 1u) {
150  } else {
152  }
153  /* This is the equation used in the HAL; seems to differ from Technical Reference Manual
154  (p.1769 eq.65, SPNU563A - March 2018) */
155  i2cClock_khz = (uint32_t)(AVCLK1_FREQ * I2C_FACTOR_MHZ_TO_HZ) /
156  (2u * (prescaler + 1u) * (pI2cInterface->CKH + dFactor));
157  wordTransmitTime_us = (I2C_FACTOR_WORD_TO_BITS * I2C_FACTOR_S_TO_US) / i2cClock_khz;
158  return wordTransmitTime_us;
159 }
160 
161 static bool I2C_WaitTransmit(i2cBASE_t *pI2cInterface, uint32_t timeout_us) {
162  FAS_ASSERT(pI2cInterface != NULL_PTR);
163  bool success = true;
164  bool timeElapsed = false;
165  uint32_t startCounter = MCU_GetFreeRunningCount();
166 
167  while (((pI2cInterface->STR & (uint32_t)I2C_NACK_INT) == 0u) &&
168  ((pI2cInterface->STR & (uint32_t)I2C_TX_INT) == 0u) && (timeElapsed == false)) {
169  timeElapsed = MCU_IsTimeElapsed(startCounter, timeout_us);
170  }
171 
172  if (timeElapsed == true) {
173  success = false;
174  }
175 
176  return success;
177 }
178 
179 static bool I2C_WaitStop(i2cBASE_t *pI2cInterface, uint32_t timeout_us) {
180  FAS_ASSERT(pI2cInterface != NULL_PTR);
181  bool success = true;
182  bool timeElapsed = false;
183  uint32_t startCounter = MCU_GetFreeRunningCount();
184 
185  while ((i2cIsStopDetected(pI2cInterface) == 0u) && (timeElapsed == false)) {
186  timeElapsed = MCU_IsTimeElapsed(startCounter, timeout_us);
187  }
188 
189  if (timeElapsed == true) {
190  success = false;
191  }
192 
193  return success;
194 }
195 
196 static uint32_t I2C_WaitForTxCompletedNotification(void) {
197  uint32_t notifiedValueTx = I2C_NO_NOTIFIED_VALUE;
198  /**
199  * Suspend task and wait for I2C DMA TX finished notification,
200  * clear notification value on entry and exit
201  */
203  return notifiedValueTx;
204 }
205 
206 static uint32_t I2C_WaitForRxCompletedNotification(void) {
207  uint32_t notifiedValueRx = I2C_NO_NOTIFIED_VALUE;
208  /**
209  * Suspend task and wait for I2C DMA RX finished notification,
210  * clear notification value on entry and exit
211  */
213  return notifiedValueRx;
214 }
215 
216 static void I2C_ClearNotifications(void) {
219 }
220 
221 /*========== Extern Function Implementations ================================*/
222 extern void I2C_Initialize(void) {
223  i2cInit();
224 }
225 
227  i2cBASE_t *pI2cInterface,
228  uint32_t slaveAddress,
229  uint32_t nrBytes,
230  uint8_t *readData) {
231  FAS_ASSERT(pI2cInterface != NULL_PTR);
232  FAS_ASSERT(readData != NULL_PTR);
233  FAS_ASSERT(nrBytes > 0u);
234  FAS_ASSERT(slaveAddress < 128u);
235  STD_RETURN_TYPE_e retVal = STD_OK;
236 
237  if ((pI2cInterface->STR & (uint32_t)I2C_BUSBUSY) == 0u) {
238  /* Clear bits */
239  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
240  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
241  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
242  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
243  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
244 
245  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
246 
247  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
248  i2cSetDirection(pI2cInterface, (uint32_t)I2C_RECEIVER); /* Set as transmitter */
249  i2cSetSlaveAdd(pI2cInterface, slaveAddress); /* Set slave address */
250  i2cSetStart(pI2cInterface); /* Start receive */
251  if (nrBytes == 1u) {
252  i2cSetStop(pI2cInterface); /* generate a STOP condition */
253  }
254  /* Receive nrBytes bytes in polling mode */
255  for (uint16_t i = 0u; i < nrBytes; i++) {
256  bool success = I2C_WaitReceive(pI2cInterface, I2C_TIMEOUT_us);
257  if (((pI2cInterface->STR & (uint32_t)I2C_NACK_INT) == (uint32_t)I2C_NACK_INT) || (success == false)) {
258  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
259  i2cSetStop(pI2cInterface);
260  retVal = STD_NOT_OK;
261  break;
262  }
263  readData[i] = (uint8)(pI2cInterface->DRR & I2C_DDR_REGISTER_DATA_MASK);
264  if (i == (nrBytes - 2u)) {
265  i2cSetStop(pI2cInterface); /* generate a STOP condition */
266  }
267  }
268 
269  bool success = I2C_WaitStop(pI2cInterface, I2C_TIMEOUT_us);
270  if (success == false) {
271  /* Set Stop condition */
272  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
273  i2cSetStop(pI2cInterface);
274  retVal = STD_NOT_OK;
275  }
276  } else {
277  retVal = STD_NOT_OK;
278  }
279 
280  return retVal;
281 }
282 
284  i2cBASE_t *pI2cInterface,
285  uint32_t slaveAddress,
286  uint32_t nrBytes,
287  uint8_t *writeData) {
288  FAS_ASSERT(pI2cInterface != NULL_PTR);
289  FAS_ASSERT(writeData != NULL_PTR);
290  FAS_ASSERT(nrBytes > 0u);
291  FAS_ASSERT(slaveAddress < 128u);
292  STD_RETURN_TYPE_e retVal = STD_OK;
293 
294  if ((pI2cInterface->STR & (uint32_t)I2C_BUSBUSY) == 0u) {
295  /* Clear bits */
296  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
297  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
298  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
299  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
300  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
301 
302  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
303  i2cSetDirection(pI2cInterface, (uint32_t)I2C_TRANSMITTER); /* Set as transmitter */
304  i2cSetSlaveAdd(pI2cInterface, slaveAddress); /* Set slave address */
305  i2cSetStop(pI2cInterface); /* Stop condition after sending nrBytes bytes */
306  i2cSetCount(pI2cInterface, nrBytes); /* Send nrBytes bytes before STOP condition */
307  i2cSetStart(pI2cInterface); /* Start transmit */
308 
309  /* Send nrBytes bytes in polling mode */
310  for (uint16_t i = 0u; i < nrBytes; i++) {
311  pI2cInterface->DXR = (uint32_t)writeData[i];
312  bool success = I2C_WaitTransmit(pI2cInterface, I2C_TIMEOUT_us);
313  if (((pI2cInterface->STR & (uint32_t)I2C_NACK_INT) == (uint32_t)I2C_NACK_INT) || (success == false)) {
314  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
315  i2cSetStop(pI2cInterface);
316  retVal = STD_NOT_OK;
317  break;
318  }
319  }
320 
321  bool success = I2C_WaitStop(pI2cInterface, I2C_TIMEOUT_us);
322  if (success == false) {
323  /* Set Stop condition */
324  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
325  i2cSetStop(pI2cInterface);
326  retVal = STD_NOT_OK;
327  }
328  } else {
329  retVal = STD_NOT_OK;
330  }
331 
332  return retVal;
333 }
334 
336  i2cBASE_t *pI2cInterface,
337  uint32_t slaveAddress,
338  uint32_t nrBytesWrite,
339  uint8_t *writeData,
340  uint32_t nrBytesRead,
341  uint8_t *readData) {
342  FAS_ASSERT(pI2cInterface != NULL_PTR);
343  FAS_ASSERT(writeData != NULL_PTR);
344  FAS_ASSERT(nrBytesWrite > 0u);
345  FAS_ASSERT(readData != NULL_PTR);
346  FAS_ASSERT(nrBytesRead > 0u);
347  FAS_ASSERT(slaveAddress < 128u);
348  STD_RETURN_TYPE_e retVal = STD_OK;
349 
350  if ((pI2cInterface->STR & (uint32_t)I2C_BUSBUSY) == 0u) {
351  /* Clear bits */
352  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
353  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
354  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
355  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
356  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
357 
358  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
359  i2cSetDirection(pI2cInterface, (uint32_t)I2C_TRANSMITTER); /* Set as transmitter */
360  i2cSetSlaveAdd(pI2cInterface, slaveAddress); /* Set slave address */
361  i2cSetStart(pI2cInterface); /* Start transmit */
362 
363  bool success = true;
364 
365  /* Send nrBytesWrite bytes in polling mode */
366  for (uint16_t i = 0u; i < nrBytesWrite; i++) {
367  pI2cInterface->DXR = (uint32_t)writeData[i];
368  success = I2C_WaitTransmit(pI2cInterface, I2C_TIMEOUT_us);
369  if (((pI2cInterface->STR & (uint32_t)I2C_NACK_INT) == (uint32_t)I2C_NACK_INT) || (success == false)) {
370  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
371  i2cSetStop(pI2cInterface);
372  retVal = STD_NOT_OK;
373  break;
374  }
375  }
376 
377  if (!(((pI2cInterface->STR & (uint32_t)I2C_NACK_INT) == (uint32_t)I2C_NACK_INT) || (success == false))) {
378  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
379  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
380  i2cSetDirection(pI2cInterface, (uint32_t)I2C_RECEIVER); /* Set as receiver */
381  i2cSetStart(pI2cInterface); /* Start receive */
382  if (nrBytesRead == 1u) {
383  i2cSetStop(pI2cInterface); /* generate a STOP condition */
384  }
385  /* Receive nrBytes bytes in polling mode */
386  for (uint16_t i = 0u; i < nrBytesRead; i++) {
387  success = I2C_WaitReceive(pI2cInterface, I2C_TIMEOUT_us);
388  if (((pI2cInterface->STR & (uint32_t)I2C_NACK_INT) == (uint32_t)I2C_NACK_INT) || (success == false)) {
389  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
390  i2cSetStop(pI2cInterface);
391  retVal = STD_NOT_OK;
392  break;
393  }
394  readData[i] = (uint8)(pI2cInterface->DRR & I2C_DDR_REGISTER_DATA_MASK);
395  if (i == (nrBytesRead - 2u)) {
396  i2cSetStop(pI2cInterface); /* generate a STOP condition */
397  }
398  }
399  }
400 
401  success = I2C_WaitStop(pI2cInterface, I2C_TIMEOUT_us);
402  if (success == false) {
403  /* Set Stop condition */
404  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
405  i2cSetStop(pI2cInterface);
406  retVal = STD_NOT_OK;
407  }
408  } else {
409  retVal = STD_NOT_OK;
410  }
411 
412  return retVal;
413 }
414 
416  i2cBASE_t *pI2cInterface,
417  uint32_t slaveAddress,
418  uint32_t nrBytes,
419  uint8_t *readData) {
420  FAS_ASSERT(pI2cInterface != NULL_PTR);
421  FAS_ASSERT(readData != NULL_PTR);
422  FAS_ASSERT(nrBytes > 1u);
423  FAS_ASSERT(slaveAddress < 128u);
424  STD_RETURN_TYPE_e retVal = STD_OK;
425 
427 
428  if ((pI2cInterface->STR & (uint32_t)I2C_BUSBUSY) == 0u) {
429  /* Clear bits */
430  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
431  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
432  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
433  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
434  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
435 
436  /* DMA config */
437  dmaChannel_t channelRx = DMA_CH0;
438  if (pI2cInterface == i2cREG1) {
439  channelRx = DMA_CHANNEL_I2C1_RX;
440  } else if (pI2cInterface == i2cREG2) {
441  channelRx = DMA_CHANNEL_I2C2_RX;
442  } else {
443  /* invalid I2C interface */
445  }
446 
448 
449  /* Go to privileged mode to write DMA config registers */
450  const int32_t raisePrivilegeResult = FSYS_RaisePrivilege();
451  FAS_ASSERT(raisePrivilegeResult == 0);
452 
453  /* Set Tx buffer address */
454  /* AXIVION Disable Style MisraC2012-1.1: Cast necessary for DMA configuration */
455  dmaRAMREG->PCP[(dmaChannel_t)channelRx].IDADDR = (uint32_t)readData;
456  /* AXIVION Enable Style MisraC2012-1.1: */
457  /* Set number of Rx bytes to receive, (nrBytes-1) over DMA */
458  dmaRAMREG->PCP[(dmaChannel_t)channelRx].ITCOUNT = ((nrBytes - 1u) << DMA_INITIAL_FRAME_COUNTER_POSITION) | 1u;
459 
460  dmaSetChEnable((dmaChannel_t)channelRx, (dmaTriggerType_t)DMA_HW);
461 
462  FSYS_SwitchToUserMode(); /* DMA config registers written, leave privileged mode */
464  /* End DMA config */
465 
466  pI2cInterface->DMACR |= (uint32_t)I2C_RXDMAEN; /* Activate I2C DMA RX */
467 
468  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
469  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
470  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
471 
472  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
473  i2cSetDirection(pI2cInterface, (uint32_t)I2C_RECEIVER); /* Set as transmitter */
474  i2cSetSlaveAdd(pI2cInterface, slaveAddress); /* Set slave address */
475  i2cSetStart(pI2cInterface); /* Start receive */
476 
477  uint32_t notificationRx = I2C_WaitForRxCompletedNotification();
478  if (notificationRx != I2C_RX_NOTIFIED_VALUE) {
479  /* Rx not happened, deactivate DMA */
480  pI2cInterface->DMACR &= ~((uint32_t)I2C_RXDMAEN);
481  /* Set Stop condition */
482  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
483  i2cSetStop(pI2cInterface);
484  retVal = STD_NOT_OK;
485  } else {
486  /* Rx happened */
487  if (pI2cInterface == i2cREG1) {
488  readData[nrBytes - 1u] = i2c_rxLastByteInterface1;
489  } else if (pI2cInterface == i2cREG2) {
490  readData[nrBytes - 1u] = i2c_rxLastByteInterface2;
491  } else {
492  /* invalid I2C interface */
494  }
495  bool success = I2C_WaitStop(pI2cInterface, I2C_TIMEOUT_us);
496  if (success == false) {
497  /* Set Stop condition */
498  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
499  i2cSetStop(pI2cInterface);
500  retVal = STD_NOT_OK;
501  }
502  }
503  } else {
504  retVal = STD_NOT_OK;
505  }
506 
507  return retVal;
508 }
509 
511  i2cBASE_t *pI2cInterface,
512  uint32_t slaveAddress,
513  uint32_t nrBytes,
514  uint8_t *writeData) {
515  FAS_ASSERT(pI2cInterface != NULL_PTR);
516  FAS_ASSERT(writeData != NULL_PTR);
517  FAS_ASSERT(nrBytes > 0u);
518  FAS_ASSERT(slaveAddress < 128u);
519  STD_RETURN_TYPE_e retVal = STD_OK;
520 
522 
523  if ((pI2cInterface->STR & (uint32_t)I2C_BUSBUSY) == 0u) {
524  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
525  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
526  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
527  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
528  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
529 
530  /* DMA config */
531  dmaChannel_t channelTx = DMA_CH0;
532  if (pI2cInterface == i2cREG1) {
533  channelTx = DMA_CHANNEL_I2C1_TX;
534  } else if (pI2cInterface == i2cREG2) {
535  channelTx = DMA_CHANNEL_I2C2_TX;
536  } else {
537  /* invalid I2C interface */
539  }
540 
542 
543  /* Go to privileged mode to write DMA config registers */
544  const int32_t raisePrivilegeResult = FSYS_RaisePrivilege();
545  FAS_ASSERT(raisePrivilegeResult == 0);
546 
547  /* Set Tx buffer address */
548  /* AXIVION Disable Style MisraC2012-1.1: Cast necessary for DMA configuration */
549  dmaRAMREG->PCP[(dmaChannel_t)channelTx].ISADDR = (uint32_t)writeData;
550  /* AXIVION Enable Style MisraC2012-1.1: */
551  /* Set number of Tx bytes to transmit */
552  dmaRAMREG->PCP[(dmaChannel_t)channelTx].ITCOUNT = (nrBytes << DMA_INITIAL_FRAME_COUNTER_POSITION) | 1u;
553 
554  dmaSetChEnable((dmaChannel_t)channelTx, (dmaTriggerType_t)DMA_HW);
555 
556  FSYS_SwitchToUserMode(); /* DMA config registers written, leave privileged mode */
558  /* end DMA config */
559 
560  /* Clear bits */
561  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
562  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
563  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
564  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
565  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
566 
567  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
568  i2cSetDirection(pI2cInterface, (uint32_t)I2C_TRANSMITTER); /* Set as transmitter */
569  i2cSetSlaveAdd(pI2cInterface, slaveAddress); /* Set slave address */
570  i2cSetStop(pI2cInterface); /* Stop condition after sending nrBytes bytes */
571  i2cSetCount(pI2cInterface, nrBytes); /* Send nrBytes bytes before STOP condition */
572  pI2cInterface->DMACR |= (uint32_t)I2C_TXDMAEN; /* Activate I2C DMA TX */
573  i2cSetStart(pI2cInterface); /* Start transmit */
574 
575  uint32_t notificationTx = I2C_WaitForTxCompletedNotification();
576  if (notificationTx != I2C_TX_NOTIFIED_VALUE) {
577  /* Tx not happened, deactivate DMA */
578  pI2cInterface->DMACR &= ~((uint32_t)I2C_TXDMAEN);
579  /* Set Stop condition */
580  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
581  i2cSetStop(pI2cInterface);
582  retVal = STD_NOT_OK;
583  } else {
584  bool success = I2C_WaitStop(pI2cInterface, I2C_TIMEOUT_us);
585  if (success == false) {
586  /* Set Stop condition */
587  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
588  i2cSetStop(pI2cInterface);
589  retVal = STD_NOT_OK;
590  }
591  }
592  } else {
593  retVal = STD_NOT_OK;
594  }
595 
596  return retVal;
597 }
598 
600  i2cBASE_t *pI2cInterface,
601  uint32_t slaveAddress,
602  uint32_t nrBytesWrite,
603  uint8_t *writeData,
604  uint32_t nrBytesRead,
605  uint8_t *readData) {
606  FAS_ASSERT(pI2cInterface != NULL_PTR);
607  FAS_ASSERT(writeData != NULL_PTR);
608  FAS_ASSERT(nrBytesWrite > 0u);
609  FAS_ASSERT(readData != NULL_PTR);
610  FAS_ASSERT(nrBytesRead > 1u);
611  FAS_ASSERT(slaveAddress < 128u);
612  STD_RETURN_TYPE_e retVal = STD_OK;
613  dmaChannel_t channelRx = DMA_CH0;
614  dmaChannel_t channelTx = DMA_CH0;
615 
617 
618  if ((pI2cInterface->STR & (uint32_t)I2C_BUSBUSY) == 0u) {
619  /* Firt write bytes */
620 
621  /* Clear bits */
622  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
623  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
624  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
625  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
626  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
627 
628  /* DMA config */
629  if (pI2cInterface == i2cREG1) {
630  channelTx = DMA_CHANNEL_I2C1_TX;
631  } else if (pI2cInterface == i2cREG2) {
632  channelTx = DMA_CHANNEL_I2C2_TX;
633  } else {
634  /* invalid I2C interface */
636  }
637 
639 
640  /* Go to privileged mode to write DMA config registers */
641  const int32_t raisePrivilegeResultWrite = FSYS_RaisePrivilege();
642  FAS_ASSERT(raisePrivilegeResultWrite == 0);
643 
644  /* Set Tx buffer address */
645  /* AXIVION Disable Style MisraC2012-1.1: Cast necessary for DMA configuration */
646  dmaRAMREG->PCP[(dmaChannel_t)channelTx].ISADDR = (uint32_t)writeData;
647  /* AXIVION Enable Style MisraC2012-1.1: */
648  /* Set number of Tx bytes to transmit */
649  dmaRAMREG->PCP[(dmaChannel_t)channelTx].ITCOUNT = (nrBytesWrite << DMA_INITIAL_FRAME_COUNTER_POSITION) | 1u;
650 
651  dmaSetChEnable((dmaChannel_t)channelTx, (dmaTriggerType_t)DMA_HW);
652 
653  FSYS_SwitchToUserMode(); /* DMA config registers written, leave privileged mode */
655  /* end DMA config */
656 
657  /* Clear bits */
658  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
659  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
660  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
661  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
662  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
663 
664  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
665  i2cSetDirection(pI2cInterface, (uint32_t)I2C_TRANSMITTER); /* Set as transmitter */
666  i2cSetSlaveAdd(pI2cInterface, slaveAddress); /* Set slave address */
667  pI2cInterface->DMACR |= (uint32_t)I2C_TXDMAEN; /* Activate I2C DMA TX */
668  i2cSetStart(pI2cInterface); /* Start transmit */
669 
670  uint32_t notificationTx = I2C_WaitForTxCompletedNotification();
671  if (notificationTx != I2C_TX_NOTIFIED_VALUE) {
672  /* Tx not happened, deactivate DMA */
673  pI2cInterface->DMACR &= ~((uint32_t)I2C_TXDMAEN);
674  /* Set Stop condition */
675  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
676  i2cSetStop(pI2cInterface);
677  retVal = STD_NOT_OK;
678  } else {
679  /* Write successful, now read */
680 
681  /* DMA config */
682  if (pI2cInterface == i2cREG1) {
683  channelRx = DMA_CHANNEL_I2C1_RX;
684  } else if (pI2cInterface == i2cREG2) {
685  channelRx = DMA_CHANNEL_I2C2_RX;
686  } else {
687  /* invalid I2C interface */
689  }
690 
692 
693  /* Go to privileged mode to write DMA config registers */
694  const int32_t raisePrivilegeResultRead = FSYS_RaisePrivilege();
695  FAS_ASSERT(raisePrivilegeResultRead == 0);
696 
697  /* Set Rx buffer address */
698  /* AXIVION Disable Style MisraC2012-1.1: Cast necessary for DMA configuration */
699  dmaRAMREG->PCP[(dmaChannel_t)channelRx].IDADDR = (uint32_t)readData;
700  /* AXIVION Enable Style MisraC2012-1.1: */
701  /* Set number of Rx bytes to receive */
702  dmaRAMREG->PCP[(dmaChannel_t)channelRx].ITCOUNT =
703  ((nrBytesRead - 1u) << DMA_INITIAL_FRAME_COUNTER_POSITION) | 1u;
704 
705  dmaSetChEnable((dmaChannel_t)channelRx, (dmaTriggerType_t)DMA_HW);
706 
707  FSYS_SwitchToUserMode(); /* DMA config registers written, leave privileged mode */
709  /* end DMA config */
710 
711  /* As we cannot wait on stop condition to be sure that all bytes have been sent on the bus,
712  wait until transmission is finished */
713  uint32_t wordTransmitTime_us = I2C_GetWordTransmitTime(pI2cInterface) + I2C_TX_TIME_MARGIN_us;
714 
715  MCU_Delay_us(wordTransmitTime_us);
716 
717  /* Clear bits */
718  pI2cInterface->MDR &= ~((uint32_t)I2C_STOP_COND);
719  pI2cInterface->MDR &= ~((uint32_t)I2C_START_COND);
720  pI2cInterface->MDR &= ~((uint32_t)I2C_REPEATMODE);
721  pI2cInterface->STR |= (uint32_t)I2C_TX_INT;
722  pI2cInterface->STR |= (uint32_t)I2C_RX_INT;
723 
724  pI2cInterface->DMACR |= (uint32_t)I2C_RXDMAEN; /* Activate I2C DMA RX */
725 
726  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
727  i2cSetMode(pI2cInterface, (uint32_t)I2C_MASTER); /* Set as master */
728  i2cSetDirection(pI2cInterface, (uint32_t)I2C_RECEIVER); /* Set as transmitter */
729  i2cSetStart(pI2cInterface); /* Start receive */
730  /* Receive nrBytes bytes with DMA */
731 
732  uint32_t notificationRx = I2C_WaitForRxCompletedNotification();
733  if (notificationRx != I2C_RX_NOTIFIED_VALUE) {
734  /* Rx not happened, deactivate DMA */
735  pI2cInterface->DMACR &= ~((uint32_t)I2C_RXDMAEN);
736  /* Set Stop condition */
737  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
738  i2cSetStop(pI2cInterface);
739  retVal = STD_NOT_OK;
740  } else {
741  /* Rx happened */
742  if (pI2cInterface == i2cREG1) {
743  readData[nrBytesRead - 1u] = i2c_rxLastByteInterface1;
744  } else if (pI2cInterface == i2cREG2) {
745  readData[nrBytesRead - 1u] = i2c_rxLastByteInterface2;
746  } else {
747  /* invalid I2C interface */
749  }
750  bool success = I2C_WaitStop(pI2cInterface, I2C_TIMEOUT_us);
751  if (success == false) {
752  /* Set Stop condition */
753  pI2cInterface->MDR |= (uint32_t)I2C_REPEATMODE;
754  i2cSetStop(pI2cInterface);
755  retVal = STD_NOT_OK;
756  }
757  }
758  }
759  } else {
760  retVal = STD_NOT_OK;
761  }
762 
763  return retVal;
764 }
765 
766 extern uint8_t I2C_ReadLastRxByte(i2cBASE_t *pI2cInterface) {
767  FAS_ASSERT(pI2cInterface != NULL_PTR);
768  uint8_t lastReadByte = (uint8)(pI2cInterface->DRR & I2C_DDR_REGISTER_DATA_MASK);
769  return lastReadByte;
770 }
771 
772 extern bool I2C_WaitReceive(i2cBASE_t *pI2cInterface, uint32_t timeout_us) {
773  FAS_ASSERT(pI2cInterface != NULL_PTR);
774  bool success = true;
775  bool timeElapsed = false;
776  uint32_t startCounter = MCU_GetFreeRunningCount();
777 
778  while (((pI2cInterface->STR & (uint32_t)I2C_RX_INT) == 0u) && (timeElapsed == false)) {
779  timeElapsed = MCU_IsTimeElapsed(startCounter, timeout_us);
780  }
781 
782  if (timeElapsed == true) {
783  success = false;
784  }
785 
786  return success;
787 }
788 
789 /*========== Externalized Static Function Implementations (Unit Test) =======*/
790 #ifdef UNITY_UNIT_TEST
791 #endif
Database module header.
Diagnosis driver header.
Headers for the driver for the DMA module.
#define DMA_CHANNEL_I2C1_TX
Definition: dma_cfg.h:85
#define DMA_CHANNEL_I2C2_TX
Definition: dma_cfg.h:87
#define DMA_CHANNEL_I2C2_RX
Definition: dma_cfg.h:88
#define DMA_INITIAL_FRAME_COUNTER_POSITION
Definition: dma_cfg.h:71
#define DMA_CHANNEL_I2C1_RX
Definition: dma_cfg.h:86
#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
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
Function to switch between user mode and privilege mode.
long FSYS_RaisePrivilege(void)
Raise privilege.
static void FSYS_SwitchToUserMode(void)
Switch back to user mode.
Definition: fsystem.h:130
static uint32_t I2C_WaitForTxCompletedNotification(void)
Wait for the I2C transmit communication to complete, using notifications.
Definition: i2c.c:196
STD_RETURN_TYPE_e I2C_WriteRead(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytesWrite, uint8_t *writeData, uint32_t nrBytesRead, uint8_t *readData)
reads from an I2C slave, blocking.
Definition: i2c.c:335
bool I2C_WaitReceive(i2cBASE_t *pI2cInterface, uint32_t timeout_us)
Waits for the I2C Rx buffer to be full.
Definition: i2c.c:772
uint8_t i2c_rxLastByteInterface2
Definition: i2c.c:77
uint8_t i2c_rxLastByteInterface1
Definition: i2c.c:75
static bool I2C_WaitTransmit(i2cBASE_t *pI2cInterface, uint32_t timeout_us)
Waits for the I2C Tx buffer to be empty.
Definition: i2c.c:161
static bool I2C_WaitStop(i2cBASE_t *pI2cInterface, uint32_t timeout_us)
Waits for a stop condition to be detected.
Definition: i2c.c:179
static uint32_t I2C_GetWordTransmitTime(i2cBASE_t *pI2cInterface)
Return transmit time of a word in microseconds.
Definition: i2c.c:137
uint8_t I2C_ReadLastRxByte(i2cBASE_t *pI2cInterface)
Used to read last byte received per I2C.
Definition: i2c.c:766
STD_RETURN_TYPE_e I2C_ReadDma(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytes, uint8_t *readData)
reads from an I2C slave, no register address written first, using DMA.
Definition: i2c.c:415
STD_RETURN_TYPE_e I2C_Read(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytes, uint8_t *readData)
reads from an I2C slave, no register address written first, blocking.
Definition: i2c.c:226
STD_RETURN_TYPE_e I2C_WriteReadDma(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytesWrite, uint8_t *writeData, uint32_t nrBytesRead, uint8_t *readData)
reads from an I2C slave, using DMA.
Definition: i2c.c:599
static uint32_t I2C_WaitForRxCompletedNotification(void)
Wait for the I2C receive communication to complete, using notifications.
Definition: i2c.c:206
static void I2C_ClearNotifications(void)
Clear pending notifications.
Definition: i2c.c:216
STD_RETURN_TYPE_e I2C_Write(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytes, uint8_t *writeData)
writes to an I2C slave, no register address written first, blocking.
Definition: i2c.c:283
STD_RETURN_TYPE_e I2C_WriteDma(i2cBASE_t *pI2cInterface, uint32_t slaveAddress, uint32_t nrBytes, uint8_t *writeData)
writes to an I2C slave, no register address written first, using DMA.
Definition: i2c.c:510
void I2C_Initialize(void)
Initialize the I2C hardware with dedicated HAL functions. Has to be called before any call to the res...
Definition: i2c.c:222
Header for the driver for the I2C module.
#define I2C_NOTIFICATION_RX_INDEX
Definition: i2c.h:85
#define I2C_TIMEOUT_us
Definition: i2c.h:69
#define I2C_FACTOR_WORD_TO_BITS
Definition: i2c.h:106
#define I2C_NOTIFICATION_TX_INDEX
Definition: i2c.h:83
#define I2C_DFACTOR_VALUE_PRESCALER_0
Definition: i2c.h:112
#define I2C_RXDMAEN
Definition: i2c.h:74
#define I2C_TX_TIME_MARGIN_us
Definition: i2c.h:117
#define I2C_DFACTOR_VALUE_PRESCALER_OTHER
Definition: i2c.h:114
#define I2C_TX_NOTIFIED_VALUE
Definition: i2c.h:89
#define I2C_FACTOR_S_TO_US
Definition: i2c.h:104
#define I2C_FACTOR_MHZ_TO_HZ
Definition: i2c.h:102
#define I2C_NOTIFICATION_TIMEOUT_ms
Definition: i2c.h:98
#define I2C_DDR_REGISTER_DATA_MASK
Definition: i2c.h:77
#define I2C_RX_NOTIFIED_VALUE
Definition: i2c.h:91
#define I2C_DFACTOR_VALUE_PRESCALER_1
Definition: i2c.h:113
#define I2C_TXDMAEN
Definition: i2c.h:72
#define I2C_NO_NOTIFIED_VALUE
Definition: i2c.h:87
#define I2C_PRESCALER_MASK
Definition: i2c.h:100
uint32_t MCU_GetFreeRunningCount(void)
Get the current value of the Free Running Counter 0 (FRC0)
Definition: mcu.c:123
void MCU_Delay_us(uint32_t delay_us)
Wait blocking a certain time in microseconds.
Definition: mcu.c:89
bool MCU_IsTimeElapsed(uint32_t startCounter, uint32_t timeout_us)
Checks if a timeout in microseconds has elapsed.
Definition: mcu.c:133
Headers for the driver for the MCU module.
Declaration of the OS wrapper interface.
OS_STD_RETURN_e OS_ClearNotificationIndexed(uint32_t indexToClear)
Clear pending notification of a task, with index.
Definition: os_freertos.c:251
OS_STD_RETURN_e OS_WaitForNotificationIndexed(uint32_t indexToWaitOn, uint32_t *pNotifiedValue, uint32_t timeout)
Wait for a notification, with index.
Definition: os_freertos.c:210
void OS_ExitTaskCritical(void)
Exit Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:154
void OS_EnterTaskCritical(void)
Enter Critical interface function for use in FreeRTOS-Tasks and FreeRTOS-ISR.
Definition: os_freertos.c:150