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

USB CDC ACM with AUDIO class on Windows

I have successfully been using USB CDC ACM class alongside USB Audio with only a MIC feature available on Mac OS. However, on Windows, only USB CDC ACM enumerates in Device Manager. The Audio class enumerates with a failure "Device USB\VID****** had a problem starting". Any ideas what could be causing this discrepancy?

Parents
  • Hi,

    I had the same problem and had posted a support ticket on this but with no reply so far.

    I just found the solution for my case so I thought to share.

    We need to include an "INTERFACE_ASSOCIATION DESCRIPTOR" (IAD) just before the "INTERFACE DESCRIPTOR" for the AudioClass Control Interface.

    On Windows, it works WITHOUT the IAD when there are NO CDC-ACM descriptors. However, once CDC-ACM descriptors are added, the AudioClass descriptors will NOT be parsed correctly during USB device enumeration. Adding the IAD solves this problem.

    Since you did not have the issues on Mac but then had it on Windows, perhaps it is a Windows problem.

  • Thank you for sharing. Could you help provide more details on where exactly to inject IAD descriptor in the USB Audio class? What goes into the descriptor and can I inject it using any of existing SDK API macros?

  • Hi,

    I tried to use their SDK but it is too convoluted for my liking. Tracing was particularly difficult with many levels of indirection and even some code were in .h files rather than in .c files. So I spent many days and nights ended up writing a bare metal version with only the minimal files from their SDK such as the startup code and bitfields etc only. What shocked me was when I got the same issues using my BareMetal version. That’s when I realized it was not their library issue.

    i will share my exact descriptors shortly and maybe help relook into their SDK to see where you would need to tweet to get it to work. Hopefully Nordic will incorporate as well into their updates.

Reply
  • Hi,

    I tried to use their SDK but it is too convoluted for my liking. Tracing was particularly difficult with many levels of indirection and even some code were in .h files rather than in .c files. So I spent many days and nights ended up writing a bare metal version with only the minimal files from their SDK such as the startup code and bitfields etc only. What shocked me was when I got the same issues using my BareMetal version. That’s when I realized it was not their library issue.

    i will share my exact descriptors shortly and maybe help relook into their SDK to see where you would need to tweet to get it to work. Hopefully Nordic will incorporate as well into their updates.

Children
  • Hi,

    I have prepared the file attached extracted based on what I used in my own bare metal source. Please see the static declarations for the descriptors at the end of the file. The extra IAD to be inserted is at line 214,215:

    test.h

    For the SDK (nRF5_SDK_16.0.0_98a08e2), I have not tested it but the place to modify is likely in "app_usbd_audio.c", in the function audio_feed_descriptors() at line 675. 

    Hope it helps.

    static bool audio_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx,
    app_usbd_class_inst_t const * p_inst,
    uint8_t * p_buff,
    size_t max_size)
    {
    static uint8_t ifaces = 0;
    ifaces = app_usbd_class_iface_count_get(p_inst);
    ASSERT(ifaces == 2);
    app_usbd_audio_t const * p_audio = audio_get(p_inst);

    APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size);

    /* INSERT CODE HERE FOR THE IAD */

    /* CONTROL INTERFACE DESCRIPTOR */
    APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
    APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface

    static app_usbd_class_iface_conf_t const * p_cur_iface = NULL;
    p_cur_iface = app_usbd_class_iface_get(p_inst, 0);

    APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber
    APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
    APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints
    APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS); // bInterfaceClass = Audio
    APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_SUBCLASS_AUDIOCONTROL); // bInterfaceSubclass (Audio Control)
    APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS_PROTOCOL_UNDEFINED); // bInterfaceProtocol
    APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface

  • Just to add on to the above, in test.h, in the static declaration of the descriptors, some values are marked as "pending". It was too easy to make a mistake changing the descriptor and forgot to update other parts. So, in my code, these are not hard coded but are automatically filled in based on the actual type and number of USB devices to be created. In case you want to test quickly, look for "pending" and enter the values based on the descriptor bytes below.

    DEVICE: 12 01 00 02 00 00 00 40 15 19 0E 52 00 01 01 02 03 01
    CONFIGURATION: 09 02 B9 00 04 01 04 C0 32
    USBD_DSC_TYPE_IF_ASSOC: 08 0B 02 02 01 01 00 00
    INTERFACE: 09 04 02 00 00 01 01 00 00
    AUDIO INTERFACE: 09 24 01 00 01 2B 00 01 03
    AUDIO INTERFACE: 0C 24 02 01 01 01 00 02 03 00 00 00
    AUDIO INTERFACE: 0D 24 06 02 01 02 01 00 01 00 01 00 00
    AUDIO INTERFACE: 09 24 03 03 02 03 00 02 00
    INTERFACE: 09 04 03 00 00 01 02 00 00
    INTERFACE: 09 04 03 01 01 01 02 00 00
    AUDIO INTERFACE: 07 24 01 01 00 01 00
    AUDIO INTERFACE: 0B 24 02 03 02 02 10 01 80 BB 00
    AUDIO ENDPOINT: 07 25 01 00 00 00 00
    ENDPOINT: 07 05 08 01 C0 00 01
    USBD_DSC_TYPE_IF_ASSOC: 08 0B 06 02 02 02 01 00
    INTERFACE: 09 04 06 00 01 02 02 01 00
    AUDIO INTERFACE: 05 24 00 10 01
    AUDIO INTERFACE: 05 24 01 03 07
    AUDIO INTERFACE: 04 24 02 02
    AUDIO INTERFACE: 05 24 06 06 07
    ENDPOINT: 07 05 83 03 40 00 10
    INTERFACE: 09 04 07 00 02 0A 00 00 00
    ENDPOINT: 07 05 84 02 40 00 00
    ENDPOINT: 07 05 04 02 40 00 00
    STRING: 04 03 09 04
    STRING: 0A 03 4D 00 41 00 4E 00 55 00
    STRING: 0A 03 50 00 52 00 4F 00 44 00
    STRING: 0A 03 53 00 54 00 52 00 33 00  

  • Brilliant, that worked for me! Thank you so much.

Related