• AVR Freaks

Hot!USB DMA Question

Author
MisterHemi
Senior Member
  • Total Posts : 171
  • Reward points : 0
  • Joined: 2017/11/02 12:24:21
  • Location: Commerce, CA USA
  • Status: offline
2019/11/05 10:11:47 (permalink)
0

USB DMA Question

I have been attempting to use the USB DMA without success.

My objective is to use DMA entirely to transfer data from USB to SPI (I2S).

If I use a function to read the data from the USB FIFO into a buffer then use the general purpose DMA to transfer the data from the buffer to SPI (I2S) it works fine.
 
When using the USB DMA I no longer get any SOF interrupts and no data but the USB DMA interrupt service routine is called.
 
My question is does anyone know if this is correct?
Unlike the general purpose DMA there are very few options to trigger interrupts.
 
Here is the simplified code using the function -> buffer -> DMA -> I2S/SPI method:

uint8_t __attribute__((coherent)) __attribute__((aligned(32))) USB_EP3_buffer[(EP3RXBUFFSIZE * 8)];
 
void __attribute__((interrupt(ipl4srs), at_vector(_USB_VECTOR), aligned(16), no_fpu, nomips16)) USB_Handler(void){
 
/* Endpoint 3 RX Interrupt Handler */
if(USBCSR1bits.EP3RXIF){ // ISOCHRONOUS Endpoint 3 Received A Packet.
led_3 = ~led_3;
 
// Get the count of bytes to be transferred from Endpoint 3.
ep3rbc = USBE3CSR2bits.RXCNT;
 
// Get Incoming USB Audio data
rxAudioISO_ep3();
 
ep3count++;
USBE3CSR1bits.RXPKTRDY = 0;
USBCSR1bits.EP3RXIF = 0;
}
 
/* Start of Frame (SOF)/MicroFrame - Audio Feedback Calculation */
if(USBCSR2bits.SOFIF){

if(usbStreamingInterface1_AltSetting != 0){
//led_1 = ~led_1; // Test
}

if(usbStreamingInterface2_AltSetting != 0){
led_2 = ~led_2; // Test
}

SOFcount++;
USBCSR2bits.SOFIF = 0; // Clear Start of Frame (SOF)/MicroFrame Interrupt.
}
 
IFS4CLR = _IFS4_USB_GENERAL_EVENT_MASK; // Reset the USB Interrupt flag.
}
 
 
void initUSBDMA(){

IEC4bits.USBDMAIE = 0; // Disable USB DMA interrupt.

IFS4bits.USBDMAIF = 0; // Clear the USB DMA Interrupt.
USBDMAINT = 0x00; // Clear Channels 1-8 USB DMA Interrupt Flags
//USBDMAINTbits.DMA1IF = 0;
//USBDMAINTbits.DMA2IF = 0;

// Set the USB DMA Interrupt Priority and Sub-Priority Levels
IPC33bits.USBDMAIP = 5;
IPC33bits.USBDMAIS = 3;

// USBDPBFD: USB Double Packet Buffer Disable Register
USBDPBFD = 0x00FF00FF;

// DMABRSTM<1:0>: DMA Burst Mode Selection bit
// 11 = Burst Mode 3: INCR16, INCR8, INCR4 or unspecified length
// 10 = Burst Mode 2: INCR8, INCR4 or unspecified length
// 01 = Burst Mode 1: INCR4 or unspecified length
// 00 = Burst Mode 0: Bursts of unspecified length
USBDMA1Cbits.DMABRSTM = 0;
USBDMA2Cbits.DMABRSTM = 0;

// DMAEP<3:0>: DMA Endpoint Assignment bits
// These bits hold the endpoint that the DMA channel is assigned to. Valid values are 0-7.
USBDMA1Cbits.DMAEP = 1; // IN Endpoint 1
USBDMA2Cbits.DMAEP = 3; // OUT Endpoint 3

// DMAMODE: DMA Transfer Mode bit
// 1 = DMA Mode1 Transfers
// 0 = DMA Mode0 Transfers
USBDMA1Cbits.DMAMODE = 0;
USBDMA2Cbits.DMAMODE = 0;

// DMADIR: DMA Transfer Direction bit
// 1 = DMA Read (TX endpoint)
// 0 = DMA Write (RX endpoint)
USBDMA1Cbits.DMADIR = 1;
USBDMA2Cbits.DMADIR = 0;

// DMAADDR<31:0>: DMA Memory Address bits
// This register identifies the current memory address of the corresponding
// DMA channel. The initial memory address written to this register during
// initialization must have a value such that its modulo 4 value is equal
// to ?0?. The lower two bits of this register are read only and cannot be
// set by software. As the DMA transfer progresses, the memory address will
// increment as bytes are transferred.
USBDMA1Abits.DMAADDR = KVA_TO_PA(&USB_EP1_buffer); // USB DMA1 memory address.
USBDMA2Abits.DMAADDR = KVA_TO_PA(&USB_EP3_buffer); // USB DMA2 memory address

// DMACOUNT<31:0>: DMA Transfer Count bits
// This register identifies the current DMA count of the transfer. Software
// will set the initial count of the transfer which identifies the entire
// transfer length. As the count progresses this count is decremented as
// bytes are transferred.
//USBDMA2Nbits.DMACOUNT = EP3RXBUFFSIZE;

// DMAREQEN: Endpoint DMA Request Enable bit
// 1 = DMA requests are enabled for this endpoint
// 0 = DMA requests are disabled for this endpoint
// USBIENCSR0 for TX endpoint, USBIENCSR1 for RX endpoint
USBE1CSR0bits.DMAREQEN = 0;
USBE3CSR1bits.DMAREQEN = 1;

// DMAREQMD: DMA Request Mode Selection bit
// 1 = DMA Request Mode 1
// 0 = DMA Request Mode 0
// USBIENCSR0 for TX endpoint, USBIENCSR1 for RX endpoint
USBE1CSR0bits.DMAREQMD = 0;
USBE3CSR1bits.DMAREQMD = 1;

// TXEDMA: TX Endpoint DMA Assertion Control bit
// 1 = DMA_REQ signal for all IN endpoints will be deasserted when MAXP-8 bytes
// have been written to an endpoint. This is Early mode.
// 0 = DMA_REQ signal for all IN endpoints will be deasserted when MAXP bytes
// have been written to an endpoint. This is Late mode.
USBOTGbits.TXEDMA = 0;

// RXEDMA: RX Endpoint DMA Assertion Control bit
// 1 = DMA_REQ signal for all OUT endpoints will be deasserted when MAXP-8 bytes
// have been written to an endpoint. This is Early mode.
// 0 = DMA_REQ signal for all OUT endpoints will be deasserted when MAXP bytes
// have been written to an endpoint. This is Late mode.
USBOTGbits.RXEDMA = 0;

// AUTOCLR: RXPKTRDY Automatic Clear Control bit
// 1 = RXPKTRDY will be automatically cleared when a packet of RXMAXP bytes
// has been unloaded from the RX FIFO. When packets of less than the maximum
// packet size are unloaded, RXPKTRDY will have to be cleared manually. When
// using a DMA to unload the RX FIFO, data is read from the RX FIFO in 4-byte
// chunks regardless of the RXMAXP.
// 0 = No automatic clearing of RXPKTRDY
//USBE3CSR1bits.AUTOCLR = 1;

// DMAIE: DMA Interrupt Enable bit
// 1 = Interrupt is enabled for this channel
// 0 = Interrupt is disabled for this channel
USBDMA1Cbits.DMAIE = 1;
USBDMA2Cbits.DMAIE = 1;

IEC4bits.USBDMAIE = 1; // Enable USB DMA interrupt.
}
 

