Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

USB Suspend/Resume Event processing issue on SDK 17.1.0

Hi All

I'm experiencing an issue with the USB Event processing, as reported by app_usbd. I'm developing on the nRF52840 using SDK 17.1.0.

In short, I think there may be an instance where USB events are being misreported under a specific edge case, and I'm seeking help on either a fix or a work-around.

I am working on a product that utilises the USBD peripheral on the nRF52840. I am using the USBD libraries within SDK 17.1.0. The product sends USB HID commands to the computer (PC or MAC). These include USB HID Wake and Sleep commands to the computer.

The issue I'm having is that, under certain circumstances, I can get my product into a state where the USB on the computer has been suspended and the computer is either sleeping or off, however app_usbd is reporting the USB state as being active.

To trigger this condition, I trigger the computer to go to sleep. The transition to sleep takes several seconds. At a time part-way through the transition to sleep, the USB becomes suspended by the host, and in the USB event handler "usbd_user_ev_handler" I see the APP_USBD_EVT_DRV_SUSPEND event. Within the debugger (I'm using Segger Embedded Studio 6.32b) I see the m_sustate variable change to SUSTATE_SUSPENDED. So far, so good.

If I wait for the computer to completely suspend or shut down, then wake the computer up again over USB with an appropriate USB HID wake-up packet, all is well.

However, if the wake-up packet is sent to the computer in the short window of time between the USB becoming suspended (m_sustate = SUSTATE_SUSPENDED) and the computer completely suspending or shutting down, the attempt to transmit a USB packet seems to trigger the app_usbd module to transition back to the active state (m_sustate = SUSTATE_ACTIVE) despite the USB host (computer) being in the suspended state and remaining suspended.

The end result is that the computer is suspended or shutdown, yet the app_usbd module continues to report the state as being active indefinitely (hld_usb_b_is_usb_running() returns true).

There is a bunch of product functionality tied into the USB state, so I need to find a fix or a work-around for this incorrect reporting of the USB state.

Looking at the logs, it looks like the attempt to send a USB HID wake-up packet to the computer during this window of time between the computer suspending the USB and the final computer suspend/shutdown generates a USB resume event (APP_USBD_EVT_DRV_RESUME). This seems to transition the app_usbd module back from the suspend state to the active state (where m_sustate = SUSTATE_ACTIVE). However, the computer ignores the USB HID wake-up command and completes the transition to sleep. When the computer finally transitions completely to suspend/shutdown there is no additional event generated. The computer is suspended/shutdown, app_usbd is in the active state and hld_usb_b_is_usb_running() continues to return true.

For completeness, here's my USB event handler, with logging statements so that I can see the USB events:

static void usbd_user_ev_handler(app_usbd_event_type_t event)
{
    switch (event)
    {
        case APP_USBD_EVT_DRV_SOF:
            break;

        case APP_USBD_EVT_DRV_RESET:
            NRF_LOG_INFO("USB: reset");
            break;

        case APP_USBD_EVT_DRV_SUSPEND:
            /* Allow the library to put the peripheral into sleep mode */
            app_usbd_suspend_req();
            NRF_LOG_INFO("USB: suspended");
            break;

        case APP_USBD_EVT_DRV_RESUME:
            NRF_LOG_INFO("USB: resume");
            break;

        case APP_USBD_EVT_STARTED:
            NRF_LOG_INFO("USB: started");
            break;

        case APP_USBD_EVT_STOPPED:
            app_usbd_disable();
            NRF_LOG_INFO("USB: stopped");
            break;

        case APP_USBD_EVT_POWER_DETECTED:
            /* USB power detected */
            if (!nrf_drv_usbd_is_enabled())
            {
                app_usbd_enable();
            }
            NRF_LOG_INFO("USB: power detected");
            break;

        case APP_USBD_EVT_POWER_REMOVED:
            /* USB power removed */
            app_usbd_stop();
            NRF_LOG_INFO("USB: power removed");
            break;

        case APP_USBD_EVT_POWER_READY:
            /* USB ready */
            app_usbd_start();
            NRF_LOG_INFO("USB: ready");
            break;

        default:
            /* There are other events, just of no interest */
            break;
    }
}


Any help would be greatly appreciated.

Parents
  • Hi Einar.. Thanks for the comment. It's helpful to know, especially when being in Australia and not having the holiday habits of other countries in the front of the mind.

    Additional info. I have tried using both Event Queue-based and Interrupt-based USB processing. The result is the same using either method.

    At the moment we are validating the SOF-based method of USB state detection, to see if it is sufficient for our application.

Reply
  • Hi Einar.. Thanks for the comment. It's helpful to know, especially when being in Australia and not having the holiday habits of other countries in the front of the mind.

    Additional info. I have tried using both Event Queue-based and Interrupt-based USB processing. The result is the same using either method.

    At the moment we are validating the SOF-based method of USB state detection, to see if it is sufficient for our application.

Children
No Data
Related