Skip to main content
Visitor II
April 5, 2023
Solved

USB device audio class up or IN stream not working.

  • April 5, 2023
  • 10 replies
  • 7728 views

Device: STM32F411RE NUCLEO

Hello, I am having some issues with STM USBD AUDIO library. For some reason I cannot get it to stream audio data to a host device in a proper way.

The device is successfully recognized as 2 channel 16 bit microphone by my PC.

When I press the record button in windows recorder or audacity nothing happens.

So far all I know is the USBD_AUDIO_DataIn is not getting called and from what I have read so far this is the function where I am supposed to be handling the sending data to host.

I have been trying to get this working for weeks and I have had it working in the past with the following conditions: I put the LL_Transmit function in the USBD_AUDIO_SOF function. This worked as the audio data is supposed to get polled every 1ms anyway. Then I had the problem that every other packet sent was empty, so I added the LL_Transmit function back into DataIn stage and now my sine wave was being sent perfectly. Which is really weird if you think about it. I cannot imagine that the library was designed to be used this way.

The weird thing is, if I do not use the SOF cb the DataIn stage is also not called.

I tried reading documentation but I just don't get this code. Too many layers too much stuff, and fully implemented for only speakers class so I constantly need to back up my workspace in case I do any "code generation" since I cannot work in the STM pre-approved user code spaces. Honestly I feel like throwing this whole library except the USB descriptors in the thrash. I mean previously I have also found the RM and registers much easyer to work with that STM Libraries and LL/HAL documentation. I'll just tell my boss to screw him and his time constraints. Since i'm not getting anywhere anyway.

Unless anyone here has some experience with this library and could tell me what I am doing wrong.

EDIT:::

Here is a picture of some code where I am trying to send just a single array over and over again.


_legacyfs_online_stmicro_images_0693W00000bhfj6QAA.png 

Here follows a picture of wireshank showing empty packets:


_legacyfs_online_stmicro_images_0693W00000bhfkxQAA.pngAs you can see

all packets are empty.

