summaryrefslogtreecommitdiff
path: root/bsp/lpc824/Libraries/peri_driver/dma/dma_8xx.h
blob: 7172688d80ef5200762f32be904705f521522583 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
/*
 * @brief LPC8xx DMA chip driver
 *
 * @note
 * Copyright(C) NXP Semiconductors, 2013
 * All rights reserved.
 *
 * @par
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * LPC products.  This software is supplied "AS IS" without any warranties of
 * any kind, and NXP Semiconductors and its licensor disclaim any and
 * all warranties, express or implied, including all implied warranties of
 * merchantability, fitness for a particular purpose and non-infringement of
 * intellectual property rights.  NXP Semiconductors assumes no responsibility
 * or liability for the use of the software, conveys no license or rights under any
 * patent, copyright, mask work right, or any other intellectual property rights in
 * or to any products. NXP Semiconductors reserves the right to make changes
 * in the software without notification. NXP Semiconductors also makes no
 * representation or warranty that such application will be suitable for the
 * specified use without further testing or modification.
 *
 * @par
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, under NXP Semiconductors' and its
 * licensor's relevant copyrights in the software, without fee, provided that it
 * is used in conjunction with NXP Semiconductors microcontrollers.  This
 * copyright, permission, and disclaimer notice must appear in all copies of
 * this code.
 */

#ifndef __DMA_8XX_H_
#define __DMA_8XX_H_

