cancel
Showing results for 
Search instead for 
Did you mean: 

USBX Audio Class frame done callback not called

nico23
Senior III

I've set up my STM32U5A9J-DK to use ThreadX and connect to my PC via USBX and Audio Class.

I'm correctly see the Audio Device on my PC and I can easily stream audio to it. The only thing is that, for some reason, the callback for new frame done is not fired

	audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_change
	= USBD_AUDIO_PlaybackStreamChange;

	audio_stream_parameter[0].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done
	= USBD_AUDIO_PlaybackStreamFrameDone;

The strage thing is that USBD_AUDIO_PlaybackStreamChange is correctly called

VOID USBD_AUDIO_PlaybackStreamChange(UX_DEVICE_CLASS_AUDIO_STREAM *audio_play_stream,
                                     ULONG alternate_setting)
{
  /* USER CODE BEGIN USBD_AUDIO_PlaybackStreamChange */

  /* Do nothing if alternate setting is 0 (stream closed).  */
  if (alternate_setting == 0)
  {
    return;
  }

  BufferCtl.state = PLAY_BUFFER_OFFSET_UNKNOWN;

  /* Start reception (stream opened).  */
  ux_device_class_audio_reception_start(audio_play_stream);

  /* USER CODE END USBD_AUDIO_PlaybackStreamChange */

  return;
}

Instead, USBD_AUDIO_PlaybackStreamFrameDone is never called

VOID USBD_AUDIO_PlaybackStreamFrameDone(UX_DEVICE_CLASS_AUDIO_STREAM *audio_play_stream,
                                        ULONG length)
{
  /* USER CODE BEGIN USBD_AUDIO_PlaybackStreamFrameDone */

  UCHAR *frame_buffer;
  ULONG frame_length;

  /* Get access to first audio input frame.  */
  ux_device_class_audio_read_frame_get(audio_play_stream, &frame_buffer, &frame_length);

...
}
21 REPLIES 21
nico23
Senior III

As expected, the issue was due to the USBX API handling of the single frequency in case the host asks to set the frequency. As explained below, no matter if the frequency asked to be set by the host is the exact same as the one the device supports. It will be automatically discharged and set into a STALL mode. Same if multiple frequency is supported but just a single frequency is specified in the array (no matter if it's the correct one).

The workaround (because this issue will need a fix at the USBX API level) is to set up the device to support multifrequency selection (even if you want to work with one frequency).

In the USBD_AUDIO_SetControlValues you need to set the current frequency as the single frequency you want as well as the array with the range of frequencies you want (which is still one)

  audio_control[0].ux_device_class_audio20_control_sampling_frequency_cur = USBD_AUDIO_FREQ_48_K;
  audio_control[0].ux_device_class_audio20_control_sampling_frequency_range = sampling_freq_range;

where

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
};

So, in summary:

Issue #1: control->ux_device_class_audio20_control_sampling_frequency != 0

If ux_device_class_audio20_control_sampling_frequency is set to a non-zero value (like 48000), the code treats it as a fixed frequency and rejects SET_CUR.

Solution: When initializing your audio control structure, make sure:

control->ux_device_class_audio20_control_sampling_frequency = 0;  // Must be 0 for variable rate
control->ux_device_class_audio20_control_sampling_frequency_cur = 48000;  // Current/default rate

 

Issue #2: Missing or Invalid Sampling Frequency Range

You need to set up ux_device_class_audio20_control_sampling_frequency_range properly. This should point to a buffer containing:

// Example for 48kHz only support
static UCHAR sampling_freq_range[] = {
    0x01, 0x00,              // wNumSubRanges = 1
    0x80, 0xBB, 0x00, 0x00,  // dMIN = 48000 (0x0000BB80)
    0x80, 0xBB, 0x00, 0x00,  // dMAX = 48000
    0x01, 0x00, 0x00, 0x00   // dRES = 1 (means variable within range)
};

and then

control->ux_device_class_audio20_control_sampling_frequency_range = sampling_freq_range;

Issue #3: n_sub <= 1 && res == 0

If you only have 1 subrange and dRES = 0, the code treats it as a fixed frequency. To allow SET_CUR with a single frequency, you need to set dRes = 1 as above.

At this point audio_stream_parameter[audio_stream_index].ux_device_class_audio_stream_parameter_callbacks.ux_device_class_audio_stream_frame_done = USBD_AUDIO_PlaybackStreamFrameDone; will be correctly called

@FBL @T_Hamdi 

FBL
ST Employee

Hi @nico23 

>  I think the BSP_AUDIO_Init_t struct, which is then used to initialize the various parameters, is declared in #include "stm32n6570_discovery_audio.h" (which I can't find on the project you linked). Where do I get the source code files for the STM32U5A9?

STM32U5A9J-DK board doesn't support natively audio BSP drivers.

An internal ticket (222940) is submitted to dedicated team to address the sampling with single frequency. I'll keep you updated once I got the confirmation.

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.