foxBMS  1.4.1
The foxBMS Battery Management System API Documentation
dma.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2022, 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 dma.c
44  * @author foxBMS Team
45  * @date 2019-12-12 (date of creation)
46  * @updated 2022-10-27 (date of last update)
47  * @version v1.4.1
48  * @ingroup DRIVERS
49  * @prefix DMA
50  *
51  * @brief Driver for the DMA module.
52  *
53  */
54 
55 /*========== Includes =======================================================*/
56 #include "dma.h"
57 
58 #include "afe_dma.h"
59 #include "i2c.h"
60 #include "spi.h"
61 
62 /*========== Macros and Definitions =========================================*/
63 
64 /*========== Static Constant and Variable Definitions =======================*/
65 
66 /*========== Extern Constant and Variable Definitions =======================*/
67 
68 /*========== Static Function Prototypes =====================================*/
69 
70 /*========== Static Function Implementations ================================*/
71 
72 /*========== Extern Function Implementations ================================*/
73 
74 void DMA_Initialize(void) {
75  /* DMA control packets configuration for SPI */
76  g_dmaCTRL dma_controlPacketSpiTx = {
77  .SADD = 0u, /* source address */
78  .DADD = 0u, /* destination address */
79  .CHCTRL = 0u, /* channel chain control */
80  .FRCNT = 0u, /* frame count */
81  .ELCNT = 1u, /* element count */
82  .ELDOFFSET = 0u, /* element destination offset */
83  .ELSOFFSET = 0u, /* element destination offset */
84  .FRDOFFSET = 0u, /* frame destination offset */
85  .FRSOFFSET = 0u, /* frame destination offset */
86  .PORTASGN = (uint32_t)PORTA_READ_PORTB_WRITE, /* port assignment */
87  .RDSIZE = (uint32_t)ACCESS_16_BIT, /* read size */
88  .WRSIZE = (uint32_t)ACCESS_16_BIT, /* write size */
89  .TTYPE = (uint32_t)FRAME_TRANSFER, /* transfer type */
90  .ADDMODERD = (uint32_t)ADDR_INC1, /* address mode read */
91  .ADDMODEWR = (uint32_t)ADDR_FIXED, /* address mode write */
92  .AUTOINIT = (uint32_t)AUTOINIT_OFF /* autoinit */
93  };
94 
95  g_dmaCTRL dma_controlPacketSpiRx = {
96  .SADD = 0u, /* source address */
97  .DADD = 0u, /* destination address */
98  .CHCTRL = 0u, /* channel chain control */
99  .FRCNT = 0u, /* frame count */
100  .ELCNT = 1u, /* element count */
101  .ELDOFFSET = 0u, /* element destination offset */
102  .ELSOFFSET = 0u, /* element destination offset */
103  .FRDOFFSET = 0u, /* frame destination offset */
104  .FRSOFFSET = 0u, /* frame destination offset */
105  .PORTASGN = (uint32_t)PORTB_READ_PORTA_WRITE, /* port assignment */
106  .RDSIZE = ACCESS_16_BIT, /* read size */
107  .WRSIZE = ACCESS_16_BIT, /* write size */
108  .TTYPE = FRAME_TRANSFER, /* transfer type */
109  .ADDMODERD = ADDR_FIXED, /* address mode read */
110  .ADDMODEWR = ADDR_INC1, /* address mode write */
111  .AUTOINIT = AUTOINIT_OFF /* autoinit */
112  };
113 
114  /* DMA control packets configuration for I2C1 */
115  g_dmaCTRL dma_controlPacketI2cTx = {
116  .SADD = 0u, /* source address */
117  .DADD = 0u, /* destination address */
118  .CHCTRL = 0u, /* channel chain control */
119  .FRCNT = 0u, /* frame count */
120  .ELCNT = 1u, /* element count */
121  .ELDOFFSET = 0u, /* element destination offset */
122  .ELSOFFSET = 0u, /* element destination offset */
123  .FRDOFFSET = 0u, /* frame destination offset */
124  .FRSOFFSET = 0u, /* frame destination offset */
125  .PORTASGN = (uint32_t)PORTA_READ_PORTB_WRITE, /* port assignment */
126  .RDSIZE = (uint32_t)ACCESS_8_BIT, /* read size */
127  .WRSIZE = (uint32_t)ACCESS_8_BIT, /* write size */
128  .TTYPE = (uint32_t)FRAME_TRANSFER, /* transfer type */
129  .ADDMODERD = (uint32_t)ADDR_INC1, /* address mode read */
130  .ADDMODEWR = (uint32_t)ADDR_FIXED, /* address mode write */
131  .AUTOINIT = (uint32_t)AUTOINIT_OFF /* autoinit */
132  };
133 
134  g_dmaCTRL dma_controlPacketI2cRx = {
135  .SADD = 0u, /* source address */
136  .DADD = 0u, /* destination address */
137  .CHCTRL = 0u, /* channel chain control */
138  .FRCNT = 0u, /* frame count */
139  .ELCNT = 1u, /* element count */
140  .ELDOFFSET = 0u, /* element destination offset */
141  .ELSOFFSET = 0u, /* element destination offset */
142  .FRDOFFSET = 0u, /* frame destination offset */
143  .FRSOFFSET = 0u, /* frame destination offset */
144  .PORTASGN = (uint32_t)PORTB_READ_PORTA_WRITE, /* port assignment */
145  .RDSIZE = (uint32_t)ACCESS_8_BIT, /* read size */
146  .WRSIZE = (uint32_t)ACCESS_8_BIT, /* write size */
147  .TTYPE = (uint32_t)FRAME_TRANSFER, /* transfer type */
148  .ADDMODERD = (uint32_t)ADDR_FIXED, /* address mode read */
149  .ADDMODEWR = (uint32_t)ADDR_INC1, /* address mode write */
150  .AUTOINIT = (uint32_t)AUTOINIT_OFF /* autoinit */
151  };
152 
153  dmaEnable();
154 
155  /* Configuration for SPI */
156 
157  for (uint8_t i = 0u; i < DMA_NUMBER_SPI_INTERFACES; i++) {
158  /* assign dma request to Tx channel */
159  dmaReqAssign((dmaChannel_t)dma_spiDmaChannels[i].txChannel, (dmaRequest_t)dma_spiDmaRequests[i].txRequest);
160  /* assign dma request to Rx channel */
161  dmaReqAssign((dmaChannel_t)dma_spiDmaChannels[i].rxChannel, (dmaRequest_t)dma_spiDmaRequests[i].rxRequest);
162 
163  /* Enable Interrupt after reception of data
164  Group A - Interrupts (FTC, LFS, HBC, and BTC) are routed to the ARM CPU
165  User software should configure only Group A interrupts */
166  /**
167  * Use Tx interrupt to transfer last word with CSHOLD = 0
168  * DO NOT ACTIVATE FOR SLAVE SPI NODES (here SPI4 used as slave)
169  * */
170  if (i != SPI_GetSpiIndex(spiREG4)) {
171  dmaEnableInterrupt(
172  (dmaChannel_t)(dmaChannel_t)dma_spiDmaChannels[i].txChannel,
173  (dmaInterrupt_t)BTC,
174  (dmaIntGroup_t)DMA_INTA);
175  }
176  /* Use Rx to determine when SPI over DMA transaction is finished */
177  dmaEnableInterrupt(
178  (dmaChannel_t)(dmaChannel_t)dma_spiDmaChannels[i].rxChannel, (dmaInterrupt_t)BTC, (dmaIntGroup_t)DMA_INTA);
179 
180  dma_controlPacketSpiTx.DADD = (uint32_t)(&(dma_spiInterfaces[i]->DAT1)) + DMA_BIG_ENDIAN_ADDRESS_16BIT;
181  dma_controlPacketSpiRx.SADD = (uint32_t)(&(dma_spiInterfaces[i]->BUF)) + DMA_BIG_ENDIAN_ADDRESS_16BIT;
182 
183  /* Set dma control packet for Tx */
184  dmaSetCtrlPacket((dmaChannel_t)dma_spiDmaChannels[i].txChannel, dma_controlPacketSpiTx);
185 
186  /* Set dma control packet for Rx */
187  dmaSetCtrlPacket((dmaChannel_t)dma_spiDmaChannels[i].rxChannel, dma_controlPacketSpiRx);
188 
189  /* Set the dma channels to trigger on h/w request */
190  dmaSetChEnable((dmaChannel_t)dma_spiDmaChannels[i].txChannel, (dmaTriggerType_t)DMA_HW);
191  dmaSetChEnable((dmaChannel_t)dma_spiDmaChannels[i].rxChannel, (dmaTriggerType_t)DMA_HW);
192  }
193 
194  /* Configuration for I2C1 */
195 
196  /* assign dma request to Tx channel */
197  dmaReqAssign((dmaChannel_t)DMA_CHANNEL_I2C_TX, (dmaRequest_t)DMA_REQ_LINE_I2C_TX);
198  /* assign dma request to Rx channel */
199  dmaReqAssign((dmaChannel_t)DMA_CHANNEL_I2C_RX, (dmaRequest_t)DMA_REQ_LINE_I2C_RX);
200 
201  /* Enable Interrupt after reception of data
202  Group A - Interrupts (FTC, LFS, HBC, and BTC) are routed to the ARM CPU
203  User software should configure only Group A interrupts */
204  dmaEnableInterrupt((dmaChannel_t)(dmaChannel_t)DMA_CHANNEL_I2C_TX, (dmaInterrupt_t)BTC, (dmaIntGroup_t)DMA_INTA);
205  dmaEnableInterrupt((dmaChannel_t)(dmaChannel_t)DMA_CHANNEL_I2C_RX, (dmaInterrupt_t)BTC, (dmaIntGroup_t)DMA_INTA);
206 
207  dma_controlPacketI2cTx.DADD = (uint32_t)(&(i2cREG1->DXR)) + DMA_BIG_ENDIAN_ADDRESS_8BIT;
208  dma_controlPacketI2cRx.SADD = (uint32_t)(&(i2cREG1->DRR)) + DMA_BIG_ENDIAN_ADDRESS_8BIT;
209 
210  /* Set dma control packet for Tx */
211  dmaSetCtrlPacket((dmaChannel_t)DMA_CHANNEL_I2C_TX, dma_controlPacketI2cTx);
212 
213  /* Set dma control packet for Rx */
214  dmaSetCtrlPacket((dmaChannel_t)DMA_CHANNEL_I2C_RX, dma_controlPacketI2cRx);
215 
216  /* Set the dma channels to trigger on h/w request */
217  dmaSetChEnable((dmaChannel_t)DMA_CHANNEL_I2C_TX, (dmaTriggerType_t)DMA_HW);
218  dmaSetChEnable((dmaChannel_t)DMA_CHANNEL_I2C_RX, (dmaTriggerType_t)DMA_HW);
219 }
220 
221 /** Function called on DMA complete interrupts (TX and RX). Defined as weak in HAL. */
222 /* AXIVION Next Codeline Style Linker-Multiple_Definition: TI HAL only provides a weak implementation */
223 void UNIT_TEST_WEAK_IMPL dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel) {
224  /* AXIVION Routine Generic-MissingParameterAssert: inttype: unchecked in interrupt */
225  /* AXIVION Routine Generic-MissingParameterAssert: channel: unchecked in interrupt */
226 
227  if (inttype == (dmaInterrupt_t)BTC) {
228  uint16_t timeoutIterations = 0u;
229  uint8_t spiIndex = 0u;
230  switch (channel) {
231  case DMA_CHANNEL_SPI1_TX:
232  case DMA_CHANNEL_SPI2_TX:
233  case DMA_CHANNEL_SPI3_TX:
234  case DMA_CHANNEL_SPI4_TX:
235  case DMA_CHANNEL_SPI5_TX:
236  /* Search for SPI index with DMA TX channel */
237  for (uint8_t i = 0u; i < DMA_NUMBER_SPI_INTERFACES; i++) {
238  if (channel == (uint32_t)dma_spiDmaChannels[i].txChannel) {
239  spiIndex = i;
240  break;
241  }
242  }
243  /**
244  * TX SPI DMA interrupt: last but one word transmitted,
245  * last word is transmitted manually (in order to write CSHOLD field)
246  */
247  timeoutIterations = SPI_TX_EMPTY_TIMEOUT_ITERATIONS;
248  /* Wait until TX buffer is free for the last word */
249  while (((dma_spiInterfaces[spiIndex]->FLG &
250  (uint32)((uint32_t)1u << SPI_TX_BUFFER_EMPTY_FLAG_POSITION)) == 0u) &&
251  (timeoutIterations > 0u)) {
252  timeoutIterations--;
253  }
254  SPI_DmaSendLastByte(spiIndex);
255  break;
256 
257  case DMA_CHANNEL_SPI1_RX:
258  case DMA_CHANNEL_SPI2_RX:
259  case DMA_CHANNEL_SPI3_RX:
260  case DMA_CHANNEL_SPI4_RX:
261  case DMA_CHANNEL_SPI5_RX:
262  /* Search for SPI index with DMA RX channel */
263  for (uint8_t i = 0u; i < DMA_NUMBER_SPI_INTERFACES; i++) {
264  if (channel == (uint32_t)dma_spiDmaChannels[i].rxChannel) {
265  spiIndex = i;
266  break;
267  }
268  }
269  /* RX SPI DMA interrupt: last word received, means SPI transmission is finished */
270  if (spiIndex == SPI_GetSpiIndex(spiREG4)) { /** SPI configured as slave */
271  /* RX DMA interrupt, transmission finished, disable DMA */
272  dma_spiInterfaces[spiIndex]->INT0 &= ~DMAREQEN_BIT;
273  /* Disable SPI to prevent unwanted reception */
274  dma_spiInterfaces[spiIndex]->GCR1 &= ~SPIEN_BIT;
275  /* Set slave SPI Chip Select pins as GIO to deactivate slave SPI Chip Select pins */
277 
278  /* Specific call for measurement ICs */
279  AFE_DmaCallback(spiIndex);
280  } else { /* SPI configured as master */
281  /* RX DMA interrupt, transmission finished, disable DMA */
282  dma_spiInterfaces[spiIndex]->INT0 &= ~DMAREQEN_BIT;
283 
284  /* Specific call for measurement ICs */
285  if (spiIndex == SPI_GetSpiIndex(spiREG1)) {
286  AFE_DmaCallback(spiIndex);
287  }
288  spi_busyFlags[spiIndex] = SPI_IDLE;
289  }
290  break;
291 
292  case DMA_CHANNEL_I2C_TX:
293  i2cREG1->DMACR &= ~(uint32)0x2u;
294  /* Wait until Stop is detected */
295  timeoutIterations = I2C_TIMEOUT_ITERATIONS;
296  while ((i2cIsStopDetected(i2cREG1) == 0u) && (timeoutIterations > 0u)) {
297  timeoutIterations--;
298  }
299  /* Clear the Stop condition */
300  i2cClearSCD(i2cREG1);
301  break;
302  case DMA_CHANNEL_I2C_RX:
303  i2cREG1->DMACR &= ~(uint32)0x1u;
304  /* Wait until Stop is detected */
305  timeoutIterations = I2C_TIMEOUT_ITERATIONS;
306  while ((i2cIsStopDetected(i2cREG1) == 0u) && (timeoutIterations > 0u)) {
307  timeoutIterations--;
308  }
309  /* Clear the Stop condition */
310  i2cClearSCD(i2cREG1);
311  break;
312  default:
313  break;
314  }
315  }
316 }
317 
318 /*========== Externalized Static Function Implementations (Unit Test) =======*/
Headers for the driver for the general DMA module of monitoring ICs.
void AFE_DmaCallback(uint8_t spiIndex)
Function called by DMA block transfer callback.
void DMA_Initialize(void)
Enables the DMA module.
Definition: dma.c:74
void UNIT_TEST_WEAK_IMPL dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
Definition: dma.c:223
Headers for the driver for the DMA module.
DMA_REQUEST_CONFIG_s dma_spiDmaRequests[DMA_NUMBER_SPI_INTERFACES]
Definition: dma_cfg.c:76
spiBASE_t * dma_spiInterfaces[DMA_NUMBER_SPI_INTERFACES]
Definition: dma_cfg.c:85
DMA_CHANNEL_CONFIG_s dma_spiDmaChannels[DMA_NUMBER_SPI_INTERFACES]
Definition: dma_cfg.c:67
#define DMA_CHANNEL_SPI1_RX
Definition: dma_cfg.h:72
#define DMA_CHANNEL_SPI5_RX
Definition: dma_cfg.h:80
#define SPIEN_BIT
Definition: dma_cfg.h:111
#define DMA_BIG_ENDIAN_ADDRESS_16BIT
Definition: dma_cfg.h:104
#define DMA_CHANNEL_SPI4_TX
Definition: dma_cfg.h:77
#define DMA_BIG_ENDIAN_ADDRESS_8BIT
Definition: dma_cfg.h:102
#define DMA_NUMBER_SPI_INTERFACES
Definition: dma_cfg.h:107
#define DMAREQEN_BIT
Definition: dma_cfg.h:109
#define DMA_CHANNEL_SPI3_RX
Definition: dma_cfg.h:76
#define DMA_CHANNEL_SPI5_TX
Definition: dma_cfg.h:79
#define DMA_CHANNEL_SPI1_TX
Definition: dma_cfg.h:71
#define DMA_CHANNEL_I2C_TX
Definition: dma_cfg.h:81
#define DMA_CHANNEL_SPI4_RX
Definition: dma_cfg.h:78
#define DMA_REQ_LINE_I2C_TX
Definition: dma_cfg.h:97
#define DMA_REQ_LINE_I2C_RX
Definition: dma_cfg.h:98
#define DMA_CHANNEL_SPI3_TX
Definition: dma_cfg.h:75
#define DMA_CHANNEL_SPI2_TX
Definition: dma_cfg.h:73
#define DMA_CHANNEL_I2C_RX
Definition: dma_cfg.h:82
#define DMA_CHANNEL_SPI2_RX
Definition: dma_cfg.h:74
#define UNIT_TEST_WEAK_IMPL
Definition: general.h:97
Header for the driver for the I2C module.
#define I2C_TIMEOUT_ITERATIONS
Definition: i2c.h:66
void SPI_DmaSendLastByte(uint8_t spiIndex)
Used to send last byte per SPI.
Definition: spi.c:458
uint8_t SPI_GetSpiIndex(spiBASE_t *pNode)
Returns index of SPI node.
Definition: spi.c:483
Headers for the driver for the SPI module.
SPI_BUSY_STATE_e spi_busyFlags[]
Definition: spi_cfg.c:260
@ SPI_IDLE
Definition: spi_cfg.h:109
#define SPI_TX_EMPTY_TIMEOUT_ITERATIONS
Definition: spi_cfg.h:96
#define SPI_TX_BUFFER_EMPTY_FLAG_POSITION
Definition: spi_cfg.h:90
#define SPI_PC0_CLEAR_HW_CS_MASK
Definition: spi_cfg.h:93