foxBMS  1.2.1
The foxBMS Battery Management System API Documentation
dma.c
Go to the documentation of this file.
1 /**
2  *
3  * @copyright © 2010 - 2021, Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from
20  * this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * We kindly request you to use one or more of the following phrases to refer to
34  * foxBMS in your hardware, software, documentation or advertising materials:
35  *
36  * - ″This product uses parts of foxBMS®″
37  * - ″This product includes parts of foxBMS®″
38  * - ″This product is derived from foxBMS®″
39  *
40  */
41 
42 /**
43  * @file dma.c
44  * @author foxBMS Team
45  * @date 2019-12-12 (date of creation)
46  * @updated 2021-12-08 (date of last update)
47  * @ingroup DRIVERS
48  * @prefix DMA
49  *
50  * @brief Driver for the DMA module.
51  *
52  */
53 
54 /*========== Includes =======================================================*/
55 #include "dma.h"
56 
57 #include "afe_dma.h"
58 #include "i2c.h"
59 #include "spi.h"
60 
61 /*========== Macros and Definitions =========================================*/
62 
63 /*========== Static Constant and Variable Definitions =======================*/
64 
65 /*========== Extern Constant and Variable Definitions =======================*/
66 
67 /*========== Static Function Prototypes =====================================*/
68 
69 /*========== Static Function Implementations ================================*/
70 
71 /*========== Extern Function Implementations ================================*/
72 
73 void DMA_Initialize(void) {
74  /* DMA control packets configuration for SPI */
75  g_dmaCTRL dma_controlPacketSpiTx = {
76  .SADD = 0u, /* source address */
77  .DADD = 0u, /* destination address */
78  .CHCTRL = 0u, /* channel chain control */
79  .FRCNT = 0u, /* frame count */
80  .ELCNT = 1u, /* element count */
81  .ELDOFFSET = 0u, /* element destination offset */
82  .ELSOFFSET = 0u, /* element destination offset */
83  .FRDOFFSET = 0u, /* frame destination offset */
84  .FRSOFFSET = 0u, /* frame destination offset */
85  .PORTASGN = (uint32_t)PORTA_READ_PORTB_WRITE, /* port assignment */
86  .RDSIZE = (uint32_t)ACCESS_16_BIT, /* read size */
87  .WRSIZE = (uint32_t)ACCESS_16_BIT, /* write size */
88  .TTYPE = (uint32_t)FRAME_TRANSFER, /* transfer type */
89  .ADDMODERD = (uint32_t)ADDR_INC1, /* address mode read */
90  .ADDMODEWR = (uint32_t)ADDR_FIXED, /* address mode write */
91  .AUTOINIT = (uint32_t)AUTOINIT_OFF /* autoinit */
92  };
93 
94  g_dmaCTRL dma_controlPacketSpiRx = {
95  .SADD = 0u, /* source address */
96  .DADD = 0u, /* destination address */
97  .CHCTRL = 0u, /* channel chain control */
98  .FRCNT = 0u, /* frame count */
99  .ELCNT = 1u, /* element count */
100  .ELDOFFSET = 0u, /* element destination offset */
101  .ELSOFFSET = 0u, /* element destination offset */
102  .FRDOFFSET = 0u, /* frame destination offset */
103  .FRSOFFSET = 0u, /* frame destination offset */
104  .PORTASGN = (uint32_t)PORTB_READ_PORTA_WRITE, /* port assignment */
105  .RDSIZE = ACCESS_16_BIT, /* read size */
106  .WRSIZE = ACCESS_16_BIT, /* write size */
107  .TTYPE = FRAME_TRANSFER, /* transfer type */
108  .ADDMODERD = ADDR_FIXED, /* address mode read */
109  .ADDMODEWR = ADDR_INC1, /* address mode write */
110  .AUTOINIT = AUTOINIT_OFF /* autoinit */
111  };
112 
113  /* DMA control packets configuration for I2C1 */
114  g_dmaCTRL dma_controlPacketI2cTx = {
115  .SADD = 0u, /* source address */
116  .DADD = 0u, /* destination address */
117  .CHCTRL = 0u, /* channel chain control */
118  .FRCNT = 0u, /* frame count */
119  .ELCNT = 1u, /* element count */
120  .ELDOFFSET = 0u, /* element destination offset */
121  .ELSOFFSET = 0u, /* element destination offset */
122  .FRDOFFSET = 0u, /* frame destination offset */
123  .FRSOFFSET = 0u, /* frame destination offset */
124  .PORTASGN = (uint32_t)PORTA_READ_PORTB_WRITE, /* port assignment */
125  .RDSIZE = (uint32_t)ACCESS_8_BIT, /* read size */
126  .WRSIZE = (uint32_t)ACCESS_8_BIT, /* write size */
127  .TTYPE = (uint32_t)FRAME_TRANSFER, /* transfer type */
128  .ADDMODERD = (uint32_t)ADDR_INC1, /* address mode read */
129  .ADDMODEWR = (uint32_t)ADDR_FIXED, /* address mode write */
130  .AUTOINIT = (uint32_t)AUTOINIT_OFF /* autoinit */
131  };
132 
133  g_dmaCTRL dma_controlPacketI2cRx = {
134  .SADD = 0u, /* source address */
135  .DADD = 0u, /* destination address */
136  .CHCTRL = 0u, /* channel chain control */
137  .FRCNT = 0u, /* frame count */
138  .ELCNT = 1u, /* element count */
139  .ELDOFFSET = 0u, /* element destination offset */
140  .ELSOFFSET = 0u, /* element destination offset */
141  .FRDOFFSET = 0u, /* frame destination offset */
142  .FRSOFFSET = 0u, /* frame destination offset */
143  .PORTASGN = (uint32_t)PORTB_READ_PORTA_WRITE, /* port assignment */
144  .RDSIZE = (uint32_t)ACCESS_8_BIT, /* read size */
145  .WRSIZE = (uint32_t)ACCESS_8_BIT, /* write size */
146  .TTYPE = (uint32_t)FRAME_TRANSFER, /* transfer type */
147  .ADDMODERD = (uint32_t)ADDR_FIXED, /* address mode read */
148  .ADDMODEWR = (uint32_t)ADDR_INC1, /* address mode write */
149  .AUTOINIT = (uint32_t)AUTOINIT_OFF /* autoinit */
150  };
151 
152  dmaEnable();
153 
154  /* Configuration for SPI */
155 
156  for (uint8_t i = 0u; i < DMA_NUMBER_SPI_INTERFACES; i++) {
157  /* assign dma request to Tx channel */
158  dmaReqAssign((dmaChannel_t)dma_spiDmaChannels[i].txChannel, (dmaRequest_t)dma_spiDmaRequests[i].txRequest);
159  /* assign dma request to Rx channel */
160  dmaReqAssign((dmaChannel_t)dma_spiDmaChannels[i].rxChannel, (dmaRequest_t)dma_spiDmaRequests[i].rxRequest);
161 
162  /* Enable Interrupt after reception of data
163  Group A - Interrupts (FTC, LFS, HBC, and BTC) are routed to the ARM CPU
164  User software should configure only Group A interrupts */
165  /**
166  * Use Tx interrupt to transfer last word with CSHOLD = 0
167  * DO NOT ACTIVATE FOR SLAVE SPI NODES (here SPI4 used as slave)
168  * */
169  if (i != SPI_GetSpiIndex(spiREG4)) {
170  dmaEnableInterrupt(
171  (dmaChannel_t)(dmaChannel_t)dma_spiDmaChannels[i].txChannel,
172  (dmaInterrupt_t)BTC,
173  (dmaIntGroup_t)DMA_INTA);
174  }
175  /* Use Rx to determine when SPI over DMA transaction is finished */
176  dmaEnableInterrupt(
177  (dmaChannel_t)(dmaChannel_t)dma_spiDmaChannels[i].rxChannel, (dmaInterrupt_t)BTC, (dmaIntGroup_t)DMA_INTA);
178 
179  dma_controlPacketSpiTx.DADD = (uint32_t)(&(dma_spiInterfaces[i]->DAT1)) + DMA_BIG_ENDIAN_ADDRESS_16BIT;
180  dma_controlPacketSpiRx.SADD = (uint32_t)(&(dma_spiInterfaces[i]->BUF)) + DMA_BIG_ENDIAN_ADDRESS_16BIT;
181 
182  /* Set dma control packet for Tx */
183  dmaSetCtrlPacket((dmaChannel_t)dma_spiDmaChannels[i].txChannel, dma_controlPacketSpiTx);
184 
185  /* Set dma control packet for Rx */
186  dmaSetCtrlPacket((dmaChannel_t)dma_spiDmaChannels[i].rxChannel, dma_controlPacketSpiRx);
187 
188  /* Set the dma channels to trigger on h/w request */
189  dmaSetChEnable((dmaChannel_t)dma_spiDmaChannels[i].txChannel, (dmaTriggerType_t)DMA_HW);
190  dmaSetChEnable((dmaChannel_t)dma_spiDmaChannels[i].rxChannel, (dmaTriggerType_t)DMA_HW);
191  }
192 
193  /* Configuration for I2C1 */
194 
195  /* assign dma request to Tx channel */
196  dmaReqAssign((dmaChannel_t)DMA_CHANNEL_I2C_TX, (dmaRequest_t)DMA_REQ_LINE_I2C_TX);
197  /* assign dma request to Rx channel */
198  dmaReqAssign((dmaChannel_t)DMA_CHANNEL_I2C_RX, (dmaRequest_t)DMA_REQ_LINE_I2C_RX);
199 
200  /* Enable Interrupt after reception of data
201  Group A - Interrupts (FTC, LFS, HBC, and BTC) are routed to the ARM CPU
202  User software should configure only Group A interrupts */
203  dmaEnableInterrupt((dmaChannel_t)(dmaChannel_t)DMA_CHANNEL_I2C_TX, (dmaInterrupt_t)BTC, (dmaIntGroup_t)DMA_INTA);
204  dmaEnableInterrupt((dmaChannel_t)(dmaChannel_t)DMA_CHANNEL_I2C_RX, (dmaInterrupt_t)BTC, (dmaIntGroup_t)DMA_INTA);
205 
206  dma_controlPacketI2cTx.DADD = (uint32_t)(&(i2cREG1->DXR)) + DMA_BIG_ENDIAN_ADDRESS_8BIT;
207  dma_controlPacketI2cRx.SADD = (uint32_t)(&(i2cREG1->DRR)) + DMA_BIG_ENDIAN_ADDRESS_8BIT;
208 
209  /* Set dma control packet for Tx */
210  dmaSetCtrlPacket((dmaChannel_t)DMA_CHANNEL_I2C_TX, dma_controlPacketI2cTx);
211 
212  /* Set dma control packet for Rx */
213  dmaSetCtrlPacket((dmaChannel_t)DMA_CHANNEL_I2C_RX, dma_controlPacketI2cRx);
214 
215  /* Set the dma channels to trigger on h/w request */
216  dmaSetChEnable((dmaChannel_t)DMA_CHANNEL_I2C_TX, (dmaTriggerType_t)DMA_HW);
217  dmaSetChEnable((dmaChannel_t)DMA_CHANNEL_I2C_RX, (dmaTriggerType_t)DMA_HW);
218 }
219 
220 /** Function called on DMA complete interrupts (TX and RX). Defined as weak in HAL. */
221 /* AXIVION Next Line Style Linker-Multiple_Definition: TI HAL only provides a weak implementation */
222 void UNIT_TEST_WEAK_IMPL dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel) {
223  if (inttype == (dmaInterrupt_t)BTC) {
224  uint16_t timeoutIterations = 0u;
225  uint8_t spiIndex = 0u;
226  switch (channel) {
227  case DMA_CHANNEL_SPI1_TX:
228  case DMA_CHANNEL_SPI2_TX:
229  case DMA_CHANNEL_SPI3_TX:
230  case DMA_CHANNEL_SPI4_TX:
231  case DMA_CHANNEL_SPI5_TX:
232  /* Search for SPI index with DMA TX channel */
233  for (uint8_t i = 0u; i < DMA_NUMBER_SPI_INTERFACES; i++) {
234  if ((uint32_t)dma_spiDmaChannels[i].txChannel == channel) {
235  spiIndex = i;
236  break;
237  }
238  }
239  /**
240  * TX SPI DMA interrupt: last but one word transmitted,
241  * last word is transmitted manually (in order to write CSHOLD field)
242  */
243  timeoutIterations = SPI_TX_EMPTY_TIMEOUT_ITERATIONS;
244  /* Wait until TX buffer is free for the last word */
245  while (((dma_spiInterfaces[spiIndex]->FLG &
246  (uint32)((uint32_t)1u << SPI_TX_BUFFER_EMPTY_FLAG_POSITION)) == 0u) &&
247  (timeoutIterations > 0u)) {
248  timeoutIterations--;
249  }
250  SPI_DmaSendLastByte(spiIndex);
251  break;
252 
253  case DMA_CHANNEL_SPI1_RX:
254  case DMA_CHANNEL_SPI2_RX:
255  case DMA_CHANNEL_SPI3_RX:
256  case DMA_CHANNEL_SPI4_RX:
257  case DMA_CHANNEL_SPI5_RX:
258  /* Search for SPI index with DMA RX channel */
259  for (uint8_t i = 0u; i < DMA_NUMBER_SPI_INTERFACES; i++) {
260  if ((uint32_t)dma_spiDmaChannels[i].rxChannel == channel) {
261  spiIndex = i;
262  break;
263  }
264  }
265  /* RX SPI DMA interrupt: last word received, means SPI transmission is finished */
266  if (spiIndex == SPI_GetSpiIndex(spiREG4)) { /** SPI configured as slave */
267  /* RX DMA interrupt, transmission finished, disable DMA */
268  dma_spiInterfaces[spiIndex]->INT0 &= ~DMAREQEN_BIT;
269  /* Disable SPI to prevent unwanted reception */
270  dma_spiInterfaces[spiIndex]->GCR1 &= ~SPIEN_BIT;
271  /* Set slave SPI Chip Select pins as GIO to deactivate slave SPI Chip Select pins */
273 
274  /* Specific call for measurement ICs */
275  AFE_DmaCallback(spiIndex);
276  } else { /* SPI configured as master */
277  /* RX DMA interrupt, transmission finished, disable DMA */
278  dma_spiInterfaces[spiIndex]->INT0 &= ~DMAREQEN_BIT;
279 
280  /* Specific call for measurement ICs */
281  if (spiIndex == SPI_GetSpiIndex(spiREG1)) {
282  AFE_DmaCallback(spiIndex);
283  }
284  spi_busyFlags[spiIndex] = SPI_IDLE;
285  }
286  break;
287 
288  case DMA_CHANNEL_I2C_TX:
289  i2cREG1->DMACR &= ~(uint32)0x2u;
290  /* Wait until Stop is detected */
291  timeoutIterations = I2C_TIMEOUT_ITERATIONS;
292  while ((i2cIsStopDetected(i2cREG1) == 0u) && (timeoutIterations > 0u)) {
293  timeoutIterations--;
294  }
295  /* Clear the Stop condition */
296  i2cClearSCD(i2cREG1);
297  break;
298  case DMA_CHANNEL_I2C_RX:
299  i2cREG1->DMACR &= ~(uint32)0x1u;
300  /* Wait until Stop is detected */
301  timeoutIterations = I2C_TIMEOUT_ITERATIONS;
302  while ((i2cIsStopDetected(i2cREG1) == 0u) && (timeoutIterations > 0u)) {
303  timeoutIterations--;
304  }
305  /* Clear the Stop condition */
306  i2cClearSCD(i2cREG1);
307  break;
308  default:
309  break;
310  }
311  }
312 }
313 
314 /*========== 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:73
void UNIT_TEST_WEAK_IMPL dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
Definition: dma.c:222
Headers for the driver for the DMA module.
DMA_REQUEST_CONFIG_s dma_spiDmaRequests[DMA_NUMBER_SPI_INTERFACES]
Definition: dma_cfg.c:77
spiBASE_t * dma_spiInterfaces[DMA_NUMBER_SPI_INTERFACES]
Definition: dma_cfg.c:86
DMA_CHANNEL_CONFIG_s dma_spiDmaChannels[DMA_NUMBER_SPI_INTERFACES]
Definition: dma_cfg.c:68
#define DMA_CHANNEL_SPI1_RX
Definition: dma_cfg.h:71
#define DMA_CHANNEL_SPI5_RX
Definition: dma_cfg.h:79
#define SPIEN_BIT
Definition: dma_cfg.h:110
#define DMA_BIG_ENDIAN_ADDRESS_16BIT
Definition: dma_cfg.h:103
#define DMA_CHANNEL_SPI4_TX
Definition: dma_cfg.h:76
#define DMA_BIG_ENDIAN_ADDRESS_8BIT
Definition: dma_cfg.h:101
#define DMA_NUMBER_SPI_INTERFACES
Definition: dma_cfg.h:106
#define DMAREQEN_BIT
Definition: dma_cfg.h:108
#define DMA_CHANNEL_SPI3_RX
Definition: dma_cfg.h:75
#define DMA_CHANNEL_SPI5_TX
Definition: dma_cfg.h:78
#define DMA_CHANNEL_SPI1_TX
Definition: dma_cfg.h:70
#define DMA_CHANNEL_I2C_TX
Definition: dma_cfg.h:80
#define DMA_CHANNEL_SPI4_RX
Definition: dma_cfg.h:77
#define DMA_REQ_LINE_I2C_TX
Definition: dma_cfg.h:96
#define DMA_REQ_LINE_I2C_RX
Definition: dma_cfg.h:97
#define DMA_CHANNEL_SPI3_TX
Definition: dma_cfg.h:74
#define DMA_CHANNEL_SPI2_TX
Definition: dma_cfg.h:72
#define DMA_CHANNEL_I2C_RX
Definition: dma_cfg.h:81
#define DMA_CHANNEL_SPI2_RX
Definition: dma_cfg.h:73
#define UNIT_TEST_WEAK_IMPL
Definition: general.h:110
Header for the driver for the I2C module.
#define I2C_TIMEOUT_ITERATIONS
Definition: i2c.h:65
void SPI_DmaSendLastByte(uint8_t spiIndex)
Used to send last byte per SPI.
Definition: spi.c:436
uint8_t SPI_GetSpiIndex(spiBASE_t *pNode)
Returns index of SPI node.
Definition: spi.c:455
Headers for the driver for the SPI module.
SPI_BUSY_STATE_e spi_busyFlags[]
Definition: spi_cfg.c:329
@ SPI_IDLE
Definition: spi_cfg.h:125
#define SPI_TX_EMPTY_TIMEOUT_ITERATIONS
Definition: spi_cfg.h:95
#define SPI_TX_BUFFER_EMPTY_FLAG_POSITION
Definition: spi_cfg.h:89
#define SPI_PC0_CLEAR_HW_CS_MASK
Definition: spi_cfg.h:92