This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

USB DMA reading garbage in specific situation



Hi,

I have written a very basic USB Driver for DSP/BIOS. I have 2 endpoints EP 2 for receiving EP 1 for transmitting.

Now I experience a problem when I run out of buffers for receiving.

I currently do the following when I get a receive Interrupt:

    DeviceObj.input.dataPacket = QUE_get(&DeviceObj.input.pendList);
    //Check if the queue was not empty
    if(DeviceObj.input.dataPacket != (IOM_Packet*)&DeviceObj.input.pendList)
    {
        LOG_printf(&trace, "Setting up DMA for receiving on packet %p\n", DeviceObj.input.dataPacket->addr);
        USB_confDmaRx(&hpdrx, CSL_USB_EP2_PACKET_SIZE_HS, DeviceObj.input.dataPacket->addr);
        USB_dmaRxStart(CSL_USB_EP2);
    }
    else
    {
        DeviceObj.input.overrun = TRUE;
    }

In the Channel submit function I check for the overrun flag:

static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
    ....  
     if(chan->overrun)
    {
        if(chan->mode == IOM_INPUT)
        {
            USB_confDmaRx(&hpdrx, CSL_USB_EP2_PACKET_SIZE_HS, chan->dataPacket->addr);
            USB_dmaRxStart(CSL_USB_EP2);
            chan->overrun = FALSE;
        }
    }
    .....
}

