2026-01-22 12:06 AM
I have implemented a USB Audio 2.0 device that receives audio from the PC host (speaker endpoint) and loops it back (microphone endpoint). The PC correctly recognizes the device, and audio playback works, but I'm experiencing unexpected low-frequency noise.
Specific symptom: When playing a pure 350Hz sine wave from the PC, the device receives not only the sine wave but also significant noise content from 0Hz to 350Hz. This noise is audible in the loopback audio sent back to the host.
The audio data flows through a simple memory copy without any DSP processing:
ux_utility_memory_copy(write_buffer, read_buffer, copy_len);
ux_device_class_audio_write_frame_commit(g_mic_stream, copy_len);I also perform FFT analysis for visualization (TouchGFX), and the spectrum confirms the low-frequency noise is present in the received audio data itself, not introduced by my processing.
I have tried to disable the microphone endpoint and keep just the speaker endpoint but the issue persists.
Any guidance on diagnosing whether this is a configuration issue versus a hardware problem would be greatly appreciated. Should I focus on the USB descriptor settings first, or investigate potential hardware/cable quality issues?
My current USB descriptor is
#define USBD_AUDIO_PLAY_FREQ_MAX USBD_AUDIO_FREQ_48_K
#define USBD_AUDIO_PLAY_CHANNEL_COUNT 2U
#define USBD_AUDIO_PLAY_RES_BIT 16U
#define USBD_AUDIO_PLAY_EPOUT_HS_MPS 28U
#define USBD_AUDIO_PLAY_EPOUT_HS_BINTERVAL 1USolved! Go to Solution.
2026-02-15 2:12 AM
I think I've found the root of the issue.
In my configuration, I have a separate thread that processes the audio buffer when it's received. I have implemented the same logic used in this example. putting the audio buffer in internal RAM as well, but the issue persisted.
My audio processing thread is created
tx_thread_create(&audio_processing_thread, "Audio Processing Thread",
audio_processing_thread_entry, 0,
pointer,
AUDIO_PROCESSING_THREAD_STACK_SIZE,
15, // Priority - adjust as needed
15,
TX_NO_TIME_SLICE,
TX_AUTO_START) != TX_SUCCESS)and has a lower priority (higher number) than the audio thread of USBX used to receive the audio data.
The main issue is that this thread uses FFT to process the audio data as
/* Perform Real FFT using ARM optimized function */
arm_rfft_fast_f32(&fft_instance, fft_input_buffer, fft_output_buffer, 0);
/* Calculate magnitude of complex output */
/* Output format: [real0, imag0, real1, imag1, ...] */
/* We only need first half (positive frequencies) */
arm_cmplx_mag_f32(fft_output_buffer, magnitudes, FFT_SIZE / 2); I've run some time measuring, and I've noticed that the entire audio processing pipeline of the thread spends between 4 and 10 ms to generate the FFT output. The two functions are blocking, and because of that, the interrupt USBD_AUDIO_PlaybackStreamFrameDone, which should be called every 1ms because a new frame is received, is not called. I guess the audio frame is dropped, and this is the root cause of the low-end noise.
I've tried to disable the thread that elaborates the audio and just use a simple loopback that only copies the frame from RX to TX with no processing. The audio turned out to be clean with no distortions or noises.
I think at this point I need to figure out how to compute the FFT in a non-blocking way.
2026-01-23 1:42 AM
Hi @nico23
Since you see the low‑frequency noise directly in the OUT data buffer, it seems more like USB audio configuration or data packing issue rather than hardware/ cable issue.
Your descriptors are not exactly what you mentioned. You can find them under ux_device_descriptors.c. Please attach your descriptor file and it's header.
To simplify debugging you can follow example provided here.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2026-01-23 2:45 AM
Hi @FBL
Thanks for the answer, and you're right.
I have attached the descriptors for the speaker; I've basically copied and pasted the one you linked. In fact, the descriptors work as the data flows, but I think there's just a misconfiguration somewhere that causes the issue
2026-01-23 9:49 AM
@nico23 Would you add feedback endpoint and update your descriptor.c file based on the example here. Also, mic related descriptors are missing.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2026-01-24 1:31 AM
I'll try to add the feedback endpoint that's missing.
@FBL wrote:Also, mic related descriptors are missing.
That's not true; there's the entire section about the mic descriptor (which is working on Windows)
/* ========================================================================= */
/* MICROPHONE STREAMING INTERFACE (Interface 2) */
/* ========================================================================= */
#if USBD_AUDIO_RECORD_ACTIVATED == 1U
/* Alt Setting 0 - Zero Bandwidth */
__USBD_FRAMEWORK_SET_IF(pdev->tclasslist[pdev->classId].Ifs[interface_index],
0x00U, 0x00U,
UX_DEVICE_CLASS_AUDIO_CLASS,
UX_DEVICE_CLASS_AUDIO_SUBCLASS_AUDIOSTREAMING,
UX_DEVICE_CLASS_AUTIO_PROTOCOL_VERSION_02_00,
0x00U);
/* Alt Setting 1 - Operational */
__USBD_FRAMEWORK_SET_IF(pdev->tclasslist[pdev->classId].Ifs[interface_index],
0x01U, 0x01U,
UX_DEVICE_CLASS_AUDIO_CLASS,
UX_DEVICE_CLASS_AUDIO_SUBCLASS_AUDIOSTREAMING,
UX_DEVICE_CLASS_AUTIO_PROTOCOL_VERSION_02_00,
0x00U);
interface_index++;
/* Microphone AS CS Interface */
pMicASCSIfDesc = ((USBD_AUDIOSCSIfDescTypeDef *)(pConf + *Sze));
pMicASCSIfDesc->bLength = (uint8_t)sizeof(USBD_AUDIOSCSIfDescTypeDef);
pMicASCSIfDesc->bDescriptorType = UX_DEVICE_CLASS_AUDIO_CS_INTERFACE;
pMicASCSIfDesc->bDescriptorSubtype = UX_DEVICE_CLASS_AUDIO_AS_GENERAL;
pMicASCSIfDesc->bTerminalLink = USBD_AUDIO_REC_TERMINAL_OUTPUT_ID;
pMicASCSIfDesc->bmControls = 0x00U;
pMicASCSIfDesc->bFormatType = UX_DEVICE_CLASS_AUDIO_FORMAT_TYPE_I;
pMicASCSIfDesc->bmFormats = 0x00000001U;
pMicASCSIfDesc->bNrChannels = USBD_AUDIO_REC_CHANNEL_COUNT;
pMicASCSIfDesc->bmChannelConfig = USBD_AUDIO_REC_CHANNEL_MAP;
pMicASCSIfDesc->iChannelNames = 0x0000U;
*Sze += (uint32_t)sizeof(USBD_AUDIOSCSIfDescTypeDef);. I'm not pasting the whole descriptor but in the file there's everything
2026-02-03 8:23 AM
Any updates?
2026-02-03 12:20 PM
I've implemented the audio feedback endpoint, which is correctly enumerated, but I still have to implement the code to correct the speed of the data flow
I probabily also need to change my buffer approach as I'm not using a true circular buffer
2026-02-15 2:12 AM
I think I've found the root of the issue.
In my configuration, I have a separate thread that processes the audio buffer when it's received. I have implemented the same logic used in this example. putting the audio buffer in internal RAM as well, but the issue persisted.
My audio processing thread is created
tx_thread_create(&audio_processing_thread, "Audio Processing Thread",
audio_processing_thread_entry, 0,
pointer,
AUDIO_PROCESSING_THREAD_STACK_SIZE,
15, // Priority - adjust as needed
15,
TX_NO_TIME_SLICE,
TX_AUTO_START) != TX_SUCCESS)and has a lower priority (higher number) than the audio thread of USBX used to receive the audio data.
The main issue is that this thread uses FFT to process the audio data as
/* Perform Real FFT using ARM optimized function */
arm_rfft_fast_f32(&fft_instance, fft_input_buffer, fft_output_buffer, 0);
/* Calculate magnitude of complex output */
/* Output format: [real0, imag0, real1, imag1, ...] */
/* We only need first half (positive frequencies) */
arm_cmplx_mag_f32(fft_output_buffer, magnitudes, FFT_SIZE / 2); I've run some time measuring, and I've noticed that the entire audio processing pipeline of the thread spends between 4 and 10 ms to generate the FFT output. The two functions are blocking, and because of that, the interrupt USBD_AUDIO_PlaybackStreamFrameDone, which should be called every 1ms because a new frame is received, is not called. I guess the audio frame is dropped, and this is the root cause of the low-end noise.
I've tried to disable the thread that elaborates the audio and just use a simple loopback that only copies the frame from RX to TX with no processing. The audio turned out to be clean with no distortions or noises.
I think at this point I need to figure out how to compute the FFT in a non-blocking way.
2026-02-17 10:32 AM - edited 2026-02-17 10:33 AM
Hello @nico23
I've started working on the recording portion as well, and just overcame something huge... When debugging, UART blocks and doesn't allow some functionalities to work. So once I disabled the debugging via UART, things started working.
My issue now is although it is showing recording, it's not picking up sounds. So I'm wondering what you did to make this work. This is what I did (and I may have missed some steps, so forgive me).
Not sure why it's not picking up sounds - I have the BSP_AUDIO_IN_Init() but not sure if there's anything else I'm missing. Any ideas? @FBL maybe you can help too?
2026-02-19 5:48 AM
Hi @nico23
Thank you for sharing your feedback. Now, you can clearly conclude that the issue is not in the USB Audio configuration itself, but in the integration of multiple threads and the scheduling of heavy processing FFT alongside the real time audio flow. The blocking FFT and magnitude computation in a lower priority thread are delaying or dropping the 1ms audio frames, which explains the low frequency artifacts you observed.
For future evolution of your design, and especially if you plan to add more advanced audio analysis (e.g. classification, anomaly detection, keyword spotting), you could consider offloading part of the processing using the STM32N6, which integrates an NPU. In such an architecture:
You can find a high level presentation of this approach in this video:
https://www.youtube.com/watch?v=29EUWNwfywI
Hi @audio
To keep the thread focused and in line with community guidelines, it is better to handle recording path issue in a separate discussion. Mixing multiple problems (loopback noise and no sound captured on a different setup) in the same thread can be confusing and make it harder for others to search and reuse the answers later.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.