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.

  • Hi,

    I am sorry for the delay.

    What is the value of APP_USBD_CONFIG_EVENT_QUEUE_ENABLE in your sdk_config.h? I ask because there is a known issue in the driver which could be the cause here. See this post for more details about that. If this is the issue you are seeing, setting APP_USBD_CONFIG_EVENT_QUEUE_ENABLE to 1 should resolve it.

  • Hi Einar

    The post you linked to does look related to my issue.

    My APP_USBD_CONFIG_EVENT_QUEUE_ENABLE is 0.

    The project development commenced with using the event queue, however as development progressed we needed to turn it off. We were having many issues with delayed processing of HID commands on MACs (Windows PCs were fine) leading to a variety of reported issues from users. The processing of USB HID commands by the USBD HID driver appeared to e delayed by up to 1 second in some circumstances, with no clear explanation as to why, as the CPU had plenty of idle time during these delays. The customer issues were completely resolved by turning off the USBD event queue.

    Whilst logically using the event queue would seem to be a good thing to do, to turn the event queue back on is to trade one issue for another.

    Out of interest, I will endeavour to re-test with the Event Queue enabled, however I am quite confident that this will cause a return of the HID issue on MACs.

  • Hi,

    I see you mentioned this in this post. From what I understand setting APP_USBD_CONFIG_EVENT_QUEUE_ENABLE to 0 will cause problems though (as you have seen), so it would be better to understand what causes the issue you see with Mac and find another fix or workaround for it. Did you try increasing the queue size as Runar suggested?

  • Hello,

    I am experiencing a similar behavior and the solution proposed here may not solve the problem:

    I am using nRF52840 with an old SDK v15.3 (which will be very difficult to update at this time of the product), and with USBD libraries, I am running the test USBCV with a compliance tool (https://www.usb.org/document-library/usb4cv)

    Every test pass successfully except for the one concerning this topic: "A suspended device must resume normal operation when resume signaling is seen on its upstream port."

    With the following configuration,

    #define APP_USBD_CONFIG_EVENT_QUEUE_ENABLE 1
    
    #define APP_USBD_CONFIG_EVENT_QUEUE_SIZE 64
    
    #define APP_USBD_CONFIG_SOF_HANDLING_MODE 1

    I still have this problem.

    Do you have any idea what I could try?

    Thanks a lot.

  • Hi,

    Can you make a new case for this issue and elaborate a bit more about your configuration and what you have learned from testing/debugging?

Related