#ifdef __cplusplus
extern "C" {
#endif

/** @defgroup DMA_8XX CHIP: LPC8xx DMA Controller driver
 * @ingroup CHIP_8XX_Drivers
 * @{
 */

/**
 * @brief DMA Controller shared registers structure
 */
typedef struct {					/*!< DMA shared registers structure */
	__IO uint32_t  ENABLESET;		/*!< DMA Channel Enable read and Set for all DMA channels */
	__I  uint32_t  RESERVED0;
	__O  uint32_t  ENABLECLR;		/*!< DMA Channel Enable Clear for all DMA channels */
	__I  uint32_t  RESERVED1;
	__I  uint32_t  ACTIVE;			/*!< DMA Channel Active status for all DMA channels */
	__I  uint32_t  RESERVED2;
	__I  uint32_t  BUSY;			/*!< DMA Channel Busy status for all DMA channels */
	__I  uint32_t  RESERVED3;
	__IO uint32_t  ERRINT;			/*!< DMA Error Interrupt status for all DMA channels */
	__I  uint32_t  RESERVED4;
	__IO uint32_t  INTENSET;		/*!< DMA Interrupt Enable read and Set for all DMA channels */
	__I  uint32_t  RESERVED5;
	__O  uint32_t  INTENCLR;		/*!< DMA Interrupt Enable Clear for all DMA channels */
	__I  uint32_t  RESERVED6;
	__IO uint32_t  INTA;			/*!< DMA Interrupt A status for all DMA channels */
	__I  uint32_t  RESERVED7;
	__IO uint32_t  INTB;			/*!< DMA Interrupt B status for all DMA channels */
	__I  uint32_t  RESERVED8;
	__O  uint32_t  SETVALID;		/*!< DMA Set ValidPending control bits for all DMA channels */
	__I  uint32_t  RESERVED9;
	__O  uint32_t  SETTRIG;			/*!< DMA Set Trigger control bits for all DMA channels */
	__I  uint32_t  RESERVED10;
	__O  uint32_t  ABORT;			/*!< DMA Channel Abort control for all DMA channels */
} LPC_DMA_COMMON_T;

/**
 * @brief DMA Controller shared registers structure
 */
typedef struct {					/*!< DMA channel register structure */
	__IO uint32_t  CFG;				/*!< DMA Configuration register */
	__I  uint32_t  CTLSTAT;			/*!< DMA Control and status register */
	__IO uint32_t  XFERCFG;			/*!< DMA Transfer configuration register */
	__I  uint32_t  RESERVED;
} LPC_DMA_CHANNEL_T;

/* Reserved bits masks... */
#define DMA_CFG_RESERVED			((3<<2)|(1<<7)|(3<<12)|0xfffc0000)
#define DMA_CTLSTAT_RESERVED		(~(1|(1<<2)))
#define DMA_XFERCFG_RESERVED		((3<<6)|(3<<10)|(0x3fu<<26))

/* DMA channel mapping - each channel is mapped to an individual peripheral
   and direction or a DMA imput mux trigger */
typedef enum {
	DMAREQ_USART0_RX,					/*!< USART0 receive DMA channel */
	DMA_CH0 = DMAREQ_USART0_RX,
	DMAREQ_USART0_TX,					/*!< USART0 transmit DMA channel */
	DMA_CH1 = DMAREQ_USART0_TX,
	DMAREQ_USART1_RX,					/*!< USART1 receive DMA channel */
	DMA_CH2 = DMAREQ_USART1_RX,
	DMAREQ_USART1_TX,					/*!< USART1 transmit DMA channel */
	DMA_CH3 = DMAREQ_USART1_TX,
	DMAREQ_USART2_RX,					/*!< USART2 receive DMA channel */
	DMA_CH4 = DMAREQ_USART2_RX,
	DMAREQ_USART2_TX,					/*!< USART2 transmit DMA channel */
	DMA_CH5 = DMAREQ_USART2_TX,
	DMAREQ_SPI0_RX,
	DMA_CH6 = DMAREQ_SPI0_RX,           /*!< SPI0 receive DMA channel */
	DMAREQ_SPI0_TX,
	DMA_CH7 = DMAREQ_SPI0_TX,           /*!< SPI0 transmit DMA channel */
	DMAREQ_SPI1_RX,
	DMA_CH8 = DMAREQ_SPI1_RX,           /*!< SPI1 receive DMA channel */
	DMAREQ_SPI1_TX,
	DMA_CH9 = DMAREQ_SPI1_TX,           /*!< SPI1 transmit DMA channel */
	DMAREQ_I2C0_MST,
	DMA_CH10 = DMAREQ_I2C0_MST,         /*!< I2C0 Master DMA channel */
	DMAREQ_I2C0_SLV,
	DMA_CH11 = DMAREQ_I2C0_SLV,         /*!< I2C0 Slave DMA channel */
	DMAREQ_I2C1_MST,
	DMA_CH12 = DMAREQ_I2C1_MST,         /*!< I2C1 Master DMA channel */
	DMAREQ_I2C1_SLV,
	DMA_CH13 = DMAREQ_I2C1_SLV,         /*!< I2C1 Slave DMA channel */
	DMAREQ_I2C2_MST,
	DMA_CH14 = DMAREQ_I2C2_MST,         /*!< I2C2 Master DMA channel */
	DMAREQ_I2C2_SLV,
	DMA_CH15 = DMAREQ_I2C2_SLV,         /*!< I2C2 Slave DMA channel */
	DMAREQ_I2C3_MST,
	DMA_CH16 = DMAREQ_I2C3_MST,         /*!< I2C2 Master DMA channel */
	DMAREQ_I2C3_SLV,
	DMA_CH17 = DMAREQ_I2C3_SLV,         /*!< I2C2 Slave DMA channel */
} DMA_CHID_T;

/* On LPC82x, Max DMA channel is 18 */
#define MAX_DMA_CHANNEL			(DMA_CH17 + 1)

/* Reserved bits masks... */
#define DMA_COMMON_RESERVED         (~(0UL) << MAX_DMA_CHANNEL)
#define DMA_ENABLESET_RESERVED		DMA_COMMON_RESERVED
#define DMA_ENABLECLR_RESERVED		DMA_COMMON_RESERVED
#define DMA_ACTIVE_RESERVED			DMA_COMMON_RESERVED
#define DMA_BUSY_RESERVED			DMA_COMMON_RESERVED
#define DMA_ERRINT_RESERVED			DMA_COMMON_RESERVED
#define DMA_INTENSET_RESERVED		DMA_COMMON_RESERVED
#define DMA_INTENCLR_RESERVED		DMA_COMMON_RESERVED
#define DMA_INTA_RESERVED			DMA_COMMON_RESERVED
#define DMA_INTB_RESERVED			DMA_COMMON_RESERVED
#define DMA_SETVALID_RESERVED		DMA_COMMON_RESERVED
#define DMA_SETTRIG_RESERVED		DMA_COMMON_RESERVED
#define DMA_ABORT_RESERVED			DMA_COMMON_RESERVED

/**
 * @brief DMA Controller register block structure
 */
typedef struct {					/*!< DMA Structure */
	__IO uint32_t  CTRL;			/*!< DMA control register */
	__I  uint32_t  INTSTAT;			/*!< DMA Interrupt status register */
	__IO uint32_t  SRAMBASE;		/*!< DMA SRAM address of the channel configuration table */
	__I  uint32_t  RESERVED2[5];
	LPC_DMA_COMMON_T DMACOMMON[1];	/*!< DMA shared channel (common) registers */
	__I  uint32_t  RESERVED0[225];
	LPC_DMA_CHANNEL_T DMACH[MAX_DMA_CHANNEL];	/*!< DMA channel registers */
} LPC_DMA_T;

/* Reserved bits masks... */
#define DMA_CTRL_RESERVED			(~1)
#define DMA_INTSTAT_RESERVED		(~7)
#define DMA_SRAMBASE_RESERVED		(0xFF)

typedef enum {
  	WIDTH_8_BITS  = 0, 
	WIDTH_16_BITS = 1, 
	WIDTH_32_BITS = 2
} DataWidth;


/**
 * @brief	Easy API, setup all required things to make DMA ready to use
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
void ChipEz_DMA_Init(uint32_t isEnableIRQ);

/**
 * @brief	Easy API, setup the next transfer for a channel, this function updates DMA descriptor
 * @param	ch		: DMA channel ID
 * @param   src_address: Source base address
 * @param   src_increment: Increment of source address after each transfer. Could be DMA_XFERCFG_SRCINC_0/1/2/4
 * @param   dst_address: Destination base address
 * @param   dst_increment: Increment of destination address after each transfer. Could be DMA_XFERCFG_DSTINC_0/1/2/4
 * @param   xfr_width: Width of transfer unit, could be WIDTH_8_BITS, WIDTH_16_BITS, or WIDTH_32_BITS
 * @param   length_bytes: Transfer length, in bytes. Must NOT makes transfer unit count exceed 1024.
 * @param   priority: Channel priority, used internally in DMA, could be from 0 (highest) to 7 (lowest)
 * @return	Nothing
 * @note	This function will set the DMA descriptor in the SRAM table to the
 *			the passed descriptor. This function is only meant to be used when
 *			the DMA channel is not active and can be used to setup the
 *			initial transfer for a linked list or ping-pong buffer or just a
 *			single transfer without a next descriptor.
 */
void ChipEz_DMA_InitChannel( DMA_CHID_T ch, uint32_t src_address, uint32_t src_increment,
		uint32_t dst_address, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes, uint32_t priority);

/**
 * @brief	Easy API, Start transfer of a DMA channel
 * @param	ch		: DMA channel ID
 * @param   src_increment: Increment of source address after each transfer. Could be DMA_XFERCFG_SRCINC_0/1/2/4. 
 *                         Should be consistent with the same parameter used in ChipEz_DMA_InitChannel()
 * @param   dst_increment: Increment of destination address after each transfer. Could be DMA_XFERCFG_DSTINC_0/1/2/4
 *                         hould be consistent with the same parameter used in ChipEz_DMA_InitChannel()
 * @param   xfr_width: Width of transfer unit, could be WIDTH_8_BITS, WIDTH_16_BITS, or WIDTH_32_BITS
 *                     Should be consistent with the same parameter used in ChipEz_DMA_InitChannel()
 * @param   length_bytes: Transfer length, in bytes. Must NOT makes transfer unit count exceed 1024.
 *                        Should be consistent with the same parameter used in ChipEz_DMA_InitChannel()
 * @param   priority: Channel priority, used internally in DMA, could be from 0 (highest) to 7 (lowest)
 * @return	Nothing
 */

void ChipEz_DMA_StartTransfer(DMA_CHID_T ch, uint32_t src_increment, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes);

/**
 * @brief   Easier API, Combine ChipEz_DMA_InitChannel and ChipEz_DMA_StartTransfer with channel busy check
            parameter is the same as ChipEz_DMA_InitChannel
   @return  TRUE when success, FALSE when current channel is busy.
 */
bool ChipEzr_DMA_Transfer( DMA_CHID_T channel, uint32_t src_address, uint32_t src_increment,
		uint32_t dst_address, uint32_t dst_increment, uint32_t xfr_width, uint32_t length_bytes, uint32_t priority);


/**
 * @brief	Easy API, Abort a DMA channel safely
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
void ChipEz_DMA_AbortChannel(DMA_CHID_T ch);

/** @defgroup DMA_COMMONDRV_8XX CHIP: LPC8xx DMA Controller driver common functions
 * @{
 */

/**
 * @brief	Initialize DMA controller
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_Init(LPC_DMA_T *pDMA)
{
	(void) pDMA;
	Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_DMA);
}

/**
 * @brief	De-Initialize DMA controller
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_DeInit(LPC_DMA_T *pDMA)
{
	(void) pDMA;
	Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_DMA);
}

/**
 * @brief	Enable DMA controller
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_Enable(LPC_DMA_T *pDMA)
{
	pDMA->CTRL = 1;
}

/**
 * @brief	Disable DMA controller
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_Disable(LPC_DMA_T *pDMA)
{
	pDMA->CTRL = 0;
}

/* DMA interrupt status bits (common) */
#define DMA_INTSTAT_ACTIVEINT       0x2		/*!< Summarizes whether any enabled interrupts are pending */
#define DMA_INTSTAT_ACTIVEERRINT    0x4		/*!< Summarizes whether any error interrupts are pending */

/**
 * @brief	Get pending interrupt or error interrupts
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	An Or'ed value of DMA_INTSTAT_* types
 * @note	If any DMA channels have an active interrupt or error interrupt
 *			pending, this functional will a common status that applies to all
 *			channels.
 */
STATIC INLINE uint32_t Chip_DMA_GetIntStatus(LPC_DMA_T *pDMA)
{
	return (pDMA->INTSTAT & ~DMA_INTSTAT_RESERVED);
}

/* DMA channel source/address/next descriptor */
typedef struct {
	uint32_t  xfercfg;		/*!< Transfer configuration (only used in linked lists and ping-pong configs) */
	uint32_t  source;		/*!< DMA transfer source end address */
	uint32_t  dest;			/*!< DMA transfer desintation end address */
	uint32_t  next;			/*!< Link to next DMA descriptor, must be 16 byte aligned */
} DMA_CHDESC_T;

/* DMA SRAM table - this can be optionally used with the Chip_DMA_SetSRAMBase()
   function if a DMA SRAM table is needed. */
extern DMA_CHDESC_T Chip_DMA_Table[MAX_DMA_CHANNEL];

/**
 * @brief	Set DMA controller SRAM base address
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	base	: The base address where the DMA descriptors will be stored
 * @return	Nothing
 * @note	A 256 byte block of memory aligned on a 256 byte boundary must be
 *			provided for this function. It sets the base address used for
 *			DMA descriptor table (16 descriptors total that use 16 bytes each).<br>
 *
 *			A pre-defined table with correct alignment can be used for this
 *			function by calling Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
 */
STATIC INLINE void Chip_DMA_SetSRAMBase(LPC_DMA_T *pDMA, uint32_t base)
{
	pDMA->SRAMBASE = base;
}

/**
 * @brief	Returns DMA controller SRAM base address
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	The base address where the DMA descriptors are stored
 */
STATIC INLINE uint32_t Chip_DMA_GetSRAMBase(LPC_DMA_T *pDMA)
{
	return (pDMA->SRAMBASE & ~DMA_SRAMBASE_RESERVED);
}

/**
 * @}
 */

/** @defgroup DMA_COMMON_8XX CHIP: LPC8xx DMA Controller driver common channel functions
 * @{
 */

/**
 * @brief	Enables a single DMA channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_EnableChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].ENABLESET = (1 << ch);
}

/**
 * @brief	Disables a single DMA channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_DisableChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].ENABLECLR = (1 << ch);
}

/**
 * @brief	Returns all enabled DMA channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	An Or'ed value of all enabled DMA channels (0 - 15)
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) is enabled. A low state is disabled.
 */
STATIC INLINE uint32_t Chip_DMA_GetEnabledChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].ENABLESET & ~DMA_ENABLESET_RESERVED);
}

