dma.c 19 KB

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