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

    Any update on this?

    The method of using the presence of SOF packets to determine USB state is a partial work-around for us, but not a complete solution. It ensures that the user interface displays the correct state. However, internally the USBD Driver is in the incorrect state. The USBD driver does not seem to cleanly recover from this situation, meaning that USB packets are not successfully sent to the host PC after this situation occurs.

    Any further advice or suggestions are 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?

Reply Children
No Data
Related