EFM32 Gecko Software Documentation  efm32g-doc-5.1.2
em_ldma.c
Go to the documentation of this file.
1 /***************************************************************************/
33 #include "em_ldma.h"
34 
35 #if defined( LDMA_PRESENT ) && ( LDMA_COUNT == 1 )
36 
37 #include <stddef.h>
38 #include "em_assert.h"
39 #include "em_bus.h"
40 #include "em_cmu.h"
41 #include "em_core.h"
42 
43 /***************************************************************************/
48 /***************************************************************************/
53 #if defined( LDMA_IRQ_HANDLER_TEMPLATE )
54 /***************************************************************************/
58 void LDMA_IRQHandler(void)
59 {
60  uint32_t ch;
61  /* Get all pending and enabled interrupts. */
62  uint32_t pending = LDMA_IntGetEnabled();
63 
64  /* Loop here on an LDMA error to enable debugging. */
65  while (pending & LDMA_IF_ERROR)
66  {
67  }
68 
69  /* Iterate over all LDMA channels. */
70  for (ch = 0; ch < DMA_CHAN_COUNT; ch++)
71  {
72  uint32_t mask = 0x1 << ch;
73  if (pending & mask)
74  {
75  /* Clear interrupt flag. */
76  LDMA->IFC = mask;
77 
78  /* Do more stuff here, execute callbacks etc. */
79  }
80  }
81 }
82 #endif
83 
84 /***************************************************************************/
90 void LDMA_DeInit(void)
91 {
92  NVIC_DisableIRQ(LDMA_IRQn);
93  LDMA->IEN = 0;
94  LDMA->CHEN = 0;
95  CMU_ClockEnable(cmuClock_LDMA, false);
96 }
97 
98 /***************************************************************************/
112 void LDMA_EnableChannelRequest(int ch, bool enable)
113 {
114  EFM_ASSERT(ch < DMA_CHAN_COUNT);
115 
116  BUS_RegBitWrite(&LDMA->REQDIS, ch, !enable);
117 }
118 
119 /***************************************************************************/
137 void LDMA_Init(const LDMA_Init_t *init)
138 {
139  EFM_ASSERT(init != NULL);
140  EFM_ASSERT(!((init->ldmaInitCtrlNumFixed << _LDMA_CTRL_NUMFIXED_SHIFT)
141  & ~_LDMA_CTRL_NUMFIXED_MASK));
142  EFM_ASSERT(!((init->ldmaInitCtrlSyncPrsClrEn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT)
143  & ~_LDMA_CTRL_SYNCPRSCLREN_MASK));
144  EFM_ASSERT(!((init->ldmaInitCtrlSyncPrsSetEn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT)
145  & ~_LDMA_CTRL_SYNCPRSSETEN_MASK));
146  EFM_ASSERT(init->ldmaInitIrqPriority < (1 << __NVIC_PRIO_BITS));
147 
148  CMU_ClockEnable(cmuClock_LDMA, true);
149 
150  LDMA->CTRL = (init->ldmaInitCtrlNumFixed << _LDMA_CTRL_NUMFIXED_SHIFT)
151  | (init->ldmaInitCtrlSyncPrsClrEn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT)
152  | (init->ldmaInitCtrlSyncPrsSetEn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT);
153 
154  LDMA->CHEN = 0;
155  LDMA->DBGHALT = 0;
156  LDMA->REQDIS = 0;
157 
158  /* Enable LDMA error interrupt. */
159  LDMA->IEN = LDMA_IEN_ERROR;
160  LDMA->IFC = 0xFFFFFFFF;
161 
162  NVIC_ClearPendingIRQ(LDMA_IRQn);
163 
164  /* Range is 0..7, 0 is highest priority. */
165  NVIC_SetPriority(LDMA_IRQn, init->ldmaInitIrqPriority);
166 
167  NVIC_EnableIRQ(LDMA_IRQn);
168 }
169 
170 /***************************************************************************/
183 void LDMA_StartTransfer(int ch,
184  const LDMA_TransferCfg_t *transfer,
185  const LDMA_Descriptor_t *descriptor)
186 {
187  uint32_t tmp;
189  uint32_t chMask = 1 << ch;
190 
191  EFM_ASSERT(ch < DMA_CHAN_COUNT);
192  EFM_ASSERT(transfer != NULL);
193  EFM_ASSERT(!(transfer->ldmaReqSel & ~_LDMA_CH_REQSEL_MASK));
194 
195  EFM_ASSERT(!((transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT)
196  & ~_LDMA_CTRL_SYNCPRSCLREN_MASK));
197  EFM_ASSERT(!((transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT)
198  & ~_LDMA_CTRL_SYNCPRSCLREN_MASK));
199  EFM_ASSERT(!((transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT)
200  & ~_LDMA_CTRL_SYNCPRSSETEN_MASK));
201  EFM_ASSERT(!((transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT)
202  & ~_LDMA_CTRL_SYNCPRSSETEN_MASK));
203 
204  EFM_ASSERT(!((transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT)
205  & ~_LDMA_CH_CFG_ARBSLOTS_MASK));
206  EFM_ASSERT(!((transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT)
207  & ~_LDMA_CH_CFG_SRCINCSIGN_MASK ) );
208  EFM_ASSERT(!((transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT)
209  & ~_LDMA_CH_CFG_DSTINCSIGN_MASK));
210  EFM_ASSERT(!((transfer->ldmaLoopCnt << _LDMA_CH_LOOP_LOOPCNT_SHIFT)
211  & ~_LDMA_CH_LOOP_LOOPCNT_MASK));
212 
213  LDMA->CH[ch].REQSEL = transfer->ldmaReqSel;
214  LDMA->CH[ch].LOOP = (transfer->ldmaLoopCnt << _LDMA_CH_LOOP_LOOPCNT_SHIFT);
215  LDMA->CH[ch].CFG = (transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT)
216  | (transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT)
217  | (transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT);
218 
219  /* Set descriptor address. */
220  LDMA->CH[ch].LINK = (uint32_t)descriptor & _LDMA_CH_LINK_LINKADDR_MASK;
221 
222  /* Clear pending channel interrupt. */
223  LDMA->IFC = chMask;
224 
225  /* Critical region. */
227 
228  /* Enable channel interrupt. */
229  LDMA->IEN |= chMask;
230 
231  if (transfer->ldmaReqDis)
232  {
233  LDMA->REQDIS |= chMask;
234  }
235 
236  if (transfer->ldmaDbgHalt)
237  {
238  LDMA->DBGHALT |= chMask;
239  }
240 
241  tmp = LDMA->CTRL;
242 
243  if (transfer->ldmaCtrlSyncPrsClrOff)
244  {
245  tmp &= ~_LDMA_CTRL_SYNCPRSCLREN_MASK
246  | (~transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT);
247  }
248 
249  if (transfer->ldmaCtrlSyncPrsClrOn)
250  {
251  tmp |= transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT;
252  }
253 
254  if (transfer->ldmaCtrlSyncPrsSetOff)
255  {
256  tmp &= ~_LDMA_CTRL_SYNCPRSSETEN_MASK
257  | (~transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT);
258  }
259 
260  if (transfer->ldmaCtrlSyncPrsSetOn)
261  {
262  tmp |= transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT;
263  }
264 
265  LDMA->CTRL = tmp;
266 
267  BUS_RegMaskedClear(&LDMA->CHDONE, chMask); /* Clear the done flag. */
268  LDMA->LINKLOAD = chMask; /* Start transfer by loading descriptor. */
269 
270  /* Critical region end. */
272 }
273 
274 /***************************************************************************/
284 void LDMA_StopTransfer(int ch)
285 {
286  uint32_t chMask = 1 << ch;
287 
288  EFM_ASSERT(ch < DMA_CHAN_COUNT);
289 
291  LDMA->IEN &= ~chMask;
292  BUS_RegMaskedClear(&LDMA->CHEN, chMask);
293  )
294 }
295 
296 /***************************************************************************/
306 bool LDMA_TransferDone(int ch)
307 {
308  bool retVal = false;
309  uint32_t chMask = 1 << ch;
310 
311  EFM_ASSERT(ch < DMA_CHAN_COUNT);
312 
314  if (((LDMA->CHEN & chMask) == 0)
315  && ((LDMA->CHDONE & chMask) == chMask))
316  {
317  retVal = true;
318  }
319  )
320  return retVal;
321 }
322 
323 /***************************************************************************/
338 uint32_t LDMA_TransferRemainingCount(int ch)
339 {
340  uint32_t remaining, done, iflag;
341  uint32_t chMask = 1 << ch;
342 
343  EFM_ASSERT(ch < DMA_CHAN_COUNT);
344 
346  iflag = LDMA->IF;
347  done = LDMA->CHDONE;
348  remaining = LDMA->CH[ch].CTRL;
349  )
350 
351  iflag &= chMask;
352  done &= chMask;
353  remaining = (remaining & _LDMA_CH_CTRL_XFERCNT_MASK)
354  >> _LDMA_CH_CTRL_XFERCNT_SHIFT;
355 
356  if (done || ((remaining == 0) && iflag))
357  {
358  return 0;
359  }
360 
361  return remaining + 1;
362 }
363 
366 #endif /* defined( LDMA_PRESENT ) && ( LDMA_COUNT == 1 ) */
Clock management unit (CMU) API.
#define CORE_DECLARE_IRQ_STATE
Definition: em_core.h:85
Emlib peripheral API "assert" implementation.
RAM and peripheral bit-field set and clear API.
#define __NVIC_PRIO_BITS
#define CORE_ENTER_ATOMIC()
Definition: em_core.h:138
#define CORE_ATOMIC_SECTION(yourcode)
Definition: em_core.h:126
Core interrupt handling API.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1453
#define CORE_EXIT_ATOMIC()
Definition: em_core.h:142
Direct memory access (LDMA) API.
#define DMA_CHAN_COUNT
__STATIC_INLINE void BUS_RegMaskedClear(volatile uint32_t *addr, uint32_t mask)
Perform a masked clear operation on peripheral register address.
Definition: em_bus.h:253
__STATIC_INLINE void BUS_RegBitWrite(volatile uint32_t *addr, unsigned int bit, unsigned int val)
Perform a single-bit write operation on a peripheral register.
Definition: em_bus.h:148