/**
 * @brief	Returns all active DMA channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	An Or'ed value of all active DMA channels (0 - 15)
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) is active. A low state is inactive. A active
 *			channel indicates that a DMA operation has been started but
 *			not yet fully completed.
 */
STATIC INLINE uint32_t Chip_DMA_GetActiveChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].ACTIVE & ~DMA_ACTIVE_RESERVED);
}

/**
 * @brief	Returns all busy DMA channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	An Or'ed value of all busy DMA channels (0 - 15)
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) is busy. A low state is not busy. A DMA
 *			channel is considered busy when there is any operation
 *			related to that channel in the DMA controller�s internal
 *			pipeline.
 */
STATIC INLINE uint32_t Chip_DMA_GetBusyChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].BUSY & ~DMA_BUSY_RESERVED);
}

/**
 * @brief	Returns pending error interrupt status for all DMA channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	An Or'ed value of all channels (0 - 15) error interrupt status
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) has a pending error interrupt. A low state
 *			indicates no error interrupt.
 */
STATIC INLINE uint32_t Chip_DMA_GetErrorIntChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].ERRINT & ~DMA_ERRINT_RESERVED);
}

/**
 * @brief	Clears a pending error interrupt status for a single DMA channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_ClearErrorIntChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].ERRINT = (1 << ch);
}

/**
 * @brief	Enables a single DMA channel's interrupt used in common DMA interrupt
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_EnableIntChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].INTENSET = (1 << ch);
}

/**
 * @brief	Disables a single DMA channel's interrupt used in common DMA interrupt
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_DisableIntChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].INTENCLR = (1 << ch);
}

/**
 * @brief	Returns all enabled interrupt channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) has an enabled interrupt for the channel.
 *			A low state indicates that the DMA channel will not contribute
 *			to the common DMA interrupt status.
 */
