Programming the USB module of PIC32MZ without Harmony (6) – USBDMA
The power of USBDMA on PIC32MZ silicon
In order to appreciate the power of USB DMA, we need to understand the ABCs of the DMA module. DMA, Direct Memory Access, is a hardware implementation of moving data between two modules without CPU’s involvement. The module can be RAM, ROM, any peripherals to name a few. Let take a look the following code:
uint8_t src[8] = {0,1,2,3,4,5,6,7};
uint8_t des[8];
des[0] = src[0];
des[1] = src[1];
des[2] = src[2];
des[3] = src[3];
des[4] = src[4];
des[5] = src[5];
des[6] = src[6];
des[7] = src[7];
This code does a very simple job – moving 8 bytes of data from a source array to a destination array. It performs this job by using the CPU instruction cycles, which is not a big deal if the data size is as small as in the sample code above. If the data is excessive, it will however become challenging for a CPU to handle the traffic in addition to all the other routine jobs. This is especially true for the PIC32MZ to handle all USB 2.0 traffic on a timely manner because the USB 2.0’s 480Mbps bandwidth easily saturates the PIC32MZ’s CPU (even if it runs at 252MHz). The USBDMA, however, doesn’t cost the CPU any instruction cycles to transmitting or receiving data, it will auto-increment the destination/source address and take care of the data movement in the background.
If you have experience using regular DMA modules on a PC32MZ, special attentions need to be paid for USB DMAs because they are separate from the regular DMAs:
- USBDMAs are dedicated to USB transfer, can’t be used for other DMA operation. Thus, USBDMAs have their own sets of registers.
- USBDMA doesn’t allow custom definition of the trigger events. For example, a DMA can be triggered on a flag from UART ISR, or SPI ISR. USBDMA can only be triggered by manually enabling DMAEN, very similar to the “FORCE” function of the other DMA modules. Setting of the Rx DMAEN should be done in the USB ISR for Rx; Setting of the Tx DMAEN should be done in the user application when it’s ready to send the data.
- The workflow for Rx USB DMA should be:
- Host(PC) sends data
- Endpoint Rx IF flags
- Enables Rx USBDMA
- Rx USBDMA IF flags
- CPU takes over
- In the case of Tx, the workflow should be: device’s user application enabling Tx USBDMA -> Tx USBMDA IF flagged -> initiate endpoint Tx -> endpoint Tx IF flagged.
- The workflow for Rx USB DMA should be:
- USBDMA doesn’t allow custom defining of the source (for OUT/Rx, or destination for IN/Tx), because the source (or destination) of the USBDMA channels is always the USB FIFO.
- USBDMA doesn’t override flags of USB ISR. In fact, USBDMA is usually forced to start inside a USB ISR by setting the DMAEN.