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

So why does your example code do just that?

en.x-cube-azrtos-h7-v3-3-0.zip\Projects\STM32H743I-EVAL\Applications\USBX\Ux_Device_Audio2.0_PlayBack\

https://www.st.com/en/embedded-software/x-cube-azrtos-h7.html

Or am I reading it wrong? As I've followed your example above

FBL
ST Employee

Hi @nico23 again, 

I agree example firmware should be updated (internal ticket 204777). As of now, the recommendation is to move the  MX_USBX_Host_Init() to USBX_APP_Host_Init().

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.


I can confirm that invoking USBX_APP_Device_Init within a thread fixes the first issue.

Now I'm still experiencing the return code 38 from the dcd function https://community.st.com/t5/stm32-mcus-embedded-software/usbx-audio-class-frame-done-callback-not-called/m-p/856896/highlight/true#M70159

Why have you accepted the solution? The problem hasn't been resolved. The frame done callback not called is STILL NOT CALLED!

Who said the issue on the top was resolved!

@FBL 

Hi @nico23 

I thought you have confirmed that movingUSBX_APP_Device_Init() inside a ThreadX thread fixes the mutex acquisition error.

You should not see an HCD context error since you are using device only. It seems an issue to be reported and need further investigation.

The value 38 decimal = 0x26 hex, which matches UX_TRANSFER_BUS_RESET in ux_api.h meaning the transfer request is failing. I suggest use USB protocol analyzer to see USB traffic and errors better than error handler.

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.


After sniffing the USB communication, it seems that the host sends a correct URB_FUNCTION_CONTROL_TRANSFER 

USB URB [Source: host] [Destination: 1.11.0] USBPcap pseudoheader length: 28 IRP ID: 0xffffe28a5cfbc4b0 IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000) URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008) IRP information: 0x00, Direction: FDO -> PDO 0000 000. = Reserved: 0x00 .... ...0 = Direction: FDO -> PDO (0x0) URB bus id: 1 Device address: 11 Endpoint: 0x00, Direction: OUT 0... .... = Direction: OUT (0) .... 0000 = Endpoint number: 0 URB transfer type: URB_CONTROL (0x02) Packet Data Length: 12 [Response in: 14444] Control transfer stage: Setup (0) [bInterfaceClass: Audio (0x01)] Setup Data bmRequestType: 0x21 0... .... = Direction: Host-to-device .01. .... = Type: Class (0x1) ...0 0001 = Recipient: Interface (0x01) bRequest: CUR (0x01) wValue: 0x0100, Clock Source Control Selector: CS_SAM_FREQ_CONTROL .... .... 0000 0000 = Channel Number: 0x00 0000 0001 .... .... = Clock Source Control Selector: CS_SAM_FREQ_CONTROL (0x01) wIndex: 0x1800 .... .... 0000 0000 = Interface Number: 0 0001 1000 .... .... = Entity ID: 24 wLength: 4 Layout 3 Parameter Block: Frequency [Hz] dCUR: 48000 Data Fragment: 80bb0000

but the device answers with USBD_STATUS_STALL_PID 

USB URB [Source: 1.11.0] [Destination: host] USBPcap pseudoheader length: 28 IRP ID: 0xffffe28a5cfbc4b0 IRP USBD_STATUS: USBD_STATUS_STALL_PID (0xc0000004) URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008) IRP information: 0x01, Direction: PDO -> FDO 0000 000. = Reserved: 0x00 .... ...1 = Direction: PDO -> FDO (0x1) URB bus id: 1 Device address: 11 Endpoint: 0x00, Direction: OUT 0... .... = Direction: OUT (0) .... 0000 = Endpoint number: 0 URB transfer type: URB_CONTROL (0x02) Packet Data Length: 0 [Request in: 14443] [Time from request: 214.000 microseconds] Control transfer stage: Complete (3) [bInterfaceClass: Audio (0x01)]

After debugging inside the USBX library, it seems the STM32 responds with stalled because it executes the function _ux_device_class_audio20_control_process and it reaches the end where there's