STATIC INLINE uint32_t Chip_DMA_GetEnableIntChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].INTENSET & ~DMA_INTENSET_RESERVED);
}

/**
 * @brief	Returns active A interrupt status for all channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) has an active A interrupt for the channel.
 *			A low state indicates that the A interrupt is not active.
 */
STATIC INLINE uint32_t Chip_DMA_GetActiveIntAChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].INTA & ~DMA_INTA_RESERVED);
}

/**
 * @brief	Clears active A interrupt status for a single channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_ClearActiveIntAChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].INTA = (1 << ch);
}

/**
 * @brief	Returns active B interrupt status for all channels
 * @param	pDMA	: The base of DMA controller on the chip
 * @return	Nothing
 * @note	A high values in bits 0 .. 15 in the return values indicates
 *			that the channel for that bit (bit 0 = channel 0, bit 1 -
 *			channel 1, etc.) has an active B interrupt for the channel.
 *			A low state indicates that the B interrupt is not active.
 */
STATIC INLINE uint32_t Chip_DMA_GetActiveIntBChannels(LPC_DMA_T *pDMA)
{
	return (pDMA->DMACOMMON[0].INTB & ~DMA_INTB_RESERVED);
}

/**
 * @brief	Clears active B interrupt status for a single channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_ClearActiveIntBChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].INTB = (1 << ch);
}

/**
 * @brief	Sets the VALIDPENDING control bit for a single channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 * @note	See the User Manual for more information for what this bit does.
 *
 */
