mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
mbed_official
Date:
Wed Jul 01 09:45:11 2015 +0100
Revision:
579:53297373a894
Child:
592:a274ee790e56
Synchronized with git revision d5b4d2ab9c47edb4dc5776e7177b0c2263459081

Full URL: https://github.com/mbedmicro/mbed/commit/d5b4d2ab9c47edb4dc5776e7177b0c2263459081/

Initial version of drivers for SAMR21

Who changed what in which revision?

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