-
Notifications
You must be signed in to change notification settings - Fork 110
Description
Describe the bug
A logic error in the _ux_device_class_audio_transmission_start function prevents the Microphone (Isochronous IN) stream from starting when the buffer is correctly primed. The function checks if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) and returns UX_BUFFER_OVERFLOW if true. However, because the microphone thread is suspended and hasn't processed its first frame yet, this condition often triggers even when data is waiting, or conversely, blocks the initial resume of the audio thread.
Inverting this logic or bypassing it allows the Host (Windows) to begin sending Isochronous IN tokens, which are otherwise never sent.
Hardware and Software Environment:
- Target device: STM32U5A9J-DK (using USB OTG HS)
- Version of Eclipse ThreadX: v6.2.1 or v6.3.0 (USBX Audio 2.0 Class)
- Toolchain and environment: IAR Embedded Workbench for ARM / STM32CubeIDE
- Diagnostics tried: - Verified USB Descriptors (Clock Source IDs, Terminal Links, and Endpoint addresses).
- Monitored USB traffic via Wireshark; confirmed Windows never sends IN tokens for the Mic interface until the library was patched.
- Traced
ux_device_class_audio_write_thread_entryand found it permanently SUSPENDED due to the initialization failure intransmission_start.
To Reproduce
Steps to reproduce the behavior:
- Initialize a USBX Audio 2.0 device with both Speaker (OUT) and Microphone (IN) interfaces.
- Link the Microphone path to the same Clock Source as the Speaker.
- In the
ux_device_class_audio_stream_changecallback, attempt to prime the Mic buffer usingux_device_class_audio_write_frame_getandux_device_class_audio_write_frame_commit. - Call
ux_device_class_audio_transmission_start. - Observe that the function returns
UX_BUFFER_OVERFLOW(0x5D) and the microphone thread never executes.
Expected behavior
The ux_device_class_audio_transmission_start function should successfully resume the audio write thread when a valid stream is configured, allowing the hardware to prepare for the first Host IN token.
Impact
Showstopper. Without the patch/inversion of the logic, it is impossible to implement a USB Audio Microphone or Loopback interface, as the Host fails to recognize the data stream and eventually returns a "Code 10" error in Device Manager.
Logs and console output
- Wireshark: Shows
SET_INTERFACE(Alt 1) for the Mic interface followed by zero Isochronous IN packets. - Debugger:
stream->ux_device_class_audio_stream_transfer_pos->ux_device_class_audio_frame_lengthis observed as0at the moment of the failing check.
Additional context
The issue seems specifically tied to the initial state of the transfer_pos structure when the stream is transitioned from Alt Setting 0 to Alt Setting 1. Even if the buffer is primed with ux_device_class_audio_write_frame_commit immediately prior to the start call, the pointer/length state within the USBX internal structures does not always satisfy the == 0 check in the way the driver expects.
Workaround: Patching the USBX Library
File: ux_device_class_audio_transmission_start.c
Description: The original logic prevents the transmission thread from resuming if the frame length is 0. However, in many initialization sequences, the length remains 0 until the thread is actually running and the hardware starts its first transfer cycle. By inverting the logic, we allow the thread to resume and the Host to begin polling.
Modified Code:
/* Check if there is frame to send (underflow). */
/* ORIGINAL: if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length == 0) */
/* PATCHED: Invert logic to allow initial thread resumption */
if (stream -> ux_device_class_audio_stream_transfer_pos -> ux_device_class_audio_frame_length > 0)
{
return(UX_BUFFER_OVERFLOW);
}Updated "Additional context" for your report
When using the original == 0 check, a "deadlock" occurs:
- The Host sends
SET_INTERFACEto enable the Microphone. ux_device_class_audio_transmission_start()is called.- The check fails (returns
UX_BUFFER_OVERFLOW) because the internaltransfer_poshasn't been updated by an active transfer yet. - The Microphone thread remains
SUSPENDED. - Because the thread is suspended, no data is ever moved to the FIFO.
- The Host (Windows) receives no data for its initial IN tokens, times out, and stops polling, resulting in Error Code 10.
By changing the condition to > 0, the function returns UX_SUCCESS when the length is 0, successfully executing _ux_device_thread_resume(). This allows the USBX audio thread to wake up, interact with the hardware driver, and satisfy the Host's requests.