This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Problems with OUT reports on USB HID

Hi,

I'm using the NRF52840 PDK version:

PCA10056

0.11.0

2018.3

With SDK version 15.2

I've been trying to develop an application based on the HID Generic example and am seeing some strange behaviours on the USB HID OUT endpoint.

I try to obtain the data in the APP_USBD_HID_USER_EVT_OUT_REPORT_READY event, at which point I use app_usbd_hid_generic_out_report_get to retrieve the data for processing in my main loop.

After more tracing and debugging, I've found that the hid_generic_ep_transfer_out handler is called when the OUT endpoint is busy.  When this happens the app_usbd_ep_transfer fails and app_usbd proceeds to stall the endpoint (in app_usbd_event_execute).

How can I avoid this situation?

Thanks,

Larry

  • OUT report size has been limited to 64 bytes (63 data + 1 id) in SDK v15.1. But this should assert when size is too big. 

    It would be easier to understand what is failing with an example project.

    Best regards,
    Kenneth

  • I'm working on it (I'm trying to derive something simple from an example, but it's not that easy).
    Anyway, once I get it working, can you tell me how I should package it for you (i.e. where can I provide you with a zip file)?

  • OK,  I've managed to reproduce the problem in a "simple" project.
    I based the project on the ble_app_blinky example, mainly because my application also uses BLE.
    You can replace the entire ble_app_blinky folder with my supplied project and it should work./

    It's using the SDK as is, except I modified app_usbd_hid_generic.c to log the status of the out transfer (see code snippet).

    I'm using Segger embedded Studio 3.52 and am testing on my PCA10056 PDK.
    How shall I deliver the zip file and command line test application?

    static ret_code_t hid_generic_ep_transfer_out(app_usbd_class_inst_t const * p_inst)
    {
    
        app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
        nrf_drv_usbd_ep_t              ep_addr   = app_usbd_hid_epout_addr_get(p_inst);
    
        /*Request setup data*/
        app_usbd_hid_report_buffer_t const * p_rep_buff;
    
        p_rep_buff = app_usbd_hid_rep_buff_out_get(&p_generic->specific.inst.hid_inst);
        NRF_DRV_USBD_TRANSFER_OUT(transfer, p_rep_buff->p_buff, p_rep_buff->size);
    
        ret_code_t ret = app_usbd_ep_transfer(ep_addr, &transfer);
        NRF_LOG_INFO("hid_generic OUT %d", ret ); 
        return ret;
    }
    
    
  • I also had to modify app_usbd_hid_generic_idle_report_set to declare the ret_code_t outside of the CRITICAL_REGION_ENTER, otherwise it would not compile  (I'm rather confused about this.  Perhaps I have a configuration issue).

    ret_code_t app_usbd_hid_generic_idle_report_set(app_usbd_hid_generic_t const * p_generic,
                                                    const void                   * p_buff,
                                                    size_t                         size)
    {
        app_usbd_class_inst_t const  * p_inst        = (app_usbd_class_inst_t const *)p_generic;
        app_usbd_hid_generic_ctx_t   * p_generic_ctx = hid_generic_ctx_get(p_generic);
    
        nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
    
        app_usbd_hid_state_flag_clr(&p_generic_ctx->hid_ctx,
                                    APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
    
        NRF_DRV_USBD_TRANSFER_IN(transfer, p_buff, size);
    
        ret_code_t ret;
        CRITICAL_REGION_ENTER();
        ret = app_usbd_ep_transfer(ep_addr, &transfer);
        if (ret == NRF_SUCCESS)
        {
            app_usbd_hid_state_flag_set(&p_generic_ctx->hid_ctx,
                                        APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
        }
        CRITICAL_REGION_EXIT();
    
        return ret;
    }
    
    
Related