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
  • To elaborate a little further, I have one of the following two expectations of app_usbd under this scenario:

    • The resume event is followed by a suspend event (i.e. app_usbd module goes to Active state under the assumption that the USB host will wake up, but reverts to the Suspended state when it is realised that the USB host has not woken up).

    OR

    • The app_usbd module does not transition out of the Suspended state, since the USB host never wakes up.

    Either of the behaviours of app_usbd listed above would result in the app_usbd module ending up in the correct final state.

Reply
  • To elaborate a little further, I have one of the following two expectations of app_usbd under this scenario:

    • The resume event is followed by a suspend event (i.e. app_usbd module goes to Active state under the assumption that the USB host will wake up, but reverts to the Suspended state when it is realised that the USB host has not woken up).

    OR

    • The app_usbd module does not transition out of the Suspended state, since the USB host never wakes up.

    Either of the behaviours of app_usbd listed above would result in the app_usbd module ending up in the correct final state.

Children
No Data
Related