4.1 DMX Controller with DMA

In the case of a DMX controller, the microcontroller will send up to 513 bytes (including the start code) from a preloaded buffer. The start code should be included as the first byte of the buffer. This makes the complete DMX packet transmission automated through the DMA. The DMA module is setup to move one byte of data at a time from the buffer to the UxTXB register. The DMA operation can be triggered by the UART Transmit Interrupt Flag (UxTXIF). Every time a byte is transmitted out of the buffer, the DMA is triggered to move the next data byte. The DMA module can be configured to stop or restart at the end of the DMX packet. The source address will increment in this case, but the destination address remains static.

The example code below is for the DMA setup to transfer 300 bytes of data into the U1TXB register. Note that the UART configuration is still required as mentioned in the section Setup for DMX Controller. The firmware required to load a byte of data into the U1TXB register is eliminated using the DMA module.

Code snippet for DMA setup to work with DMX Controller

Note: This code example is written for PIC18F25K42. Minor edits might be needed to use it for other devices that feature the DMA module.

void DMA1_Initialize(void)
 {
     DMA1SSA = &TX_DATA;       //set source start address
     DMA1DSA = &U1TXB;         //set destination start address
     DMA1CON1 = 0x03;          //DMODE=00|DSTP=0|SMR=00|SMODE=01|SSTP=1 
     DMA1SSZ = 0x012C;         //set source size = 300 bytes
     DMA1DSZ = 0x0001;         //set destination size = 1 byte
     DMA1SIRQ = 0x1C;          //set DMA Transfer Trigger Source = U1TX     
     DMA1AIRQ = 0x00;          //set DMA Transfer abort Source    
    
     PIR2bits.DMA1DCNTIF = 0;  //clear Destination Count Interrupt Flag    
     PIR2bits.DMA1SCNTIF = 0;  //clear Source Count Interrupt Flag
     PIR2bits.DMA1AIF = 0;     //clear abort Interrupt Flag
     PIR2bits.DMA1ORIF = 0;    //clear overrun Interrupt Flag
     PIE2bits.DMA1DCNTIE = 0;  //disable Destination Count Interrupt 
     PIE2bits.DMA1SCNTIE = 0;  //disable Source Count Interrupt
     PIE2bits.DMA1AIE = 0;     //disable abort Interrupt 
     PIE2bits.DMA1ORIE = 0;    //disable 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
 }

Note: 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;