Now when I get to the mdSubmitChan function and call the USB_dmaRxStart function from there I do not receive the data I sended from the HOST. Instead I get the data I have sended from the DEVICE to the HOST sometime earlier. I also made sure that no Transmit is in progress when calling dmaRxStart. But shortly before I get to the mdSubmitChan function I get an interrupted for a Transmit request but I do NOT call confDmaTx/dmaTxStart then. I dont know if that matters.

 

  • Hi,

    I assume you are using the C5515 EVM and CSL 2.10 release.

    For the CPPI DMA on C5515 USB module, there will be no RX EP interrupt when the RX packet is received. There will be a RX CDMA completion interrupt when the RX packet is received. For the TX packet, there will be a TX EP interrupt AND a TX CDMA completion interrupt.

    To process the RX CDMA in the RX EP interrupt is incorrect.

     if (queuePend1 & 0x0400)
     {
      /* pop packet descriptor from queue */
      queRegVal = usbRegisters->QMQN[26].CTRL1D;;

    #if (defined(CHIP_C5505_C5515) || defined(CHIP_C5504_C5514))

      USB_dmaRxStop(CSL_USB_EP2, usbDataBuffer,
                    CSL_USB_EP2_PACKET_SIZE_FS, FALSE);
    #else
      USB_dmaRxStop(CSL_USB_EP2, usbDataBuffer,
                    CSL_USB_EP2_PACKET_SIZE_FS, TRUE);
    #endif

      USB_confDmaRx(&hpdrx, CSL_USB_EP2_PACKET_SIZE_FS, usbDataBuffer);
      USB_dmaRxStart(CSL_USB_EP2);

      queuePend1 = 0;
     }

    in usb_isr() is the correct way to process the RX CDMA completion.

    Make sure you are using CSL 2.10. The CSL 2.01 has a FIFO allocation bug.  Your content mess up may be caused by the FIFO allocation bug.

    If you still having problem with USB CDMA, please send us the usb_isr(), so that we can further debug your problem.

     

    Best regards,

    Ming

  • Hi,

    thx for your answer (I use the evm5505 sorry I somehow forgot that to mention). Il will try out yout suggestions tomorrow and upgrade to the CSL 2.10. Just to make it clear as far as I understand now I call USB_confDmaRx/USB_dmaRxStart as soon as I have a buffer ready to receive and the usb controller will take care filling that buffer as soon as the host sends data is that correct?

    But how do I handle transmissions then? i.e. I get a TX interrupt  but I dont have any buffer to send? Would it be ok to do nothing then and do a USB_confDmaRx/USB_dmaRxStart in the mdSubmitChan function? Or should I mask that interrupt when I have no buffer ready?

  • Hi,

    First of all, if you are using the VC5505 EVM, you will need to modify the compiler options in csl_general.h (uncomment //#define CHIP_VC5505). By default, the CSL 2.10 is assuming C5515 EVM.

    The USB_confDmaRX/USB_dmaRxStart is not provoding the receiving buffer for the current RX packet. They are providing the receiving buffer for the future RX packet. That is why you can see the following lines in the processing for USB reset interrupt (CSL_USB_GBL_INT_RESET):

      USB_confDmaRx(&hpdrx, CSL_USB_EP2_PACKET_SIZE_FS, usbDataBuffer);
      USB_dmaRxStart(CSL_USB_EP2);

    It put one buffer into the RX free buffer queue (Q00). The first RX packet will be put into that buffer by the USB CPPI DMA when the packet arrives, The CDMA will then put the filled buffer into the RX completion queue (Q26) and send CPU a RX completion interrupt. Upon the reception of the RX completion interrupt, the CPU is responsible to put in another buffer into the RX free buffer queue (Q00) for receiving future RX packet.

    For TX, the situation is different, because the TX packet is initiated by the USB device (C5515).

      USB_confDmaTx(&hpdtx, CSL_USB_EP1_PACKET_SIZE_FS, usbDataBuffer, TRUE);
      USB_dmaTxStart(CSL_USB_EP1);

    will put usDataBuffer into the TX submission Queue (Q16). The CDMA will copy the data from the usbDataBuffer to the USB EP FIFO, whenever the USB EP FIFO is empty. The data will not go to the USB host until the IN token from the host is arrived. When the data copy from the usbDataBuffer to the USB EP FIFO is done (could be before the data actually send to USB host), the CDMA will move the TX buffer (usbDataBuffer) into the TX completion Queue (Q24) and send a TX completion interrupt (and an optional TX EP interrupt) to CPU. Upon the reception of the TX completion interrupt ( if (queuePend1 & 0x0100) ), the CPU should do the following:

     if (queuePend1 & 0x0100)
     {
      /* pop packet descriptor from queue */
      queRegVal = usbRegisters->QMQN[24].CTRL1D;;

    #if (defined(CHIP_C5505_C5515) || defined(CHIP_C5504_C5514))

      USB_confDmaTx(&hpdtx, CSL_USB_EP1_PACKET_SIZE_HS, usbDataBuffer, FALSE);
    #else
      USB_confDmaTx(&hpdtx, CSL_USB_EP1_PACKET_SIZE_HS, usbDataBuffer, TRUE);
    #endif
      //USB_dmaTxStart(CSL_USB_EP1);
     }

    Since the RX EP interrupt and the TX EP interrupt are replaced by the RX/TX completion interrupts, therefore we do not need to process them:

     /* Check Data Out Ready */
     if((pContext->dwIntSourceL & CSL_USB_RX_INT_EP1) ||
        (pContext->dwIntSourceL & CSL_USB_RX_INT_EP2) ||
        (pContext->dwIntSourceL & CSL_USB_RX_INT_EP3) ||
        (pContext->dwIntSourceL & CSL_USB_RX_INT_EP4))
     {
     }

     /* Check Data In Ready */
     if((pContext->dwIntSourceL & CSL_USB_TX_INT_EP1) ||
        (pContext->dwIntSourceL & CSL_USB_TX_INT_EP2) ||
        (pContext->dwIntSourceL & CSL_USB_TX_INT_EP3) ||
        (pContext->dwIntSourceL & CSL_USB_TX_INT_EP4))
     {
     }

    Another USB issue we recently found is that the USB CDMA cannot handle the RX or TX packet with size is not multiple of 4, so you may have to know the size of the incoming packet, before you decide to use CDMA or CPU polling to get  the data. If it has the size of multiple of 4, then you can use the CDMA, otherwise, you wil have to use CPU polling.

    Best regards,

     

    Ming  

     

  • Hi,

    First thank you for your excelent explanation it made things MUCH more clearer for me. I really think that such a toturial like explanation should go in the documentation of the CSL it would have saved me months of work. Or is it there and I missed it somehow?

    I just upgraded to the 2.10 CSL and my code suddenly worked. But I will modify my code to your suggestions anyway seems much more streightforward to me.

    I already figured out that you can only send messages of a specific size thought it maybe an error on my side. Thx for pointing that out.

    Best regards,

    hunt0r