/* Request or parameter not supported. */
_ux_device_stack_endpoint_stall(endpoint);

From what I'm understanding, the device is failing one of the checks inside the case UX_DEVICE_CLASS_AUDIO20_CUR: regarding the audio sampling frequency.

My host has a set frequency of 48kHz, and my device descriptor (https://github.com/NicoCaldo/NovaSonus_ThreadX/blob/main/USBX/App/ux_device_descriptors.c) which is a copy-paste of the one linked by @T_Hamdi https://github.com/stm32-hotspot/STM32WBA-BLE-USBx-Class-Audio/blob/main/Projects/STM32WBA65I-DK1/Applications/USBX/Ux_Device_Audio_2.0_Standalone/USBX/App/ux_device_descriptors.c ) defines the frequency as 48kHz

ULONG USBD_AUDIO20_PLAYBACK_FREQENCIES[USBD_AUDIO_PLAY_FREQ_COUNT] = {
  USBD_AUDIO_FREQ_48_K,
};

and in VOID USBD_AUDIO_SetControlValues(VOID)

  audio_control[0].ux_device_class_audio20_control_cs_id                = USBD_AUDIO_PLAY_CLOCK_SOURCE_ID;
  audio_control[0].ux_device_class_audio20_control_sampling_frequency   = USBD_AUDIO_FREQ_48_K;
  audio_control[0].ux_device_class_audio20_control_fu_id                = USBD_AUDIO_PLAY_FEATURE_UNIT_ID;

So I'm not understanding why it's failing

nico23
Senior III

So, I think ultimately there's a bug in the USBX api when it comes to setting frequency.

If I'm choosing to support a single frequency, i.e. 48k, why does the device in the sampling frequency control SET request break and return if multiple frequencies are not supported?

It does the same while checking if it's a fixed single frequency. 

            /* Sampling frequency control, SET request.  */
            if ((request_type & UX_REQUEST_DIRECTION) == UX_REQUEST_OUT &&
                (control_selector == UX_DEVICE_CLASS_AUDIO20_CS_SAM_FREQ_CONTROL))
            {
                switch(request)
                {
                case UX_DEVICE_CLASS_AUDIO20_CUR:

                    /* Check request parameter.  */
                    if (request_length != 4)
                        break;

                    /* Check if multiple frequency supported.  */
                    if (control -> ux_device_class_audio20_control_sampling_frequency != 0)
                        break;

...

                    /* Check if it's fixed single frequency.  */
                    if (n_sub <= 1 && res == 0)
                        break;

Isn't it more correct to first check if the frequency the host is trying to set matches the only frequency the device can set? If not, it breaks and returns, stalling the device.

What's your take @FBL @T_Hamdi 

FBL
ST Employee

Hi @nico23 

An internal ticket 222275 is submitted to dedicated team regarding the HCD context issue.

Regarding the stall, would you simplify your project to narrow down the issue to simply streaming via SAI like the example N6 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.


FBL
ST Employee

Hi @nico23 

I think the order of initialization regarding setting the audio frequency and control is different. 

If this function is called too early, the USBX audio class control handler may see a zero or invalid frequency, causing it to stall on frequency SET requests.

The example firmware sets explicit audio playback parameters (sample rate, bits per sample, volume) after USBX init, which may also be required to keep the device and USBX stack synchronized.

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.


nico23
Senior III

I'll try to use SAI as in the project you linked, but the issue regarding the frequency check still remains. If you choose a single frequency and, for some reason, the host checks if multi-frequency is supported, it automatically stalls.

Setting

audio_control[0].ux_device_class_audio20_control_sampling_frequency   = USBD_AUDIO_FREQ_48_K;

automatically triggers

                    if (control -> ux_device_class_audio20_control_sampling_frequency != 0)
                        break;

if there's a set request UX_DEVICE_CLASS_AUDIO20_CUR

One question @FBL about your example, 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?

nico23_0-1763758110776.png