This example shows the code snippet for the setup of the DMA module to transfer data from a look-up table stored in the Program Flash Memory into the PWM duty cycle register. Each byte transfer is triggered by the roll-over of Timer0. The code also sets up an abort trigger when an Interrupt-on-Change (IOC) is detected. The data is stored in an array called “PWM_DATA” and each time the Timer0 rolls over a byte is transferred from the array into the PWM duty cycle register. User firmware does not need to set the DGO bit in the DMA1CON0 register as the timer overflow will automatically set it. Since the SSTP and DSTP bits are cleared, the DMA module will continue to operate until an abort trigger is detected. When an abort trigger is detected, the DGO, AIRQEN and SIRQEN bits are cleared. User firmware has to set the SIRQEN and AIRQEN to re-enable the DMA module.

void DMA1_Initialize(void)
    DMA1SSA = &PWM_DATA;          //set source start address
    DMA1DSA = &PWM5DCH;           //set destination start address 
    DMA1CON1 = 0x0A;              //DMODE = 00 | DSTP = 0 | SMR = 01 | SMODE = 01 | SSTP = 1  
    DMA1SSZ = 0x00AC;             //set source size = 172 bytes
    DMA1DSZ = 0x0001;             //set destination size
    DMA1SIRQ = 0x1F;              //set DMA Transfer Trigger Source = TMR0
    DMA1AIRQ = 0x07;              //set DMA Transfer abort Source = IOC
    PIR2bits.DMA1DCNTIF = 0;      //clear Destination Count Interrupt Flag bit
    PIR2bits.DMA1SCNTIF = 0;      //clear Source Count Interrupt Flag bit
    PIR2bits.DMA1AIF = 0;         //clear abort Interrupt Flag bit
    PIR2bits.DMA1ORIF = 0;        //clear overrun Interrupt Flag bit
    PIE2bits.DMA1DCNTIE = 0;      //disable Destination Count 0 Interrupt
    PIE2bits.DMA1SCNTIE = 0;      //disable Source Count Interrupt
    PIE2bits.DMA1AIE = 1;         //enable abort Interrupt
    PIE2bits.DMA1ORIE = 0;        // isable overrun Interrupt 
    asm("BCF INTCON0,7");         //disable Global Interrupts

    asm ("BANKSEL PRLOCK");       //    
    asm ("MOVLW 0x55");           //    
    asm ("MOVWF PRLOCK");         //Arbiter Priority lock
    asm ("MOVLW 0xAA");           //sequence
    asm ("MOVWF PRLOCK");         //     
    asm ("BSF PRLOCK, 0");        //  
    asm("BSF INTCON0,7");        //enable Global Interrupts
    DMA1CON0 = 0x80;              //EN = 1 | SIRQEN = 0 | DGO = 0 |xx| AIRQEN = 0 |x| XIP = 0

User firmware can set the SIRQEN bit whenever the DMA transaction needs to start. This can be done by the following line of code.

DMA1CON0bits.SIRQEN = 1;

The following lines of code need to be used to restart the DMA module and it will continue to run until an abort trigger is received.

DMA1CON0bits.SIRQEN = 1;
DMA1CON0bits.AIRQEN = 1;