Skip to main content
August 10, 2015
Question

How to cancel transfer on OUT pipe of USB?

  • August 10, 2015
  • 3 replies
  • 949 views
Posted on August 10, 2015 at 10:14

Is there any way to cancel OUT transfer (receive) on STM32 using CubeF4 library?

I use USB in my device to communicate with PC (STM32 is ''device'', PC is ''host''). If client (PC side) program is ''crashed'' and my software protocol is not terminated correctly I have to send ''reset'' command to control (0) pipe of USB and handle it on STM32 side. The problem is that before the client application crashed last time, MCU firmware used USBD_LL_PrepareReceive function and device is waiting for data from PC!  I _have_ to cancel that transfer without resetting whole USB device stack. Is there any way to do that with CubeF4 library?
    This topic has been closed for replies.

    3 replies

    August 10, 2015
    Posted on August 10, 2015 at 13:00

    OK, I got it   Edit: no, bad code!

    PCD_HandleTypeDef *hpcd =hUsbDevice.pData;

    USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;

        USB_OTG_OUTEndpointTypeDef* outEp = GetOutEndpoint(&hUsbDevice, NDC_IF0_OUT_EP);

        USB_OTG_INEndpointTypeDef* inEp = GetInEndpoint(&hUsbDevice, NDC_IF0_IN_EP);

        //set global OUT NAK

        USBx->GINTMSK &= ~USB_OTG_GINTMSK_GONAKEFFM;

    if((USBx->GINTSTS & USB_OTG_GINTMSK_GONAKEFFM) == 0){

    USBx_DEVICE->DCTL |= USB_OTG_DCTL_SGONAK;

    while((USBx->GINTSTS & USB_OTG_GINTMSK_GONAKEFFM) == 0){}

    }

    //begin disable EP

        USBx_DEVICE->DOEPMSK &= ~USB_OTG_DOEPMSK_EPDM; //Mask EP disabled interrupt for polling

    outEp->DOEPCTL |= USB_OTG_DOEPCTL_SNAK | USB_OTG_DOEPCTL_EPDIS; //Begin disable

    while((outEp->DOEPINT & USB_OTG_DOEPINT_EPDISD) == 0){} //Wait for disabled flag

    outEp->DOEPINT = USB_OTG_DOEPINT_EPDISD; //Clear endpoint disabled interrupt

    USBx_DEVICE->DOEPMSK |= USB_OTG_DOEPMSK_EPDM;//Unmask EP disabled interrupt

    USBD_LL_FlushEP(&hUsbDevice, NDC_IF0_OUT_EP); //Flush EP FIFO

    outEp->DOEPTSIZ = 0;

    USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK; //Disable global OUT NAK

    //Disable IN endpoint

    //stop tramsmission

    USBx_DEVICE->DIEPMSK &= ~USB_OTG_DIEPMSK_INEPNEM; //mask NAK effective interrupt

    inEp->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;

    while((inEp->DIEPINT & USB_OTG_DIEPINT_INEPNE) == 0){} //wait 'till stopped

    //disable endpoint

    USBx_DEVICE->DIEPMSK &= ~USB_OTG_DIEPMSK_EPDM; //Mask EP disabled interrupt for polling

    inEp->DIEPCTL |= USB_OTG_DIEPCTL_SNAK | USB_OTG_DIEPCTL_EPDIS; //begin disable

    while((inEp->DIEPINT & USB_OTG_DIEPINT_EPDISD) == 0){}//wait for disable done

    inEp->DIEPINT = USB_OTG_DIEPINT_EPDISD; //Clear endpoint disabled interrupt

    USBx_DEVICE->DIEPMSK |= USB_OTG_DIEPMSK_EPDM; //unmask;

    USBD_LL_FlushEP(&hUsbDevice, NDC_IF0_IN_EP);

    inEp->DIEPTSIZ = 0;

    //unmask NAK EFFECTIVE interrupt

    USBx_DEVICE->DIEPMSK |= USB_OTG_DIEPMSK_INEPNEM;

    inEp->DIEPCTL |= USB_OTG_DIEPCTL_CNAK;

    while((inEp->DIEPCTL & USB_OTG_DIEPCTL_NAKSTS) != 0){}

    inEp->DIEPINT = USB_OTG_DIEPINT_INEPNE; //Clear NAK effective interrupt

    September 23, 2015
    Posted on September 23, 2015 at 16:45

    Code in my previous post is not working good if DMA mode enabled in USB.

    Here is correct version:

     portENTER_CRITICAL();

    PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)hUsbDevice.pData;

    USB_OTG_GlobalTypeDef *USBx = hpcd->Instance;

    USB_OTG_OUTEndpointTypeDef* outEp = USBx_OUTEP(hpcd->OUT_ep[NDC_IF0_OUT_EP & 0x7F].num);

    USB_OTG_INEndpointTypeDef* inEp = USBx_INEP(hpcd->IN_ep[NDC_IF0_IN_EP & 0x7F].num);

    //Disable OUT endpoint

    if((outEp->DOEPCTL & USB_OTG_DOEPCTL_EPENA) == USB_OTG_DOEPCTL_EPENA){

    //set global OUT NAK

    USBx->GINTMSK &= ~USB_OTG_GINTMSK_GONAKEFFM;

    if((USBx->GINTSTS & USB_OTG_GINTMSK_GONAKEFFM) == 0){

    USBx_DEVICE->DCTL |= USB_OTG_DCTL_SGONAK;

    while((USBx->GINTSTS & USB_OTG_GINTMSK_GONAKEFFM) == 0){}

    }

    //begin disable OUT EP

    USBx_DEVICE->DOEPMSK &= ~USB_OTG_DOEPMSK_EPDM; //Mask EP disabled interrupt for polling

    outEp->DOEPCTL |= USB_OTG_DOEPCTL_SNAK | USB_OTG_DOEPCTL_EPDIS; //Begin disable

    while((outEp->DOEPINT & USB_OTG_DOEPINT_EPDISD) == 0){} //Wait for disabled flag

    outEp->DOEPINT = USB_OTG_DOEPINT_EPDISD; //Clear endpoint disabled interrupt

    USBx_DEVICE->DOEPMSK |= USB_OTG_DOEPMSK_EPDM;//Unmask EP disabled interrupt

    USBD_LL_FlushEP(&hUsbDevice, NDC_IF0_OUT_EP); //Flush EP FIFO

    USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK; //Disable global OUT NAK

    USBx->GINTMSK |= USB_OTG_GINTMSK_GONAKEFFM;

    }

    outEp->DOEPTSIZ = 0;

    //Disable IN endpoint

    if ((inEp->DIEPCTL & USB_OTG_DIEPCTL_EPENA) == USB_OTG_DIEPCTL_EPENA){

    USBx_DEVICE->DIEPMSK &= ~USB_OTG_DIEPMSK_INEPNEM; //mask NAK effective interrupt

    USBx_DEVICE->DIEPMSK &= ~USB_OTG_DIEPMSK_EPDM; //Mask EP disabled interrupt for polling

    inEp->DIEPCTL |= USB_OTG_DIEPCTL_SNAK;

    while((inEp->DIEPINT & USB_OTG_DIEPINT_INEPNE) == 0){} //wait 'till stopped

    inEp->DIEPCTL |= (USB_OTG_DIEPCTL_EPDIS | USB_OTG_DIEPCTL_SNAK);

    while((inEp->DIEPINT & USB_OTG_DIEPINT_EPDISD) == 0){}//wait for disable done

    inEp->DIEPINT = USB_OTG_DIEPINT_EPDISD; //Clear endpoint disabled interrupt

    USBx_DEVICE->DIEPMSK |= USB_OTG_DIEPMSK_EPDM; //unmask;

    USBD_LL_FlushEP(&hUsbDevice, NDC_IF0_IN_EP);

    inEp->DIEPCTL |= USB_OTG_DIEPCTL_CNAK;

    while((inEp->DIEPCTL & USB_OTG_DIEPCTL_NAKSTS) != 0){}

    inEp->DIEPINT = USB_OTG_DIEPINT_INEPNE; //Clear NAK effective interrupt

    //unmask NAK EFFECTIVE interrupt

    USBx_DEVICE->DIEPMSK |= USB_OTG_DIEPMSK_INEPNEM;

    }

    inEp->DIEPTSIZ = 0;

    //can clear custom software  RX/TX buffers here

            //...

    portEXIT_CRITICAL();

    October 6, 2015
    Posted on October 06, 2015 at 20:43

    Update: small bugfixes in interrupts handling, now forking perfect in any tested conditions!