-
Notifications
You must be signed in to change notification settings - Fork 110
Description
USBX Audio 2.0: SET_CUR request incorrectly rejected for single-frequency devices
Describe the bug
The USBX Audio 2.0 class implementation in _ux_device_class_audio20_control_process() incorrectly rejects SET_CUR requests from the host when a device is configured to support only a single sampling frequency. Even when the host requests the exact frequency that the device supports (e.g., 48kHz), the device responds with a STALL, causing USB enumeration to fail and preventing audio streaming callbacks from being invoked.
Target device: STM32U5A9J-DK (also affects STM32H7, STM32N6, STM32WBA series)
Eclipse ThreadX version: 6.4.0 (issue present in X-CUBE-AZRTOS-H7 v3.3.0 and current USBX releases 6.2.1)
Toolchain and environment:
- IAR Embedded Workbench / STM32CubeIDE
- ThreadX + USBX stack
- USB Audio 2.0 Device Class
What have you tried to diagnose or workaround this issue:
-
Used USB protocol analyzer (USBPcap/Wireshark) to capture traffic - confirmed host sends valid SET_CUR request for CS_SAM_FREQ_CONTROL with correct frequency (48000 Hz), but device responds with
USBD_STATUS_STALL_PID -
Debugged into
_ux_device_class_audio20_control_process()and identified the code breaks early in two locations:- First break:
if (control->ux_device_class_audio20_control_sampling_frequency != 0) break; - Second break:
if (n_sub <= 1 && res == 0) break;
- First break:
-
Discovered workaround: Configure device as "variable frequency" even when supporting only one frequency:
audio_control[0].ux_device_class_audio20_control_sampling_frequency = 0; // Must be 0 audio_control[0].ux_device_class_audio20_control_sampling_frequency_cur = 48000; audio_control[0].ux_device_class_audio20_control_sampling_frequency_range = sampling_freq_range; // Range with dRES = 1 (not 0) static UCHAR sampling_freq_range[] = { 0x01, 0x00, // wNumSubRanges = 1 0x80, 0xBB, 0x00, 0x00, // dMIN = 48000 0x80, 0xBB, 0x00, 0x00, // dMAX = 48000 0x01, 0x00, 0x00, 0x00 // dRES = 1 (critical!) };
-
Community discussion with detailed analysis: https://community.st.com/t5/stm32-mcus-embedded-software/usbx-audio-class-frame-done-callback-not-called/td-p/855262
To Reproduce
Steps to reproduce the behavior:
- Create a USBX Audio 2.0 device project using ThreadX
- Configure audio control for single frequency support:
audio_control[0].ux_device_class_audio20_control_cs_id = 0x18; audio_control[0].ux_device_class_audio20_control_sampling_frequency = 48000; // Fixed frequency audio_control[0].ux_device_class_audio20_control_sampling_frequency_range = NULL;
- Set Clock Source descriptor with
bmControls = 0x03(read/write) or even0x01(read-only) - Register frame done callback:
audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = USBD_AUDIO_PlaybackStreamFrameDone;
- Connect device to PC and attempt to stream audio
- Observe:
- USB enumeration appears successful
- Host sends SET_CUR request for sampling frequency (Entity ID 24, Control Selector 0x01, frequency 48000 Hz)
- Device responds with STALL (
USBD_STATUS_STALL_PID) _ux_device_stack_transfer_request()returnsUX_TRANSFER_BUS_RESET(0x26)- Frame done callback is never called
Expected behavior
- When host sends SET_CUR request with frequency = 48000 Hz (matching device's supported frequency), device should accept the request and return
UX_SUCCESS - Device should only STALL if requested frequency does not match supported frequency
- After successful frequency negotiation,
ux_device_class_audio_stream_frame_donecallback should be invoked for each received audio frame - Audio streaming should work without requiring the "multi-frequency workaround"
Impact
Showstopper - This issue completely prevents USB Audio 2.0 devices with single fixed frequencies from functioning properly. It affects:
- All audio streaming callbacks (
frame_done) are never invoked - Cannot implement USB Audio 2.0 devices with fixed sample rates (common use case)
- Developers must use a non-intuitive workaround that contradicts descriptor semantics
- ST example code (X-CUBE-AZRTOS) contains this issue and misleads developers
Logs and console output
USB capture showing STALL response:
Frame 14443: Host -> Device (SET_CUR request)
bmRequestType: 0x21 (Host-to-device, Class, Interface)
bRequest: 0x01 (CUR)
wValue: 0x0100 (CS_SAM_FREQ_CONTROL, Channel 0)
wIndex: 0x1800 (Interface 0, Entity ID 24)
wLength: 4
Data: 80 BB 00 00 (48000 Hz in little-endian)
Frame 14444: Device -> Host (STALL response)
IRP USBD_STATUS: USBD_STATUS_STALL_PID (0xc0000004)
URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
Packet Data Length: 0
Full USB capture and debug logs available if needed.
Additional context
Root cause analysis:
In _ux_device_class_audio20_control_process(), the SET_CUR handler for sampling frequency contains these checks:
case UX_DEVICE_CLASS_AUDIO20_CUR:
if (request_length != 4)
break;
/* Check if multiple frequency supported. */
if (control->ux_device_class_audio20_control_sampling_frequency != 0)
break; // ❌ Rejects ALL SET_CUR for fixed frequencies
// ... validation code ...
/* Check if it's fixed single frequency. */
if (n_sub <= 1 && res == 0)
break; // ❌ Also rejects single-frequency rangesBoth conditions cause early break, leading to endpoint STALL at function end.
Proposed fix:
Before rejecting, validate if requested frequency matches supported frequency:
case UX_DEVICE_CLASS_AUDIO20_CUR:
if (request_length != 4)
break;
/* Get frequency to set. */
freq = _ux_utility_long_get(transfer->ux_slave_transfer_request_data_pointer);
/* Check if fixed single frequency. */
if (control->ux_device_class_audio20_control_sampling_frequency != 0)
{
/* Accept if frequency matches */
if (freq == control->ux_device_class_audio20_control_sampling_frequency)
return(UX_SUCCESS);
/* Otherwise reject */
break;
}
/* Variable frequency mode - existing validation logic */
// ...Related issues:
- ST Community discussion: https://community.st.com/t5/stm32-mcus-embedded-software/usbx-audio-class-frame-done-callback-not-called/td-p/855262/page/2 and https://community.st.com/t5/stm32-mcus-embedded-software/usbx-audio-class-frame-done-callback-not-called/td-p/855262/page/3
USB Audio 2.0 spec compliance:
The USB Audio 2.0 specification allows devices with single fixed frequencies to respond to SET_CUR requests. The descriptor's bmControls field should determine if SET_CUR is allowed, not internal implementation details. Current USBX behavior violates this principle.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status