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:
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 }