NRF52840 consumer device USBD HID setup

Hi Im new to nordic.

Currently Im porting a project from ESP32 to nrf52840 dongle as a USB HID device.

I have to set up a HID comsumer device to control the media function (volume +/-, mute, play pause... etc)

But I cant find any example doing this. Is there any reference for me to study?

Thanks alot!

  • Im not using Zephyr. Is there another example I could follow with softdevice? Thanks!

  • I hv study some info and constructed a descriptor like this:

    #define APP_USBD_HID_CONSUMER_REPORT_DSC {                                      \
        0x05, 0x0C,       /* Usage Page (Consumer)                          */      \
        0x09, 0x01,       /* Usage (Consumer Control)                       */      \
        0xA1, 0x01,       /* Collection (Application)                       */      \
        0x85, 0x00,       /*   Report Id (0)                                */      \
        0x15, 0x00,       /*   Logical minimum (0)                          */      \
        0x25, 0x01,       /*   Logical maximum (1)                          */      \
        0x09, 0xE9, 	  /*   Usage (Volume Up)					bit 0	*/      \
        0x09, 0xEA, 	  /*   Usage (Volume Down) 					bit 1	*/      \
        0x09, 0xE2, 	  /*   Usage (Mute)							bit 2	*/      \
        0x09, 0x30, 	  /*   Usage (Power)						bit 3	*/      \
        0x0A, 0x23,0x02,  /*   Usage (AC Home) 						bit 4	*/      \
        0x0A, 0x24,0x02,  /*   Usage (AC Back) 						bit 5	*/      \
        0x09, 0xCD,       /*   Usage (Play/Pause)					bit 6	*/      \
        0x09, 0xB6,       /*   Usage (Scan Previous Track)			bit 7	*/      \
        0x09, 0xB5,       /*   Usage (Scan Next Track)				bit 8	*/      \
        0x75, 0x01, 	/*	 Report Size (1)									*/  \
        0x95, 0x09, 	/*	 Report Count (9)									*/  \
        0x81, 0x02, 	/*	 Input (Data, Variable, Absolute)					*/  \
        0x75, 0x01, 	/*	 Report Size (1)									*/  \
        0x95, 0x07, 	/*	 Report Count (7)									*/  \
        0x81, 0x01, 	/*	 Input (Constant)									*/  \
        0xC0,              /* End Collection                                    */  \
    }

    I set up the HID using generic API

    APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(consumer_desc, APP_USBD_HID_CONSUMER_REPORT_DSC);
    static const app_usbd_hid_subclass_desc_t * reps[] = {&consumer_desc};
    
    APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_consumer,
                                    APP_USBD_INTERFACE_COMSUER,
                                    hid_consumer_user_ev_handler,
                                    (NRF_DRV_USBD_EPIN3),
                                    reps,
                                    REPORT_IN_QUEUE_SIZE,
                                    REPORT_OUT_MAXSIZE,
                                    REPORT_FEATURE_MAXSIZE,
                                    APP_USBD_HID_SUBCLASS_BOOT,
                                    APP_USBD_HID_PROTO_GENERIC);

    And the report should look like:

    typedef struct {
        uint8_t u8_id;
        uint8_t u8p_btn[2];
    }hid_report_t;

    After append the HID

    app_usbd_class_inst_t const * class_inst_consumer;
    class_inst_consumer = &m_app_hid_consumer.base;
    err_code = app_usbd_class_append(class_inst_consumer);
    APP_ERROR_CHECK(err_code);

    I send out the report by this

    hid_report_t report;
    
    report.u8_id = 0;
    report.u8_btn[0] = 0x01;    // should be volume +
    report.u8_btn[1] = 0x00;
    
    ret_code_t err_code = app_usbd_hid_generic_in_report_set(&m_app_hid_consumer, u8p_report, sizeof(u8p_report));
    APP_ERROR_CHECK(err_code);

    Computer recongize the dongle as HID, but no respond after sending the report

    Which part I missed or have to correct in order to make this work?
    Thanks!

  • After several trial & error, my final descriptor go like this

    #define APP_USBD_HID_CONSUMER_REPORT_DSC {                                      \
        0x05, 0x0C,       /* Usage Page (desktop)                           */      \
        0x09, 0x01,       /* Usage (Consumer Control)                       */      \
        0xA1, 0x01,       /* Collection (Application)                       */      \
        0x15, 0x00,       /* Logical minimum (0)                            */      \
        0x25, 0x01,       /* Logical maximum (1)                            */      \
        0x75, 0x01, 	  /* Report Size (1)								*/      \
        0x95, 0x07, 	  /* Report Count (7)								*/      \
        0x09, 0xE9, 	  /* Usage (Volume Up)                      bit 0	*/      \
        0x09, 0xEA, 	  /* Usage (Volume Down) 					bit 1	*/      \
        0x09, 0xE2, 	  /* Usage (Mute)							bit 2	*/      \
        0x09, 0xB7, 	  /* Usage (Stop)                           bit 3	*/      \
        0x09, 0xCD,       /* Usage (Play/Pause)                     bit 4	*/      \
        0x09, 0xB6,       /* Usage (Scan Previous Track)			bit 5	*/      \
        0x09, 0xB5,       /* Usage (Scan Next Track)				bit 6	*/      \
        0x81, 0x02, 	  /* Input (Data, Variable, Absolute)               */      \
        0x75, 0x01, 	  /* Report Size (1)								*/      \
        0x95, 0x01, 	  /* Report Count (1)								*/      \
        0x81, 0x03, 	  /* Input (Constant)								*/      \
        0xC0,             /* End Collection                                 */      \
    }

    As I dont need power and AC function so I shrinked the data to 7 bits and padded 1 bits to make a byte

    The report in function simplifed as follow

    void ctrl_hid_media_command(uint8_t u8_report) {
        // Send the HID report
        ret_code_t err_code = app_usbd_hid_generic_in_report_set(&m_app_hid_consumer, &u8_report, sizeof(u8_report));
        APP_ERROR_CHECK(err_code);
    }

    And it finally works!

    Thanks for everyone who gave help.

    And admin plz close this ticket. Thanks!

Related