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.

Not Receiving USB_EVENT_CONNECTED events in USB OTG Host with TM4C1294KCPDT

Other Parts Discussed in Thread: TM4C1294KCPDT

I am converting an existing Stellaris product into one using the TM4C1294KCPDT chip.  The USB OTG Device side works correctly, but the Host side does not.

I have traced the problem to the events being sent to my USBHCDEvents function -- it is receiving USB_EVENT_DISCONNECTED events every two seconds when a gamepad-like device is attached but it never receives a USB_EVENT_CONNECTED event.  (The OTG polling is set for two seconds.)

My USB_OTGModeCallback function, which is called from the TIVAWARE at an interrupt level, does report that it is oscillating between the eUSBModeHost and the eUSBModeNone modes at the two second rate.  

I also notice that my USBHHandpadCallback never seems to be called.  Is suspect this is a consequence of the never fulling connecting....

Suggestions?

Tom

Code bit 1:

// Declare the USB Events driver interface.
DECLARE_EVENT_DRIVER(g_sUSBEventDriver, 0, 0, USBHCDEvents);
void USBHCDEvents(void *pvData);

// The global that holds all of the host drivers in use in the application.
// Two class drivers are supported -- HID and USBEvents
static const tUSBHostClassDriver * const g_ppHostClassDrivers[] =
{
        &g_sUSBHIDClassDriver,
        &g_sUSBEventDriver
};

// This global holds the number of class drivers in the g_ppHostClassDrivers list.
static const uint32_t g_ui32NumHostClassDrivers =
    sizeof(g_ppHostClassDrivers) / sizeof(tUSBHostClassDriver *);


Code bit 2:


