DMA

The DMA system is used to transfer the ADC conversion results to the ADC result buffer. The DMA system can work in IDLE sleep mode, and together with the event system the CPU can be left in idle mode without wake-up by RTC or ADC interrupt service routines.

When an ADC conversion is completed, the ADC signals to the DMA system, and the DMA system transfers the ADC conversion result to the buffer directly without using the CPU. The CPU will stay in idle sleep mode until the DMA transfer is completed, and then wakes up to perform the data processing.

Although the extra power consumption used by the DMA module is relatively small, it still consumes some power. Therefore, in applications where the amount of data to be moved is small, interrupts do not happen very frequently, the current reduction achieved by the DMA might not be significant. In this application the addition of DMA removes only 64 relatively short ADC ISRs in one complete cycle.

The more data transferred in the application, the greater the power reduction will be by using DMA. In addition, the DMA will reduce the CPU workload, freeing the CPU for other tasks, and thus increasing your total system performance. It may also allow you to operate the system at a lower frequency and thus saving power.

In this application the amount of data to be transferred is so small that the reduction of power by enabling the DMA is not very significant.

The initialization routine is as below:

// Enable DMA clock domain
PR.PRGEN &= ~PR_DMA_bm;

/* Reset DMA controller just to make sure everything is from scratch */
DMA.CTRL = DMA_RESET_bm;
// Enable DMA module
DMA.CTRL = DMA_ENABLE_bm | DMA_DBUFMODE_CH01_gc | DMA_PRIMODE_RR0123_gc;

// Clear interrupt flags
DMA.INTFLAGS = 0;

// Configure address handle mode
DMA.CH0.ADDRCTRL = DMA_CH_SRCRELOAD_BURST_gc
		    | DMA_CH_SRCDIR_INC_gc
	            | DMA_CH_DESTRELOAD_BLOCK_gc
		    | DMA_CH_DESTDIR_INC_gc;

// Configure trigger source
DMA.CH0.TRIGSRC = DMA_CH_TRIGSRC_ADCA_CH0_gc;

// Transfer 2 byte for every trigger. the total transfer byte will be 64*2 = 128
DMA.CH0.TRFCNT = 128;

// Assign source address
DMA.CH0.SRCADDR0 = (uint8_t)((uint16_t)&(ADCA.CH0.RES));
DMA.CH0.SRCADDR1 = (uint8_t)((uint16_t)&(ADCA.CH0.RES) >> 8);
DMA.CH0.SRCADDR2 = 0;
	 
// Assign destination address
DMA.CH0.DESTADDR0 = (uint8_t)((uint16_t)adc_result[0]);
DMA.CH0.DESTADDR1 = (uint8_t)((uint16_t)adc_result[0] >> 8);
DMA.CH0.DESTADDR2 = 0;
	
// Enable interrupt
DMA.CH0.CTRLB = DMA_CH_TRNINTLVL_LO_gc;

// Set transfer mode and enable transfer
DMA.CH0.CTRLA = DMA_CH_ENABLE_bm
		 | DMA_CH_BURSTLEN_2BYTE_gc
		 | DMA_CH_SINGLE_bm;