STATIC INLINE void Chip_DMA_SetValidChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].SETVALID = (1 << ch);
}

/**
 * @brief	Sets the TRIG bit for a single channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 * @note	See the User Manual for more information for what this bit does.
 */
STATIC INLINE void Chip_DMA_SetTrigChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].SETTRIG = (1 << ch);
}

/**
 * @brief	Aborts a DMA operation for a single channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 * @note	To abort a channel, the channel should first be disabled. Then wait
 *			until the channel is no longer busy by checking the corresponding
 *			bit in BUSY. Finally, abort the channel operation. This prevents the
 *			channel from restarting an incomplete operation when it is enabled
 *			again.
 */
STATIC INLINE void Chip_DMA_AbortChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	pDMA->DMACOMMON[0].ABORT = (1 << ch);
}

/**
 * @}
 */


/** @defgroup DMA_CHANNEL_8XX CHIP: LPC8xx DMA Controller driver channel specific functions
 * @{
 */

/* Support macro for DMA_CHDESC_T */
#define DMA_ADDR(addr)      ((uint32_t) (addr))

/* Support definitions for setting the configuration of a DMA channel. You
   will need to get more information on these options from the User manual. */
#define DMA_CFG_PERIPHREQEN     (1 << 0)	/*!< Enables Peripheral DMA requests */
#define DMA_CFG_HWTRIGEN        (1 << 1)	/*!< Use hardware triggering via imput mux */
#define DMA_CFG_TRIGPOL_LOW     (0 << 4)	/*!< Hardware trigger is active low or falling edge */
#define DMA_CFG_TRIGPOL_HIGH    (1 << 4)	/*!< Hardware trigger is active high or rising edge */
#define DMA_CFG_TRIGTYPE_EDGE   (0 << 5)	/*!< Hardware trigger is edge triggered */
#define DMA_CFG_TRIGTYPE_LEVEL  (1 << 5)	/*!< Hardware trigger is level triggered */
#define DMA_CFG_TRIGBURST_SNGL  (0 << 6)	/*!< Single transfer. Hardware trigger causes a single transfer */
#define DMA_CFG_TRIGBURST_BURST (1 << 6)	/*!< Burst transfer (see UM) */
#define DMA_CFG_BURSTPOWER_1    (0 << 8)	/*!< Set DMA burst size to 1 transfer */
#define DMA_CFG_BURSTPOWER_2    (1 << 8)	/*!< Set DMA burst size to 2 transfers */
#define DMA_CFG_BURSTPOWER_4    (2 << 8)	/*!< Set DMA burst size to 4 transfers */
#define DMA_CFG_BURSTPOWER_8    (3 << 8)	/*!< Set DMA burst size to 8 transfers */
#define DMA_CFG_BURSTPOWER_16   (4 << 8)	/*!< Set DMA burst size to 16 transfers */
#define DMA_CFG_BURSTPOWER_32   (5 << 8)	/*!< Set DMA burst size to 32 transfers */
#define DMA_CFG_BURSTPOWER_64   (6 << 8)	/*!< Set DMA burst size to 64 transfers */
#define DMA_CFG_BURSTPOWER_128  (7 << 8)	/*!< Set DMA burst size to 128 transfers */
#define DMA_CFG_BURSTPOWER_256  (8 << 8)	/*!< Set DMA burst size to 256 transfers */
#define DMA_CFG_BURSTPOWER_512  (9 << 8)	/*!< Set DMA burst size to 512 transfers */
#define DMA_CFG_BURSTPOWER_1024 (10 << 8)	/*!< Set DMA burst size to 1024 transfers */
#define DMA_CFG_BURSTPOWER(n)   ((n) << 8)	/*!< Set DMA burst size to 2^n transfers, max n=10 */
#define DMA_CFG_SRCBURSTWRAP    (1 << 14)	/*!< Source burst wrapping is enabled for this DMA channel */
#define DMA_CFG_DSTBURSTWRAP    (1 << 15)	/*!< Destination burst wrapping is enabled for this DMA channel */
#define DMA_CFG_CHPRIORITY(p)   ((p) << 16)	/*!< Sets DMA channel priority, min 0 (highest), max 3 (lowest) */

