mbed library sources

Fork of mbed-src by mbed official

Committer:
mbed_official
Date:
Fri Jul 17 09:15:10 2015 +0100
Revision:
592:a274ee790e56
Parent:
579:53297373a894
Synchronized with git revision e7144f83a8d75df80c4877936b6ffe552b0be9e6

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

More API implementation for SAMR21

Who changed what in which revision?

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