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.

TM4C123GE6PM: Unplugging USB cable doesn't fire ISR disconnect event

Part Number: TM4C123GE6PM

Hello,

I have a USB link up and running with the USB stack (USB ware) as a HID device.  I'm seeing that when I plug the USB cable in I get a "USB_EVENT_CONNECTED" event that fires in the ISR.  This is great.  The problem I see next is upon unplugging the cable.  When I unplug the cable I do not get a "USB_EVENT_DISCONNECTED".  Instead the "USB_EVENT_DISCONNECTED" fires when I plug the cable back in. 

So my sequence of ISR events are basically as follows, upon plugging in a USB cable I get a "USB_EVENT_DISCONNECTED" event first then a "USB_EVENT_CONNECTED".  This is an issue because my firmware needs to know when the USB link is plugged in / connected.  

My configuration code for the USB driver at power up is as follows:

    //
    // D+/D- pins (PD4, PD5) Enable initialize
    //
    GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);


    //
    // Set the USB stack mode to Device mode with VBUS monitoring.
    //
    USBStackModeSet(0, eUSBModeForceDevice, 0);

    //
    // Pass our device information to the USB library and place the device
    // on the bus.
    //
    USBDHIDInit(0, &g_sHIDDataPipeDevice);
    //IntPrioritySet(INT_USB0, 0x60);


    //
    // Enable Global processor interrupts
    //
    IntMasterEnable();

My receive ISR handler code is as follows:

// Receive handler
uint32_t
RXHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData,
                void *pvMsgData)
{

	//WTimer0_Set_Counter(/*counter*/ 80000000/10);		// Attempt to fix rate problem with deepsleep() mode

    // Debug info
    static int countRXAvailable=0;
    static int countIdleTimeout=0;
    static int countGetReportBuffer=0;
    static int countGetReport=0;
    static int countSetReport=0;
    static int countDefault=0;

    static int eventListIdx=0;
    // End debug vars
    uint32_t readPacketSize;


    //Debug info
    //eventList[eventListIdx++]=ui32Event;
    if(eventListIdx==20)
        {
            eventListIdx=0;
        }

    switch(ui32Event)
    {
    case USB_EVENT_CONNECTED:
        USBState|=1;


        // Change USB priority level so it doesn't interfere with ADC when running
        IntPrioritySet(INT_USB0, 0x60);
        USB_Enumerated = 1; // Flag showing USB connected or disconnected

        break;
    case USB_EVENT_DISCONNECTED:
        USBState&=0xfe;
        USB_Enumerated = 0;	// Flag showing USB connected or disconnected

        break;
    case USB_EVENT_RX_AVAILABLE:
        countRXAvailable++;
        RXData.state=1;
        RXData.size=(uint16_t) (ui32MsgData&0xffff);
        USBDHIDPacketRead(&g_sHIDDataPipeDevice, RXData.buffer, RXData.size, true);
        _nop();

        // Required for now to break out of burst mode locked loop
        if(RXData.buffer[1] == 0x03){
          BurstMode_Unlock = 1;
        }

        break;
    case USBD_HID_EVENT_IDLE_TIMEOUT:
        // Not defining a timeout.
        countIdleTimeout++;
        break;

    case USBD_HID_EVENT_GET_REPORT_BUFFER:
    	// Return Rx buffer to usb driverlib so
    	// the report can be stored
        countGetReportBuffer++;


        readPacketSize=(uint32_t)pvMsgData;
        if(readPacketSize>MAX_PACKET_SIZE)
            {
                _nop(); //Shouldn't happen
            }

        return((uint32_t)RXData.buffer);
        break;
    case USBD_HID_EVENT_GET_REPORT:
    	// Host is requesting a particular report
        countGetReport++;
        break;
    case USBD_HID_EVENT_SET_REPORT:
    	// Report receive buffer is ready to
    	// be read.
        countSetReport++;
        // TODO: check report ID
        //set size to let the application know that there is data.
        RXData.size=(uint16_t) (ui32MsgData&0xffff);
        RXData.state=1;
        break;

    // sounds like this is required by the new driver
    case USB_EVENT_SUSPEND:
        break;

    // sounds like this is required by the new driver
    case USB_EVENT_RESUME:
        break;

    // added this trying to debug new USB comm bug - 1/15/2018
    case USB_EVENT_ERROR:
            while(1);

        break;

    default:
        countDefault++;
        break;
    }

    // Pretty sure default return should be 0. Need to verify
    return 1;

}

Is there some configuration in the driver that you have to enable to detec plugging and unplugging properly?  I'm surprised by this behavior.  Any help is greatly appreciated!

  • Hello Robbie,

    See the following: 

    I am surprised you are getting the event at all, but if you need it real time as you described then you cannot use:

    USBStackModeSet(0, eUSBModeForceDevice, 0);

  • If I'm just using this as a basic hid device would my problem be solved just by changing to "eUSBModeDevice" without introducing bugs to my basic read/write messages - hid reports?

  • I also noticed some, what seems to be, conflicting direction in TI's documentation.

    Page 1349 of the Tiva datasheets says: 

    This signal senses the state of the USB ID signal.
    The USB PHY enables an integrated pull-up, and
    an external element (USB connector) indicates the
    initial state of the USB controller (pulled down is
    the A side of the cable and pulled up is the B side).

     In the USB lib driver guide I found two different descriptions

    Description 1 page 275 of document SW-TM4C-USBL-UG-2.1.4.178 describing eUSBModeDevice:

    Operate in USB device mode with active monitoring of VBUS and the ID
    pin must be pulled to a logic high value

    Direction 2 in section 1.1 page 5 under operating modes, paragraph 3:

    If
    the application needs to receive disconnect events it uses the eUSBModeDevice setting and must
    connect the VBUS pin to the USB connector and leave the ID pin unconnected.

    Really all i need to do is get the PHY to tell me when a disconnect and reconnect happens.  From reading through the documentation I feel like TI is saying to do mutually exclusive things.  Should the ID pin just be tied to Vcc (3.3V) or VBUS or should an internal pullup for the ID pin be enabled in the PHY.

    It seems like eUSBModeDevice is what I should be using, but I'm unsure what to do with the ID pin. when I change my code to the following

    USBStackModeSet(0, eUSBModeDevice, 0);

    with the ID pin floating (disconnected) I get nothing on my USB bus so I'm assuming section 1.1 where it says to leave ID floating is not really correct?

  • Hello Robbie,

    I am not sure that saying 'must' leave the USB0ID pin unconnected makes sense really, pretty sure that the tUSBMode documentation is right. I don't see why ID would need to be unconnected. Really VBUS should be the key here...

    From our LaunchPad user guide: On the EK-TM4C123GXL Tiva C Series LaunchPad, USB_VBUS of the device connector (J9) is routed to pin PB1 of the microcontroller (U1) via a 0-ohm resistor R29. However, R29 is not populated. Because of this, the application does not receive any USB_EVENT_DISCONNECTED event but (with very limited testing) the application seems to work just fine. 

    So that would once more indicate VBUS is key.

    Did you check to see if VBUS is receiving the voltage right?

    Also can you test this on a LaunchPad at all by populating R29?

    As for ID pin, you can try using an internal pull-up first. I don't recall ever needing an external one. By the way, in general do not use VBUS but VCC. While the device has 5V tolerant pins, VBUS should be the only one with 5V on it.

  • Hi Ralph,

    Thank you for your time.  It seems that all the examples with the Ti Ware archive use the force mode set.  I ended up getting this up and running by setting the VBUS and ID pins correctly manually with the GPIO api in the driver library.  I think this is up and running reliably now.