/**
 * @brief	Setup a DMA channel configuration
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @param	cfg		: An Or'ed value of DMA_CFG_* values that define the channel's configuration
 * @return	Nothing
 * @note	This function sets up all configurable options for the DMA channel.
 *			These options are usually set once for a channel and then unchanged.<br>
 *
 *			The following example show how to configure the channel for peripheral
 *			DMA requests, burst transfer size of 1 (in 'transfers', not bytes),
 *			continuous reading of the same source address, incrementing destination
 *			address, and highest channel priority.<br>
 *			Example: Chip_DMA_SetupChannelConfig(pDMA, SSP0_RX_DMA,
 *				(DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_BURST | DMA_CFG_BURSTPOWER_1 |
 *				DMA_CFG_SRCBURSTWRAP | DMA_CFG_CHPRIORITY(0)));<br>
 *
 *			The following example show how to configure the channel for an external
 *			trigger from the imput mux with low edge polarity, a burst transfer size of 8,
 *			incrementing source and destination addresses, and lowest channel
 *			priority.<br>
 *			Example: Chip_DMA_SetupChannelConfig(pDMA, DMA_CH14,
 *				(DMA_CFG_HWTRIGEN | DMA_CFG_TRIGPOL_LOW | DMA_CFG_TRIGTYPE_EDGE |
 *				DMA_CFG_TRIGBURST_BURST | DMA_CFG_BURSTPOWER_8 |
 *				DMA_CFG_CHPRIORITY(3)));<br>
 *
 *			For non-peripheral DMA triggering (DMA_CFG_HWTRIGEN definition), use the
 *			DMA input mux functions to configure the DMA trigger source for a DMA channel.
 */
