USBFS - Issues handling connect after disconnect

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

Hi all,

I'm coming across a problem with my firmware for a USB Mouse+Keyboard composite device using the USBFS component.  The device is self-powered rather than bus powered.  Long story short, I'm sometimes having problems gracefully handling USB disconnect/reconnect.  I manage to connect normally when I plug to a host PC, but sometimes I am unable to connect/reconnect unless I fully power cycle the PSoC.  Windows will usually just throw a "USB Device has malfunctioned" pop-up at me.  Sometimes it will just show the composite device in the device manager with a little yellow marker on it denoting that "The Device Could Not Start".  

I had thought this code working but something must be wrong that I'm not seeing.  My USB functions are below with descriptions, maybe someone will see something I'm not catching:

I have two variables in my usb source file that serve as flags used in the code below:

//Connection to host has been established

volatile static bool USB_IsConnected                = false;

//VUSB has been detected

static bool USB_VBusPresent                         = false;

I call USBFS_Start() only once, when the PSoC first starts. To actually begin exchanging data with the host, I call USB_Init():

/** USB_Init

*  - Attempts to begin communication with USB host

*  - Returns bGetConfiguration status.

*/

static bool USB_Init (void){

   

    USBFS_InitComponent(0,USBFS_DWR_POWER_OPERATION);

    CyDelay(50);

    if (USBFS_bGetConfiguration()){

        USBFS_LoadInEP(USB_KEYBOARD_ENDPOINT_NUM,(uint8_t *)USB_KeyboardDataBuff,USB_KEYBOARD_DATA_SIZE);

        USBFS_LoadInEP(USB_MOUSE_ENDPOINT_NUM,(uint8_t *)USB_MouseDataBuff,USB_MOUSE_DATA_SIZE);

        return true;

    }

   

    return false;

}

My main USB function is Process_USB():

/** Process_USB

*  - Handles USB Connection/Disconnection

*  - Handles Endpoint data exchange for Mouse+Keyboard

*/

void Process_USB (void){

    static bool is_connected = false, conn_prev = false;

    static keyboard_led_t led_data_prev;

   

    is_connected = USB_UpdateConnection();

   

    if (is_connected){

        /*We are currently connected*/

        if (USBFS_bGetEPAckState(USB_MOUSE_ENDPOINT_NUM)){

            /*Mouse Data Updated Here - Snipped*/

        }

       

        if (USBFS_bGetEPAckState(USB_KEYBOARD_ENDPOINT_NUM)){

            /*Keyboard Data Updated Here - Snipped*/

           

        }

       

    } else if (conn_prev) {

        /*Connection lost, terminate EPs*/

        USBFS_TerminateEP(USB_KEYBOARD_ENDPOINT_NUM);  

        USBFS_TerminateEP(USB_MOUSE_ENDPOINT_NUM);  

    }

   

    conn_prev = is_connected;

   

    LED_2_Write(is_connected);

   

}

The main thing I want to point out is the call to USB_UpdateConnection, which governs the behavior of this function.  If we are connected, it will update endpoints and exhange data with the host.  If not, the endpoints are terminated, to be restarted in USB_Init() upon reconnection.

In order to track the state of my USB connection.  I am regularly calling my USB_UpdateConnection() function every time I enter Process_USB().  When VBUS is present, and we are not currently enumerated with the host, this function will call USB_Init() to attempt to enumerate.  If it fails, it will try again on the next time through.  If VBUS is not present, the flags will be set as such to begin calling USB_Init() once VBUS returns.

/** USB_UpdateConnection

*  - Handles USB Enumeration when VBUS is detected

*  - returns:  0 -> No VBUS/Host detected

*              1 -> Enumerated with host

*/

static bool USB_UpdateConnection (void){

    static bool connected = false;

   

    if (USBFS_VBusPresent() == USBFS_VBUS_VALID){

        /*VBUS is present*/

        USB_VBusPresent = true;

       

        if (!connected){

            /*New connection, Enumerate*/  

            #ifdef DEBUG_USB

                    DBG_UART_PutStringConst("USB: CONNECTING\r\n"); 

            #endif

            if (USB_Init()){

                #ifdef DEBUG_USB

                    DBG_UART_PutStringConst("USB: CONNECTED\r\n"); 

                #endif

                USB_IsConnected = true;

                connected = true;

            }

           

        }

       

    } else {

        /*No VBUS Present*/

        if (connected){

            /*Disconnected*/

            #ifdef DEBUG_USB

                DBG_UART_PutStringConst("USB: DISCONNECT\r\n"); 

            #endif

            connected = false;

        }

       

        USB_IsConnected = false;

        USB_VBusPresent = false;

        connected = false;

    }

   

    if (!USB_IsConnected && USB_VBusPresent){

        /*No Data Connection, but VBus still present*/

        #ifdef DEBUG_USB

            DBG_UART_PutStringConst("USB: NO HOST\r\n"); 

        #endif

        connected = false;

    }

   

    return connected;

}

I also have an activity check I am calling every 100mS to keep an eye on USB activity to trigger a reconnect:

/** USB_Timeout_Tick

*  - Checks USB activity every 500mS

*  - Detects when no activity has occurred, denoting a connection problem,

*    and sets USB_IsConnected to match.

*/

void USB_Timeout_Tick (void){

    static uint8_t counter = 0;

    if (USB_IsConnected){

       

        if (++counter >= USB_DATA_TIMEOUT_COUNT){

            if (!USBFS_CheckActivity()){

                #ifdef DEBUG_USB

                    DBG_UART_PutStringConst("USB: ACT TIMEOUT\r\n"); 

                #endif

                USB_IsConnected = false;

            }

            counter = 0;

        }

       

    } else {

        counter = 0;

    }

   

}

This counter will trigger an activity check every 500mS.  If no activity on the bus, it will flag as disconnected, and will attempt to reconnect in USB_UpdateConnection().  In my case, I haven't seen this actually trigger in this instance, but I figured I'd include it for completeness.

For some reason this setup is not 100% reliable to make a USB connection to a host (I've tested both my Windows 7 PC and a Raspberry Pi).  It works most of the time, but will for some reason I can't determine just get stuck calling USB_Init() and USBFS_bGetConfiguration() simply never returns true.  It then spends all eternity attempting to enumerate and not being able to do so.

Does anyone out there maybe have some tips of what I could try here to make connection/reconnection to the host a more reliable process?  I can't seem to figure out the "Trigger" for what's causing it to sometimes just not work.  Even writing this up, this same code is now suddenly working, but it's only a matter of time before I start having problems with it again.

0 Likes
9 Replies