t
Fork of mbed-dev by
targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0P/drivers/dma/dma.c@15:a81a8d6c1dfe, 2015-11-04 (annotated)
- Committer:
- mbed_official
- Date:
- Wed Nov 04 16:30:11 2015 +0000
- Revision:
- 15:a81a8d6c1dfe
Synchronized with git revision 46af745ef4405614c3fa49abbd9a706a362ea514
Full URL: https://github.com/mbedmicro/mbed/commit/46af745ef4405614c3fa49abbd9a706a362ea514/
Renamed TARGET_SAM_CortexM0+ to TARGET_SAM_CortexM0P for compatiblity with online compiler
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbed_official | 15:a81a8d6c1dfe | 1 | /* |
mbed_official | 15:a81a8d6c1dfe | 2 | * \file |
mbed_official | 15:a81a8d6c1dfe | 3 | * |
mbed_official | 15:a81a8d6c1dfe | 4 | * \brief SAM Direct Memory Access Controller Driver |
mbed_official | 15:a81a8d6c1dfe | 5 | * |
mbed_official | 15:a81a8d6c1dfe | 6 | * Copyright (C) 2014-2015 Atmel Corporation. All rights reserved. |
mbed_official | 15:a81a8d6c1dfe | 7 | * |
mbed_official | 15:a81a8d6c1dfe | 8 | * \asf_license_start |
mbed_official | 15:a81a8d6c1dfe | 9 | * |
mbed_official | 15:a81a8d6c1dfe | 10 | * \page License |
mbed_official | 15:a81a8d6c1dfe | 11 | * |
mbed_official | 15:a81a8d6c1dfe | 12 | * Redistribution and use in source and binary forms, with or without |
mbed_official | 15:a81a8d6c1dfe | 13 | * modification, are permitted provided that the following conditions are met: |
mbed_official | 15:a81a8d6c1dfe | 14 | * |
mbed_official | 15:a81a8d6c1dfe | 15 | * 1. Redistributions of source code must retain the above copyright notice, |
mbed_official | 15:a81a8d6c1dfe | 16 | * this list of conditions and the following disclaimer. |
mbed_official | 15:a81a8d6c1dfe | 17 | * |
mbed_official | 15:a81a8d6c1dfe | 18 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
mbed_official | 15:a81a8d6c1dfe | 19 | * this list of conditions and the following disclaimer in the documentation |
mbed_official | 15:a81a8d6c1dfe | 20 | * and/or other materials provided with the distribution. |
mbed_official | 15:a81a8d6c1dfe | 21 | * |
mbed_official | 15:a81a8d6c1dfe | 22 | * 3. The name of Atmel may not be used to endorse or promote products derived |
mbed_official | 15:a81a8d6c1dfe | 23 | * from this software without specific prior written permission. |
mbed_official | 15:a81a8d6c1dfe | 24 | * |
mbed_official | 15:a81a8d6c1dfe | 25 | * 4. This software may only be redistributed and used in connection with an |
mbed_official | 15:a81a8d6c1dfe | 26 | * Atmel microcontroller product. |
mbed_official | 15:a81a8d6c1dfe | 27 | * |
mbed_official | 15:a81a8d6c1dfe | 28 | * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED |
mbed_official | 15:a81a8d6c1dfe | 29 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
mbed_official | 15:a81a8d6c1dfe | 30 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE |
mbed_official | 15:a81a8d6c1dfe | 31 | * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR |
mbed_official | 15:a81a8d6c1dfe | 32 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
mbed_official | 15:a81a8d6c1dfe | 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
mbed_official | 15:a81a8d6c1dfe | 34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
mbed_official | 15:a81a8d6c1dfe | 35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
mbed_official | 15:a81a8d6c1dfe | 36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
mbed_official | 15:a81a8d6c1dfe | 37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
mbed_official | 15:a81a8d6c1dfe | 38 | * POSSIBILITY OF SUCH DAMAGE. |
mbed_official | 15:a81a8d6c1dfe | 39 | * |
mbed_official | 15:a81a8d6c1dfe | 40 | * \asf_license_stop |
mbed_official | 15:a81a8d6c1dfe | 41 | * |
mbed_official | 15:a81a8d6c1dfe | 42 | */ |
mbed_official | 15:a81a8d6c1dfe | 43 | /* |
mbed_official | 15:a81a8d6c1dfe | 44 | * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> |
mbed_official | 15:a81a8d6c1dfe | 45 | */ |
mbed_official | 15:a81a8d6c1dfe | 46 | |
mbed_official | 15:a81a8d6c1dfe | 47 | #include <string.h> |
mbed_official | 15:a81a8d6c1dfe | 48 | #include "dma.h" |
mbed_official | 15:a81a8d6c1dfe | 49 | #include "clock.h" |
mbed_official | 15:a81a8d6c1dfe | 50 | #include "system_interrupt.h" |
mbed_official | 15:a81a8d6c1dfe | 51 | |
mbed_official | 15:a81a8d6c1dfe | 52 | struct _dma_module { |
mbed_official | 15:a81a8d6c1dfe | 53 | volatile bool _dma_init; |
mbed_official | 15:a81a8d6c1dfe | 54 | volatile uint32_t allocated_channels; |
mbed_official | 15:a81a8d6c1dfe | 55 | uint8_t free_channels; |
mbed_official | 15:a81a8d6c1dfe | 56 | }; |
mbed_official | 15:a81a8d6c1dfe | 57 | |
mbed_official | 15:a81a8d6c1dfe | 58 | struct _dma_module _dma_inst = { |
mbed_official | 15:a81a8d6c1dfe | 59 | ._dma_init = false, |
mbed_official | 15:a81a8d6c1dfe | 60 | .allocated_channels = 0, |
mbed_official | 15:a81a8d6c1dfe | 61 | .free_channels = CONF_MAX_USED_CHANNEL_NUM, |
mbed_official | 15:a81a8d6c1dfe | 62 | }; |
mbed_official | 15:a81a8d6c1dfe | 63 | |
mbed_official | 15:a81a8d6c1dfe | 64 | /** Maximum retry counter for resuming a job transfer. */ |
mbed_official | 15:a81a8d6c1dfe | 65 | #define MAX_JOB_RESUME_COUNT 10000 |
mbed_official | 15:a81a8d6c1dfe | 66 | |
mbed_official | 15:a81a8d6c1dfe | 67 | /** DMA channel mask. */ |
mbed_official | 15:a81a8d6c1dfe | 68 | #define DMA_CHANNEL_MASK (0x1f) |
mbed_official | 15:a81a8d6c1dfe | 69 | |
mbed_official | 15:a81a8d6c1dfe | 70 | COMPILER_ALIGNED(16) |
mbed_official | 15:a81a8d6c1dfe | 71 | DmacDescriptor descriptor_section[CONF_MAX_USED_CHANNEL_NUM] SECTION_DMAC_DESCRIPTOR; |
mbed_official | 15:a81a8d6c1dfe | 72 | |
mbed_official | 15:a81a8d6c1dfe | 73 | /** Initial write back memory section. */ |
mbed_official | 15:a81a8d6c1dfe | 74 | COMPILER_ALIGNED(16) |
mbed_official | 15:a81a8d6c1dfe | 75 | static DmacDescriptor _write_back_section[CONF_MAX_USED_CHANNEL_NUM] SECTION_DMAC_DESCRIPTOR; |
mbed_official | 15:a81a8d6c1dfe | 76 | |
mbed_official | 15:a81a8d6c1dfe | 77 | /** Internal DMA resource pool. */ |
mbed_official | 15:a81a8d6c1dfe | 78 | static struct dma_resource* _dma_active_resource[CONF_MAX_USED_CHANNEL_NUM]; |
mbed_official | 15:a81a8d6c1dfe | 79 | |
mbed_official | 15:a81a8d6c1dfe | 80 | /* DMA channel interrup flag. */ |
mbed_official | 15:a81a8d6c1dfe | 81 | uint8_t g_chan_interrupt_flag[CONF_MAX_USED_CHANNEL_NUM]= {0}; |
mbed_official | 15:a81a8d6c1dfe | 82 | |
mbed_official | 15:a81a8d6c1dfe | 83 | /** |
mbed_official | 15:a81a8d6c1dfe | 84 | * \brief Find a free channel for a DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 85 | * |
mbed_official | 15:a81a8d6c1dfe | 86 | * Find a channel for the requested DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 87 | * |
mbed_official | 15:a81a8d6c1dfe | 88 | * \return Status of channel allocation. |
mbed_official | 15:a81a8d6c1dfe | 89 | * \retval DMA_INVALID_CHANNEL No channel available |
mbed_official | 15:a81a8d6c1dfe | 90 | * \retval count Allocated channel for the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 91 | */ |
mbed_official | 15:a81a8d6c1dfe | 92 | static uint8_t _dma_find_first_free_channel_and_allocate(void) |
mbed_official | 15:a81a8d6c1dfe | 93 | { |
mbed_official | 15:a81a8d6c1dfe | 94 | uint8_t count; |
mbed_official | 15:a81a8d6c1dfe | 95 | uint32_t tmp; |
mbed_official | 15:a81a8d6c1dfe | 96 | bool allocated = false; |
mbed_official | 15:a81a8d6c1dfe | 97 | |
mbed_official | 15:a81a8d6c1dfe | 98 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 99 | |
mbed_official | 15:a81a8d6c1dfe | 100 | tmp = _dma_inst.allocated_channels; |
mbed_official | 15:a81a8d6c1dfe | 101 | |
mbed_official | 15:a81a8d6c1dfe | 102 | for (count = 0; count < CONF_MAX_USED_CHANNEL_NUM; ++count) { |
mbed_official | 15:a81a8d6c1dfe | 103 | if (!(tmp & 0x00000001)) { |
mbed_official | 15:a81a8d6c1dfe | 104 | /* If free channel found, set as allocated and return |
mbed_official | 15:a81a8d6c1dfe | 105 | *number */ |
mbed_official | 15:a81a8d6c1dfe | 106 | |
mbed_official | 15:a81a8d6c1dfe | 107 | _dma_inst.allocated_channels |= 1 << count; |
mbed_official | 15:a81a8d6c1dfe | 108 | _dma_inst.free_channels--; |
mbed_official | 15:a81a8d6c1dfe | 109 | allocated = true; |
mbed_official | 15:a81a8d6c1dfe | 110 | |
mbed_official | 15:a81a8d6c1dfe | 111 | break; |
mbed_official | 15:a81a8d6c1dfe | 112 | } |
mbed_official | 15:a81a8d6c1dfe | 113 | |
mbed_official | 15:a81a8d6c1dfe | 114 | tmp = tmp >> 1; |
mbed_official | 15:a81a8d6c1dfe | 115 | } |
mbed_official | 15:a81a8d6c1dfe | 116 | |
mbed_official | 15:a81a8d6c1dfe | 117 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 118 | |
mbed_official | 15:a81a8d6c1dfe | 119 | if (!allocated) { |
mbed_official | 15:a81a8d6c1dfe | 120 | return DMA_INVALID_CHANNEL; |
mbed_official | 15:a81a8d6c1dfe | 121 | } else { |
mbed_official | 15:a81a8d6c1dfe | 122 | return count; |
mbed_official | 15:a81a8d6c1dfe | 123 | } |
mbed_official | 15:a81a8d6c1dfe | 124 | } |
mbed_official | 15:a81a8d6c1dfe | 125 | |
mbed_official | 15:a81a8d6c1dfe | 126 | /** |
mbed_official | 15:a81a8d6c1dfe | 127 | * \brief Release an allocated DMA channel. |
mbed_official | 15:a81a8d6c1dfe | 128 | * |
mbed_official | 15:a81a8d6c1dfe | 129 | * \param[in] channel Channel id to be released |
mbed_official | 15:a81a8d6c1dfe | 130 | * |
mbed_official | 15:a81a8d6c1dfe | 131 | */ |
mbed_official | 15:a81a8d6c1dfe | 132 | static void _dma_release_channel(uint8_t channel) |
mbed_official | 15:a81a8d6c1dfe | 133 | { |
mbed_official | 15:a81a8d6c1dfe | 134 | _dma_inst.allocated_channels &= ~(1 << channel); |
mbed_official | 15:a81a8d6c1dfe | 135 | _dma_inst.free_channels++; |
mbed_official | 15:a81a8d6c1dfe | 136 | } |
mbed_official | 15:a81a8d6c1dfe | 137 | |
mbed_official | 15:a81a8d6c1dfe | 138 | /** |
mbed_official | 15:a81a8d6c1dfe | 139 | * \brief Configure the DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 140 | * |
mbed_official | 15:a81a8d6c1dfe | 141 | * \param[in] dma_resource Pointer to a DMA resource instance |
mbed_official | 15:a81a8d6c1dfe | 142 | * \param[out] resource_config Configurations of the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 143 | * |
mbed_official | 15:a81a8d6c1dfe | 144 | */ |
mbed_official | 15:a81a8d6c1dfe | 145 | static void _dma_set_config(struct dma_resource *resource, |
mbed_official | 15:a81a8d6c1dfe | 146 | struct dma_resource_config *resource_config) |
mbed_official | 15:a81a8d6c1dfe | 147 | { |
mbed_official | 15:a81a8d6c1dfe | 148 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 149 | Assert(resource_config); |
mbed_official | 15:a81a8d6c1dfe | 150 | uint32_t temp_CHCTRLB_reg; |
mbed_official | 15:a81a8d6c1dfe | 151 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 152 | |
mbed_official | 15:a81a8d6c1dfe | 153 | /** Select the DMA channel and clear software trigger */ |
mbed_official | 15:a81a8d6c1dfe | 154 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 155 | DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << resource->channel_id)); |
mbed_official | 15:a81a8d6c1dfe | 156 | |
mbed_official | 15:a81a8d6c1dfe | 157 | temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(resource_config->priority) | \ |
mbed_official | 15:a81a8d6c1dfe | 158 | DMAC_CHCTRLB_TRIGSRC(resource_config->peripheral_trigger) | \ |
mbed_official | 15:a81a8d6c1dfe | 159 | DMAC_CHCTRLB_TRIGACT(resource_config->trigger_action); |
mbed_official | 15:a81a8d6c1dfe | 160 | |
mbed_official | 15:a81a8d6c1dfe | 161 | |
mbed_official | 15:a81a8d6c1dfe | 162 | if(resource_config->event_config.input_action) { |
mbed_official | 15:a81a8d6c1dfe | 163 | temp_CHCTRLB_reg |= DMAC_CHCTRLB_EVIE | DMAC_CHCTRLB_EVACT( |
mbed_official | 15:a81a8d6c1dfe | 164 | resource_config->event_config.input_action); |
mbed_official | 15:a81a8d6c1dfe | 165 | } |
mbed_official | 15:a81a8d6c1dfe | 166 | |
mbed_official | 15:a81a8d6c1dfe | 167 | /** Enable event output, the event output selection is configured in |
mbed_official | 15:a81a8d6c1dfe | 168 | * each transfer descriptor */ |
mbed_official | 15:a81a8d6c1dfe | 169 | if (resource_config->event_config.event_output_enable) { |
mbed_official | 15:a81a8d6c1dfe | 170 | temp_CHCTRLB_reg |= DMAC_CHCTRLB_EVOE; |
mbed_official | 15:a81a8d6c1dfe | 171 | } |
mbed_official | 15:a81a8d6c1dfe | 172 | |
mbed_official | 15:a81a8d6c1dfe | 173 | /* Write config to CTRLB register */ |
mbed_official | 15:a81a8d6c1dfe | 174 | DMAC->CHCTRLB.reg = temp_CHCTRLB_reg; |
mbed_official | 15:a81a8d6c1dfe | 175 | |
mbed_official | 15:a81a8d6c1dfe | 176 | |
mbed_official | 15:a81a8d6c1dfe | 177 | |
mbed_official | 15:a81a8d6c1dfe | 178 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 179 | } |
mbed_official | 15:a81a8d6c1dfe | 180 | |
mbed_official | 15:a81a8d6c1dfe | 181 | /** |
mbed_official | 15:a81a8d6c1dfe | 182 | * \brief DMA interrupt service routine. |
mbed_official | 15:a81a8d6c1dfe | 183 | * |
mbed_official | 15:a81a8d6c1dfe | 184 | */ |
mbed_official | 15:a81a8d6c1dfe | 185 | void DMAC_Handler( void ) |
mbed_official | 15:a81a8d6c1dfe | 186 | { |
mbed_official | 15:a81a8d6c1dfe | 187 | uint8_t active_channel; |
mbed_official | 15:a81a8d6c1dfe | 188 | struct dma_resource *resource; |
mbed_official | 15:a81a8d6c1dfe | 189 | uint8_t isr; |
mbed_official | 15:a81a8d6c1dfe | 190 | uint32_t write_size; |
mbed_official | 15:a81a8d6c1dfe | 191 | uint32_t total_size; |
mbed_official | 15:a81a8d6c1dfe | 192 | |
mbed_official | 15:a81a8d6c1dfe | 193 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 194 | |
mbed_official | 15:a81a8d6c1dfe | 195 | /* Get Pending channel */ |
mbed_official | 15:a81a8d6c1dfe | 196 | active_channel = DMAC->INTPEND.reg & DMAC_INTPEND_ID_Msk; |
mbed_official | 15:a81a8d6c1dfe | 197 | |
mbed_official | 15:a81a8d6c1dfe | 198 | Assert(_dma_active_resource[active_channel]); |
mbed_official | 15:a81a8d6c1dfe | 199 | |
mbed_official | 15:a81a8d6c1dfe | 200 | /* Get active DMA resource based on channel */ |
mbed_official | 15:a81a8d6c1dfe | 201 | resource = _dma_active_resource[active_channel]; |
mbed_official | 15:a81a8d6c1dfe | 202 | |
mbed_official | 15:a81a8d6c1dfe | 203 | /* Select the active channel */ |
mbed_official | 15:a81a8d6c1dfe | 204 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 205 | isr = DMAC->CHINTFLAG.reg; |
mbed_official | 15:a81a8d6c1dfe | 206 | |
mbed_official | 15:a81a8d6c1dfe | 207 | /* Calculate block transfer size of the DMA transfer */ |
mbed_official | 15:a81a8d6c1dfe | 208 | total_size = descriptor_section[resource->channel_id].BTCNT.reg; |
mbed_official | 15:a81a8d6c1dfe | 209 | write_size = _write_back_section[resource->channel_id].BTCNT.reg; |
mbed_official | 15:a81a8d6c1dfe | 210 | resource->transfered_size = total_size - write_size; |
mbed_official | 15:a81a8d6c1dfe | 211 | |
mbed_official | 15:a81a8d6c1dfe | 212 | /* DMA channel interrupt handler */ |
mbed_official | 15:a81a8d6c1dfe | 213 | if (isr & DMAC_CHINTENCLR_TERR) { |
mbed_official | 15:a81a8d6c1dfe | 214 | /* Clear transfer error flag */ |
mbed_official | 15:a81a8d6c1dfe | 215 | DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR; |
mbed_official | 15:a81a8d6c1dfe | 216 | |
mbed_official | 15:a81a8d6c1dfe | 217 | /* Set I/O ERROR status */ |
mbed_official | 15:a81a8d6c1dfe | 218 | resource->job_status = STATUS_ERR_IO; |
mbed_official | 15:a81a8d6c1dfe | 219 | |
mbed_official | 15:a81a8d6c1dfe | 220 | /* Execute the callback function */ |
mbed_official | 15:a81a8d6c1dfe | 221 | if ((resource->callback_enable & (1<<DMA_CALLBACK_TRANSFER_ERROR)) && |
mbed_official | 15:a81a8d6c1dfe | 222 | (resource->callback[DMA_CALLBACK_TRANSFER_ERROR])) { |
mbed_official | 15:a81a8d6c1dfe | 223 | resource->callback[DMA_CALLBACK_TRANSFER_ERROR](resource); |
mbed_official | 15:a81a8d6c1dfe | 224 | } |
mbed_official | 15:a81a8d6c1dfe | 225 | } else if (isr & DMAC_CHINTENCLR_TCMPL) { |
mbed_official | 15:a81a8d6c1dfe | 226 | /* Clear the transfer complete flag */ |
mbed_official | 15:a81a8d6c1dfe | 227 | DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; |
mbed_official | 15:a81a8d6c1dfe | 228 | |
mbed_official | 15:a81a8d6c1dfe | 229 | /* Set job status */ |
mbed_official | 15:a81a8d6c1dfe | 230 | resource->job_status = STATUS_OK; |
mbed_official | 15:a81a8d6c1dfe | 231 | |
mbed_official | 15:a81a8d6c1dfe | 232 | /* Execute the callback function */ |
mbed_official | 15:a81a8d6c1dfe | 233 | if ((resource->callback_enable & (1 << DMA_CALLBACK_TRANSFER_DONE)) && |
mbed_official | 15:a81a8d6c1dfe | 234 | (resource->callback[DMA_CALLBACK_TRANSFER_DONE])) { |
mbed_official | 15:a81a8d6c1dfe | 235 | resource->callback[DMA_CALLBACK_TRANSFER_DONE](resource); |
mbed_official | 15:a81a8d6c1dfe | 236 | } |
mbed_official | 15:a81a8d6c1dfe | 237 | } else if (isr & DMAC_CHINTENCLR_SUSP) { |
mbed_official | 15:a81a8d6c1dfe | 238 | /* Clear channel suspend flag */ |
mbed_official | 15:a81a8d6c1dfe | 239 | DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP; |
mbed_official | 15:a81a8d6c1dfe | 240 | |
mbed_official | 15:a81a8d6c1dfe | 241 | /* Set job status */ |
mbed_official | 15:a81a8d6c1dfe | 242 | resource->job_status = STATUS_SUSPEND; |
mbed_official | 15:a81a8d6c1dfe | 243 | |
mbed_official | 15:a81a8d6c1dfe | 244 | /* Execute the callback function */ |
mbed_official | 15:a81a8d6c1dfe | 245 | if ((resource->callback_enable & (1 << DMA_CALLBACK_CHANNEL_SUSPEND)) && |
mbed_official | 15:a81a8d6c1dfe | 246 | (resource->callback[DMA_CALLBACK_CHANNEL_SUSPEND])) { |
mbed_official | 15:a81a8d6c1dfe | 247 | resource->callback[DMA_CALLBACK_CHANNEL_SUSPEND](resource); |
mbed_official | 15:a81a8d6c1dfe | 248 | } |
mbed_official | 15:a81a8d6c1dfe | 249 | } |
mbed_official | 15:a81a8d6c1dfe | 250 | |
mbed_official | 15:a81a8d6c1dfe | 251 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 252 | } |
mbed_official | 15:a81a8d6c1dfe | 253 | |
mbed_official | 15:a81a8d6c1dfe | 254 | /** |
mbed_official | 15:a81a8d6c1dfe | 255 | * \brief Initializes config with predefined default values. |
mbed_official | 15:a81a8d6c1dfe | 256 | * |
mbed_official | 15:a81a8d6c1dfe | 257 | * This function will initialize a given DMA configuration structure to |
mbed_official | 15:a81a8d6c1dfe | 258 | * a set of known default values. This function should be called on |
mbed_official | 15:a81a8d6c1dfe | 259 | * any new instance of the configuration structure before being |
mbed_official | 15:a81a8d6c1dfe | 260 | * modified by the user application. |
mbed_official | 15:a81a8d6c1dfe | 261 | * |
mbed_official | 15:a81a8d6c1dfe | 262 | * The default configuration is as follows: |
mbed_official | 15:a81a8d6c1dfe | 263 | * \li Software trigger is used as the transfer trigger |
mbed_official | 15:a81a8d6c1dfe | 264 | * \li Priority level 0 |
mbed_official | 15:a81a8d6c1dfe | 265 | * \li Only software/event trigger |
mbed_official | 15:a81a8d6c1dfe | 266 | * \li Requires a trigger for each transaction |
mbed_official | 15:a81a8d6c1dfe | 267 | * \li No event input /output |
mbed_official | 15:a81a8d6c1dfe | 268 | * \li DMA channel is disabled during sleep mode (if has the feature) |
mbed_official | 15:a81a8d6c1dfe | 269 | * \param[out] config Pointer to the configuration |
mbed_official | 15:a81a8d6c1dfe | 270 | * |
mbed_official | 15:a81a8d6c1dfe | 271 | */ |
mbed_official | 15:a81a8d6c1dfe | 272 | void dma_get_config_defaults(struct dma_resource_config *config) |
mbed_official | 15:a81a8d6c1dfe | 273 | { |
mbed_official | 15:a81a8d6c1dfe | 274 | Assert(config); |
mbed_official | 15:a81a8d6c1dfe | 275 | /* Set as priority 0 */ |
mbed_official | 15:a81a8d6c1dfe | 276 | config->priority = DMA_PRIORITY_LEVEL_0; |
mbed_official | 15:a81a8d6c1dfe | 277 | /* Only software/event trigger */ |
mbed_official | 15:a81a8d6c1dfe | 278 | config->peripheral_trigger = 0; |
mbed_official | 15:a81a8d6c1dfe | 279 | /* Transaction trigger */ |
mbed_official | 15:a81a8d6c1dfe | 280 | config->trigger_action = DMA_TRIGGER_ACTON_TRANSACTION; |
mbed_official | 15:a81a8d6c1dfe | 281 | |
mbed_official | 15:a81a8d6c1dfe | 282 | /* Event configurations, no event input/output */ |
mbed_official | 15:a81a8d6c1dfe | 283 | config->event_config.input_action = DMA_EVENT_INPUT_NOACT; |
mbed_official | 15:a81a8d6c1dfe | 284 | config->event_config.event_output_enable = false; |
mbed_official | 15:a81a8d6c1dfe | 285 | #ifdef FEATURE_DMA_CHANNEL_STANDBY |
mbed_official | 15:a81a8d6c1dfe | 286 | config->run_in_standby = false; |
mbed_official | 15:a81a8d6c1dfe | 287 | #endif |
mbed_official | 15:a81a8d6c1dfe | 288 | } |
mbed_official | 15:a81a8d6c1dfe | 289 | |
mbed_official | 15:a81a8d6c1dfe | 290 | /** |
mbed_official | 15:a81a8d6c1dfe | 291 | * \brief Allocate a DMA with configurations. |
mbed_official | 15:a81a8d6c1dfe | 292 | * |
mbed_official | 15:a81a8d6c1dfe | 293 | * This function will allocate a proper channel for a DMA transfer request. |
mbed_official | 15:a81a8d6c1dfe | 294 | * |
mbed_official | 15:a81a8d6c1dfe | 295 | * \param[in,out] dma_resource Pointer to a DMA resource instance |
mbed_official | 15:a81a8d6c1dfe | 296 | * \param[in] transfer_config Configurations of the DMA transfer |
mbed_official | 15:a81a8d6c1dfe | 297 | * |
mbed_official | 15:a81a8d6c1dfe | 298 | * \return Status of the allocation procedure. |
mbed_official | 15:a81a8d6c1dfe | 299 | * |
mbed_official | 15:a81a8d6c1dfe | 300 | * \retval STATUS_OK The DMA resource was allocated successfully |
mbed_official | 15:a81a8d6c1dfe | 301 | * \retval STATUS_ERR_NOT_FOUND DMA resource allocation failed |
mbed_official | 15:a81a8d6c1dfe | 302 | */ |
mbed_official | 15:a81a8d6c1dfe | 303 | enum status_code dma_allocate(struct dma_resource *resource, |
mbed_official | 15:a81a8d6c1dfe | 304 | struct dma_resource_config *config) |
mbed_official | 15:a81a8d6c1dfe | 305 | { |
mbed_official | 15:a81a8d6c1dfe | 306 | uint8_t new_channel; |
mbed_official | 15:a81a8d6c1dfe | 307 | |
mbed_official | 15:a81a8d6c1dfe | 308 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 309 | |
mbed_official | 15:a81a8d6c1dfe | 310 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 311 | |
mbed_official | 15:a81a8d6c1dfe | 312 | if (!_dma_inst._dma_init) { |
mbed_official | 15:a81a8d6c1dfe | 313 | /* Initialize clocks for DMA */ |
mbed_official | 15:a81a8d6c1dfe | 314 | #if (SAML21) || (SAMC20) || (SAMC21) |
mbed_official | 15:a81a8d6c1dfe | 315 | system_ahb_clock_set_mask(MCLK_AHBMASK_DMAC); |
mbed_official | 15:a81a8d6c1dfe | 316 | #else |
mbed_official | 15:a81a8d6c1dfe | 317 | system_ahb_clock_set_mask(PM_AHBMASK_DMAC); |
mbed_official | 15:a81a8d6c1dfe | 318 | system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBB, |
mbed_official | 15:a81a8d6c1dfe | 319 | PM_APBBMASK_DMAC); |
mbed_official | 15:a81a8d6c1dfe | 320 | #endif |
mbed_official | 15:a81a8d6c1dfe | 321 | |
mbed_official | 15:a81a8d6c1dfe | 322 | /* Perform a software reset before enable DMA controller */ |
mbed_official | 15:a81a8d6c1dfe | 323 | DMAC->CTRL.reg &= ~DMAC_CTRL_DMAENABLE; |
mbed_official | 15:a81a8d6c1dfe | 324 | DMAC->CTRL.reg = DMAC_CTRL_SWRST; |
mbed_official | 15:a81a8d6c1dfe | 325 | |
mbed_official | 15:a81a8d6c1dfe | 326 | /* Setup descriptor base address and write back section base |
mbed_official | 15:a81a8d6c1dfe | 327 | * address */ |
mbed_official | 15:a81a8d6c1dfe | 328 | DMAC->BASEADDR.reg = (uint32_t)descriptor_section; |
mbed_official | 15:a81a8d6c1dfe | 329 | DMAC->WRBADDR.reg = (uint32_t)_write_back_section; |
mbed_official | 15:a81a8d6c1dfe | 330 | |
mbed_official | 15:a81a8d6c1dfe | 331 | /* Enable all priority level at the same time */ |
mbed_official | 15:a81a8d6c1dfe | 332 | DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf); |
mbed_official | 15:a81a8d6c1dfe | 333 | |
mbed_official | 15:a81a8d6c1dfe | 334 | _dma_inst._dma_init = true; |
mbed_official | 15:a81a8d6c1dfe | 335 | } |
mbed_official | 15:a81a8d6c1dfe | 336 | |
mbed_official | 15:a81a8d6c1dfe | 337 | /* Find the proper channel */ |
mbed_official | 15:a81a8d6c1dfe | 338 | new_channel = _dma_find_first_free_channel_and_allocate(); |
mbed_official | 15:a81a8d6c1dfe | 339 | |
mbed_official | 15:a81a8d6c1dfe | 340 | /* If no channel available, return not found */ |
mbed_official | 15:a81a8d6c1dfe | 341 | if (new_channel == DMA_INVALID_CHANNEL) { |
mbed_official | 15:a81a8d6c1dfe | 342 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 343 | |
mbed_official | 15:a81a8d6c1dfe | 344 | return STATUS_ERR_NOT_FOUND; |
mbed_official | 15:a81a8d6c1dfe | 345 | } |
mbed_official | 15:a81a8d6c1dfe | 346 | |
mbed_official | 15:a81a8d6c1dfe | 347 | /* Set the channel */ |
mbed_official | 15:a81a8d6c1dfe | 348 | resource->channel_id = new_channel; |
mbed_official | 15:a81a8d6c1dfe | 349 | |
mbed_official | 15:a81a8d6c1dfe | 350 | /** Perform a reset for the allocated channel */ |
mbed_official | 15:a81a8d6c1dfe | 351 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 352 | DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE; |
mbed_official | 15:a81a8d6c1dfe | 353 | DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST; |
mbed_official | 15:a81a8d6c1dfe | 354 | |
mbed_official | 15:a81a8d6c1dfe | 355 | #ifdef FEATURE_DMA_CHANNEL_STANDBY |
mbed_official | 15:a81a8d6c1dfe | 356 | if(config->run_in_standby) { |
mbed_official | 15:a81a8d6c1dfe | 357 | DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_RUNSTDBY; |
mbed_official | 15:a81a8d6c1dfe | 358 | } |
mbed_official | 15:a81a8d6c1dfe | 359 | #endif |
mbed_official | 15:a81a8d6c1dfe | 360 | |
mbed_official | 15:a81a8d6c1dfe | 361 | /** Configure the DMA control,channel registers and descriptors here */ |
mbed_official | 15:a81a8d6c1dfe | 362 | _dma_set_config(resource, config); |
mbed_official | 15:a81a8d6c1dfe | 363 | |
mbed_official | 15:a81a8d6c1dfe | 364 | resource->descriptor = NULL; |
mbed_official | 15:a81a8d6c1dfe | 365 | |
mbed_official | 15:a81a8d6c1dfe | 366 | /* Log the DMA resource into the internal DMA resource pool */ |
mbed_official | 15:a81a8d6c1dfe | 367 | _dma_active_resource[resource->channel_id] = resource; |
mbed_official | 15:a81a8d6c1dfe | 368 | |
mbed_official | 15:a81a8d6c1dfe | 369 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 370 | |
mbed_official | 15:a81a8d6c1dfe | 371 | return STATUS_OK; |
mbed_official | 15:a81a8d6c1dfe | 372 | } |
mbed_official | 15:a81a8d6c1dfe | 373 | |
mbed_official | 15:a81a8d6c1dfe | 374 | /** |
mbed_official | 15:a81a8d6c1dfe | 375 | * \brief Free an allocated DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 376 | * |
mbed_official | 15:a81a8d6c1dfe | 377 | * This function will free an allocated DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 378 | * |
mbed_official | 15:a81a8d6c1dfe | 379 | * \param[in,out] resource Pointer to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 380 | * |
mbed_official | 15:a81a8d6c1dfe | 381 | * \return Status of the free procedure. |
mbed_official | 15:a81a8d6c1dfe | 382 | * |
mbed_official | 15:a81a8d6c1dfe | 383 | * \retval STATUS_OK The DMA resource was freed successfully |
mbed_official | 15:a81a8d6c1dfe | 384 | * \retval STATUS_BUSY The DMA resource was busy and can't be freed |
mbed_official | 15:a81a8d6c1dfe | 385 | * \retval STATUS_ERR_NOT_INITIALIZED DMA resource was not initialized |
mbed_official | 15:a81a8d6c1dfe | 386 | */ |
mbed_official | 15:a81a8d6c1dfe | 387 | enum status_code dma_free(struct dma_resource *resource) |
mbed_official | 15:a81a8d6c1dfe | 388 | { |
mbed_official | 15:a81a8d6c1dfe | 389 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 390 | Assert(resource->channel_id != DMA_INVALID_CHANNEL); |
mbed_official | 15:a81a8d6c1dfe | 391 | |
mbed_official | 15:a81a8d6c1dfe | 392 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 393 | |
mbed_official | 15:a81a8d6c1dfe | 394 | /* Check if channel is busy */ |
mbed_official | 15:a81a8d6c1dfe | 395 | if (dma_is_busy(resource)) { |
mbed_official | 15:a81a8d6c1dfe | 396 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 397 | return STATUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 398 | } |
mbed_official | 15:a81a8d6c1dfe | 399 | |
mbed_official | 15:a81a8d6c1dfe | 400 | /* Check if DMA resource was not allocated */ |
mbed_official | 15:a81a8d6c1dfe | 401 | if (!(_dma_inst.allocated_channels & (1 << resource->channel_id))) { |
mbed_official | 15:a81a8d6c1dfe | 402 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 403 | return STATUS_ERR_NOT_INITIALIZED; |
mbed_official | 15:a81a8d6c1dfe | 404 | } |
mbed_official | 15:a81a8d6c1dfe | 405 | |
mbed_official | 15:a81a8d6c1dfe | 406 | /* Release the DMA resource */ |
mbed_official | 15:a81a8d6c1dfe | 407 | _dma_release_channel(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 408 | |
mbed_official | 15:a81a8d6c1dfe | 409 | /* Reset the item in the DMA resource pool */ |
mbed_official | 15:a81a8d6c1dfe | 410 | _dma_active_resource[resource->channel_id] = NULL; |
mbed_official | 15:a81a8d6c1dfe | 411 | |
mbed_official | 15:a81a8d6c1dfe | 412 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 413 | |
mbed_official | 15:a81a8d6c1dfe | 414 | return STATUS_OK; |
mbed_official | 15:a81a8d6c1dfe | 415 | } |
mbed_official | 15:a81a8d6c1dfe | 416 | |
mbed_official | 15:a81a8d6c1dfe | 417 | /** |
mbed_official | 15:a81a8d6c1dfe | 418 | * \brief Start a DMA transfer. |
mbed_official | 15:a81a8d6c1dfe | 419 | * |
mbed_official | 15:a81a8d6c1dfe | 420 | * This function will start a DMA transfer through an allocated DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 421 | * |
mbed_official | 15:a81a8d6c1dfe | 422 | * \param[in,out] resource Pointer to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 423 | * |
mbed_official | 15:a81a8d6c1dfe | 424 | * \return Status of the transfer start procedure. |
mbed_official | 15:a81a8d6c1dfe | 425 | * |
mbed_official | 15:a81a8d6c1dfe | 426 | * \retval STATUS_OK The transfer was started successfully |
mbed_official | 15:a81a8d6c1dfe | 427 | * \retval STATUS_BUSY The DMA resource was busy and the transfer was not started |
mbed_official | 15:a81a8d6c1dfe | 428 | * \retval STATUS_ERR_INVALID_ARG Transfer size is 0 and transfer was not started |
mbed_official | 15:a81a8d6c1dfe | 429 | */ |
mbed_official | 15:a81a8d6c1dfe | 430 | enum status_code dma_start_transfer_job(struct dma_resource *resource) |
mbed_official | 15:a81a8d6c1dfe | 431 | { |
mbed_official | 15:a81a8d6c1dfe | 432 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 433 | Assert(resource->channel_id != DMA_INVALID_CHANNEL); |
mbed_official | 15:a81a8d6c1dfe | 434 | |
mbed_official | 15:a81a8d6c1dfe | 435 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 436 | |
mbed_official | 15:a81a8d6c1dfe | 437 | /* Check if resource was busy */ |
mbed_official | 15:a81a8d6c1dfe | 438 | if (resource->job_status == STATUS_BUSY) { |
mbed_official | 15:a81a8d6c1dfe | 439 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 440 | return STATUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 441 | } |
mbed_official | 15:a81a8d6c1dfe | 442 | |
mbed_official | 15:a81a8d6c1dfe | 443 | /* Check if transfer size is valid */ |
mbed_official | 15:a81a8d6c1dfe | 444 | if (resource->descriptor->BTCNT.reg == 0) { |
mbed_official | 15:a81a8d6c1dfe | 445 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 446 | return STATUS_ERR_INVALID_ARG; |
mbed_official | 15:a81a8d6c1dfe | 447 | } |
mbed_official | 15:a81a8d6c1dfe | 448 | |
mbed_official | 15:a81a8d6c1dfe | 449 | /* Enable DMA interrupt */ |
mbed_official | 15:a81a8d6c1dfe | 450 | system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_DMA); |
mbed_official | 15:a81a8d6c1dfe | 451 | |
mbed_official | 15:a81a8d6c1dfe | 452 | /* Set the interrupt flag */ |
mbed_official | 15:a81a8d6c1dfe | 453 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 454 | DMAC->CHINTENSET.reg = (DMAC_CHINTENSET_MASK & g_chan_interrupt_flag[resource->channel_id]); |
mbed_official | 15:a81a8d6c1dfe | 455 | /* Set job status */ |
mbed_official | 15:a81a8d6c1dfe | 456 | resource->job_status = STATUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 457 | |
mbed_official | 15:a81a8d6c1dfe | 458 | /* Set channel x descriptor 0 to the descriptor base address */ |
mbed_official | 15:a81a8d6c1dfe | 459 | memcpy(&descriptor_section[resource->channel_id], resource->descriptor, |
mbed_official | 15:a81a8d6c1dfe | 460 | sizeof(DmacDescriptor)); |
mbed_official | 15:a81a8d6c1dfe | 461 | |
mbed_official | 15:a81a8d6c1dfe | 462 | /* Enable the transfer channel */ |
mbed_official | 15:a81a8d6c1dfe | 463 | DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; |
mbed_official | 15:a81a8d6c1dfe | 464 | |
mbed_official | 15:a81a8d6c1dfe | 465 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 466 | |
mbed_official | 15:a81a8d6c1dfe | 467 | return STATUS_OK; |
mbed_official | 15:a81a8d6c1dfe | 468 | } |
mbed_official | 15:a81a8d6c1dfe | 469 | |
mbed_official | 15:a81a8d6c1dfe | 470 | /** |
mbed_official | 15:a81a8d6c1dfe | 471 | * \brief Abort a DMA transfer. |
mbed_official | 15:a81a8d6c1dfe | 472 | * |
mbed_official | 15:a81a8d6c1dfe | 473 | * This function will abort a DMA transfer. The DMA channel used for the DMA |
mbed_official | 15:a81a8d6c1dfe | 474 | * resource will be disabled. |
mbed_official | 15:a81a8d6c1dfe | 475 | * The block transfer count will be also calculated and written to the DMA |
mbed_official | 15:a81a8d6c1dfe | 476 | * resource structure. |
mbed_official | 15:a81a8d6c1dfe | 477 | * |
mbed_official | 15:a81a8d6c1dfe | 478 | * \note The DMA resource will not be freed after calling this function. |
mbed_official | 15:a81a8d6c1dfe | 479 | * The function \ref dma_free() can be used to free an allocated resource. |
mbed_official | 15:a81a8d6c1dfe | 480 | * |
mbed_official | 15:a81a8d6c1dfe | 481 | * \param[in,out] resource Pointer to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 482 | * |
mbed_official | 15:a81a8d6c1dfe | 483 | */ |
mbed_official | 15:a81a8d6c1dfe | 484 | void dma_abort_job(struct dma_resource *resource) |
mbed_official | 15:a81a8d6c1dfe | 485 | { |
mbed_official | 15:a81a8d6c1dfe | 486 | uint32_t write_size; |
mbed_official | 15:a81a8d6c1dfe | 487 | uint32_t total_size; |
mbed_official | 15:a81a8d6c1dfe | 488 | |
mbed_official | 15:a81a8d6c1dfe | 489 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 490 | Assert(resource->channel_id != DMA_INVALID_CHANNEL); |
mbed_official | 15:a81a8d6c1dfe | 491 | |
mbed_official | 15:a81a8d6c1dfe | 492 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 493 | |
mbed_official | 15:a81a8d6c1dfe | 494 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 495 | DMAC->CHCTRLA.reg = 0; |
mbed_official | 15:a81a8d6c1dfe | 496 | |
mbed_official | 15:a81a8d6c1dfe | 497 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 498 | |
mbed_official | 15:a81a8d6c1dfe | 499 | /* Get transferred size */ |
mbed_official | 15:a81a8d6c1dfe | 500 | total_size = descriptor_section[resource->channel_id].BTCNT.reg; |
mbed_official | 15:a81a8d6c1dfe | 501 | write_size = _write_back_section[resource->channel_id].BTCNT.reg; |
mbed_official | 15:a81a8d6c1dfe | 502 | resource->transfered_size = total_size - write_size; |
mbed_official | 15:a81a8d6c1dfe | 503 | |
mbed_official | 15:a81a8d6c1dfe | 504 | resource->job_status = STATUS_ABORTED; |
mbed_official | 15:a81a8d6c1dfe | 505 | } |
mbed_official | 15:a81a8d6c1dfe | 506 | |
mbed_official | 15:a81a8d6c1dfe | 507 | /** |
mbed_official | 15:a81a8d6c1dfe | 508 | * \brief Suspend a DMA transfer. |
mbed_official | 15:a81a8d6c1dfe | 509 | * |
mbed_official | 15:a81a8d6c1dfe | 510 | * This function will request to suspend the transfer of the DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 511 | * The channel is kept enabled, can receive transfer triggers (the transfer |
mbed_official | 15:a81a8d6c1dfe | 512 | * pending bit will be set), but will be removed from the arbitration scheme. |
mbed_official | 15:a81a8d6c1dfe | 513 | * The channel operation can be resumed by calling \ref dma_resume_job(). |
mbed_official | 15:a81a8d6c1dfe | 514 | * |
mbed_official | 15:a81a8d6c1dfe | 515 | * \note This function sets the command to suspend the DMA channel |
mbed_official | 15:a81a8d6c1dfe | 516 | * associated with a DMA resource. The channel suspend interrupt flag |
mbed_official | 15:a81a8d6c1dfe | 517 | * indicates whether the transfer is truly suspended. |
mbed_official | 15:a81a8d6c1dfe | 518 | * |
mbed_official | 15:a81a8d6c1dfe | 519 | * \param[in] resource Pointer to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 520 | * |
mbed_official | 15:a81a8d6c1dfe | 521 | */ |
mbed_official | 15:a81a8d6c1dfe | 522 | void dma_suspend_job(struct dma_resource *resource) |
mbed_official | 15:a81a8d6c1dfe | 523 | { |
mbed_official | 15:a81a8d6c1dfe | 524 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 525 | Assert(resource->channel_id != DMA_INVALID_CHANNEL); |
mbed_official | 15:a81a8d6c1dfe | 526 | |
mbed_official | 15:a81a8d6c1dfe | 527 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 528 | |
mbed_official | 15:a81a8d6c1dfe | 529 | /* Select the channel */ |
mbed_official | 15:a81a8d6c1dfe | 530 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 531 | |
mbed_official | 15:a81a8d6c1dfe | 532 | /* Send the suspend request */ |
mbed_official | 15:a81a8d6c1dfe | 533 | DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_SUSPEND; |
mbed_official | 15:a81a8d6c1dfe | 534 | |
mbed_official | 15:a81a8d6c1dfe | 535 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 536 | } |
mbed_official | 15:a81a8d6c1dfe | 537 | |
mbed_official | 15:a81a8d6c1dfe | 538 | /** |
mbed_official | 15:a81a8d6c1dfe | 539 | * \brief Resume a suspended DMA transfer. |
mbed_official | 15:a81a8d6c1dfe | 540 | * |
mbed_official | 15:a81a8d6c1dfe | 541 | * This function try to resume a suspended transfer of a DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 542 | * |
mbed_official | 15:a81a8d6c1dfe | 543 | * \param[in] resource Pointer to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 544 | * |
mbed_official | 15:a81a8d6c1dfe | 545 | */ |
mbed_official | 15:a81a8d6c1dfe | 546 | void dma_resume_job(struct dma_resource *resource) |
mbed_official | 15:a81a8d6c1dfe | 547 | { |
mbed_official | 15:a81a8d6c1dfe | 548 | uint32_t bitmap_channel; |
mbed_official | 15:a81a8d6c1dfe | 549 | uint32_t count = 0; |
mbed_official | 15:a81a8d6c1dfe | 550 | |
mbed_official | 15:a81a8d6c1dfe | 551 | Assert(resource); |
mbed_official | 15:a81a8d6c1dfe | 552 | Assert(resource->channel_id != DMA_INVALID_CHANNEL); |
mbed_official | 15:a81a8d6c1dfe | 553 | |
mbed_official | 15:a81a8d6c1dfe | 554 | /* Get bitmap of the allocated DMA channel */ |
mbed_official | 15:a81a8d6c1dfe | 555 | bitmap_channel = (1 << resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 556 | |
mbed_official | 15:a81a8d6c1dfe | 557 | /* Check if channel was suspended */ |
mbed_official | 15:a81a8d6c1dfe | 558 | if (resource->job_status != STATUS_SUSPEND) { |
mbed_official | 15:a81a8d6c1dfe | 559 | return; |
mbed_official | 15:a81a8d6c1dfe | 560 | } |
mbed_official | 15:a81a8d6c1dfe | 561 | |
mbed_official | 15:a81a8d6c1dfe | 562 | system_interrupt_enter_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 563 | |
mbed_official | 15:a81a8d6c1dfe | 564 | /* Send resume request */ |
mbed_official | 15:a81a8d6c1dfe | 565 | DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id); |
mbed_official | 15:a81a8d6c1dfe | 566 | DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_RESUME; |
mbed_official | 15:a81a8d6c1dfe | 567 | |
mbed_official | 15:a81a8d6c1dfe | 568 | system_interrupt_leave_critical_section(); |
mbed_official | 15:a81a8d6c1dfe | 569 | |
mbed_official | 15:a81a8d6c1dfe | 570 | /* Check if transfer job resumed */ |
mbed_official | 15:a81a8d6c1dfe | 571 | for (count = 0; count < MAX_JOB_RESUME_COUNT; count++) { |
mbed_official | 15:a81a8d6c1dfe | 572 | if ((DMAC->BUSYCH.reg & bitmap_channel) == bitmap_channel) { |
mbed_official | 15:a81a8d6c1dfe | 573 | break; |
mbed_official | 15:a81a8d6c1dfe | 574 | } |
mbed_official | 15:a81a8d6c1dfe | 575 | } |
mbed_official | 15:a81a8d6c1dfe | 576 | |
mbed_official | 15:a81a8d6c1dfe | 577 | if (count < MAX_JOB_RESUME_COUNT) { |
mbed_official | 15:a81a8d6c1dfe | 578 | /* Job resumed */ |
mbed_official | 15:a81a8d6c1dfe | 579 | resource->job_status = STATUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 580 | } else { |
mbed_official | 15:a81a8d6c1dfe | 581 | /* Job resume timeout */ |
mbed_official | 15:a81a8d6c1dfe | 582 | resource->job_status = STATUS_ERR_TIMEOUT; |
mbed_official | 15:a81a8d6c1dfe | 583 | } |
mbed_official | 15:a81a8d6c1dfe | 584 | } |
mbed_official | 15:a81a8d6c1dfe | 585 | |
mbed_official | 15:a81a8d6c1dfe | 586 | /** |
mbed_official | 15:a81a8d6c1dfe | 587 | * \brief Create a DMA transfer descriptor with configurations. |
mbed_official | 15:a81a8d6c1dfe | 588 | * |
mbed_official | 15:a81a8d6c1dfe | 589 | * This function will set the transfer configurations to the DMA transfer |
mbed_official | 15:a81a8d6c1dfe | 590 | * descriptor. |
mbed_official | 15:a81a8d6c1dfe | 591 | * |
mbed_official | 15:a81a8d6c1dfe | 592 | * \param[in] descriptor Pointer to the DMA transfer descriptor |
mbed_official | 15:a81a8d6c1dfe | 593 | * \param[in] config Pointer to the descriptor configuration structure |
mbed_official | 15:a81a8d6c1dfe | 594 | * |
mbed_official | 15:a81a8d6c1dfe | 595 | */ |
mbed_official | 15:a81a8d6c1dfe | 596 | void dma_descriptor_create(DmacDescriptor* descriptor, |
mbed_official | 15:a81a8d6c1dfe | 597 | struct dma_descriptor_config *config) |
mbed_official | 15:a81a8d6c1dfe | 598 | { |
mbed_official | 15:a81a8d6c1dfe | 599 | /* Set block transfer control */ |
mbed_official | 15:a81a8d6c1dfe | 600 | descriptor->BTCTRL.bit.VALID = config->descriptor_valid; |
mbed_official | 15:a81a8d6c1dfe | 601 | descriptor->BTCTRL.bit.EVOSEL = config->event_output_selection; |
mbed_official | 15:a81a8d6c1dfe | 602 | descriptor->BTCTRL.bit.BLOCKACT = config->block_action; |
mbed_official | 15:a81a8d6c1dfe | 603 | descriptor->BTCTRL.bit.BEATSIZE = config->beat_size; |
mbed_official | 15:a81a8d6c1dfe | 604 | descriptor->BTCTRL.bit.SRCINC = config->src_increment_enable; |
mbed_official | 15:a81a8d6c1dfe | 605 | descriptor->BTCTRL.bit.DSTINC = config->dst_increment_enable; |
mbed_official | 15:a81a8d6c1dfe | 606 | descriptor->BTCTRL.bit.STEPSEL = config->step_selection; |
mbed_official | 15:a81a8d6c1dfe | 607 | descriptor->BTCTRL.bit.STEPSIZE = config->step_size; |
mbed_official | 15:a81a8d6c1dfe | 608 | |
mbed_official | 15:a81a8d6c1dfe | 609 | /* Set transfer size, source address and destination address */ |
mbed_official | 15:a81a8d6c1dfe | 610 | descriptor->BTCNT.reg = config->block_transfer_count; |
mbed_official | 15:a81a8d6c1dfe | 611 | descriptor->SRCADDR.reg = config->source_address; |
mbed_official | 15:a81a8d6c1dfe | 612 | descriptor->DSTADDR.reg = config->destination_address; |
mbed_official | 15:a81a8d6c1dfe | 613 | |
mbed_official | 15:a81a8d6c1dfe | 614 | /* Set next transfer descriptor address */ |
mbed_official | 15:a81a8d6c1dfe | 615 | descriptor->DESCADDR.reg = config->next_descriptor_address; |
mbed_official | 15:a81a8d6c1dfe | 616 | } |
mbed_official | 15:a81a8d6c1dfe | 617 | |
mbed_official | 15:a81a8d6c1dfe | 618 | /** |
mbed_official | 15:a81a8d6c1dfe | 619 | * \brief Add a DMA transfer descriptor to a DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 620 | * |
mbed_official | 15:a81a8d6c1dfe | 621 | * This function will add a DMA transfer descriptor to a DMA resource. |
mbed_official | 15:a81a8d6c1dfe | 622 | * If there was a transfer descriptor already allocated to the DMA resource, |
mbed_official | 15:a81a8d6c1dfe | 623 | * the descriptor will be linked to the next descriptor address. |
mbed_official | 15:a81a8d6c1dfe | 624 | * |
mbed_official | 15:a81a8d6c1dfe | 625 | * \param[in] resource Pointer to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 626 | * \param[in] descriptor Pointer to the transfer descriptor |
mbed_official | 15:a81a8d6c1dfe | 627 | * |
mbed_official | 15:a81a8d6c1dfe | 628 | * \retval STATUS_OK The descriptor is added to the DMA resource |
mbed_official | 15:a81a8d6c1dfe | 629 | * \retval STATUS_BUSY The DMA resource was busy and the descriptor is not added |
mbed_official | 15:a81a8d6c1dfe | 630 | */ |
mbed_official | 15:a81a8d6c1dfe | 631 | enum status_code dma_add_descriptor(struct dma_resource *resource, |
mbed_official | 15:a81a8d6c1dfe | 632 | DmacDescriptor* descriptor) |
mbed_official | 15:a81a8d6c1dfe | 633 | { |
mbed_official | 15:a81a8d6c1dfe | 634 | DmacDescriptor* desc = resource->descriptor; |
mbed_official | 15:a81a8d6c1dfe | 635 | |
mbed_official | 15:a81a8d6c1dfe | 636 | if (resource->job_status == STATUS_BUSY) { |
mbed_official | 15:a81a8d6c1dfe | 637 | return STATUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 638 | } |
mbed_official | 15:a81a8d6c1dfe | 639 | |
mbed_official | 15:a81a8d6c1dfe | 640 | /* Look up for an empty space for the descriptor */ |
mbed_official | 15:a81a8d6c1dfe | 641 | if (desc == NULL) { |
mbed_official | 15:a81a8d6c1dfe | 642 | resource->descriptor = descriptor; |
mbed_official | 15:a81a8d6c1dfe | 643 | } else { |
mbed_official | 15:a81a8d6c1dfe | 644 | /* Looking for end of descriptor link */ |
mbed_official | 15:a81a8d6c1dfe | 645 | while(desc->DESCADDR.reg != 0) { |
mbed_official | 15:a81a8d6c1dfe | 646 | desc = (DmacDescriptor*)(desc->DESCADDR.reg); |
mbed_official | 15:a81a8d6c1dfe | 647 | } |
mbed_official | 15:a81a8d6c1dfe | 648 | |
mbed_official | 15:a81a8d6c1dfe | 649 | /* Set to the end of descriptor list */ |
mbed_official | 15:a81a8d6c1dfe | 650 | desc->DESCADDR.reg = (uint32_t)descriptor; |
mbed_official | 15:a81a8d6c1dfe | 651 | } |
mbed_official | 15:a81a8d6c1dfe | 652 | |
mbed_official | 15:a81a8d6c1dfe | 653 | return STATUS_OK; |
mbed_official | 15:a81a8d6c1dfe | 654 | } |