STATIC INLINE void Chip_DMA_SetupChannelConfig(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t cfg)
{
	pDMA->DMACH[ch].CFG = cfg;
}

/* DMA channel control and status register definitions */
#define DMA_CTLSTAT_VALIDPENDING    (1 << 0)	/*!< Valid pending flag for this channel */
#define DMA_CTLSTAT_TRIG            (1 << 2)	/*!< Trigger flag. Indicates that the trigger for this channel is currently set */

/**
 * @brief	Returns channel specific status flags
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	AN Or'ed value of DMA_CTLSTAT_VALIDPENDING and DMA_CTLSTAT_TRIG
 */
STATIC INLINE uint32_t Chip_DMA_GetChannelStatus(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	return (pDMA->DMACH[ch].XFERCFG & ~DMA_XFERCFG_RESERVED);
}

/* DMA channel transfer configuration registers definitions */
#define DMA_XFERCFG_CFGVALID        (1 << 0)	/*!< Configuration Valid flag */
#define DMA_XFERCFG_RELOAD          (1 << 1)	/*!< Indicates whether the channels control structure will be reloaded when the current descriptor is exhausted */
#define DMA_XFERCFG_SWTRIG          (1 << 2)	/*!< Software Trigger */
#define DMA_XFERCFG_CLRTRIG         (1 << 3)	/*!< Clear Trigger */
#define DMA_XFERCFG_SETINTA         (1 << 4)	/*!< Set Interrupt flag A for this channel to fire when descriptor is complete */
#define DMA_XFERCFG_SETINTB         (1 << 5)	/*!< Set Interrupt flag B for this channel to fire when descriptor is complete */
#define DMA_XFERCFG_WIDTH_8         (0 << 8)	/*!< 8-bit transfers are performed */
#define DMA_XFERCFG_WIDTH_16        (1 << 8)	/*!< 16-bit transfers are performed */
#define DMA_XFERCFG_WIDTH_32        (2 << 8)	/*!< 32-bit transfers are performed */
#define DMA_XFERCFG_SRCINC_0        (0 << 12)	/*!< DMA source address is not incremented after a transfer */
#define DMA_XFERCFG_SRCINC_1        (1 << 12)	/*!< DMA source address is incremented by 1 (width) after a transfer */
#define DMA_XFERCFG_SRCINC_2        (2 << 12)	/*!< DMA source address is incremented by 2 (width) after a transfer */
#define DMA_XFERCFG_SRCINC_4        (3 << 12)	/*!< DMA source address is incremented by 4 (width) after a transfer */
#define DMA_XFERCFG_DSTINC_0        (0 << 14)	/*!< DMA destination address is not incremented after a transfer */
#define DMA_XFERCFG_DSTINC_1        (1 << 14)	/*!< DMA destination address is incremented by 1 (width) after a transfer */
#define DMA_XFERCFG_DSTINC_2        (2 << 14)	/*!< DMA destination address is incremented by 2 (width) after a transfer */
#define DMA_XFERCFG_DSTINC_4        (3 << 14)	/*!< DMA destination address is incremented by 4 (width) after a transfer */
#define DMA_XFERCFG_XFERCOUNT(n)    ((n - 1) << 16)	/*!< DMA transfer count in 'transfers', between (0)1 and (1023)1024 */

/**
 * @brief	Setup a DMA channel transfer configuration
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @param	cfg		: An Or'ed value of DMA_XFERCFG_* values that define the channel's transfer configuration
 * @return	Nothing
 * @note	This function sets up the transfer configuration for the DMA channel.<br>
 *
 *			The following example show how to configure the channel's transfer for
 *			multiple transfer descriptors (ie, ping-pong), interrupt 'A' trigger on
 *			transfer descriptor completion, 128 byte size transfers, and source and
 *			destination address increment.<br>
 *			Example: Chip_DMA_SetupChannelTransfer(pDMA, SSP0_RX_DMA,
 *				(DMA_XFERCFG_CFGVALID | DMA_XFERCFG_RELOAD | DMA_XFERCFG_SETINTA |
 *				DMA_XFERCFG_WIDTH_8 | DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_1 |
 *				DMA_XFERCFG_XFERCOUNT(128)));<br>
 */
