mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
Diff: targets/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c
- Revision:
- 149:156823d33999
- Parent:
- 144:ef7eb2e8f9f7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/dma_api.c Fri Oct 28 11:17:30 2016 +0100 @@ -0,0 +1,202 @@ +/***************************************************************************//** + * @file dma_api.c + ******************************************************************************* + * @section License + * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b> + ******************************************************************************* + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#include <stdint.h> +#include "dma_api_HAL.h" +#include "em_device.h" +#include "em_cmu.h" + +#ifdef DMA_PRESENT +#include "em_dma.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]; + +#elif defined (__CC_ARM) +DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMACTRL_CH_CNT * 2] __attribute__ ((aligned(DMACTRL_ALIGNMENT))); + +#elif defined (__GNUC__) +DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMACTRL_CH_CNT * 2] __attribute__ ((aligned(DMACTRL_ALIGNMENT), section("dma"))); + +#else +#error Undefined toolkit, need to define alignment +#endif +#endif /* DMA_PRESENT */ + +uint32_t channels = 0; // Bit vector of taken channels +bool enabled = false; + +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; + + 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; +} + +int dma_channel_allocate(uint32_t capabilities) +{ + int i; + // Check if 2d copy is required + if (DMA_CAP_2DCOPY & capabilities) { + if (channels & 1) { + // Channel already in use + return DMA_ERROR_OUT_OF_CHANNELS; + } else { + channels |= 1 << 0; + return 0; + } + } + for (i = 1; i < DMA_CHAN_COUNT; i++) { + if ((channels & (1 << i)) == 0) { + // Channel available + channels |= 1 << i; + return i; + } + } + // Check if channel 0 is available + if ((channels & 1 ) == 0) { + channels |= 1 << 0; + return 0; + } + // Couldn't find a channel. + return DMA_ERROR_OUT_OF_CHANNELS; +} + +int dma_channel_free(int 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); +} + +#endif /* LDMA_PRESENT */