Skip to main content
Associate
June 23, 2026
Question

STM32N6 USBX Composite Device - Dual CDC ACM + UVC Enumeration Failure

  • June 23, 2026
  • 3 replies
  • 14 views

Board: STM32N6 (Custom board with USB OTG HS)

I am trying to create a USB composite device with:
  - CDC ACM Instance 0 (LOG port) - Interfaces 0, 1
  - CDC ACM Instance 1 (DATA port for GenICam/GenCP) - Interfaces 2, 3
  - UVC VIDEO class - Interfaces 4, 5

Dual CDC works perfectly. However, when I add CLASS_TYPE_VIDEO to UserClassInstance[], the device fails to enumerate entirely (not visible in lsusb).

  ---
  Working Configuration (Dual CDC Only)

  // ux_device_descriptors.c
  uint8_t UserClassInstance[USBD_MAX_CLASS_INTERFACES] = {
    CLASS_TYPE_CDC_ACM,   // CDC0 - interfaces 0,1 - endpoints 0x81,0x82,0x03
    CLASS_TYPE_CDC_ACM,   // CDC1 - interfaces 2,3 - endpoints 0x84,0x85,0x06
  };

  Result: Device enumerates as 0483:5710, two /dev/ttyACM ports appear, communication works.

  ---
  Failing Configuration (Dual CDC + VIDEO)

  uint8_t UserClassInstance[USBD_MAX_CLASS_INTERFACES] = {
    CLASS_TYPE_CDC_ACM,   // CDC0 - interfaces 0,1
    CLASS_TYPE_CDC_ACM,   // CDC1 - interfaces 2,3
    CLASS_TYPE_VIDEO,     // UVC  - interfaces 4,5 - endpoint 0x87
  };

  Result: Device does not enumerate at all. Not visible in lsusb. LEDs still blink (FreeRTOS running), so firmware is executing.

  ---
  What We've Tried

  1. Identified aInterfaceNr Bug in CubeMX-Generated Code

  In USBD_FrameWork_VIDEO_Desc(), line ~1007:

  pVideoVCInDesc->aInterfaceNr = 0x01U;  // HARDCODED!

  This is correct for standalone UVC (VS interface = 1), but wrong for composite where VS interface = 5.

  2. Attempted Fix: Patch aInterfaceNr After Descriptor Build 

// In USER CODE section of USBD_FrameWork_AddToConfDesc()
  if (pdev->tclasslist[pdev->classId].ClassType == CLASS_TYPE_VIDEO)
  {
    // ... setup interfaces 4,5 and endpoint 0x87 ...

    uint32_t video_desc_start_offset = pdev->CurrConfDescSz;

    // Build VIDEO descriptors using CubeMX function
    USBD_FrameWork_VIDEO_Desc(pdev, (uint32_t)pCmpstConfDesc, &pdev->CurrConfDescSz);

    // Patch aInterfaceNr at offset 29 from VIDEO descriptor start
    // Layout: IAD(8) + VC_IF(9) + CS_VC_Header[12] = offset 29
    uint8_t *video_desc_ptr = pCmpstConfDesc + video_desc_start_offset;
    video_desc_ptr[29] = pdev->tclasslist[pdev->classId].Ifs[1];  // = 5

    return UX_SUCCESS;
  }

  Result: Still fails to enumerate.

  3. Tried Disabling VIDEO USBX Registration

  Kept VIDEO in UserClassInstance (descriptors built) but disabled:
 

#if 0
  ux_device_stack_class_register(_ux_system_device_class_video_name, ...);
  #endif

  Result: Still fails to enumerate. This confirms the issue is in descriptor building, not USBX class registration.

  4. Tried Different VIDEO Endpoints

  Tested 0x83, 0x86, 0x87 - all fail.

  5. Verified Structure Sizes

  USBD_VIDEOCSVCIfDescTypeDef: 13 bytes
  USBD_VIDEOInputTerminalDescTypeDef: 8 bytes
  USBD_VIDEOOutputTerminalDescTypeDef: 9 bytes
  USBD_VIDEOVSHeaderDescTypeDef: 14 bytes
  USBD_VIDEOPayloadFormatDescTypeDef: 11 bytes
  USBD_VIDEOFrameDescTypeDef: 30 bytes

  All match USB Video Class 1.1 spec for our configuration.

  ---
  Header Configuration 

