2.2 DMA

This application uses two DMA modules, as shown in Figure 2-1. One DMA module feeds data from the look-up table (LUT) into the DAC, and the other DMA feeds the Analog-to-Digital Converter (ADC) reading from a potentiometer to the period value of the Timer2 module, which determines the frequency of the waveform.
Figure 2-1. AWG Block Diagram

The DAC feeder (DMA1) is configured to be triggered by the Timer2 output. The source address and length are user selectable and the destination is DAC1DAT. The period selector (DMA2) is configured to be triggered by the conversion complete flag of the continuously converting ADC, which is continuously sampling a potentiometer. The source is the upper byte of the left-justified output, and the destination is the Timer2 period value.

Set DMA Source

void dma_setSource(uint8_t dma, void * source, uint16_t length){
    DMASELECT = dma;
    DMAnCON0bits.EN = 0; 
    DMAnSSA = source;
    DMAnSSZH = (length >> 8) & 0xFF;
    DMAnSSZL = length & 0xFF;  
    DMAnCON0bits.EN = 1;
}

DMA1 - Look-Up Table to Data Transfer

DMASELECT = 0;
DMAnCON1bits.DMODE = 0b00;    // Destination pointer unchanged
DMAnCON1bits.SMODE = 0b01;    // Increment source pointer
DMAnDSA = &DAC1DATL;
DMAnDSZL = 1;                 // Destination size 1
DMAnSIRQ = 0x1B;              // TMR2 trigger
DMAnCON0bits.SIRQEN = 1;      // Allow hardware to trigger start

DMA1 - ADC to TMR2 Data Transfer

DMASELECT = 1;
DMAnDSA = &T2PR;            // Destination TMR0H
DMAnDSZL = 1;               // Destination size 1
DMAnSSZH = 0;
DMAnSSZL = 1;               // Source size 1
DMAnSSA = &ADRESH;          // Source ADC
DMAnSIRQ = 0xA;             // ADC Conversion
DMAnCON0bits.SIRQEN = 1;    // Allow hardware to trigger start
DMAnCON0bits.EN = 1;