t
Fork of mbed-dev by
Diff: targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c
- Revision:
- 50:a417edff4437
- Parent:
- 0:9b334a45a8ff
- Child:
- 144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c Wed Jan 13 12:45:11 2016 +0000 +++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c Fri Jan 15 07:45:16 2016 +0000 @@ -30,10 +30,20 @@ #include <stdint.h> #include "dma_api_HAL.h" +#include "em_device.h" +#include "em_cmu.h" +#include "em_int.h" + +#ifdef DMA_PRESENT #include "em_dma.h" -#include "em_cmu.h" +#endif + +#ifdef LDMA_PRESENT +#include "em_ldma.h" +#endif /** DMA control block array, requires proper alignment. */ +#ifdef DMA_PRESENT #if defined (__ICCARM__) #pragma data_alignment=DMACTRL_ALIGNMENT DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMACTRL_CH_CNT * 2]; @@ -47,6 +57,7 @@ #else #error Undefined toolkit, need to define alignment #endif +#endif /* DMA_PRESENT */ uint32_t channels = 0; // Bit vector of taken channels bool enabled = false; @@ -54,15 +65,32 @@ void dma_init(void) { if (enabled) return; + +#if defined DMA_PRESENT + CMU_ClockEnable(cmuClock_DMA, true); + CMU_ClockEnable(cmuClock_HFPER, true); // FIXME: DMA is clocked via HFCORECLK, why HFPERCLK? + DMA_Init_TypeDef dmaInit; - CMU_ClockEnable(cmuClock_DMA, true); - CMU_ClockEnable(cmuClock_HFPER, true); - - /* Configure general DMA issues */ dmaInit.hprot = 0; dmaInit.controlBlock = dmaControlBlock; DMA_Init(&dmaInit); + +#elif defined LDMA_PRESENT + CMU_ClockEnable(cmuClock_LDMA, true); + + LDMA_Init_t ldmaInit; + + ldmaInit.ldmaInitCtrlNumFixed = 0; /* All channels round-robin */ + ldmaInit.ldmaInitCtrlSyncPrsClrEn = 0; /* Do not allow PRS to clear SYNCTRIG */ + ldmaInit.ldmaInitCtrlSyncPrsSetEn = 0; /* Do not allow PRS to set SYNCTRIG */ + ldmaInit.ldmaInitIrqPriority = 2; /* IRQ Priority */ + + LDMA_Init(&ldmaInit); +#else +#error "Unrecognized DMA peripheral" +#endif + enabled = true; } @@ -97,7 +125,87 @@ int dma_channel_free(int channelid) { - channels &= ~(1 << channelid); + if( channelid >= 0 ) { + channels &= ~(1 << channelid); + } + return 0; } +#ifdef LDMA_PRESENT + +/* LDMA emlib API extensions */ + +typedef struct { + LDMAx_CBFunc_t callback; + void *userdata; +} LDMA_InternCallback_t; + +static LDMA_InternCallback_t ldmaCallback[DMA_CHAN_COUNT]; + +void LDMAx_StartTransfer( int ch, + LDMA_TransferCfg_t *transfer, + LDMA_Descriptor_t *descriptor, + LDMAx_CBFunc_t cbFunc, + void *userData ) +{ + ldmaCallback[ch].callback = cbFunc; + ldmaCallback[ch].userdata = userData; + + LDMA_StartTransfer(ch, transfer, descriptor); +} + +void LDMA_IRQHandler( void ) +{ + uint32_t pending, chnum, chmask; + + /* Get all pending and enabled interrupts */ + pending = LDMA->IF; + pending &= LDMA->IEN; + + /* Check for LDMA error */ + if ( pending & LDMA_IF_ERROR ) + { + /* Loop here to enable the debugger to see what has happened */ + while (1) + ; + } + + /* Iterate over all LDMA channels. */ + for ( chnum = 0, chmask = 1; + chnum < DMA_CHAN_COUNT; + chnum++, chmask <<= 1 ) + { + if ( pending & chmask ) + { + /* Clear interrupt flag. */ + LDMA->IFC = chmask; + + /* Do more stuff here, execute callbacks etc. */ + if ( ldmaCallback[chnum].callback ) + { + ldmaCallback[chnum].callback(chnum, false, ldmaCallback[chnum].userdata); + } + } + } +} + +/***************************************************************************//** + * @brief + * Check if LDMA channel is enabled. + * + * @param[in] ch + * LDMA channel to check. + * + * @return + * true if channel is enabled, false if not. + ******************************************************************************/ +bool LDMAx_ChannelEnabled( int ch ) +{ + EFM_ASSERT(ch < DMA_CHAN_COUNT); + uint32_t chMask = 1 << ch; + return (bool)(LDMA->CHEN & chMask); + INT_Disable(); +} + +#endif /* LDMA_PRESENT */