why?

    This topic has been closed for replies.
    Best answer by MWolt.1

    If anyone is interested in the solution.

    Ignore the Data in stage. Many examples of people who use it but I have encountered many more examples of people who can't get it to work.

    Enable SOF

    Just count the SOF in the USBD_AUDIO_SOF callback.

    From main or whatever, send whatever amount of packets is required to be sent with the USB_LL_Trasmit function, whenever SOF > 0.

    ***** that we cannot use the interrupts but whatever it's an stm library.

    10 replies

    Super User
    April 5, 2023
    • maybe - take a look: - has Audio Class 2.0 (UAC2) device

    https://github.com/hathach/tinyusb

    MWolt.1Author
    Visitor II
    April 6, 2023

    Hi thank you for your reply.

    I am not using an RTOS (never have before). Also I am using the MP3 encoder from STM which is assembly. Encoding a MP3 frame takes multiple USB frames. I cannot really call the tinyUSB task handler from there.

    Lets say I were to use tinyUSB with RTOS. Would it be possible to have the RTOS handle USB while in the encoding function or does it still wait until it returns before handling USB task? I guess I would be able to configure that?

    MWolt.1Author
    Visitor II
    April 6, 2023

    Here is a picture of some code where I am trying to send just a single array over and over again.


    _legacyfs_online_stmicro_images_0693W00000bhfj6QAA.png 

    Here follows a picture of wireshank showing empty packets:


    _legacyfs_online_stmicro_images_0693W00000bhfkxQAA.pngAs you can see

    all packets are empty.

    why?

    MWolt.1AuthorAnswer
    Visitor II
    April 25, 2023

    If anyone is interested in the solution.

    Ignore the Data in stage. Many examples of people who use it but I have encountered many more examples of people who can't get it to work.

    Enable SOF

    Just count the SOF in the USBD_AUDIO_SOF callback.

    From main or whatever, send whatever amount of packets is required to be sent with the USB_LL_Trasmit function, whenever SOF > 0.

    ***** that we cannot use the interrupts but whatever it's an stm library.

    Visitor II
    October 27, 2024

    Hello, I have exactly the same problem as you have. Could you share the code you implemented for solving?

    Explorer
    October 28, 2024

    Hi, 

    this works somehow; https://github.com/VincentGijsen/STM32F401_working_i2s_to-USB/blob/main/Middlewares/ST/STM32_USB_Device_Library/Class/AUDIO/Src/usbd_audio.c but quite hacky.. ok for hobby, perhaps not so much for commercial products ;)

     

    I also observed issues between various versions of the SDK. (Tip: double check any code example is done with identical STM library version !!)

    I never succeeded in implementing it flawless. Issue ( in my code) remains to deal with 2 independend clocks (usb and i2s source). Naive implementation will problem latch fixed set of frames on SOF trigger, and throw away or duplicate frames cached from I2s, if I cannot/will not try to slave either usb or i2s to other end..

     

    at this point I’m contemplating to try other mcu product for future audio/usb hobby projects. 

    Visitor II
    August 9, 2023

    Maybe its too late, but i'd like to add my solution, if somebody else will ever suffer with this problem.

    I got exactly the same problem and after 4 weeks of sttruggling with it I found out that is an issue of my current latest firmware packages - 1.27.1.

    After compiling code with 1.26.0 version everything works fine with DataIn function as it should be.

    Super User
    August 9, 2023

    And what is the difference between them?

    JW

    Explorer
    January 1, 2024

    i have it running (also after burning way too much time...with 1.28), now on 1.27.

     

    it does not work entirely though, but the DATA_IN(in) is atleast called.  Now my data seems to be 'half', but that is a bug to resolve, either an DMA/I2S (in) issue or USB related... time will tell

    for the curious, i've added my project below (and future reference)

    Explorer
    January 7, 2024

    for future reference: i have rudimentary working version (V1.28).

    IS2 source -> USB audio dst working, just for for anybody that cares for the topic.

     

    the buffer mechanism is "crude" presently, read: artifacts while ingesting i2s, likely issue of mis-aligned clocks from host -> stm <-i2s source.

     

    As my source is presently a Bluetooth module, i cannot change it's clock behavior.... future works.

    code: VincentGijsen/STM32F401_working_i2s_to-USB (github.com)

     

     

    Explorer II
    October 3, 2025

    I found the solution.

    1) You do not need SOF interrupts, disable them.

    2) STM32 HAL works perfectly fine. The problem emerges because the HOST reacts to USBD_LL_Transmit() only after several SOF frames. This means that USBD_LL_Transmit() in this code is useless:

    USBD_LL_OpenEP(pdev, AUDIO_IN_EP, USBD_EP_TYPE_ISOC, USB_BUF_SIZE);
    pdev->ep_in[AUDIO_IN_EP & 0xFU].is_used = 1U;
    USBD_LL_FlushEP(pdev, AUDIO_IN_EP);
    USBD_LL_Transmit(pdev, AUDIO_IN_EP, (uint8_t*)&someData, SEND_SAMPLES * 2);

    3) All we need is to wait for some time (5 SOF frames on my Windows 11 system) after USBD_LL_OpenEP() and only then call USBD_LL_Transmit()

    Bad way: call USBD_LL_Transmit() from SOF interrupt. As soon as you've got first USBD_AUDIO_DataIn() callback, only call USBD_LL_Transmit() from USBD_AUDIO_DataIn().

    The good way: disable SOF interrupts. Monitor when HOST selected alternate mode, do a first USBD_LL_Transmit() with some delay from the main loop. All the consequent transfers will be automatically handled by USBD_AUDIO_DataIn(), from which you transfer microphone signal using USBD_LL_Transmit().

    I will use the latter method in my mic for youtubers project. Both methods work and tested on STM32H7B0 under Windows 11, but I need to confirm yet if it is the same for Android/Linux and MacOS.

     

    Explorer
    October 13, 2025

    I continue my answer from the accepted solution.

    Recently i was working similar project for a demonstration only, my code did not work. I started debugging from the from the SOF() which was never called.
    Then i tracked the flow, USB interrupt->usb pcd IRQ handler->generic SOF callback()->Class specific SOF()

    where the callback failed is after IRQ handler it was not going to any SOF callback, what was suggested is to look for SOF interrupt enable(usb interrupt working i.e. global interrupt is active), so i did just selected activate_SOF() althogh this has different purpose but this worked.

    If you dont want to activate_SOF() on IOC as it will rewrite all your files, you could try changing it via /USB_DEVICE/Target/usbd_conf.c

    Edit the line
    hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
     
    to
     
    hpcd_USB_OTG_FS.Init.Sof_enable = ENABLE;
    Explorer II
    October 13, 2025

    I don't think that enabling SOF interrupt is a good idea. First of all, it results in useless interrupts at 1ms rate, because the host sends SOFs even when there is no recording initiated. And second,  it feels safer to do data transfer from dataIn(), and documentation from ST describes dataIn() as callback which has exactly this purpose. Instead of messing with SOF, we can make function pointers in user code: when alternate configuration is chosen, call function from main.c to set some flag. Check for this flag in the main loop and perform HAL_Delay(), then call second custom function, this time from usbsd_audio.c to do first ll_transmit().  Do all consequent ll_transmit()s from dataIn(). Nothing is being overwritten by code generation then. Correct me if I am wrong, but what exactly we are going to do in SOF interrupt?