uint16_t rxAudioISO_ep3(){
ep3rbc = USBE3CSR2bits.RXCNT; // Endpoint 3 - Received Bytes Count
tempData = (uint8_t *)&USBFIFO3;
int i;
for(i = 0; i < ep3rbc; i++){
USB_EP3_buffer[i] = *(tempData + (i & 3));
}

// CHEN: Channel Enable bit(2)
// 1 = Channel is enabled
// 0 = Channel is disabled
DCH3CONbits.CHEN = 1; // DMA Channel 3 is Enabled.

// CFORCE: DMA Forced Transfer bit
// 1 = A DMA transfer is forced to begin when this bit is written to a '1'
// 0 = This bit always reads '0'
DCH3ECONbits.CFORCE = 1;

return ep3rbc;
}

 
 
Here is the simplified code using the USB DMA -> buffer -> general purpose DMA -> I2S/SPI method:

uint8_t __attribute__((coherent)) __attribute__((aligned(32))) USB_EP3_buffer[(EP3RXBUFFSIZE * 8)];
 
void __attribute__((interrupt(ipl4srs), at_vector(_USB_VECTOR), aligned(16), no_fpu, nomips16)) USB_Handler(void){
 
/* Endpoint 3 RX Interrupt Handler */
if(USBCSR1bits.EP3RXIF){ // ISOCHRONOUS Endpoint 3 Received A Packet.
led_3 = ~led_3;
 
// Get the count of bytes to be transferred from Endpoint 3.
ep3rbc = USBE3CSR2bits.RXCNT;
 
// DMAEN: DMA Enable bit
// 1 = Enable the DMA transfer and start the transfer
// 0 = Disable the DMA transfer
USBDMA2Cbits.DMAEN = 1;
 
ep3count++;
USBE3CSR1bits.RXPKTRDY = 0;
USBCSR1bits.EP3RXIF = 0;
}
 
/* Start of Frame (SOF)/MicroFrame - Audio Feedback Calculation */
if(USBCSR2bits.SOFIF){

if(usbStreamingInterface1_AltSetting != 0){
//led_1 = ~led_1; // Test
}

if(usbStreamingInterface2_AltSetting != 0){
led_2 = ~led_2; // Test
}

SOFcount++;
USBCSR2bits.SOFIF = 0; // Clear Start of Frame (SOF)/MicroFrame Interrupt.
}
 
 
void __attribute__((interrupt(ipl5srs), at_vector(_USB_DMA_VECTOR), aligned(16), no_fpu, nomips16)) USBDMA_Handler(void){

if(USBDMAINTbits.DMA1IF){


USBDMAINTbits.DMA1IF = 0;
}

if(USBDMAINTbits.DMA2IF){

// CHEN: Channel Enable bit(2)
// 1 = Channel is enabled
// 0 = Channel is disabled
DCH3CONbits.CHEN = 1; // DMA Channel 3 is Enabled.

// CFORCE: DMA Forced Transfer bit
// 1 = A DMA transfer is forced to begin when this bit is written to a '1'
// 0 = This bit always reads '0'
DCH3ECONbits.CFORCE = 1;

led_1 = ~led_1;
}

if(USBDMA1Cbits.DMAERR){
// Clear the error
USBDMA1Cbits.DMAERR = 0;
}

if(USBDMA2Cbits.DMAERR){
// Clear the error
USBDMA2Cbits.DMAERR = 0;
}

led_4r = ~led_4r;
IFS4CLR = _IFS4_USB_DMA_EVENT_MASK;
}
 

 
post edited by MisterHemi - 2019/11/05 13:17:10

My configuration:
MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
 
Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
#1

12 Replies Related Threads

    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 03:17:43 (permalink)
    0
    Ok... maybe someone will know the answers. Here are some questions:
     
    1) The general purpose DMA uses Physical Addresses to access memory or peripherals, does the USB DMA also use Physical Addresses?
     
    2) In relation to the first question, does the USB DMA have it's own memory or is it shared memory?
     

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #2
    JarekC
    New Member
    • Total Posts : 26
    • Reward points : 0
    • Joined: 2016/10/20 07:06:52
    • Location: 0
    • Status: offline
    Re: USB DMA Question 2019/11/08 09:51:59 (permalink)
    0
    Hi,
    Where in your example you set the registry USBDMAxN (DMACOUNT)?
     
    Ad1. I think USB  DMA uses Physical Address, code snippet from the PLIB  library:
        /* DMA ADDR register program */
        usbhs->DMA_CHANNEL[dmaChannel - 1].DMAADDR = KVA_TO_PA(address);

     
    Ad2. USB module has own 9kB RAM memory for endpoint FIFOs
     
    Regards
    JarekC.DIY
    #3
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 10:07:06 (permalink)
    0
    I have it set as so:
     
    In my ISR endpoint 3:

    ep3rbc = USBE3CSR2bits.RXCNT;

    // Set the count of bytes to be transferred via USB DMA 2 to the buffer/register.
    USBDMA2Nbits.DMACOUNT = ep3rbc;

     
    In the initialization:

     
    USBDMA2Abits.DMAADDR = KVA_TO_PA(&USB_EP3_buffer);   // USB DMA2 memory address
     

    post edited by MisterHemi - 2019/11/08 10:10:09

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #4
    JarekC
    New Member
    • Total Posts : 26
    • Reward points : 0
    • Joined: 2016/10/20 07:06:52
    • Location: 0
    • Status: offline
    Re: USB DMA Question 2019/11/08 10:12:40 (permalink)
    0
    I asked about USBDMAxN (DMACOUNT).
    #5
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 10:14:36 (permalink)
    0
    JarekC
    I asked about USBDMAxN (DMACOUNT).




    I caught that and edited to add that. In my ISR I set the count/value.

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #6
    JarekC
    New Member
    • Total Posts : 26
    • Reward points : 0
    • Joined: 2016/10/20 07:06:52
    • Location: 0
    • Status: offline
    Re: USB DMA Question 2019/11/08 10:33:18 (permalink)
    0
    I think you should clear  RXPKTRDY bit not in EP3 ISR but after finished USB DMA transfer (in USB DMA ISR).
    #7
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 13:26:58 (permalink)
    0
    JarekC
    I think you should clear  RXPKTRDY bit not in EP3 ISR but after finished USB DMA transfer (in USB DMA ISR).




    I think I tried that too but let me try just to be sure I did that already.
     
    I'll let you know the results soon.

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #8
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 13:41:58 (permalink)
    0
    Same result.... Here's what I have so far.
     
    In the USB ISR:

     
    /* Endpoint 3 RX Interrupt Handler */
    if(USBE3CSR1bits.RXPKTRDY){ // ISOCHRONOUS Endpoint 3 Received A Packet.

    // Get the count of bytes to be transferred from Endpoint 3.
    ep3rbc = USBE3CSR2bits.RXCNT;

    // Set the count of bytes to be transferred via USB DMA 2 to the buffer/register.
    USBDMA2Nbits.DMACOUNT = ep3rbc;

    DCH3CSIZbits.CHCSIZ = ep3rbc;

    USBDMA2Cbits.DMAIE = 1;

    // DMAEN: DMA Enable bit
    // 1 = Enable the DMA transfer and start the transfer
    // 0 = Disable the DMA transfer
    USBDMA2Cbits.DMAEN = 1;

    enableAudioOut = TRUE;

    ep3count++;

    USBCSR1bits.EP3RXIF = 0;
    led_3 = ~led_3;
    }
     

     
     
    In the USB DMA ISR:

     
    void __attribute__((interrupt(ipl5srs), at_vector(_USB_DMA_VECTOR), aligned(16), no_fpu, nomips16)) USBDMA_Handler(void){

    if(USBDMAINTbits.DMA1IF == 1){


    USBDMAINTbits.DMA1IF = 0;
    //led_4g = ~led_4g;
    }

    //if(USBDMAINTbits.DMA2IF == 1){ // <- Never flagged
    if(enableAudioOut == TRUE){

    DCH3CSIZbits.CHCSIZ = ep3rbc;

    // CHEN: Channel Enable bit(2)
    // 1 = Channel is enabled
    // 0 = Channel is disabled
    DCH3CONbits.CHEN = 1; // DMA Channel 3 is Enabled.

    // CFORCE: DMA Forced Transfer bit
    // 1 = A DMA transfer is forced to begin when this bit is written to a '1'
    // 0 = This bit always reads '0'
    DCH3ECONbits.CFORCE = 1;

    USBE3CSR1bits.RXPKTRDY = 0;
    enableAudioOut = FALSE;
    led_1 = ~led_1;
    }

    if(USBDMA1Cbits.DMAERR){
    // Clear the error
    USBDMA1Cbits.DMAERR = 0;
    }

    if(USBDMA2Cbits.DMAERR){
    // Clear the error
    USBDMA2Cbits.DMAERR = 0;
    }

    IFS4CLR = _IFS4_USB_DMA_EVENT_MASK;
    led_4r = ~led_4r;
    }
     


    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #9
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 14:11:29 (permalink)
    0
    For completeness and just in case someone sees something I forgot or missed i'll post the code to initialize the USB and USB DMA.
     
    Order of operation:
    1) Initialize USB
    2) Initialize USB DMA (I made it a separate function for other instances where I may not need or use it).
    3) Enable USB (USBCSR0bits.SOFTCONN = 1;)
     
    USB Initialization:

    void initUSB(){

    // Configure the USB hardware and registers.
    USBCSR0bits.SOFTCONN = 0; // 1 = The USB D+/D- lines are enabled and active,
    // 0 = The USB D+/D- lines are disabled and are tri-stated.

    USBCSR0bits.HSEN = 1; // 1 = Enable High Speed (480Mbps) USB mode.

    /* Disable Endpoint interrupts */
    USBCSR1bits.EP0IE = 0; // Endpoint 0 interrupt disable
    USBCSR1bits.EP1TXIE = 0; // Endpoint 1 TX interrupt disable
    USBCSR2bits.EP2RXIE = 0; // Endpoint 2 RX interrupt disable
    USBCSR2bits.EP3RXIE = 0; // Endpoint 3 RX interrupt disable
    USBCSR1bits.EP4TXIE = 0; // Endpoint 4 TX interrupt disable
    USBCSR2bits.EP5RXIE = 0; // Endpoint 5 RX interrupt disable
    USBCSR1bits.EP6TXIE = 0; // Endpoint 5 TX interrupt disable

    USBCSR2bits.SOFIE = 0; // Disable Start of Frame event interrupt.

    USBCSR2bits.RESETIE = 0;

    USBCRCONbits.USBIE = 0; // Disable general interrupt from USB module
    IEC4bits.USBIE = 0; // Disable the USB interrupt.

    // Clear the interrupt flags
    IFS4CLR = _IFS4_USB_GENERAL_EVENT_MASK;
    USBCSR0bits.EP0IF = 0;
    USBCSR0bits.EP1TXIF = 0;
    USBCSR1bits.EP2RXIF = 0;
    USBCSR1bits.EP3RXIF = 0;
    USBCSR0bits.EP4TXIF = 0;
    USBCSR1bits.EP5RXIF = 0;
    USBCSR0bits.EP6TXIF = 0;
    USBCSR2bits.SOFIF = 0;

    IPC33bits.USBIP = 4; // USB Interrupt Priority.
    IPC33bits.USBIS = 3; // USB Interrupt Sub-Priority.

    // MODE: Endpoint Direction Control bit
    // 1 = Endpoint is TX
    // 0 = Endpoint is RX
    USBE1CSR0bits.MODE = 1; // 1 = Endpoint is TX.
    USBE2CSR0bits.MODE = 0; // 0 = Endpoint is RX
    USBE3CSR0bits.MODE = 0; // 0 = Endpoint is RX.
    USBE4CSR0bits.MODE = 1; // 1 = Endpoint is TX
    USBE5CSR0bits.MODE = 0; // 0 = Endpoint is RX
    USBE6CSR0bits.MODE = 1; // 1 = Endpoint is TX

    // Configure endpoint 0 first.
    USBE0CSR0bits.TXMAXP = EP0BUFFSIZE; // Set endpoint 0 buffer size (multiples of 8).

    // These are multiples of 8, e.g.- "1" is 8 bytes, "8" is 64 bytes
    USBE1CSR0bits.TXMAXP = EP1TXBUFFSIZE; // Endpoint 1 - Maximum TX Payload Per Transaction Control bits
    USBE2CSR1bits.RXMAXP = EP2RXBUFFSIZE; // Endpoint 2 - Maximum RX Payload per transaction Control bits
    USBE3CSR1bits.RXMAXP = EP3RXBUFFSIZE; // Endpoint 3 - Maximum RX Payload Per Transaction Control bits
    USBE4CSR0bits.TXMAXP = EP4TXBUFFSIZE; // Endpoint 4 - Maximum TX Payload per transaction Control bits
    USBE5CSR1bits.RXMAXP = EP5RXBUFFSIZE; // Endpoint 5 - Maximum RX Payload per transaction Control bits
    USBE6CSR0bits.TXMAXP = EP6TXBUFFSIZE; // Endpoint 6 - Maximum TX Payload per transaction Control bits

    USBE1CSR2bits.PROTOCOL = 1; // Endpoint 1 - TX Endpoint Protocol Control bits
    USBE2CSR3bits.PROTOCOL = 1; // Endpoint 2 - RX Endpoint Protocol Control bits
    USBE3CSR3bits.PROTOCOL = 1; // Endpoint 3 - RX Endpoint Protocol Control bits
    USBE4CSR2bits.PROTOCOL = 1; // Endpoint 4 - TX Endpoint Protocol Control bits
    USBE5CSR3bits.PROTOCOL = 2; // Endpoint 5 - RX Endpoint Protocol Control bits
    USBE6CSR2bits.PROTOCOL = 2; // Endpoint 6 - TX Endpoint Protocol Control bits
    //PROTOCOL<1:0>: RX/TX Endpoint Protocol Control bits
    //11 = Interrupt
    //10 = Bulk
    //01 = Isochronous
    //00 = Control

    // ISOUPD: ISO Update bit (Device mode only; unimplemented in Host mode)
    // 1 = USB module will wait for a SOF token from the time TXPKTRDY is set
    // before sending the packet.
    // 0 = No change in behavior.
    USBCSR0bits.ISOUPD = 1;


    // DYNFIFOS: Dynamic FIFO Sizing Option bit
    // 1 = Dynamic FIFO sizing is supported
    // 0 = No Dynamic FIFO sizing is supported
    USBE0CSR3bits.DYNFIFOS = 1;


    // Datasheet DS60001320E-page 232
    // 1111 = Reserved
    // 1110 = Reserved
    // 1101 = 8192 bytes
    // 1100 = 4096 bytes
    // 1011 = 2038 bytes
    // 1010 = 1024 bytes
    // 1001 = 512 bytes
    // 1000 = 256 bytes
    // 0111 = 128 bytes
    // 0110 = 64 bytes
    // 0101 = 32 bytes
    // 0100 = 16 bytes
    // 0011 = 8 bytes
    // 0010 = Reserved
    // 0001 = Reserved
    // 0000 = Reserved or endpoint has not been configured
    USBE1CSR3bits.TXFIFOSZ = 0xC; // Transmit FIFO Size bits - 4096 bytes
    USBE2CSR3bits.RXFIFOSZ = 0x3; // Receive FIFO Size bits - 8 bytes
    USBE3CSR3bits.RXFIFOSZ = 0xC; // Receive FIFO Size bits - 4096 bytes
    USBE4CSR3bits.TXFIFOSZ = 0x3; // Transmit FIFO Size bits - 8 bytes
    USBE5CSR3bits.RXFIFOSZ = 0x3; // Receive FIFO Size bits - 8 bytes
    USBE6CSR3bits.TXFIFOSZ = 0x3; // Transmit FIFO Size bits - 8 bytes

    // Endpoint TX/RX Polling Interval/NAK Limit bits
    // For Interrupt and Isochronous transfers, this field defines the polling
    // interval for the endpoint. For Bulk end-points, this field sets the
    // number of frames/microframes after which the endpoint should time out on
    // receiving a stream of NAK responses.
    //
    // Transfer Type Speed Valid Values(m) Interpretation
    // Isochronous Full or High 0x01 to 0x10 Polling interval is
    // 2^(m-1) frames/microframes.
    USBE1CSR2bits.TXINTERV = 0x01;
    USBE3CSR3bits.RXINTERV = 0x01;

    // MULT<4:0>: Multiplier Control bits
    // For Isochronous/Interrupt endpoints or of packet splitting on Bulk
    // endpoints, multiplies RXMAXP/TXMAXP by MULT+1 for the payload size.
    // For Bulk endpoints, MULT can be up to 32 and defines the number of ?USB?
    // packets of the specified payload into which a single data packet placed
    // in the FIFO should be split, prior to transfer. The data packet is
    // required to be an exact multiple of the payload specified by TXMAXP.
    // For Isochronous/Interrupts endpoints operating in Hi-Speed mode, MULT may
    // be either 2 or 3 and specifies the maximum number of such transactions
    // that can take place in a single microframe.
    USBE1CSR0bits.MULT = 2; // TX
    USBE3CSR1bits.MULT = 2; // RX

    // NOTE: We don't set the TX speed in device mode, as noted below from the
    // data sheet (DS60001320D-page 223):
    // TX Endpoint Operating Speed Control bits (Host mode)
    // In HOST mode it would use CSR2 to set the TX speed, for example:
    // USBExCSR2bits.SPEED = z;
    // Where x is the endpoint number and z is the speed.
    USBE3CSR3bits.SPEED = 1; // Endpoint 3: RX Endpoint Operating Speed Control bits - High speed

    // ISO: Isochronous Endpoint Control bit (Device mode)
    // 1 = Enable the TX/RX endpoint for Isochronous transfers
    // 0 = Enable the TX/RX endpoint for Bulk/Interrupt transfers
    USBE1CSR0bits.ISO = 1; // Isochronous TX Endpoint Enable bit (Device mode).
    USBE2CSR1bits.ISO = 1; // Isochronous RX Endpoint Enable bit (Device mode).
    USBE3CSR1bits.ISO = 1; // Isochronous RX Endpoint Enable bit (Device mode).
    USBE4CSR0bits.ISO = 1; // Isochronous TX Endpoint Enable bit (Device mode).
    USBE5CSR1bits.ISO = 0; // Isochronous RX Endpoint Disable bit (Device mode).
    USBE6CSR0bits.ISO = 0; // Isochronous TX Endpoint Disable bit (Device mode).

    /* Enable Endpoint interrupts */
    USBCSR1bits.EP0IE = 1; // Endpoint 0 interrupt enable
    USBCSR1bits.EP1TXIE = 1; // Endpoint 1 TX interrupt enable
    USBCSR2bits.EP2RXIE = 1; // Endpoint 2 RX interrupt enable
    USBCSR2bits.EP3RXIE = 1; // Endpoint 3 RX interrupt enable
    USBCSR1bits.EP4TXIE = 1; // Endpoint 4 TX interrupt enable
    USBCSR2bits.EP5RXIE = 1; // Endpoint 5 RX interrupt enable
    USBCSR1bits.EP6TXIE = 1; // Endpoint 5 TX interrupt enable

    USBCSR2bits.SOFIE = 0; // Enable Start of Frame event interrupt.

    USBCSR2bits.RESETIE = 1;

    USBCRCONbits.USBIE = 1; // Enable general interrupt from USB module.
    IEC4bits.USBIE = 1; // Enable the USB interrupt.

    }

     
    USB DMA Initialization:

    void initUSBDMA(){

    IEC4bits.USBDMAIE = 0; // Disable USB DMA interrupt.
    IFS4CLR = _IFS4_USB_DMA_EVENT_MASK;
    USBDMAINT = 0x00; // Clear Channels 1-8 USB DMA Interrupt Flags

    // Set the USB DMA Interrupt Priority and Sub-Priority Levels
    IPC33bits.USBDMAIP = 5;
    IPC33bits.USBDMAIS = 3;

    // USBDPBFD: USB Double Packet Buffer Disable Register
    USBDPBFD = 0x00FF00FF;

    // DMABRSTM<1:0>: DMA Burst Mode Selection bit
    // 11 = Burst Mode 3: INCR16, INCR8, INCR4 or unspecified length
    // 10 = Burst Mode 2: INCR8, INCR4 or unspecified length
    // 01 = Burst Mode 1: INCR4 or unspecified length
    // 00 = Burst Mode 0: Bursts of unspecified length
    USBDMA2Cbits.DMABRSTM = 3; // <- NOTE: I've tried modes 0 and 3 with the same results.

    // DMAEP<3:0>: DMA Endpoint Assignment bits
    // These bits hold the endpoint that the DMA channel is assigned to. Valid values are 0-7.
    USBDMA2Cbits.DMAEP = 3; // OUT Endpoint 3

    // DMAMODE: DMA Transfer Mode bit
    // 1 = DMA Mode1 Transfers
    // 0 = DMA Mode0 Transfers
    USBDMA2Cbits.DMAMODE = 0;

    // DMADIR: DMA Transfer Direction bit
    // 1 = DMA Read (TX endpoint)
    // 0 = DMA Write (RX endpoint)
    USBDMA2Cbits.DMADIR = 0;

    // DMAADDR<31:0>: DMA Memory Address bits
    // This register identifies the current memory address of the corresponding
    // DMA channel. The initial memory address written to this register during
    // initialization must have a value such that its modulo 4 value is equal
    // to '0'. The lower two bits of this register are read only and cannot be
    // set by software. As the DMA transfer progresses, the memory address will
    // increment as bytes are transferred.
    USBDMA2Abits.DMAADDR = KVA_TO_PA(&USB_EP3_buffer); // USB DMA2 memory address

    // DMAREQEN: Endpoint DMA Request Enable bit
    // 1 = DMA requests are enabled for this endpoint
    // 0 = DMA requests are disabled for this endpoint
    // USBIENCSR0 for TX endpoint, USBIENCSR1 for RX endpoint
    USBE3CSR1bits.DMAREQEN = 1;

    // DMAREQMD: DMA Request Mode Selection bit
    // 1 = DMA Request Mode 1
    // 0 = DMA Request Mode 0
    // USBIENCSR0 for TX endpoint, USBIENCSR1 for RX endpoint
    USBE3CSR1bits.DMAREQMD = 0;

    // TXEDMA: TX Endpoint DMA Assertion Control bit
    // 1 = DMA_REQ signal for all IN endpoints will be deasserted when MAXP-8 bytes
    // have been written to an endpoint. This is Early mode.
    // 0 = DMA_REQ signal for all IN endpoints will be deasserted when MAXP bytes
    // have been written to an endpoint. This is Late mode.
    USBOTGbits.TXEDMA = 0;

    // RXEDMA: RX Endpoint DMA Assertion Control bit
    // 1 = DMA_REQ signal for all OUT endpoints will be deasserted when MAXP-8 bytes
    // have been written to an endpoint. This is Early mode.
    // 0 = DMA_REQ signal for all OUT endpoints will be deasserted when MAXP bytes
    // have been written to an endpoint. This is Late mode.
    USBOTGbits.RXEDMA = 0;

    // AUTOCLR: RXPKTRDY Automatic Clear Control bit
    // 1 = RXPKTRDY will be automatically cleared when a packet of RXMAXP bytes
    // has been unloaded from the RX FIFO. When packets of less than the maximum
    // packet size are unloaded, RXPKTRDY will have to be cleared manually. When
    // using a DMA to unload the RX FIFO, data is read from the RX FIFO in 4-byte
    // chunks regardless of the RXMAXP.
    // 0 = No automatic clearing of RXPKTRDY
    //USBE3CSR1bits.AUTOCLR = 1;

    // DMAIE: DMA Interrupt Enable bit
    // 1 = Interrupt is enabled for this channel
    // 0 = Interrupt is disabled for this channel
    USBDMA2Cbits.DMAIE = 1;

    IEC4bits.USBDMAIE = 1; // Enable USB DMA interrupt.

    }


    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #10
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 20:07:22 (permalink)
    0
    Additional information: When SOF interrupts are enabled the USB DMA ISR isn't called.
     
    So I had to disable it:

    USBCSR2bits.SOFIE = 0;      // Disable Start of Frame event interrupt.

     
    I thought this was odd because from what i've read Isochronous transfers being immediately after the Start of Frame (SOF) and perhaps the SOF interrupt might be needed when using some type of synchronization.
     
    I suppose you could just as easily read the Last Received Frame Number bits, such as:

    frmNmbr = USBCSR3bits.RFRMNUM;

     

    As stated here:  www.usbmadesimple.co.uk/ums_7.htm#sof_pkt
    "At high speed the 1 ms frame is divided into 8 microframes of 125 us. A SOF is sent at the start of each of these 8 microframes, each having the same frame number, which then increments every 1 ms frame."
     
    "For example, an isochronous endpoint will be assigned one transfer per frame."

     

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #11
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/08 20:24:28 (permalink)
    0
    A diagram of USB transfers can be found here: https://microchipdeveloper.com/usb:transfer

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #12
    MisterHemi
    Senior Member
    • Total Posts : 171
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: USB DMA Question 2019/11/13 03:24:10 (permalink)
    0
    This seems to be a reoccurring question but no one has posted an answer (see the following links). It makes me wonder if there's an issue with the USB DMA. The interrupts work but it seems the USB DMA isn't transferring anything.
    I'm using my own USB device stack but in one of the post below it also seems to be a problem (perhaps in the past) with Harmony too.
     
    https://www.microchip.com/forums/m1001152.aspx
     
    https://www.microchip.com/forums/m1005621.aspx

    For example if you look at project msd_basic, you have these functions
     - _DRV_USBHS_HOST_IRPTransmitFIFOLoad, and
     - _DRV_USBHS_HOST_IRPReceiveFIFOUnload,
     
    both decide whether or not to use DMA by calling _DRV_USBHS_HOST_GetFreeDMAChannel, which always return false, so they revert to manually loading the RX/TX FIFOs. Seems like a placeholder for later implementation.

     
    Other related post:
    https://www.microchip.com/forums/m695465.aspx
     
    https://www.microchip.com/forums/m979883.aspx

    The system is running under FreeRTOS - I also noticed that the DMA interrrupt never triggers so I have disabled using DMA with the USB.

    I did get the interrupt to work but it was odd and I don't remember what made the difference.

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS High Sierra (10.14.5) and MPLAB X IDE v5.20
     
    Curiosity PIC32MZ EF, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #13
    Jump to:
    © 2019 APG vNext Commercial Version 4.5