ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
group-onsemi 0:098463de4c5d 1 /***************************************************************************//**
group-onsemi 0:098463de4c5d 2 * @file dma_api.c
group-onsemi 0:098463de4c5d 3 *******************************************************************************
group-onsemi 0:098463de4c5d 4 * @section License
group-onsemi 0:098463de4c5d 5 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
group-onsemi 0:098463de4c5d 6 *******************************************************************************
group-onsemi 0:098463de4c5d 7 *
group-onsemi 0:098463de4c5d 8 * SPDX-License-Identifier: Apache-2.0
group-onsemi 0:098463de4c5d 9 *
group-onsemi 0:098463de4c5d 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
group-onsemi 0:098463de4c5d 11 * not use this file except in compliance with the License.
group-onsemi 0:098463de4c5d 12 * You may obtain a copy of the License at
group-onsemi 0:098463de4c5d 13 *
group-onsemi 0:098463de4c5d 14 * http://www.apache.org/licenses/LICENSE-2.0
group-onsemi 0:098463de4c5d 15 *
group-onsemi 0:098463de4c5d 16 * Unless required by applicable law or agreed to in writing, software
group-onsemi 0:098463de4c5d 17 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
group-onsemi 0:098463de4c5d 18 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
group-onsemi 0:098463de4c5d 19 * See the License for the specific language governing permissions and
group-onsemi 0:098463de4c5d 20 * limitations under the License.
group-onsemi 0:098463de4c5d 21 *
group-onsemi 0:098463de4c5d 22 ******************************************************************************/
group-onsemi 0:098463de4c5d 23
group-onsemi 0:098463de4c5d 24 #include <stdint.h>
group-onsemi 0:098463de4c5d 25 #include "dma_api_HAL.h"
group-onsemi 0:098463de4c5d 26 #include "em_device.h"
group-onsemi 0:098463de4c5d 27 #include "em_cmu.h"
group-onsemi 0:098463de4c5d 28
group-onsemi 0:098463de4c5d 29 #ifdef DMA_PRESENT
group-onsemi 0:098463de4c5d 30 #include "em_dma.h"
group-onsemi 0:098463de4c5d 31 #endif
group-onsemi 0:098463de4c5d 32
group-onsemi 0:098463de4c5d 33 #ifdef LDMA_PRESENT
group-onsemi 0:098463de4c5d 34 #include "em_ldma.h"
group-onsemi 0:098463de4c5d 35 #endif
group-onsemi 0:098463de4c5d 36
group-onsemi 0:098463de4c5d 37 /** DMA control block array, requires proper alignment. */
group-onsemi 0:098463de4c5d 38 #ifdef DMA_PRESENT
group-onsemi 0:098463de4c5d 39 #if defined (__ICCARM__)
group-onsemi 0:098463de4c5d 40 #pragma data_alignment=DMACTRL_ALIGNMENT
group-onsemi 0:098463de4c5d 41 DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMACTRL_CH_CNT * 2];
group-onsemi 0:098463de4c5d 42
group-onsemi 0:098463de4c5d 43 #elif defined (__CC_ARM)
group-onsemi 0:098463de4c5d 44 DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMACTRL_CH_CNT * 2] __attribute__ ((aligned(DMACTRL_ALIGNMENT)));
group-onsemi 0:098463de4c5d 45
group-onsemi 0:098463de4c5d 46 #elif defined (__GNUC__)
group-onsemi 0:098463de4c5d 47 DMA_DESCRIPTOR_TypeDef dmaControlBlock[DMACTRL_CH_CNT * 2] __attribute__ ((aligned(DMACTRL_ALIGNMENT), section("dma")));
group-onsemi 0:098463de4c5d 48
group-onsemi 0:098463de4c5d 49 #else
group-onsemi 0:098463de4c5d 50 #error Undefined toolkit, need to define alignment
group-onsemi 0:098463de4c5d 51 #endif
group-onsemi 0:098463de4c5d 52 #endif /* DMA_PRESENT */
group-onsemi 0:098463de4c5d 53
group-onsemi 0:098463de4c5d 54 uint32_t channels = 0; // Bit vector of taken channels
group-onsemi 0:098463de4c5d 55 bool enabled = false;
group-onsemi 0:098463de4c5d 56
group-onsemi 0:098463de4c5d 57 void dma_init(void)
group-onsemi 0:098463de4c5d 58 {
group-onsemi 0:098463de4c5d 59 if (enabled) return;
group-onsemi 0:098463de4c5d 60
group-onsemi 0:098463de4c5d 61 #if defined DMA_PRESENT
group-onsemi 0:098463de4c5d 62 CMU_ClockEnable(cmuClock_DMA, true);
group-onsemi 0:098463de4c5d 63 CMU_ClockEnable(cmuClock_HFPER, true); // FIXME: DMA is clocked via HFCORECLK, why HFPERCLK?
group-onsemi 0:098463de4c5d 64
group-onsemi 0:098463de4c5d 65 DMA_Init_TypeDef dmaInit;
group-onsemi 0:098463de4c5d 66
group-onsemi 0:098463de4c5d 67 dmaInit.hprot = 0;
group-onsemi 0:098463de4c5d 68 dmaInit.controlBlock = dmaControlBlock;
group-onsemi 0:098463de4c5d 69 DMA_Init(&dmaInit);
group-onsemi 0:098463de4c5d 70
group-onsemi 0:098463de4c5d 71 #elif defined LDMA_PRESENT
group-onsemi 0:098463de4c5d 72 CMU_ClockEnable(cmuClock_LDMA, true);
group-onsemi 0:098463de4c5d 73
group-onsemi 0:098463de4c5d 74 LDMA_Init_t ldmaInit;
group-onsemi 0:098463de4c5d 75
group-onsemi 0:098463de4c5d 76 ldmaInit.ldmaInitCtrlNumFixed = 0; /* All channels round-robin */
group-onsemi 0:098463de4c5d 77 ldmaInit.ldmaInitCtrlSyncPrsClrEn = 0; /* Do not allow PRS to clear SYNCTRIG */
group-onsemi 0:098463de4c5d 78 ldmaInit.ldmaInitCtrlSyncPrsSetEn = 0; /* Do not allow PRS to set SYNCTRIG */
group-onsemi 0:098463de4c5d 79 ldmaInit.ldmaInitIrqPriority = 2; /* IRQ Priority */
group-onsemi 0:098463de4c5d 80
group-onsemi 0:098463de4c5d 81 LDMA_Init(&ldmaInit);
group-onsemi 0:098463de4c5d 82 #else
group-onsemi 0:098463de4c5d 83 #error "Unrecognized DMA peripheral"
group-onsemi 0:098463de4c5d 84 #endif
group-onsemi 0:098463de4c5d 85
group-onsemi 0:098463de4c5d 86 enabled = true;
group-onsemi 0:098463de4c5d 87 }
group-onsemi 0:098463de4c5d 88
group-onsemi 0:098463de4c5d 89 int dma_channel_allocate(uint32_t capabilities)
group-onsemi 0:098463de4c5d 90 {
group-onsemi 0:098463de4c5d 91 int i;
group-onsemi 0:098463de4c5d 92 // Check if 2d copy is required
group-onsemi 0:098463de4c5d 93 if (DMA_CAP_2DCOPY & capabilities) {
group-onsemi 0:098463de4c5d 94 if (channels & 1) {
group-onsemi 0:098463de4c5d 95 // Channel already in use
group-onsemi 0:098463de4c5d 96 return DMA_ERROR_OUT_OF_CHANNELS;
group-onsemi 0:098463de4c5d 97 } else {
group-onsemi 0:098463de4c5d 98 channels |= 1 << 0;
group-onsemi 0:098463de4c5d 99 return 0;
group-onsemi 0:098463de4c5d 100 }
group-onsemi 0:098463de4c5d 101 }
group-onsemi 0:098463de4c5d 102 for (i = 1; i < DMA_CHAN_COUNT; i++) {
group-onsemi 0:098463de4c5d 103 if ((channels & (1 << i)) == 0) {
group-onsemi 0:098463de4c5d 104 // Channel available
group-onsemi 0:098463de4c5d 105 channels |= 1 << i;
group-onsemi 0:098463de4c5d 106 return i;
group-onsemi 0:098463de4c5d 107 }
group-onsemi 0:098463de4c5d 108 }
group-onsemi 0:098463de4c5d 109 // Check if channel 0 is available
group-onsemi 0:098463de4c5d 110 if ((channels & 1 ) == 0) {
group-onsemi 0:098463de4c5d 111 channels |= 1 << 0;
group-onsemi 0:098463de4c5d 112 return 0;
group-onsemi 0:098463de4c5d 113 }
group-onsemi 0:098463de4c5d 114 // Couldn't find a channel.
group-onsemi 0:098463de4c5d 115 return DMA_ERROR_OUT_OF_CHANNELS;
group-onsemi 0:098463de4c5d 116 }
group-onsemi 0:098463de4c5d 117
group-onsemi 0:098463de4c5d 118 int dma_channel_free(int channelid)
group-onsemi 0:098463de4c5d 119 {
group-onsemi 0:098463de4c5d 120 if( channelid >= 0 ) {
group-onsemi 0:098463de4c5d 121 channels &= ~(1 << channelid);
group-onsemi 0:098463de4c5d 122 }
group-onsemi 0:098463de4c5d 123
group-onsemi 0:098463de4c5d 124 return 0;
group-onsemi 0:098463de4c5d 125 }
group-onsemi 0:098463de4c5d 126
group-onsemi 0:098463de4c5d 127 #ifdef LDMA_PRESENT
group-onsemi 0:098463de4c5d 128
group-onsemi 0:098463de4c5d 129 /* LDMA emlib API extensions */
group-onsemi 0:098463de4c5d 130
group-onsemi 0:098463de4c5d 131 typedef struct {
group-onsemi 0:098463de4c5d 132 LDMAx_CBFunc_t callback;
group-onsemi 0:098463de4c5d 133 void *userdata;
group-onsemi 0:098463de4c5d 134 } LDMA_InternCallback_t;
group-onsemi 0:098463de4c5d 135
group-onsemi 0:098463de4c5d 136 static LDMA_InternCallback_t ldmaCallback[DMA_CHAN_COUNT];
group-onsemi 0:098463de4c5d 137
group-onsemi 0:098463de4c5d 138 void LDMAx_StartTransfer( int ch,
group-onsemi 0:098463de4c5d 139 LDMA_TransferCfg_t *transfer,
group-onsemi 0:098463de4c5d 140 LDMA_Descriptor_t *descriptor,
group-onsemi 0:098463de4c5d 141 LDMAx_CBFunc_t cbFunc,
group-onsemi 0:098463de4c5d 142 void *userData )
group-onsemi 0:098463de4c5d 143 {
group-onsemi 0:098463de4c5d 144 ldmaCallback[ch].callback = cbFunc;
group-onsemi 0:098463de4c5d 145 ldmaCallback[ch].userdata = userData;
group-onsemi 0:098463de4c5d 146
group-onsemi 0:098463de4c5d 147 LDMA_StartTransfer(ch, transfer, descriptor);
group-onsemi 0:098463de4c5d 148 }
group-onsemi 0:098463de4c5d 149
group-onsemi 0:098463de4c5d 150 void LDMA_IRQHandler( void )
group-onsemi 0:098463de4c5d 151 {
group-onsemi 0:098463de4c5d 152 uint32_t pending, chnum, chmask;
group-onsemi 0:098463de4c5d 153
group-onsemi 0:098463de4c5d 154 /* Get all pending and enabled interrupts */
group-onsemi 0:098463de4c5d 155 pending = LDMA->IF;
group-onsemi 0:098463de4c5d 156 pending &= LDMA->IEN;
group-onsemi 0:098463de4c5d 157
group-onsemi 0:098463de4c5d 158 /* Check for LDMA error */
group-onsemi 0:098463de4c5d 159 if ( pending & LDMA_IF_ERROR )
group-onsemi 0:098463de4c5d 160 {
group-onsemi 0:098463de4c5d 161 /* Loop here to enable the debugger to see what has happened */
group-onsemi 0:098463de4c5d 162 while (1)
group-onsemi 0:098463de4c5d 163 ;
group-onsemi 0:098463de4c5d 164 }
group-onsemi 0:098463de4c5d 165
group-onsemi 0:098463de4c5d 166 /* Iterate over all LDMA channels. */
group-onsemi 0:098463de4c5d 167 for ( chnum = 0, chmask = 1;
group-onsemi 0:098463de4c5d 168 chnum < DMA_CHAN_COUNT;
group-onsemi 0:098463de4c5d 169 chnum++, chmask <<= 1 )
group-onsemi 0:098463de4c5d 170 {
group-onsemi 0:098463de4c5d 171 if ( pending & chmask )
group-onsemi 0:098463de4c5d 172 {
group-onsemi 0:098463de4c5d 173 /* Clear interrupt flag. */
group-onsemi 0:098463de4c5d 174 LDMA->IFC = chmask;
group-onsemi 0:098463de4c5d 175
group-onsemi 0:098463de4c5d 176 /* Do more stuff here, execute callbacks etc. */
group-onsemi 0:098463de4c5d 177 if ( ldmaCallback[chnum].callback )
group-onsemi 0:098463de4c5d 178 {
group-onsemi 0:098463de4c5d 179 ldmaCallback[chnum].callback(chnum, false, ldmaCallback[chnum].userdata);
group-onsemi 0:098463de4c5d 180 }
group-onsemi 0:098463de4c5d 181 }
group-onsemi 0:098463de4c5d 182 }
group-onsemi 0:098463de4c5d 183 }
group-onsemi 0:098463de4c5d 184
group-onsemi 0:098463de4c5d 185 /***************************************************************************//**
group-onsemi 0:098463de4c5d 186 * @brief
group-onsemi 0:098463de4c5d 187 * Check if LDMA channel is enabled.
group-onsemi 0:098463de4c5d 188 *
group-onsemi 0:098463de4c5d 189 * @param[in] ch
group-onsemi 0:098463de4c5d 190 * LDMA channel to check.
group-onsemi 0:098463de4c5d 191 *
group-onsemi 0:098463de4c5d 192 * @return
group-onsemi 0:098463de4c5d 193 * true if channel is enabled, false if not.
group-onsemi 0:098463de4c5d 194 ******************************************************************************/
group-onsemi 0:098463de4c5d 195 bool LDMAx_ChannelEnabled( int ch )
group-onsemi 0:098463de4c5d 196 {
group-onsemi 0:098463de4c5d 197 EFM_ASSERT(ch < DMA_CHAN_COUNT);
group-onsemi 0:098463de4c5d 198 uint32_t chMask = 1 << ch;
group-onsemi 0:098463de4c5d 199 return (bool)(LDMA->CHEN & chMask);
group-onsemi 0:098463de4c5d 200 }
group-onsemi 0:098463de4c5d 201
group-onsemi 0:098463de4c5d 202 #endif /* LDMA_PRESENT */