// ux_device_descriptors.h
  #define USBD_MAX_SUPPORTED_CLASS                       3U
  #define USBD_MAX_CLASS_ENDPOINTS                       9U
  #define USBD_MAX_CLASS_INTERFACES                      12U
  #define USBD_CDC_ACM_CLASS_ACTIVATED                   1U
  #define USBD_VIDEO_CLASS_ACTIVATED                     1U
  #define USBD_COMPOSITE_USE_IAD                         1U
  #define USBD_FRAMEWORK_MAX_DESC_SZ                     600U

// Endpoint allocations
  #define USBD_CDCACM_EPINCMD_ADDR    0x81U  // CDC0
  #define USBD_CDCACM_EPIN_ADDR       0x82U
  #define USBD_CDCACM_EPOUT_ADDR      0x03U

  #define USBD_CDCACM1_EPINCMD_ADDR   0x84U  // CDC1 (custom)
  #define USBD_CDCACM1_EPIN_ADDR      0x85U
  #define USBD_CDCACM1_EPOUT_ADDR     0x06U

  #define USBD_VIDEO_EPIN_ADDR        0x87U  // VIDEO

 

 

  1. Is there another hardcoded interface number in the VIDEO descriptor besides aInterfaceNr that needs patching for composite devices?
  2. Is our offset calculation correct? We calculate aInterfaceNr at byte 29 from VIDEO descriptor start:
    - IAD: 8 bytes
    - Standard VC Interface: 9 bytes
    - CS VC Header offset to aInterfaceNr: 12 bytes
    - Total: 29 bytes
  3. Has anyone successfully implemented CDC+UVC composite on STM32N6 with USBX? If so, what modifications were required?
  4. Is there a known issue with USBX VIDEO class in composite configurations that we should be aware of?
  5. Should we be using a different approach - perhaps building the VIDEO descriptors entirely in USER CODE rather than patching the CubeMX output?

3 replies

Visitor
June 23, 2026

Since the device completely disappears from lsusb as soon as CLASS_TYPE_VIDEO is added, I'd focus on descriptor integrity rather than USBX class registration. The fact that disabling ux_device_stack_class_register() for VIDEO doesn't change the behavior strongly suggests the host is rejecting the configuration descriptor before enumeration completes.

A few things I'd check:

  • Verify the final wTotalLength in the configuration descriptor matches the actual descriptor size after your patching.

  • Confirm that all interface numbers referenced inside the UVC class-specific descriptors are updated correctly, not just aInterfaceNr.

  • Capture the raw configuration descriptor and validate it with a USB descriptor parser (lsusb -v on a working build can be useful for comparison).

  • Double-check endpoint counts and interface counts in the IAD and configuration descriptor headers.

  • If possible, temporarily build a minimal CDC + UVC configuration (one CDC instance only) to determine whether the issue is related to composite complexity or the VIDEO descriptor itself.

Personally, I'd lean toward generating the UVC descriptors manually in USER CODE rather than patching CubeMX output, especially if CubeMX was originally designed around a standalone UVC configuration. A single incorrect length, interface reference, or descriptor offset is enough to prevent enumeration entirely.

ST Technical Moderator
June 26, 2026

Hi ​@jeslet_joy, ​@clear_peak78 

Would you share minimum firmware to reproduce the issue?

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Associate
June 30, 2026

Hi ​@FBL 

Please find attached the minimal firmware to reproduce the issue.

  The project includes:
  - Dual CDC ACM + UVC composite configuration
  - CubeMX .ioc file

Build and flash the Appli project, then connect USB. On Linux host, dmesg shows error -32 during configuration descriptor read.