//*****************************************************************************
//
// USB initialization
//
// Hint:  Unlike the rest of usb.c, this function runs prior to starting
//            multi-tasking.
//
//*****************************************************************************
void USB_USBOTGinit(void)
{
    uint32_t ui32PLLFreqHz;
    bool bResult;
    Error_Block eb;

    //------------------------------------------------------------------------------------------------------
    //    Set up the chip hardware
    //------------------------------------------------------------------------------------------------------

    // Enable the USB peripheral and PLL (if required)
    SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    // SysCtlUSBPLLEnable(); // Required for TM4C123, must not be present for TM4C129.....

    // Tell the USB library the PLL frequency
    ui32PLLFreqHz = 480000000;
    bResult = USBOTGFeatureSet(0, USBLIB_FEATURE_USBPLL, &ui32PLLFreqHz);
    if (!bResult)
    {
        System_printf("USBLIB_FEATURE_USBPLL failed!\n");
        System_flush();
    }

    // Setup USB host power control signal pins
    // (Hint:  USB TIVAWARE manual states other pins are handled by OTG init See Section 4.2.1)
    GPIOPinConfigure(GPIO_PA6_USB0EPEN);
    GPIOPinConfigure(GPIO_PA7_USB0PFLT);
    GPIOPinTypeUSBDigital(NEWP_GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7);
    USBHCDPowerConfigInit(0, USBHCD_FAULT_LOW | USBHCD_FAULT_VBUS_DIS | USBHCD_VBUS_FILTER | USBHCD_VBUS_AUTO_HIGH);

    // Setup VBUS, ID, D+ and D- pins for USB operation
    GPIOPinTypeUSBAnalog(NEWP_GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    GPIOPinTypeUSBAnalog(NEWP_GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);

    //------------------------------------------------------------------------------------------------------
    //    Initialize the USB OTG state
    //------------------------------------------------------------------------------------------------------
    USBStackModeSet(0, eUSBModeOTG, USB_OTGModeCallback); // set up the stack and OTG mode change callback function
    g_eUSBState = STATE_NO_DEVICE;  // Indicate, initially, that we are waiting for a device to be connected
    g_eUSBDeviceState = DEVICE_STATE_NOT_CONFIGURED;  // Indicate, initially, that we are not configured

    //------------------------------------------------------------------------------------------------------
    //    Initialize the device stacks
    //------------------------------------------------------------------------------------------------------
    //
    // Initialize the transmit and receive buffers.
    //
    USBBufferInit(&g_sTxBuffer);
    USBBufferInit(&g_sRxBuffer);

    // Only Bulk Transfer type of device is supported
    USBDBulkInit(0, &g_sBulkDevice);

    //------------------------------------------------------------------------------------------------------
    //    Initialize the host stacks
    //------------------------------------------------------------------------------------------------------
    // Register the host class drivers.
    USBHCDRegisterDrivers(0, g_ppHostClassDrivers, g_ui32NumHostClassDrivers);  // Hint: only driver registered is HID

     // Initialize the handpad driver.  As part of that process, open an instance of the handpad driver.
    USBHHandpadOpen(pui8InBuffer, pui8OutBuffer);

    // Initialize the host control stack
    USBHCDInit(0, g_pui8HCDPool, HCD_MEMORY_SIZE);

    //------------------------------------------------------------------------------------------------------
    //    Set up the HAL to deal with USBOTG interrupts
    //------------------------------------------------------------------------------------------------------
    Error_init(&eb);

    Hwi_Params_init(&USBOTG_Hwi_Params);
    USBOTG_Hwi_Params.priority = USB0_Priority;
    USBOTG_Hwi_Params.enableInt = true;

    USBOTG_Hwi_Handle = Hwi_create(INT_USB0, USB0OTGModeIntHandler_wrapper, &USBOTG_Hwi_Params, &eb);
    if (NULL == USBOTG_Hwi_Handle)
    {
        System_abort("USBOTG Hwi create failed");
    }

    //------------------------------------------------------------------------------------------------------
    //    Initialize and Enable the USB controller
    //------------------------------------------------------------------------------------------------------
    // Initialize the loop timer reference time
    ui32LastPassTicks = Clock_getTicks();

    // Initialize and Enable the USB controller
    USBOTGModeInit(0, ui32MillisecToTicks(0, USBOTG_POLLING_RATE_MS), g_pui8HCDPool, HCD_MEMORY_SIZE);


Code bit 3 (from my handpad driver file):
void
USBHHandpadOpen(uint8_t *pui8InBuffer, uint8_t *pui8OutBuffer)
{
   // Save the callback and data pointers.
    g_sUSBHHandpad.pfnCallback = USBHHandpadCallback;

    // Save the instance pointer for the HID device that was opened.
    g_sUSBHHandpad.psHIDInstance = USBHHIDOpen(eUSBHHIDClassVendor, USBHHandpadCallback, (void *)&g_sUSBHHandpad);

    // Save the buffer memory locations and the buffer size
    g_sUSBHHandpad.pui8InBuffer = pui8InBuffer;
    g_sUSBHHandpad.pui8OutBuffer = pui8OutBuffer;
    g_sUSBHHandpad.ui32HIDFlags = ~USBHHANDPAD_DEVICE_PRESENT; // Initialize with device not connected
}


.

  • Hello Tom,

    I have seen a similar issue where the USB_CONNECT event is not getting triggered due to descriptor failure. Can you add the debug print in the usbhostenum.c to see which descriptor check is failing?

    Regards
    Amit
  • Hi Amit,

    Please be more specific about where you want the debug print added (which function? where?).

    I poked around a bit and found that the USBHCDGetConfigDescriptor and USBHCDGetDeviceDescriptor functions are not getting called while I was unable to enable a breakpoint in the USBHCDStringDescriptorGet because the breakpoint manager claims there is no code associated with statements within the function.

    I was able to enable a breakpoint in the ProcessUSBDeviceStateMachine function's  case eHCDDevReset and verify that USBHCDReset(0); in executed.  I enabled a breakpoint in the case eHCDDevConnected: but that breakpoint never tripped.  So, for some reason the ProcessUSBDeviceStateMachine is not being called again until the OTG goes through its host->device-> host cycle again.  {These comments reference code in the usbhostenum.c file}



    Aside: we had an issue on the device side where TIVAWARE uses endpoint 1 for both data_in and data_out but our convention was to move data_out to endpoint 2. Is there something that needs to get changed for the host side?

    Regards,
    Tom

  • Hello Tom,

    The enumeration is handled over control endpoint which is be default endpoint 0. So there is nothing from the device side debug that needs to be brought into this case.

    A debug of this scenario requires a LeCroy USB Analyzer to see what transactions are being generated by the Host controller for the device, so that we can co-relate it to the usblib host code. Do you have one that is available with you?

    Regards
    Amit
  • Hi Amit,

    Sorry, we do not have any USB Analyzer tools. 

    Just to be clear, the current configuration consists of a gamepad-like device (we call it a handpad)  that is connected to the TIVA board USB port.  The cable is captive in the handpad; the handpad is always device and contains a PIC18F87J50 (the handpad has been used for a couple of years with our existing Stellarisware product).  The other end of the cable is a USB mini-AB with the ID pin connected to ground in the AB connector. 

    Perhaps we can make some progress just using the emulator on the TIVA board.  I believe the TIVAWARE code is attempting to send a reset to the handpad after a connect.  At least the reset function is called...  What is supposed to happen next?  Perhaps I can put a breakpoint on that section in the TIVAWARE USBLIB and see if it is getting there.

    Tom

  • Hello Tom,

    The first thing the host does is sen GET_DESCRIPTOR command for the Device Descriptor. Then it sends the SET_ADDRESS followed by a Bus Reset. Once that is done it now sends GET_DESCRIPTOR for the device descriptor with the address set in SET_ADDRESS.

    In the usbhostenum.c you need to look for USBHCDGetDeviceDescriptor API followed by USBHCDSetAddress, then followed by a USBHCDReset and USBHCDGetDeviceDescriptor.

    Regards
    Amit
  • Hi Amit,
    Was away from this for a few days to deal with something else.

    I have confirmed that the USBHCDGetDeviceDescriptor and USBHCDSetAddress functions are never called.

    I modified the ProcessUSBDeviceStateMachine(tUSBHDeviceState iOldState, uint32_t ui32DevIndex) in usbhostenum.c as follows:

    //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    //
    // 2015-10-26 TF patch for debugging
    //
    tUSBHDeviceState myDeviceState;
    myDeviceState = g_sUSBHCD.piDeviceState[ui32DevIndex];
    if (eHCDIdle != myDeviceState)
    {
    if (eHCDDevDisconnected != myDeviceState) // Breakpoint 1 placed here
    {
    if (eHCDDevReset != myDeviceState) // Breakpoint 2 placed here
    {
    myDeviceState = eHCDIdle; // Breakpoint 3 placed here
    }
    }
    //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    // Below is the existing TI code:

    switch(g_sUSBHCD.piDeviceState[ui32DevIndex])
    {

    I also added a } at the end of the switch so the code functionality was basically unchanged.

    I the first thing that happened was Breakpoint 1 tripped. Disabling Breakpoint 1 and resetting the system, Breakpoint 2 tripped. Breakpoint 3 never tripped even with BP1 and BP2 disabled. Every time the breakpoint tripped, ui32Devindex was 0.

    Suggestions?

    Tom
  • Hi Tom,

    It sounds like the OTG keypad device is not self powered and receives power from an GPIO enable switch?
    Assume this is a custom board and you have confirmed in debug USB CTRL register the device Vbus bit toggles when it is plugged into the OTG port?

    The USB device enumerator polls and asserts a Boolean switch for this register bit ever it becomes true. Event device connected will not trigger without it first asserting.
  • Hi Amit,

    Yes, the handpad device is VBUS powered. My OTG polling interval is set for 2 seconds. The VBUS from the TIVA board is going high for about 750 milliseconds and then goes low for about 2 1/4 seconds.

    I assume you mean the USBDEVCTL register in the TIVA chip. In checking it I found that it normally is 0x80 which is consistent for behavior for it being a device waiting for an external PC host to connect. I did occasionally find the register set to 0x19 but I think the TIVAWARE then proceeded to issue a disconnect event. Once I paused execution and found the register to be 0x5D but the TIVAWARE then continued into its OTG device / host switching mode...

    Suggestion?
    Tom
  • Additional data point. I have verified that the interrupt handler is actually seeing the connect on power up (usbhostenum.c line 3927) and it is executing the "g_sUSBHCD.ui32IntEvents |= INT_EVENT_CONNECT;" {INT_EVENT_CONNECT = 0x10} statement, but by the time the USBHCDMain() is called (usbhostenum.c line 4714) the value of g_sUSBHCD.ui32IntEvents has been changed to {0x04} which is INT_EVENT_DISCONNECT.

    Perhaps something is timing out?

    I don't know if this is related, but I am using the HAL in TI-RTOS to handle interrupts.  The note on page 164 of the kernal v6.41 User's Guide (SPRUEX3O dated October 2014) says that all manipulation of interrupts needs to be done the the HAL API.  I noticed that the USBHCDMain function uses the OS_INT_DISABLE macro to disable the USB interrupt.  Is this OK or is there a possible conflict with the HAL interrupt handler?


    --Tom

  • Hello Tom

    Yes, that is fine as it will reenable the interrupt using OS_INT_ENABLE. If you can send me the binary file with the following information

    1. Crystal Frequency
    2. What I can connect to the TM4C to emulate an external device/host to emulate the problem

    I would be able to setup a USB bench to debug and point to possible issues.

    Regards
    Amit
  • Hi Amit,

    This may get complicated due to IP and other issues....  Before I approach my management, I need to know where this hardware/info would be going.  Would this go to you or someone else?  Inside the U.S. or do we have export issues to deal with?  If within the U.S., what city? 

    It might be better to continue this discussion via email telephone (see my myTI profile).

    Regards,

    Tom

  • Hi Tom,
    >gamepad-like device (we call it a handpad) that is connected to the TIVA board USB port.

    Not yet posted a debug report of the USB control register showing and confirming the handpad device has indeed tested true, connected and USB -ID confirmed. If that never happens it may be a hardware related issue. The USB device mode driver polls for connections events occurring. So in any event VBUS pin would be toggling 1/0 in refresh mode and ID pin set true. Who could say what the result might be in SW if only the ID pin was present without VBUS or visa versa?
  • Hi Amit (and BP101),

    I have found and resolved the problem. There are two issues that caused it. Note that the timings mentioned below were measured using an external oscilloscope.

    1. Our handpad product -- For regulatory reasons related to our application, the handpad will reset itself (via a watchdog) under several circumstances. One of these is if the handpad is in a connected, but not configured, state for 250 msec. When it resets, it briefly removes the pull-up resistor from the D+. This causes the chip/TIVAWARE to (correctly) assume the device has initiated a disconnect. Under normal operation this functionality is not invoked; the time out is long enough so that it never gets invoked unless something really goes wrong with the USB interface. But...

    2. The XDS100v2 emulator / TM4C1294KCPT chip / TIVAWARE -- When executing on the chip, the latency between the electrical connect (D+ getting pulled up) and the USBOTG interrupt being invoked is about 125 msec. This is fine and does not cause the watchdog timeout mentioned in #1. It also is consistent with our previous Stellaris-based design. However, when running the exact same code on the emulator, the latency is about 375 msec which is so long that the watchdog in our device times out and effectively generates a device disconnect. We modified the handpad firmware to eliminate the timeout for testing purposes and the connection worked correctly every time. I have not dug into why the emulator causes the long latency, but have a workable solution for now. I also have verified that non-USB interrupts do not have latency periods anywhere close to this long.....

    Anyway, thanks for your help.
    Tom
  • Hello Tom

    Regarding point 2: The emulator must not change the timings. If you keep the emulator connected w/o Break points or watch points does the timing remain at 375 ms

    Regards
    Amit
  • Hi Tom,
    Seems someone tipped you off to hardware being the culprit and self awarded question answered not so rewarding to those who have assisted.
  • Hi Amit,


    After eliminating all breakpoints and watches, I have confirmed that the USB interrupt latency is definitely different when running on the emulator when compared to the USB interrupt latency when running on the chip.  The previously reported USB interrupt latency time when running on the emulator seem to be unchanged even when the breakpoints and watches are eliminated.

    Regards,

    Tom

  • Hello Tom,

    What emulator are you using?

    Regards
    Amit
  • Blackhawk XDS100v2 ARM
  • Hello Tom,

    The emulator when connected should in no way affect the device operation unless instructed via Break Points and Watch Points. A simple method to check is to have a timer running a PWM at 1/1000 of the system clock. With or without the emulator it shall output 1/1000 of the system clock

    Regards
    Amit