1 /**
2 *********************************************************************************
3 *
4 * @file ald_dma.c
5 * @brief DMA module driver.
6 *
7 * @version V1.0
8 * @date 09 Nov 2017
9 * @author AE Team
10 * @note
11 *
12 * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
13 *
14 * SPDX-License-Identifier: Apache-2.0
15 *
16 * Licensed under the Apache License, Version 2.0 (the License); you may
17 * not use this file except in compliance with the License.
18 * You may obtain a copy of the License at
19 *
20 * www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 *
28 *********************************************************************************
29 * @verbatim
30 ==============================================================================
31 ##### How to use this driver #####
32 ==============================================================================
33 [..]
34 The DMA driver can be used as follows:
35
36 (#) System initialization invokes ald_dma_init(), ald_cmu_init() --> ald_dma_init().
37
38 (#) Declare a dma_handle_t handle structure.
39
40 (#) Configure the dma_handle_t structure, you can configure the
41 dma_config_t structure with the help of ald_dma_config_struct().
42
43 (#) Enable the DMA Configure:
44 (##) Memory -- memory: call ald_dma_config_auto().
45 (##) Peripheral -- memory: call ald_dma_config_basic().
46 (##) If you want use the dma easily, you can do this:
47 (+++) Memory -- memory: call ald_dma_config_auto_easy().
48 (+++) Peripheral -- memory: call ald_dma_config_basic_easy().
49
50 (#) Enable the DMA request signal:
51 (##) Memory -- memory: the DMA request signal is request automatic.
52 (##) Peripheral -- memory: you need enable peripheral request signal.
53
54 (#) If you enable DMA interrupt, the callback will be invoked:
55 (##) When DMA transfer is completed, the cplt_cbk() will be invoked.
56 (##) When DMA bus occurs error, the err_cbk() will be invoked.
57
58 (#) If you don't enable the DMA interrupt, you need do this:
59 (##) Polling the ald_dma_get_flag_status(), this function's parameter is channel
60 or DMA_ERR.
61 (+++) When the function's Parameter is channel, if retval is SET, it means
62 the DMA transfer is completed. at this moment, you can do something,
63 and then, you need invoke ald_dma_clear_flag_status() to clear flag.
64
65 (+++) When the function's Parameter is DMA_ERR, if retval is SET, it means
66 the DMA bus occurs error. at this moment, you can do something,
67 and then, you need invoke ald_dma_clear_flag_status() to clear flag.
68
69 @endverbatim
70 */
71
72 #include <string.h>
73 #include "ald_conf.h"
74 #include "ald_dma.h"
75
76
77 /** @addtogroup ES32FXXX_ALD
78 * @{
79 */
80
81 /** @defgroup DMA DMA
82 * @brief DMA module driver
83 * @{
84 */
85
86 #ifdef ALD_DMA
87 /** @defgroup DMA_Private_Variables DMA Private Variables
88 * @{
89 */
90 dma_descriptor_t dma0_ctrl_base[28] __attribute__ ((aligned(512)));
91 dma_call_back_t dma0_cbk[6];
92 /**
93 * @}
94 */
95
96 /** @defgroup DMA_Private_Functions DMA Private Functions
97 * @{
98 */
99
100 /**
101 * @brief Configure DMA channel using dma_config_t structure
102 * @param DMAx: Pointer to DMA peripheral
103 * @param mode: DMA transfer mode. see @ref dma_cycle_ctrl_t
104 * @param p: Pointer to dma_cycle_ctrl_t which contains
105 * DMA channel parameter. see @ref dma_config_t
106 * @retval None
107 */
dma_config_base(DMA_TypeDef * DMAx,dma_cycle_ctrl_t mode,dma_config_t * p)108 static void dma_config_base(DMA_TypeDef *DMAx, dma_cycle_ctrl_t mode, dma_config_t *p)
109 {
110 dma_descriptor_t *descr;
111
112 assert_param(IS_DMA(DMAx));
113 assert_param(IS_CYCLECTRL_TYPE(mode));
114 assert_param(p->src != NULL);
115 assert_param(p->dst != NULL);
116 assert_param(IS_DMA_DATA_SIZE(p->size));
117 assert_param(IS_DMA_DATASIZE_TYPE(p->data_width));
118 assert_param(IS_DMA_DATAINC_TYPE(p->src_inc));
119 assert_param(IS_DMA_DATAINC_TYPE(p->dst_inc));
120 assert_param(IS_DMA_ARBITERCONFIG_TYPE(p->R_power));
121 assert_param(IS_FUNC_STATE(p->primary));
122 assert_param(IS_FUNC_STATE(p->burst));
123 assert_param(IS_FUNC_STATE(p->high_prio));
124 assert_param(IS_FUNC_STATE(p->interrupt));
125 assert_param(IS_DMA_MSEL_TYPE(p->msel));
126 assert_param(IS_DMA_MSIGSEL_TYPE(p->msigsel));
127 assert_param(IS_DMA_CHANNEL(p->channel));
128
129 if (p->primary)
130 descr = (dma_descriptor_t *)(DMAx->CTRLBASE) + p->channel;
131 else
132 descr = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + p->channel;
133
134 if (p->src_inc == DMA_DATA_INC_NONE)
135 descr->src = p->src;
136 else
137 descr->src = (void *)((uint32_t)p->src + ((p->size - 1) << (uint32_t)p->src_inc));
138
139 if (p->dst_inc == DMA_DATA_INC_NONE)
140 descr->dst = p->dst;
141 else
142 descr->dst = (void *)((uint32_t)p->dst + ((p->size - 1) << (uint32_t)p->dst_inc));
143
144 descr->ctrl.cycle_ctrl = mode;
145 descr->ctrl.next_useburst = 0;
146 descr->ctrl.n_minus_1 = p->size - 1;
147 descr->ctrl.R_power = p->R_power;
148 descr->ctrl.src_prot_ctrl = 0,
149 descr->ctrl.dst_prot_ctrl = 0,
150 descr->ctrl.src_size = p->data_width;
151 descr->ctrl.src_inc = p->src_inc;
152 descr->ctrl.dst_size = p->data_width;
153 descr->ctrl.dst_inc = p->dst_inc;
154
155 if (p->primary)
156 WRITE_REG(DMAx->CHPRIALTCLR, (1 << p->channel));
157 else
158 WRITE_REG(DMAx->CHPRIALTSET, (1 << p->channel));
159
160 if (p->burst)
161 WRITE_REG(DMAx->CHUSEBURSTSET, (1 << p->channel));
162 else
163 WRITE_REG(DMAx->CHUSEBURSTCLR, (1 << p->channel));
164
165 if (p->high_prio)
166 WRITE_REG(DMAx->CHPRSET, (1 << p->channel));
167 else
168 WRITE_REG(DMAx->CHPRCLR, (1 << p->channel));
169
170 if (p->interrupt)
171 SET_BIT(DMAx->IER, (1 << p->channel));
172 else
173 CLEAR_BIT(DMAx->IER, (1 << p->channel));
174
175 MODIFY_REG(DMAx->CH_SELCON[p->channel], DMA_CH0_SELCON_MSEL_MSK, p->msel << DMA_CH0_SELCON_MSEL_POSS);
176 MODIFY_REG(DMAx->CH_SELCON[p->channel], DMA_CH0_SELCON_MSIGSEL_MSK, p->msigsel << DMA_CH0_SELCON_MSIGSEL_POSS);
177 return;
178 }
179
180 /**
181 * @brief Handle DMA interrupt
182 * @retval None
183 */
ald_dma_irq_handler(void)184 void ald_dma_irq_handler(void)
185 {
186 uint32_t i, reg = DMA0->IFLAG;
187
188 for (i = 0; i < DMA_CH_COUNT; ++i) {
189 if (READ_BIT(reg, (1 << i))) {
190 if (dma0_cbk[i].cplt_cbk != NULL)
191 dma0_cbk[i].cplt_cbk(dma0_cbk[i].cplt_arg);
192
193 ald_dma_clear_flag_status(DMA0, i);
194 }
195 }
196
197 if (READ_BIT(reg, (1U << DMA_ERR))) {
198 ald_dma_clear_flag_status(DMA0, DMA_ERR);
199
200 for (i = 0; i < DMA_CH_COUNT; ++i) {
201 if (((DMA0->CHENSET >> i) & 0x1) && (dma0_cbk[i].err_cbk != NULL))
202 dma0_cbk[i].err_cbk(dma0_cbk[i].err_arg);
203 }
204 }
205
206 return;
207 }
208 /**
209 * @}
210 */
211
212 /** @defgroup DMA_Public_Functions DMA Public Functions
213 * @{
214 */
215
216 /** @defgroup DMA_Public_Functions_Group1 Initialization functions
217 * @brief Initialization functions
218 *
219 * @verbatim
220 ===================================================================
221
222 #### Initialization functions ####
223
224 ===================================================================
225 [..]
226 This subsection provides two functions to Initilizate DMA:
227 (+) ald_dma_reset(): Reset the DMA register.
228
229 (+) ald_dma_init(): Initializate the DMA module. this function is
230 invoked by ald_cmu_init().
231 this function do this:
232 (++) Initializte private variable dma_ctrl_base and dma_cbk.
233 (++) Reset DMA register.
234 (++) Set DMA interrupt priority: preempt_prio=1, sub_priority=1
235 (++) Enable DMA interrupt.
236 (++) Enable DMA bus error interrupt.
237 (++) Configure CTRLBASE resigter.
238 (++) Enable DMA module.
239
240 (+) ald_dma_config_struct(): Configure dma_config_t
241 structure using default parameter.
242
243 (+) ald_dma_config_sg_alt_desc(): Configure dma_descriptor_t
244 structure using specified parameter. This function used
245 in scatter-gather mode(memory or peripheral).
246 @endverbatim
247 * @{
248 */
249
250 /**
251 * @brief Reset the DMA register
252 * @param DMAx: Pointer to DMA peripheral
253 * @retval None
254 */
ald_dma_reset(DMA_TypeDef * DMAx)255 void ald_dma_reset(DMA_TypeDef *DMAx)
256 {
257 uint32_t i;
258
259 assert_param(IS_DMA(DMAx));
260
261 WRITE_REG(DMAx->CFG, 0x0);
262 WRITE_REG(DMAx->CHUSEBURSTCLR, 0xFFF);
263 WRITE_REG(DMAx->CHREQMASKCLR, 0xFFF);
264 WRITE_REG(DMAx->CHENCLR, 0xFFF);
265 WRITE_REG(DMAx->CHPRIALTCLR, 0xFFF);
266 WRITE_REG(DMAx->CHPRCLR, 0xFFF);
267 WRITE_REG(DMAx->ERRCLR, 0x1);
268 WRITE_REG(DMAx->IER, 0x0);
269 WRITE_REG(DMAx->ICFR, 0x80000FFF);
270
271 for (i = 0; i < DMA_CH_COUNT; ++i)
272 WRITE_REG(DMAx->CH_SELCON[i], 0x0);
273
274 return;
275 }
276
277 /**
278 * @brief DMA module initialization, this function
279 * is invoked by ald_cmu_init().
280 * @param DMAx: Pointer to DMA peripheral
281 * @retval None
282 */
ald_dma_init(DMA_TypeDef * DMAx)283 void ald_dma_init(DMA_TypeDef *DMAx)
284 {
285 assert_param(IS_DMA(DMAx));
286
287 memset(dma0_ctrl_base, 0x0, sizeof(dma0_ctrl_base));
288 memset(dma0_cbk, 0x0, sizeof(dma0_cbk));
289
290 ald_dma_reset(DMAx);
291 NVIC_SetPriority(DMA_IRQn, 2);
292 NVIC_EnableIRQ(DMA_IRQn);
293 SET_BIT(DMAx->IER, DMA_IER_DMAERRIE_MSK);
294
295 WRITE_REG(DMAx->CTRLBASE, (uint32_t)&dma0_ctrl_base);
296 SET_BIT(DMAx->CFG, DMA_CFG_MASTER_ENABLE_MSK);
297
298 return;
299 }
300
301 /**
302 * @brief Configure dma_config_t structure using default parameter.
303 * User can invoked this function, before configure dma_config_t
304 * @param p: Pointer to dma_config_t structure, see @ref dma_config_t
305 * @retval None
306 */
ald_dma_config_struct(dma_config_t * p)307 void ald_dma_config_struct(dma_config_t *p)
308 {
309 p->data_width = DMA_DATA_SIZE_BYTE;
310 p->src_inc = DMA_DATA_INC_BYTE;
311 p->dst_inc = DMA_DATA_INC_BYTE;
312 p->R_power = DMA_R_POWER_1;
313 p->primary = ENABLE;
314 p->burst = DISABLE;
315 p->high_prio = DISABLE;
316 p->interrupt = ENABLE;
317
318 return;
319 }
320
321 /**
322 * @brief Configure dma_descriptor_t structure using specified parameter.
323 * @note This function used in scatter-gather mode(memory or peripheral).
324 * @param desc: Address of the alternate descriptor.
325 * @param config: Pointer to the dma_config_t structure.
326 * @param memory: Memory or peripheral scatter-gather.
327 * @retval None
328 */
ald_dma_config_sg_alt_desc(dma_descriptor_t * desc,dma_config_t * config,uint8_t memory)329 void ald_dma_config_sg_alt_desc(dma_descriptor_t *desc, dma_config_t *config, uint8_t memory)
330 {
331 if ((desc == NULL) || (config == NULL))
332 return;
333
334 if (config->src_inc == DMA_DATA_INC_NONE)
335 desc->src = config->src;
336 else
337 desc->src = (void *)((uint32_t)config->src + ((config->size - 1) << (uint32_t)config->data_width));
338
339 if (config->dst_inc == DMA_DATA_INC_NONE)
340 desc->dst = config->dst;
341 else
342 desc->dst = (void *)((uint32_t)config->dst + ((config->size - 1) << (uint32_t)config->data_width));
343
344 desc->ctrl.cycle_ctrl = memory ? DMA_CYCLE_CTRL_MEM_SG_ALTERNATE : DMA_CYCLE_CTRL_PER_SG_ALTERNATE;
345 desc->ctrl.next_useburst = memory ? 0 : 1;
346 desc->ctrl.n_minus_1 = config->size - 1;
347 desc->ctrl.R_power = config->R_power;
348 desc->ctrl.src_prot_ctrl = 0;
349 desc->ctrl.dst_prot_ctrl = 0;
350 desc->ctrl.src_size = config->data_width;
351 desc->ctrl.src_inc = config->src_inc;
352 desc->ctrl.dst_size = config->data_width;
353 desc->ctrl.dst_inc = config->dst_inc;
354
355 return;
356 }
357
358 /**
359 * @}
360 */
361
362 /** @defgroup DMA_Public_Functions_Group2 Configure DMA channel functions
363 * @brief Configure DMA channel functions
364 *
365 * @verbatim
366 ===================================================================
367
368 #### Configure DMA channel functions ####
369
370 ===================================================================
371 [..]
372 This subsection provides some functions allowing to configure
373 DMA channel. Include two type DMA transfer:
374 (+) Carry data from memory to memory, this mode APIs are:
375 (++) ald_dma_config_auto(): Configure DMA channel according to
376 the specified parameter in the dma_handle_t structure.
377 (++) ald_dma_restart_auto(): Restart DMA transmitted.
378 (++) ald_dma_config_auto_easy(): Configure DMA channel according
379 to the specified parameter. If you want use the dma easily,
380 you can invoke this function.
381 (++) ald_dma_config_sg_mem(): Carry data used scatter-gather mode.
382 (+) Carry data from peripheral to memory or from memory to peripheral,
383 this mode APIs are:
384 (++) ald_dma_config_basic(): Configure DMA channel according to
385 the specified parameter in the dma_handle_t structure.
386 (++) ald_dma_restart_basic(): Restart DMA transmitted.
387 (++) ald_dma_config_basic_easy(): Configure DMA channel according
388 to the specified parameter. If you want use the dma easily,
389 you can invoke this function.
390 (++) ald_dma_ping_pong(): Carry data used ping-pong mode.
391 (++) ald_dma_config_sg_per(): Carry data used scatter-gather mode.
392
393 @endverbatim
394 * @{
395 */
396
397 /**
398 * @brief Configure DMA channel according to the specified parameter
399 * in the dma_handle_t structure. The DMA mode is automatic.
400 * This mode is used to carry data from memory to memory.
401 * @param hperh: Pointer to DMA_handle_t structure that contains
402 * configuration information for specified DMA channel.
403 * @retval None
404 */
ald_dma_config_auto(dma_handle_t * hperh)405 void ald_dma_config_auto(dma_handle_t *hperh)
406 {
407 dma0_cbk[hperh->config.channel].cplt_cbk = hperh->cplt_cbk;
408 dma0_cbk[hperh->config.channel].err_cbk = hperh->err_cbk;
409 dma0_cbk[hperh->config.channel].cplt_arg = hperh->cplt_arg;
410 dma0_cbk[hperh->config.channel].err_arg = hperh->err_arg;
411 dma_config_base(hperh->perh, DMA_CYCLE_CTRL_AUTO, &hperh->config);
412
413 ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
414 WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
415 SET_BIT(hperh->perh->CHSWREQ, (1 << hperh->config.channel));
416
417 return;
418 }
419
420 /**
421 * @brief Restart DMA transmitted. The DMA mode is automatic.
422 * The other parameters have not changed except 'size' and 'addr'.
423 * @param hperh: Pointer to DMA_handle_t structure that contains
424 * configuration information for specified DMA channel.
425 * @param src: Source data begin pointer
426 * @param dst: Destination data begin pointer
427 * @param size: Size.
428 * @retval None
429 */
ald_dma_restart_auto(dma_handle_t * hperh,void * src,void * dst,uint16_t size)430 void ald_dma_restart_auto(dma_handle_t *hperh, void *src, void *dst, uint16_t size)
431 {
432 dma_descriptor_t *descr;
433
434 if (hperh->config.primary)
435 descr = (dma_descriptor_t *)(hperh->perh->CTRLBASE) + hperh->config.channel;
436 else
437 descr = (dma_descriptor_t *)(hperh->perh->ALTCTRLBASE) + hperh->config.channel;
438
439 if (src) {
440 if (hperh->config.src_inc == DMA_DATA_INC_NONE)
441 descr->src = src;
442 else
443 descr->src = (void *)((uint32_t)src + ((size - 1) << (uint32_t)hperh->config.data_width));
444 }
445
446 if (dst) {
447 if (hperh->config.dst_inc == DMA_DATA_INC_NONE)
448 descr->dst = dst;
449 else
450 descr->dst = (void *)((uint32_t)dst + ((size - 1) << (uint32_t)hperh->config.data_width));
451 }
452
453 ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
454 descr->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_AUTO;
455 descr->ctrl.n_minus_1 = size - 1;
456 WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
457 SET_BIT(hperh->perh->CHSWREQ, (1 << hperh->config.channel));
458 return;
459 }
460
461 /**
462 * @brief Configure DMA channel according to the specified parameter.
463 * The DMA mode is automatic. This mode is used to carry data
464 * from memory to memory. If User want use the dma easily,
465 * they can invoke this function.
466 * @param DMAx: Pointer to DMA peripheral
467 * @param src: Source data begin pointer
468 * @param dst: Destination data begin pointer
469 * @param size: The total number of DMA transfers that DMA cycle contains
470 * @param channel: Channel index which will be used.
471 * @param cbk: DMA complete callback function
472 * @retval None
473 */
ald_dma_config_auto_easy(DMA_TypeDef * DMAx,void * src,void * dst,uint16_t size,uint8_t channel,void (* cbk)(void * arg))474 void ald_dma_config_auto_easy(DMA_TypeDef *DMAx, void *src, void *dst,
475 uint16_t size, uint8_t channel, void (*cbk)(void *arg))
476 {
477 dma_handle_t hperh;
478
479 assert_param(IS_DMA(DMAx));
480
481 ald_dma_config_struct(&hperh.config);
482 hperh.config.src = src;
483 hperh.config.dst = dst;
484 hperh.config.size = size;
485 hperh.config.msel = DMA_MSEL_NONE;
486 hperh.config.msigsel = DMA_MSIGSEL_NONE;
487 hperh.config.channel = channel;
488
489 hperh.perh = DMAx;
490 hperh.cplt_cbk = cbk;
491 hperh.cplt_arg = NULL;
492 hperh.err_cbk = NULL;
493
494 ald_dma_clear_flag_status(DMAx, channel);
495 ald_dma_config_auto(&hperh);
496
497 return;
498 }
499
500 /**
501 * @brief Configure DMA channel according to the specified parameter
502 * in the dma_handle_t structure. The DMA mode is basic.
503 * This mode is used to carry data from peripheral to memory
504 * or from memory to peripheral.
505 * @param hperh: Pointer to dma_handle_t structure that contains
506 * configuration information for specified DMA channel.
507 * @retval None
508 */
ald_dma_config_basic(dma_handle_t * hperh)509 void ald_dma_config_basic(dma_handle_t *hperh)
510 {
511 dma0_cbk[hperh->config.channel].cplt_cbk = hperh->cplt_cbk;
512 dma0_cbk[hperh->config.channel].err_cbk = hperh->err_cbk;
513 dma0_cbk[hperh->config.channel].cplt_arg = hperh->cplt_arg;
514 dma0_cbk[hperh->config.channel].err_arg = hperh->err_arg;
515
516 ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
517 dma_config_base(hperh->perh, DMA_CYCLE_CTRL_BASIC, &hperh->config);
518 WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
519
520 return;
521 }
522
523 /**
524 * @brief Restart DMA transmitted. The DMA mode is basic.
525 * The other parameters have not changed except 'size' and 'addr'.
526 * @param hperh: Pointer to DMA_handle_t structure that contains
527 * configuration information for specified DMA channel.
528 * @param src: Source data begin pointer
529 * @param dst: Destination data begin pointer
530 * @param size: Size.
531 * @retval None
532 */
ald_dma_restart_basic(dma_handle_t * hperh,void * src,void * dst,uint16_t size)533 void ald_dma_restart_basic(dma_handle_t *hperh, void *src, void *dst, uint16_t size)
534 {
535 dma_descriptor_t *descr;
536
537 if (hperh->config.primary)
538 descr = (dma_descriptor_t *)(hperh->perh->CTRLBASE) + hperh->config.channel;
539 else
540 descr = (dma_descriptor_t *)(hperh->perh->ALTCTRLBASE) + hperh->config.channel;
541
542 if (src) {
543 if (hperh->config.src_inc == DMA_DATA_INC_NONE)
544 descr->src = src;
545 else
546 descr->src = (void *)((uint32_t)src + ((size - 1) << (uint32_t)hperh->config.data_width));
547 }
548
549 if (dst) {
550 if (hperh->config.dst_inc == DMA_DATA_INC_NONE)
551 descr->dst = dst;
552 else
553 descr->dst = (void *)((uint32_t)dst + ((size - 1) << (uint32_t)hperh->config.data_width));
554 }
555
556 ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
557 descr->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_BASIC;
558 descr->ctrl.n_minus_1 = size - 1;
559 WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
560
561 return;
562 }
563
564 /**
565 * @brief Configure DMA channel according to the specified parameter.
566 * The DMA mode is basic. This mode is used to carry data
567 * from peripheral to memory or negative direction. If user want
568 * use the dma easily, they can invoke this function.
569 * @param DMAx: Pointer to DMA peripheral
570 * @param src: Source data begin pointer
571 * @param dst: Destination data begin pointer
572 * @param size: The total number of DMA transfers that DMA cycle contains
573 * @param msel: Input source to DMA channel @ref dma_msel_t
574 * @param msigsel: Input signal to DMA channel @ref dma_msigsel_t
575 * @param channel: Channel index which will be used
576 * @param cbk: DMA complete callback function
577 * @retval None
578 */
ald_dma_config_basic_easy(DMA_TypeDef * DMAx,void * src,void * dst,uint16_t size,dma_msel_t msel,dma_msigsel_t msigsel,uint8_t channel,void (* cbk)(void * arg))579 void ald_dma_config_basic_easy(DMA_TypeDef *DMAx, void *src, void *dst, uint16_t size, dma_msel_t msel,
580 dma_msigsel_t msigsel, uint8_t channel, void (*cbk)(void *arg))
581 {
582 dma_handle_t hperh;
583
584 assert_param(IS_DMA(DMAx));
585 ald_dma_config_struct(&hperh.config);
586
587 if (((uint32_t)src) >= 0x40000000)
588 hperh.config.src_inc = DMA_DATA_INC_NONE;
589
590 if (((uint32_t)dst) >= 0x40000000)
591 hperh.config.dst_inc = DMA_DATA_INC_NONE;
592
593 hperh.config.src = src;
594 hperh.config.dst = dst;
595 hperh.config.size = size;
596 hperh.config.msel = msel;
597 hperh.config.msigsel = msigsel;
598 hperh.config.channel = channel;
599
600 hperh.perh = DMAx;
601 hperh.cplt_cbk = cbk;
602 hperh.cplt_arg = NULL;
603 hperh.err_cbk = NULL;
604
605 ald_dma_clear_flag_status(DMAx, channel);
606 ald_dma_config_basic(&hperh);
607
608 return;
609 }
610
611 /**
612 * @brief Configure DMA channel according to the specified parameter.
613 * The DMA mode is ping-pong.
614 * @note The ping-pong mode does not support memory to memory.
615 * @param DMAx: Pointer to DMA peripheral.
616 * @param config: Pointer to the dma_config_t structure which contains
617 * the specified parameters.
618 * @param first: Whether it is the first transmission. 1-first, 0-not first.
619 * @param cbk: DMA complete callback function.
620 * @retval None
621 */
ald_dma_config_ping_pong(DMA_TypeDef * DMAx,dma_config_t * config,uint8_t first,void (* cbk)(void * arg))622 void ald_dma_config_ping_pong(DMA_TypeDef *DMAx, dma_config_t *config,
623 uint8_t first, void (*cbk)(void *arg))
624 {
625 dma_descriptor_t *desc;
626
627 assert_param(IS_DMA(DMAx));
628 assert_param(config->src != NULL);
629 assert_param(config->dst != NULL);
630 assert_param(IS_DMA_DATA_SIZE(config->size));
631 assert_param(IS_DMA_DATASIZE_TYPE(config->data_width));
632 assert_param(IS_DMA_DATAINC_TYPE(config->src_inc));
633 assert_param(IS_DMA_DATAINC_TYPE(config->dst_inc));
634 assert_param(IS_DMA_ARBITERCONFIG_TYPE(config->R_power));
635 assert_param(IS_FUNC_STATE(config->primary));
636 assert_param(IS_FUNC_STATE(config->burst));
637 assert_param(IS_FUNC_STATE(config->high_prio));
638 assert_param(IS_FUNC_STATE(config->interrupt));
639 assert_param(IS_DMA_MSEL_TYPE(config->msel));
640 assert_param(IS_DMA_MSIGSEL_TYPE(config->msigsel));
641 assert_param(IS_DMA_CHANNEL(config->channel));
642
643 dma0_cbk[config->channel].cplt_cbk = cbk;
644 dma0_cbk[config->channel].err_cbk = NULL;
645 dma0_cbk[config->channel].cplt_arg = NULL;
646 dma0_cbk[config->channel].err_arg = NULL;
647
648 if (config->primary)
649 desc = (dma_descriptor_t *)(DMAx->CTRLBASE) + config->channel;
650 else
651 desc = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + config->channel;
652
653 if (config->src_inc == DMA_DATA_INC_NONE)
654 desc->src = config->src;
655 else
656 desc->src = (void *)((uint32_t)config->src + ((config->size - 1) << (uint32_t)config->data_width));
657
658 if (config->dst_inc == DMA_DATA_INC_NONE)
659 desc->dst = config->dst;
660 else
661 desc->dst = (void *)((uint32_t)config->dst + ((config->size - 1) << (uint32_t)config->data_width));
662
663 desc->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_PINGPONG;
664 desc->ctrl.next_useburst = 0;
665 desc->ctrl.n_minus_1 = config->size - 1;
666 desc->ctrl.R_power = config->R_power;
667 desc->ctrl.src_prot_ctrl = 0,
668 desc->ctrl.dst_prot_ctrl = 0,
669 desc->ctrl.src_size = config->data_width;
670 desc->ctrl.src_inc = config->src_inc;
671 desc->ctrl.dst_size = config->data_width;
672 desc->ctrl.dst_inc = config->dst_inc;
673
674 if (!first)
675 return;
676
677 if (config->primary)
678 WRITE_REG(DMAx->CHPRIALTCLR, (1 << config->channel));
679 else
680 WRITE_REG(DMAx->CHPRIALTSET, (1 << config->channel));
681
682 if (config->burst)
683 WRITE_REG(DMAx->CHUSEBURSTSET, (1 << config->channel));
684 else
685 WRITE_REG(DMAx->CHUSEBURSTCLR, (1 << config->channel));
686
687 if (config->high_prio)
688 WRITE_REG(DMAx->CHPRSET, (1 << config->channel));
689 else
690 WRITE_REG(DMAx->CHPRCLR, (1 << config->channel));
691
692 if (config->interrupt)
693 SET_BIT(DMAx->IER, (1 << config->channel));
694 else
695 CLEAR_BIT(DMAx->IER, (1 << config->channel));
696
697 MODIFY_REG(DMAx->CH_SELCON[config->channel], DMA_CH0_SELCON_MSEL_MSK, config->msel << DMA_CH0_SELCON_MSEL_POSS);
698 MODIFY_REG(DMAx->CH_SELCON[config->channel], DMA_CH0_SELCON_MSIGSEL_MSK, config->msigsel << DMA_CH0_SELCON_MSIGSEL_POSS);
699
700 WRITE_REG(DMAx->ICFR, (1 << config->channel));
701 WRITE_REG(DMAx->CHENSET, (1 << config->channel));
702
703 return;
704 }
705
706 /**
707 * @brief Configure DMA channel according to the specified parameter.
708 * The DMA mode is memory scatter-gather.
709 * @param DMAx: Pointer to DMA peripheral.
710 * @param desc: Pointer to first alternate descriptor.
711 * @param nr: Number of the alternate descriptor.
712 * @param channel: Channel index which will be used.
713 * @param cbk: DMA complete callback function.
714 * @retval None
715 */
ald_dma_config_sg_mem(DMA_TypeDef * DMAx,dma_descriptor_t * desc,uint32_t nr,uint8_t channel,void (* cbk)(void * arg))716 void ald_dma_config_sg_mem(DMA_TypeDef *DMAx, dma_descriptor_t *desc, uint32_t nr,
717 uint8_t channel, void (*cbk)(void *arg))
718 {
719 dma_descriptor_t *tmp = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
720 dma_descriptor_t *_tmp = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
721
722 assert_param(IS_DMA(DMAx));
723 assert_param(IS_DMA_CHANNEL(channel));
724
725 if ((desc == NULL) || (nr == 0))
726 return;
727
728 dma0_cbk[channel].cplt_cbk = cbk;
729 dma0_cbk[channel].err_cbk = NULL;
730 dma0_cbk[channel].cplt_arg = NULL;
731 dma0_cbk[channel].err_arg = NULL;
732
733 tmp->src = (void *)((uint32_t)desc + (((nr << 2) - 1) << DMA_DATA_INC_WORD));
734 tmp->dst = (void *)((uint32_t)_tmp + ((4 - 1) << DMA_DATA_INC_WORD));
735 tmp->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_MEM_SG_PRIMARY;
736 tmp->ctrl.next_useburst = 0;
737 tmp->ctrl.n_minus_1 = (nr << 2) - 1;
738 tmp->ctrl.R_power = DMA_R_POWER_4;
739 tmp->ctrl.src_prot_ctrl = 0,
740 tmp->ctrl.dst_prot_ctrl = 0,
741 tmp->ctrl.src_size = DMA_DATA_SIZE_WORD;
742 tmp->ctrl.src_inc = DMA_DATA_INC_WORD;
743 tmp->ctrl.dst_size = DMA_DATA_SIZE_WORD;
744 tmp->ctrl.dst_inc = DMA_DATA_INC_WORD;
745
746 desc[nr - 1].ctrl.cycle_ctrl = DMA_CYCLE_CTRL_AUTO;
747 WRITE_REG(DMAx->CHPRIALTCLR, (1 << channel));
748 WRITE_REG(DMAx->CHUSEBURSTCLR, (1 << channel));
749 WRITE_REG(DMAx->CHPRCLR, (1 << channel));
750
751 WRITE_REG(DMAx->ICFR, (1 << channel));
752 SET_BIT(DMAx->IER, (1 << channel));
753 WRITE_REG(DMAx->CHENSET, (1 << channel));
754 SET_BIT(DMAx->CHSWREQ, (1 << channel));
755
756 return;
757 }
758
759 /**
760 * @brief Configure DMA channel according to the specified parameter.
761 * The DMA mode is peripheral scatter-gather.
762 * @note The size of the first transmission must be 5.
763 * @param DMAx: Pointer to DMA peripheral.
764 * @param desc: Pointer to first alternate descriptor.
765 * @param nr: Number of the alternate descriptor.
766 * @param burst: 1-Enable burst, 0-Disable burst.
767 * @param msel: Input source to DMA channel @ref dma_msel_t
768 * @param msigsel: Input signal to DMA channel @ref dma_msigsel_t
769 * @param channel: Channel index which will be used.
770 * @param cbk: DMA complete callback function.
771 * @retval None
772 */
ald_dma_config_sg_per(DMA_TypeDef * DMAx,dma_descriptor_t * desc,uint32_t nr,uint8_t burst,dma_msel_t msel,dma_msigsel_t msigsel,uint8_t channel,void (* cbk)(void * arg))773 void ald_dma_config_sg_per(DMA_TypeDef *DMAx, dma_descriptor_t *desc, uint32_t nr, uint8_t burst,
774 dma_msel_t msel, dma_msigsel_t msigsel, uint8_t channel, void (*cbk)(void *arg))
775 {
776 dma_descriptor_t *tmp = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
777 dma_descriptor_t *_tmp = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
778
779 assert_param(IS_DMA(DMAx));
780 assert_param(IS_DMA_MSEL_TYPE(msel));
781 assert_param(IS_DMA_MSIGSEL_TYPE(msigsel));
782 assert_param(IS_DMA_CHANNEL(channel));
783
784 if ((desc == NULL) || (nr == 0))
785 return;
786
787 dma0_cbk[channel].cplt_cbk = cbk;
788 dma0_cbk[channel].err_cbk = NULL;
789 dma0_cbk[channel].cplt_arg = NULL;
790 dma0_cbk[channel].err_arg = NULL;
791
792 tmp->src = (void *)((uint32_t)desc + (((nr << 2) - 1) << DMA_DATA_INC_WORD));
793 tmp->dst = (void *)((uint32_t)_tmp + ((4 - 1) << DMA_DATA_INC_WORD));
794 tmp->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_PER_SG_PRIMARY;
795 tmp->ctrl.next_useburst = 0;
796 tmp->ctrl.n_minus_1 = (nr << 2) - 1;
797 tmp->ctrl.R_power = DMA_R_POWER_4;
798 tmp->ctrl.src_prot_ctrl = 0,
799 tmp->ctrl.dst_prot_ctrl = 0,
800 tmp->ctrl.src_size = DMA_DATA_SIZE_WORD;
801 tmp->ctrl.src_inc = DMA_DATA_INC_WORD;
802 tmp->ctrl.dst_size = DMA_DATA_SIZE_WORD;
803 tmp->ctrl.dst_inc = DMA_DATA_INC_WORD;
804
805 desc[nr - 1].ctrl.cycle_ctrl = DMA_CYCLE_CTRL_BASIC;
806 WRITE_REG(DMAx->CHPRIALTCLR, (1 << channel));
807 burst ? (DMAx->CHUSEBURSTSET = (1 << channel)) : (DMAx->CHUSEBURSTCLR, (1 << channel));
808 WRITE_REG(DMAx->CHPRCLR, (1 << channel));
809
810 MODIFY_REG(DMAx->CH_SELCON[channel], DMA_CH0_SELCON_MSEL_MSK, msel << DMA_CH0_SELCON_MSEL_POSS);
811 MODIFY_REG(DMAx->CH_SELCON[channel], DMA_CH0_SELCON_MSIGSEL_MSK, msigsel << DMA_CH0_SELCON_MSIGSEL_POSS);
812
813 WRITE_REG(DMAx->ICFR, (1 << channel));
814 SET_BIT(DMAx->IER, (1 << channel));
815 WRITE_REG(DMAx->CHENSET, (1 << channel));
816
817 return;
818 }
819 /**
820 * @}
821 */
822
823 /** @defgroup DMA_Public_Functions_Group3 DMA Control functions
824 * @brief DMA control functions
825 *
826 * @verbatim
827 ===================================================================
828
829 #### DMA control functions ####
830
831 ===================================================================
832 [..]
833 This subsection provides some functions allowing to control DMA:
834 (+) ald_dma_channel_config(): Control DMA channel ENABLE/DISABLE.
835 (+) ald_dma_interrupt_config(): Control DMA channel interrupt ENABLE or
836 DISABLE.
837 (+) ald_dma_get_it_status(): Check whether the specified channel
838 interrupt is SET or RESET.
839 (+) ald_dma_get_flag_status(): Check whether the specified channel
840 flag is SET or RESET.
841 (+) ald_dma_clear_flag_status(): Clear the specified channel
842 pending flag
843
844 @endverbatim
845 * @{
846 */
847
848 /**
849 * @brief Configure channel enable or disable. It will unbind descriptor with
850 * channel, when channel has been disable.
851 * @param DMAx: Pointer to DMA peripheral
852 * @param channel: channel index
853 * @param state: status of channel:
854 * @arg ENABLE: Enable the channel
855 * @arg DISABLE: Disable the channel
856 * @retval None
857 */
ald_dma_channel_config(DMA_TypeDef * DMAx,uint8_t channel,type_func_t state)858 void ald_dma_channel_config(DMA_TypeDef *DMAx, uint8_t channel, type_func_t state)
859 {
860 dma_descriptor_t *descr, *alt_descr;
861
862 assert_param(IS_DMA(DMAx));
863 assert_param(IS_DMA_CHANNEL(channel));
864 assert_param(IS_FUNC_STATE(state));
865
866 descr = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
867 alt_descr = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
868
869 if (state) {
870 WRITE_REG(DMAx->CHENSET, (1 << channel));
871 }
872 else {
873 memset(descr, 0x00, sizeof(dma_descriptor_t));
874 memset(alt_descr, 0x00, sizeof(dma_descriptor_t));
875 WRITE_REG(DMAx->CH_SELCON[channel], 0x0);
876 WRITE_REG(DMAx->CHENCLR, (1 << channel));
877 }
878
879 return;
880 }
881
882 /**
883 * @brief Configure the interrupt enable or disable
884 * @param DMAx: Pointer to DMA peripheral
885 * @param channel: Channel index or DMA_ERR.
886 * @arg 0~5: Channel index
887 * @arg DMA_ERR: DMA bus error
888 * @param state: status of channel:
889 * @arg ENABLE: Enable the channel
890 * @arg DISABLE: Disable the channel
891 *
892 * @retval None
893 */
ald_dma_interrupt_config(DMA_TypeDef * DMAx,uint8_t channel,type_func_t state)894 void ald_dma_interrupt_config(DMA_TypeDef *DMAx, uint8_t channel, type_func_t state)
895 {
896 assert_param(IS_DMA(DMAx));
897 assert_param(IS_DMA_IT_TYPE(channel));
898 assert_param(IS_FUNC_STATE(state));
899
900 if (state)
901 SET_BIT(DMAx->IER, (1 << channel));
902 else
903 CLEAR_BIT(DMAx->IER, (1 << channel));
904
905 return;
906 }
907
908 /**
909 * @brief Check whether the specified channel interrupt
910 * is set or reset
911 * @param DMAx: Pointer to DMA peripheral
912 * @param channel: Channel index or DMA_ERR
913 * @arg 0~5: Channel index
914 * @arg DMA_ERR: DMA bus error
915 * @retval Status:
916 * - SET: Channel interrupt is set
917 * - RESET: Channel interrupt is reset
918 */
ald_dma_get_it_status(DMA_TypeDef * DMAx,uint8_t channel)919 it_status_t ald_dma_get_it_status(DMA_TypeDef *DMAx, uint8_t channel)
920 {
921 assert_param(IS_DMA(DMAx));
922 assert_param(IS_DMA_IT_TYPE(channel));
923
924 if (READ_BIT(DMAx->IER, (1 << channel)))
925 return SET;
926
927 return RESET;
928 }
929
930 /**
931 * @brief Check whether the specified channel flag
932 * is set or reset
933 * @param DMAx: Pointer to DMA peripheral
934 * @param channel: Channel index or DMA_ERR
935 * @arg 0~5: Channel index
936 * @arg DMA_ERR: DMA bus error
937 * @retval Status:
938 * - SET: Channel flag is set
939 * - RESET: Channel flag is reset
940 */
ald_dma_get_flag_status(DMA_TypeDef * DMAx,uint8_t channel)941 flag_status_t ald_dma_get_flag_status(DMA_TypeDef *DMAx, uint8_t channel)
942 {
943 assert_param(IS_DMA(DMAx));
944 assert_param(IS_DMA_IT_TYPE(channel));
945
946 if (READ_BIT(DMAx->IFLAG, (1 << channel)))
947 return SET;
948
949 return RESET;
950 }
951
952 /**
953 * @brief Clear the specified channel pending flag
954 * @param DMAx: Pointer to DMA peripheral
955 * @param channel: Channel index or DMA_ERR
956 * @arg 0~5: Channel index
957 * @arg DMA_ERR: DMA bus error
958 * @retval None
959 */
ald_dma_clear_flag_status(DMA_TypeDef * DMAx,uint8_t channel)960 void ald_dma_clear_flag_status(DMA_TypeDef *DMAx, uint8_t channel)
961 {
962 assert_param(IS_DMA(DMAx));
963 assert_param(IS_DMA_IT_TYPE(channel));
964
965 WRITE_REG(DMAx->ICFR, (1 << channel));
966 return;
967 }
968
969 /**
970 * @brief Get the completion status of the descriptor
971 * @param DMAx: Pointer to DMA peripheral
972 * @param channel: Channel index
973 * @retval Completion status:
974 * - DMA_DESCP_CPLT_PRI: Primary descriptor has been completed
975 * - DMA_DESCP_CPLT_ALT: Alternate descriptor has been completed
976 * - DMA_DESCP_CPLT_ALL: Both primary and alternate descriptors have been completed
977 */
ald_dma_descriptor_cplt_get(DMA_TypeDef * DMAx,uint8_t channel)978 dma_descrp_cplt_t ald_dma_descriptor_cplt_get(DMA_TypeDef *DMAx, uint8_t channel)
979 {
980 uint8_t pri, alt;
981 dma_descriptor_t *desc;
982
983 assert_param(IS_DMA(DMAx));
984 assert_param(IS_DMA_IT_TYPE(channel));
985
986 desc = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
987 pri = desc->ctrl.cycle_ctrl;
988 desc = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
989 alt = desc->ctrl.cycle_ctrl;
990
991 if ((pri == 0) && (alt == 0))
992 return DMA_DESCP_CPLT_ALL;
993
994 if (pri == 0)
995 return DMA_DESCP_CPLT_PRI;
996 else
997 return DMA_DESCP_CPLT_ALT;
998 }
999 /**
1000 * @}
1001 */
1002
1003 /**
1004 * @}
1005 */
1006 #endif /* ALD_DMA */
1007 /**
1008 * @}
1009 */
1010
1011 /**
1012 * @}
1013 */
1014