EZR32 Leopard Gecko Software Documentation  ezr32lg-doc-4.2.1
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_int.h"
42 
43 /***************************************************************************/
48 /***************************************************************************/
205 #if defined( LDMA_IRQ_HANDLER_TEMPLATE )
206 /***************************************************************************/
210 void LDMA_IRQHandler( void )
211 {
212  uint32_t pending, chnum, chmask;
213 
214  /* Get all pending and enabled interrupts */
215  pending = LDMA->IF;
216  pending &= LDMA->IEN;
217 
218  /* Check for LDMA error */
219  if ( pending & LDMA_IF_ERROR )
220  {
221  /* Loop here to enable the debugger to see what has happened */
222  while (1)
223  ;
224  }
225 
226  /* Iterate over all LDMA channels. */
227  for ( chnum = 0, chmask = 1;
228  chnum < DMA_CHAN_COUNT;
229  chnum++, chmask <<= 1 )
230  {
231  if ( pending & chmask )
232  {
233  /* Clear interrupt flag. */
234  LDMA->IFC = chmask;
235 
236  /* Do more stuff here, execute callbacks etc. */
237  }
238  }
239 }
240 #endif
241 
242 /***************************************************************************/
248 void LDMA_DeInit( void )
249 {
250  NVIC_DisableIRQ( LDMA_IRQn );
251  LDMA->IEN = 0;
252  LDMA->CHEN = 0;
253  CMU_ClockEnable( cmuClock_LDMA, false );
254 }
255 
256 /***************************************************************************/
263 void LDMA_Init( LDMA_Init_t *init )
264 {
265  EFM_ASSERT( init != NULL );
266  EFM_ASSERT( !( ( init->ldmaInitCtrlNumFixed << _LDMA_CTRL_NUMFIXED_SHIFT )
267  & ~_LDMA_CTRL_NUMFIXED_MASK ) );
268  EFM_ASSERT( !( ( init->ldmaInitCtrlSyncPrsClrEn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT )
269  & ~_LDMA_CTRL_SYNCPRSCLREN_MASK ) );
270  EFM_ASSERT( !( ( init->ldmaInitCtrlSyncPrsSetEn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT )
271  & ~_LDMA_CTRL_SYNCPRSSETEN_MASK ) );
272  EFM_ASSERT( init->ldmaInitIrqPriority < ( 1 << __NVIC_PRIO_BITS ) );
273 
274  CMU_ClockEnable( cmuClock_LDMA, true );
275 
276  LDMA->CTRL = ( init->ldmaInitCtrlNumFixed << _LDMA_CTRL_NUMFIXED_SHIFT )
277  | ( init->ldmaInitCtrlSyncPrsClrEn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT )
278  | ( init->ldmaInitCtrlSyncPrsSetEn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT );
279 
280  LDMA->CHEN = 0;
281  LDMA->DBGHALT = 0;
282  LDMA->REQDIS = 0;
283 
284  /* Enable LDMA error interrupt. */
285  LDMA->IEN = LDMA_IEN_ERROR;
286  LDMA->IFC = 0xFFFFFFFF;
287 
288  NVIC_ClearPendingIRQ( LDMA_IRQn );
289 
290  /* Range is 0..7, 0 is highest priority. */
291  NVIC_SetPriority( LDMA_IRQn, init->ldmaInitIrqPriority );
292 
293  NVIC_EnableIRQ( LDMA_IRQn );
294 }
295 
296 /***************************************************************************/
309 void LDMA_StartTransfer( int ch,
310  LDMA_TransferCfg_t *transfer,
311  LDMA_Descriptor_t *descriptor )
312 {
313  uint32_t tmp;
314  uint32_t chMask = 1 << ch;
315 
316  EFM_ASSERT( ch < DMA_CHAN_COUNT );
317  EFM_ASSERT( transfer != NULL );
318  EFM_ASSERT( !( transfer->ldmaReqSel & ~_LDMA_CH_REQSEL_MASK ) );
319 
320  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT )
321  & ~_LDMA_CTRL_SYNCPRSCLREN_MASK ) );
322  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT )
323  & ~_LDMA_CTRL_SYNCPRSCLREN_MASK ) );
324  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT )
325  & ~_LDMA_CTRL_SYNCPRSSETEN_MASK ) );
326  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT )
327  & ~_LDMA_CTRL_SYNCPRSSETEN_MASK ) );
328 
329  EFM_ASSERT( !( ( transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT )
330  & ~_LDMA_CH_CFG_ARBSLOTS_MASK ) );
331  EFM_ASSERT( !( ( transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT )
332  & ~_LDMA_CH_CFG_SRCINCSIGN_MASK ) );
333  EFM_ASSERT( !( ( transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT )
334  & ~_LDMA_CH_CFG_DSTINCSIGN_MASK ) );
335  EFM_ASSERT( !( ( transfer->ldmaLoopCnt << _LDMA_CH_LOOP_LOOPCNT_SHIFT )
336  & ~_LDMA_CH_LOOP_LOOPCNT_MASK ) );
337 
338  LDMA->CH[ ch ].REQSEL = transfer->ldmaReqSel;
339 
340  LDMA->CH[ ch ].LOOP =
341  ( transfer->ldmaLoopCnt << _LDMA_CH_LOOP_LOOPCNT_SHIFT );
342 
343  LDMA->CH[ ch ].CFG =
344  ( transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT )
345  | ( transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT )
346  | ( transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT );
347 
348  /* Set descriptor address. */
349  LDMA->CH[ ch ].LINK = (uint32_t)descriptor & _LDMA_CH_LINK_LINKADDR_MASK;
350 
351  /* Clear pending channel interrupt. */
352  LDMA->IFC = chMask;
353 
354  /* Critical region. */
355  INT_Disable();
356 
357  /* Enable channel interrupt. */
358  LDMA->IEN |= chMask;
359 
360  if ( transfer->ldmaReqDis )
361  {
362  LDMA->REQDIS |= chMask;
363  }
364 
365  if ( transfer->ldmaDbgHalt )
366  {
367  LDMA->DBGHALT |= chMask;
368  }
369 
370  tmp = LDMA->CTRL;
371 
372  if ( transfer->ldmaCtrlSyncPrsClrOff )
373  {
374  tmp &= ~_LDMA_CTRL_SYNCPRSCLREN_MASK
375  | (~transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT);
376  }
377 
378  if ( transfer->ldmaCtrlSyncPrsClrOn )
379  {
380  tmp |= transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT;
381  }
382 
383  if ( transfer->ldmaCtrlSyncPrsSetOff )
384  {
385  tmp &= ~_LDMA_CTRL_SYNCPRSSETEN_MASK
386  | (~transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT);
387  }
388 
389  if ( transfer->ldmaCtrlSyncPrsSetOn )
390  {
391  tmp |= transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT;
392  }
393 
394  LDMA->CTRL = tmp;
395 
396  BUS_RegMaskedClear(&LDMA->CHDONE, chMask); /* Clear the done flag. */
397  LDMA->LINKLOAD = chMask; /* Enable descriptor load. */
398  BUS_RegMaskedSet(&LDMA->CHEN, chMask); /* Enable channel. */
399 
400  /* Critical region end. */
401  INT_Enable();
402 }
403 
404 /***************************************************************************/
414 void LDMA_StopTransfer( int ch )
415 {
416  uint32_t chMask = 1 << ch;
417 
418  EFM_ASSERT( ch < DMA_CHAN_COUNT );
419 
420  INT_Disable();
421 
422  LDMA->IEN &= ~chMask;
423  BUS_RegMaskedClear(&LDMA->CHEN, chMask);
424 
425  INT_Enable();
426 }
427 
428 /***************************************************************************/
438 bool LDMA_TransferDone( int ch )
439 {
440  bool retVal = false;
441  uint32_t chMask = 1 << ch;
442 
443  EFM_ASSERT( ch < DMA_CHAN_COUNT );
444 
445  INT_Disable();
446  if ( ( ( LDMA->CHEN & chMask ) == 0 )
447  && ( ( LDMA->CHDONE & chMask ) == chMask ) )
448  {
449  retVal = true;
450  }
451  INT_Enable();
452  return retVal;
453 }
454 
455 /***************************************************************************/
470 uint32_t LDMA_TransferRemainingCount( int ch )
471 {
472  uint32_t remaining, done, iflag;
473  uint32_t chMask = 1 << ch;
474 
475  EFM_ASSERT( ch < DMA_CHAN_COUNT );
476 
477  INT_Disable();
478  iflag = LDMA->IF;
479  done = LDMA->CHDONE;
480  remaining = LDMA->CH[ ch ].CTRL;
481  INT_Enable();
482 
483  iflag &= chMask;
484  done &= chMask;
485  remaining = ( remaining
486  & _LDMA_CH_CTRL_XFERCNT_MASK )
487  >> _LDMA_CH_CTRL_XFERCNT_SHIFT;
488 
489  if ( done || ( ( remaining == 0 ) && iflag ) )
490  {
491  return 0;
492  }
493 
494  return remaining + 1;
495 }
496 
499 #endif /* defined( LDMA_PRESENT ) && ( LDMA_COUNT == 1 ) */
Clock management unit (CMU) API.
Emlib peripheral API "assert" implementation.
RAM and peripheral bit-field set and clear API.
__STATIC_INLINE uint32_t INT_Enable(void)
Enable interrupts.
Definition: em_int.h:94
Interrupt enable/disable unit API.
#define DMA_CHAN_COUNT
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1369
__STATIC_INLINE void BUS_RegMaskedSet(volatile uint32_t *addr, uint32_t mask)
Perform a masked set operation on peripheral register address.
Definition: em_bus.h:219
Direct memory access (LDMA) API.
__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:251
#define __NVIC_PRIO_BITS
__STATIC_INLINE uint32_t INT_Disable(void)
Disable interrupts.
Definition: em_int.h:71