STATIC INLINE void Chip_DMA_SetupChannelTransfer(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t cfg)
{
	pDMA->DMACH[ch].XFERCFG = cfg;
}

/**
 * @brief	Set DMA transfer register interrupt bits (safe)
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @param	mask	: Bits to set
 * @return	Nothing
 * @note	This function safely sets bits in the DMA channel specific XFERCFG
 *			register.
 */
STATIC INLINE void Chip_DMA_SetTranBits(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t mask)
{
	/* Read and write values may not be the same, write 0 to
	   undefined bits */
	pDMA->DMACH[ch].XFERCFG = (pDMA->DMACH[ch].XFERCFG & ~DMA_XFERCFG_RESERVED) | mask;
}

/**
 * @brief	Clear DMA transfer register interrupt bits (safe)
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @param	mask	: Bits to clear
 * @return	Nothing
 * @note	This function safely clears bits in the DMA channel specific XFERCFG
 *			register.
 */
STATIC INLINE void Chip_DMA_ClearTranBits(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t mask)
{
	/* Read and write values may not be the same, write 0 to
	   undefined bits */
	pDMA->DMACH[ch].XFERCFG &= ~(DMA_XFERCFG_RESERVED | mask);
}

/**
 * @brief	Update the transfer size in an existing DMA channel transfer configuration
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @param	trans	: Number of transfers to update the transfer configuration to (1 - 1023)
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_SetupChannelTransferSize(LPC_DMA_T *pDMA, DMA_CHID_T ch, uint32_t trans)
{
	pDMA->DMACH[ch].XFERCFG = (pDMA->DMACH[ch].XFERCFG & ~(DMA_XFERCFG_RESERVED | (0x3FF << 16))) | DMA_XFERCFG_XFERCOUNT(trans);
}

/**
 * @brief	Sets a DMA channel configuration as valid
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_SetChannelValid(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	Chip_DMA_SetTranBits(pDMA, ch, DMA_XFERCFG_CFGVALID);
}

/**
 * @brief	Sets a DMA channel configuration as invalid
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_SetChannelInValid(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	Chip_DMA_ClearTranBits(pDMA, ch, DMA_XFERCFG_CFGVALID);
}

/**
 * @brief	Performs a software trigger of the DMA channel
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	Nothing
 */
STATIC INLINE void Chip_DMA_SWTriggerChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	Chip_DMA_SetTranBits(pDMA, ch, DMA_XFERCFG_SWTRIG);
}

/**
 * @brief	Checks if the given channel is active or not
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @return	1 if channel @a ch is active; 0 if channel @a ch is not active
 */
STATIC INLINE bool Chip_DMA_IsChannelActive(LPC_DMA_T *pDMA, DMA_CHID_T ch)
{
	return (pDMA->DMACOMMON[0].ACTIVE & (1 << ch)) != 0;
}

/**
 * @brief	Sets up a DMA channel with the passed DMA transfer descriptor
 * @param	pDMA	: The base of DMA controller on the chip
 * @param	ch		: DMA channel ID
 * @param	desc	: Pointer to DMA transfer descriptor
 * @return	false if the DMA channel was active, otherwise true
 * @note	This function will set the DMA descriptor in the SRAM table to the
 *			the passed descriptor. This function is only meant to be used when
 *			the DMA channel is not active and can be used to setup the
 *			initial transfer for a linked list or ping-pong buffer or just a
 *			single transfer without a next descriptor.<br>
 *
 *			If using this function to write the initial transfer descriptor in
 *			a linked list or ping-pong buffer configuration, it should contain a
 *			non-NULL 'next' field pointer.
 */
STATIC INLINE bool Chip_DMA_SetupTranChannel(LPC_DMA_T *pDMA, DMA_CHID_T ch, const DMA_CHDESC_T *desc)
{
	/* If channel is active return false */
	if (Chip_DMA_IsChannelActive(pDMA, ch))
		return false;

	/* Assign the descriptor to descriptor table */
	((DMA_CHDESC_T *) (pDMA->SRAMBASE & ~DMA_SRAMBASE_RESERVED))[ch] = *desc;
	return true;
}


/**
 * @}
 */

#endif /* __DMA_8XX_H_ */