UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
1,959 Views
Registered: ‎11-17-2016

How to get USB event when a packet is send using usbps_v2_2 baremetal

At the moment, I am able to send data between my PC and the Zynq using a USB link using DMA.

 

I need to get an event at the end of each block tranfer to be able to manage my buffers content. I have 2 buffers and I want to PingPong between these 2 buffers to transmit data from the Zynq, in device mode, to the PC.

 

I register my event handler using the following call:

Status = XUsbPs_EpSetHandler(UsbInstancePtr, 1, XUSBPS_EP_DIRECTION_IN, XUsbPs_Ep1EventHandler, UsbInstancePtr);

 

I enable the interrupts calling:

XUsbPs_IntrEnable(UsbInstancePtr, XUSBPS_IXR_UR_MASK | XUSBPS_IXR_UI_MASK);

 

I know the my XUsbPs_Ep1EventHandler() is called at the end of a small transfer of 1 block.

 

My problem is when the answer contains more than 2 blocks. I need to be notify when the content of 1 block is tranferred over USB so I can update the content of the buffer and call XUsbPs_EpQueueRequest(InstancePtr, 1, pbUsbBuffer, length, FALSE);

to queue the new content to be send over USB.

 

What should I do to get notified when the queued buffer is processed by the USB driver?

0 Kudos
1 Reply
1,920 Views
Registered: ‎11-17-2016

Re: How to get USB event when a packet is send using usbps_v2_2 baremetal

I tried to enable all the interrupts using the call:

XUsbPs_IntrEnable(UsbInstancePtr, XUSBPS_IXR_ALL);
without success.

 

In ug585-Zynq-7000-TRM.pdf, page 413, it is written:

After a dTD is processed, the controller will generate an interrupt if its IOC bit is set = 1.

 

I digged deeper in the usbps_v2_2 library code.

 

In XUsbPx_EpQueueRequest(), the IOC bit is set

do {
    Length = (BufferLen > XUSBPS_dTD_BUF_MAX_SIZE) ? XUSBPS_dTD_BUF_MAX_SIZE : BufferLen;
    /* Attach the provided buffer to the current descriptor.*/
    Status = XUsbPs_dTDAttachBuffer(Ep->dTDHead, BufferPtr, Length);
    if (XST_SUCCESS != Status) {
        return XST_FAILURE;
    }
    BufferLen -= Length;
    BufferPtr += Length;

    XUsbPs_dTDSetActive(Ep->dTDHead);
    if (BufferLen == 0 && (ReqZero == FALSE)) {
        XUsbPs_dTDSetIOC(Ep->dTDHead);
        exit = 0;
    }
    XUsbPs_dTDClrTerminate(Ep->dTDHead);
    XUsbPs_dTDFlushCache(Ep->dTDHead);

    /* Advance the head descriptor pointer to the next descriptor. */
    Ep->dTDHead = XUsbPs_dTDGetNLP(Ep->dTDHead);
    /* Terminate the next descriptor and flush the cache.*/
    XUsbPs_dTDInvalidateCache(Ep->dTDHead);
    /* Tell the caller if we do not have any descriptors available. */
    if (XUsbPs_dTDIsActive(Ep->dTDHead)) {
        return XST_USB_NO_DESC_AVAILABLE;
    }

    if (ReqZero && BufferLen == 0) {
        ReqZero = FALSE;
    }

} while(BufferLen || exit);

 

In my case BufferLen is 4096XUSBPS_dTD_BUF_MAX_SIZE is 16*1024 and ReqZero is FALSE.

 

In XUsbPs_InterHandler(), it handles the Enpoint Interrupts

/***************************************************************
*
* Handle Endpoint interrupts.
*
*/
if (IrqSts & XUSBPS_IXR_UI_MASK) {
    u32 EpStat;
    u32 EpCompl;

    /* ENDPOINT 0 SETUP PACKET HANDLING
    *
    * Check if we got a setup packet on endpoint 0. Currently we
    * only check for setup packets on endpoint 0 as we would not
    * expect setup packets on any other endpoint (even though it
    * is possible to send setup packets on other endpoints).
    */
    EpStat = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
                                                 XUSBPS_EPSTAT_OFFSET);
    if (EpStat & 0x0001) {
        /* Handle the setup packet */
        XUsbPs_IntrHandleEp0Setup(InstancePtr);

        /* Re-Prime the endpoint.
        * Endpoint is de-primed if a setup packet comes in.
        */
        XUsbPs_EpPrime(InstancePtr, 0, XUSBPS_EP_DIRECTION_OUT);
    }

    /* Check for RX and TX complete interrupts. */
    EpCompl = XUsbPs_ReadReg(InstancePtr->Config.BaseAddress,
                                                     XUSBPS_EPCOMPL_OFFSET);


    /* ACK the complete interrupts. */
    XUsbPs_WriteReg(InstancePtr->Config.BaseAddress,
    XUSBPS_EPCOMPL_OFFSET, EpCompl);

 

    /* Check OUT (RX) endpoints. */
    if (EpCompl & XUSBPS_EP_OUT_MASK) {
        XUsbPs_IntrHandleRX(InstancePtr, EpCompl);
    }

 

    /* Check IN (TX) endpoints. */
    if (EpCompl & XUSBPS_EP_IN_MASK) {
        XUsbPs_IntrHandleTX(InstancePtr, EpCompl);
    }
}

 

In XUsbPs_InterHandelTX(), the list of dTD is examined and the registered Endpoint Handler is called if the buffer has been send.

while (Ep->dTDTail != Ep->dTDHead) {

    XUsbPs_dTDInvalidateCache(Ep->dTDTail);

 

    /* If the descriptor is not active then the buffer has
    * not been sent yet.
    */
    if (XUsbPs_dTDIsActive(Ep->dTDTail)) {
        break;
    }

 

    if (Ep->HandlerFunc) {
        void *BufPtr;

        BufPtr = (void *) XUsbPs_ReaddTD(Ep->dTDTail,
                                                                 XUSBPS_dTDUSERDATA);

        Ep->HandlerFunc(Ep->HandlerRef, Index,
                                       XUSBPS_EP_EVENT_DATA_TX,
                                       BufPtr);
    }

    Ep->dTDTail = XUsbPs_dTDGetNLP(Ep->dTDTail);
}

 

As far as I can tell, it looks like the interrupt is generated when the dTD list is emptied but not at each buffer transmission.

 

Any ideas why the interrupt is not generated after sending each dTD buffer?

 

0 Kudos