Skip to main content
Robmar
Senior II
July 12, 2026
Solved

USB microphone to H743 host streams mic then data freezes

  • July 12, 2026
  • 33 replies
  • 599 views

Connected an USB microphone to an H743 as host and it streams mic audio perfectly at 48 KHz for around 5 seconds then the data freezes.
SOF is still being called as is AudioHost_IsoDataReadyISR() from the STM IRQ driver, DMA is running (its set to use DMA, I tried without but same behaviour), but the same 96 bytes are transfered every uS: I can clear the receive buffer but it gets refilled with the same data.  Attempts to re-init the pipes etc etc fail to restore streaming.
Also, any pause in the servicing of the call to AudioHost_IsoDataReadyISR() results in exactly the same repeat data arriving.

This is my own code based on STM’s examples, as I said it runs perfectly for many seconds, if I unplug the microphone it runs again when plugged back in for the same good few seconds.

Is there an approved way to restore audio streaming without a full reset when there is an occasional timing glitch in servicing the AudioHost_IsoDataReadyISR() call?

Best answer by Robmar

You need to test it with an actual commerical USB microphone otherwise the tests aren’t

 going to be conclusive.

https://docs.espressif.com/projects/esp-usb/en/latest/esp32s2/usb_host/usb_host_notes_dwc_otg.html

UPDATE:  I have now solved the problem by rewritting the STM HOST USB handler and adding extensive driver code, including making it a fully composite CDC, Audio and HID driver.  I would recommend anyone trying to implement a host driver to refer to the above mentioned STM errata for the USB controller in their MCUs.
I have also rewritten the STM Device USB driver to support composite CDC, Audio and HID, with audio rates from 48 to 192 KHz.  If any one is interested in this code they should PM me.

33 replies

Robmar
RobmarAuthor
Senior II
July 13, 2026

There must be a standard way to reactivate the stream after  pause in serviving Notify, I tried this below but it did nothng.
 

static void AUDIO_HOST_HardRecoverChannel(USBH_HandleTypeDef *phost, uint8_t pipe_num)

{

USB_OTG_GlobalTypeDef *USBx = ((HCD_HandleTypeDef *)phost->pData)->Instance;

USB_OTG_HostChannelTypeDef *hc = (USB_OTG_HostChannelTypeDef *)

(((uint32_t)USBx) + USB_OTG_HOST_CHANNEL_BASE + (pipe_num * USB_OTG_HOST_CHANNEL_SIZE));



// 1. Request halt

hc->HCCHAR |= USB_OTG_HCCHAR_CHDIS;

hc->HCCHAR |= USB_OTG_HCCHAR_CHENA;



// 2. Wait for hardware to confirm the channel actually halted

uint32_t timeout = 1000;

while ((hc->HCCHAR & USB_OTG_HCCHAR_CHENA) && timeout--)

; // hardware clears CHENA itself when truly halted



// 3. Clear any pending interrupt flags for this channel

hc->HCINT = 0xFFFFFFFF;



// 4. Flush the RX FIFO (required per reference manual before re-submitting)

USBx->GRSTCTL |= USB_OTG_GRSTCTL_RXFFLSH;

timeout = 1000;

while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) && timeout--)

;

}

 

Robmar
RobmarAuthor
Senior II
July 14, 2026

STM managers clearly don’t value support, as a result of this, many clients have adopted the ESP32 platform, which has comprehensive USB support

ST Technical Moderator
July 14, 2026

Hi ​@Robmar 

Would you provide minimum firmware to reproduce?

Can you point me directly in which file AudioHost_IsoDataReadyISR is defined STMicroelectronics/stm32-mw-usb-host: Provides the USB Host library part of the STM32Cube MCU Component "middleware" for all STM32xx series

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Robmar
RobmarAuthor
Senior II
July 14, 2026

Hi, thanks for the reply.  There is no host audio code samples for audio as far as I am aware.

My Host audio driver works perfectly for around 6 seconds, receiving 96 byte packets perfectly every 1mS, I have a GPIO toggle on the ISOCreceive Notify that shows 1000uS spacing on calls that then stretches during a few seconds from a 1000:1000:1000 timing to 1200:800:1000 or less, a sort of slow drift with the centre of every 3 sets of pulses drifting back to 1000:1000:1000 and repeating.
I wonder if the USB mic’s and H743 (25MHz xtal) 48 MHz clocks are beating, then a USB_OTG_HCINT_TXERR and USB_OTG_HCINT_BBERR can occur, a missed packet, is the odd/even packet bit out of step?

Anyway after that the host receives the last packet forever via DMA into its sole receive buffer, SOF and ISOCreceiver keep firing, no errors appear, same data.  I have erased the data buffer with memset but it gets refilled with same data as last packet before the errors.

So a lost packet can happen, even heavy noise could cause it.

My questsion is how to recover Host operation without unplugging the microphone, there must be an approved way, with minimal interruption?

I can’t post my USB code without posting my entire project.  As I said the issue is error recovery.
I also have USB audio at 192 KHz working perfectly, with DMA enabled, but with this Mars Gaming microphone, timing drift occurs, which does not happen with a PC.  The Mic works fine on the PC, so I guess the PC driver syncs or recovers better.



 

ST Technical Moderator
July 14, 2026

Hi ​@Robmar 

You can refer to these examples for USB Host audio : 

STM32CubeH7/Projects/STM32H743I-EVAL/Applications/USB_Host/AUDIO_Standalone at master · STMicroelectronics/STM32CubeH7

x-cube-azrtos-h7/Projects/STM32H747I-DISCO/Applications/USBX/Ux_Host_Audio at main · STMicroelectronics/x-cube-azrtos-h7

 

For USB isochronous audio, missed packets are not recoverable. No handshake for Isochronous transfers. 

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Robmar
RobmarAuthor
Senior II
July 14, 2026

The lost packet data isn’t the issue.  Thanks  for the links but the examples are very basic without any recovery methods.

The issue is that audio packet transfer fails and cannot be restarted, although SOF and Notify of packet arrival continues, the packet data transfered is always the last packet sent before the desync/lost signal.

My question is how to recover Host operation without unplugging the microphone, with minimal interruption?

An STM engineer versed in USB would know the answer because it would be a non-functional design if the only recovery method was a power down.

I would appreciate if someone who knows the USB core can answer my question?

Robmar
RobmarAuthor
Senior II
July 15, 2026

Following the advice from STM tech FBL below, I checked the STM GitHub, the relevant code file is :
usbh_audio.c

Its just an incomplete skeleton of a driver, I can’t see any code that actually handles data reception.

STM yet again show their contempt for clients needing USB support.

That they are losing business hand over foot to the ESP32 platform which has excellent USB support, is no surprise.
 

ST Technical Moderator
July 15, 2026

OK ​@Robmar  the repeat of the last packet could be the failure.

If receive servicing is being delayed occasionally (not deterministically from your observations), this can be an issue in our controller. But as I said, I need to reproduce on my end with our HAL/frameworks before escalating the issue.

 

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Robmar
RobmarAuthor
Senior II
July 16, 2026

I can show you exactly where the error is detected in the STM IRQ handler, 

File: stm32h7xx_hal_hcd.c
Routine: static void HCD_HC_IN_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum)

When mic stops streaming (or streaming starts repeating the ast frame, error USB_OTG_HCINT_TXERR occurs and is detected here:

else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_TXERR))

{

__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR); // Transaction error

hhcd->hc[chnum].state = HC_XACTERR; // Note: This occured when the USB mic stopped

(void)USB_HC_Halt(hhcd->Instance, chnum);

}

else

{

/* ... */

}

From here execution falls through to this section of code below in the same routine:-

 

After the above error, execution falls through here, deliverying the Notify with the NOTREADY status and the pipe halted.

else if ((hhcd->hc[chnum].state == f) ||

(hhcd->hc[chnum].state == HC_DATATGLERR))

{

hhcd->hc[chnum].state = HC_HALTED;

hhcd->hc[chnum].ErrCnt++;

if (hhcd->hc[chnum].ErrCnt > 2U)  Note: ErrCnt is 1

{

hhcd->hc[chnum].ErrCnt = 0U;



if (hhcd->hc[chnum].do_ssplit == 1U)

{

hhcd->hc[chnum].do_csplit = 0U;

hhcd->hc[chnum].ep_ss_schedule = 0U;

__HAL_HCD_CLEAR_HC_CSPLT(chnum);

}



hhcd->hc[chnum].urb_state = URB_ERROR;

}

else

{

hhcd->hc[chnum].urb_state = URB_NOTREADY;



if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL) ||

(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))

{

/* re-activate the channel */

tmpreg = USBx_HC(chnum)->HCCHAR;

tmpreg &= ~USB_OTG_HCCHAR_CHDIS;

tmpreg |= USB_OTG_HCCHAR_CHENA;

USBx_HC(chnum)->HCCHAR = tmpreg;

}

}

}

It then calls :

#else

HAL_HCD_HC_NotifyURBChange_Callback(hhcd, chnum, hhcd->hc[chnum].urb_state);


Which calls my AudioHost_IsoDataReadyISR() code, as it does with every packet received during streaming, but with NOTREADY ERROR status.

So teh STM handler issued a halt:

__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR); // Transaction error

hhcd->hc[chnum].state = HC_XACTERR; // Note: This occured when the USB mic stopped

(void)USB_HC_Halt(hhcd->Instance, chnum);



I just need to know how to get the channel streaming again with the USB mic.

mƎALLEm
ST Technical Moderator
July 16, 2026

@Robmar 

Your post have been edited to comply with ST community rules: How to write your question to maximize your chances to find a solution

In next time and for code readability, please use “Code” insertion option to paste your code:

Thank you for your understanding.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.
Georgy Moshkin
Senior
July 16, 2026

STM32 USB audio works perfectly for microphone. All you need is to send data  when USB audio class requested it, not when adc/i2s/i2c microphone interrupt occurs. Obviously you need to skip or insert samples. Please explain how you send microphone data to USB to get better advice

Check my STM32 Bootloader - flash your STM32 with AES-encrypted binaries right from web browser!
Robmar
RobmarAuthor
Senior II
July 16, 2026

Yes I know that, as mentioned in my post, it does work for 6 seconds during that time the mic seems to get our of sync with the host, or visa versa. the SOF calls are 1mS, but the packet returns from the device start to lag.  This causes a BLERR babble error, halts the channel, and then the host seems to keep working, but the data received by DMA, is always the same packet.
So it seems that something is missing in the recovery.  I had a similar issue with this error on the OUT channel, and added code to reset the channel, but the same code doesn’t work on the IN channel.

Georgy Moshkin
Senior
July 30, 2026

Why there should be any “recovery”? It is not a common practice to reset the channel from time to time in USB, and there should no be such issues. To ensure that your firmware works correctly, send a sawtooth instead of actual microphone data:

for (int i=0; i<buffer_length; i++)
{
buf[i]=a;
a++;
}

I’ve investigated USB packets from several microphones like Boya, Fifine, etc., and each one of them relies on the interrupt from the host. Therefore, regardless of their internal sampling rate imprecision, they are always ready to send the data to the host. The best way is to do the test with a generated sawtooth and check it in Audacity or other audio editor. Use sawtooth or sinewave and ensure that there are no clicks/pops.

If you sending data actively using USB HAL function, this will probably fail 100% one way or another (unless you figure out USB descriptors and events that allow the device to control the stream, but it seems that none of commercial USB microphones does it this way).

I send data to microphone like shown below. SOF interrupt is disabled, and there are no timers/etc. stuff is going on. This will obviously will be out of sync with the STM32 ADC/I2S/I2C microphone stream. The micTransferCallbackPtr() handles this by skipping/doubling few samples in the microphone stream, so there is always data ready.

uint8_t DEV_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) {
if (epnum == (AUDIO_IN_EP & 0x7F))
{
if (micState != MIC_IDLE)
{
micState = MIC_RECORDING;

micTransferCallbackPtr();
//USBD_LL_Transmit(pdev, AUDIO_IN_EP, (uint8_t*)&(*pcm_data_ptr)[pcm_idx], MIC_FRAME_SIZE*2);


}
}
return USBD_OK;

}

 

Check my STM32 Bootloader - flash your STM32 with AES-encrypted binaries right from web browser!
Robmar
RobmarAuthor
Senior II
July 16, 2026

For example can I modify the STM handler to handle the USB_OTG_HCINT_TXERR error so that it restores the channel and requests another packet, or is their a recommended method to recover?

This is the modified handler code:

if (hhcd->hc[chnum].do_ssplit == 1U)

{

hhcd->hc[chnum].do_csplit = 0U;

hhcd->hc[chnum].ep_ss_schedule = 0U;

__HAL_HCD_CLEAR_HC_CSPLT(chnum);

}

hhcd->hc[chnum].urb_state = URB_ERROR;

}

else

{

//hhcd->hc[chnum].urb_state = URB_NOTREADY;

/* mod 20260710 add test xyx8 trying to ublock mic stream blockage DID NOT HELP */

if (hhcd->hc[chnum].ep_type == EP_TYPE_ISOC)

{

// For mic: treat TXERR as transient, re-prime the IN transfer

hhcd->hc[chnum].urb_state = URB_IDLE; // or a custom “retry” state GW8RDI Did return NOTREADY

hhcd->hc[chnum].ErrCnt = 0U;

// Flush RX FIFO to clear any partial frame

USB_FlushRxFifo(hhcd->Instance);

// Re-activate channel

tmpreg = USBx_HC(chnum)->HCCHAR;

tmpreg &= ~USB_OTG_HCCHAR_CHDIS;

tmpreg |= USB_OTG_HCCHAR_CHENA;

USBx_HC(chnum)->HCCHAR = tmpreg;

// Re-submit the isochronous IN request for the mic

HAL_HCD_HC_SubmitRequest(hhcd,

chnum,

1, /* Dir IN */

hhcd->hc[chnum].ep_type, /* USBH_EP_ISO */

1, /* Token unused for ISOC */

hhcd->hc[chnum].xfer_buff,

hhcd->hc[chnum].xfer_len, 0);

} // End mod

else if ((hhcd->hc[chnum].ep_type == EP_TYPE_CTRL) ||

(hhcd->hc[chnum].ep_type == EP_TYPE_BULK))

{

 

ST Technical Moderator
July 16, 2026

Hi ​@Robmar 

We have already identified similar issues in HCD_HC_IN_IRQHandler API linked to compute number of packets. Still not sure if it’s related to clear errors flags. Our teams will investigate the reported behavior as well. 

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Robmar
RobmarAuthor
Senior II
July 30, 2026

Could you give me the link to that one, I’d like to check if it affects are code.  Thanks

Robmar
RobmarAuthor
Senior II
July 16, 2026

It will be hard to believe this is a bug, though we have had to make two other patches to this USB IRQ handler to stop lock ups in Device mode.

What we are seeing in host mode audo ISOC transfer looks similar to the Device side lockup, but so far we haven’t got this fix to solve the issue in Host mode.

In this routine:

void HCD_HC_OUT_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum)

We had to add this;
 

/*BUG FIX AFTER (STM V1.12.1 Update): Resolved USB Host Channel Stalls (this may be incorrect but it does reactivate the channel)
Context: In previous HAL USB versions (V1.11.2 and earlier), a Transaction Error (TXERR)
occurring while DMA was enabled would increment the error counter but fail
to re-prime the hardware. This left the channel in a 'Disabled' state (CHENA=0),
causing the Host to stop sending IN tokens indefinitely.
Impact on Audio: This resulted in 50ms+ silence periods, triggering device-side
watchdogs and subsequently causing BBERR (Babble) errors during violent resyncs.
Fix: Manually re-activate the channel by clearing CHDIS and setting CHENA in
the HCCHAR register. This forces an immediate hardware retry of the transaction,
maintaining stream continuity and preventing DMA pointer misalignment (byte-shifting).
*/

/* Re-activate the channel */

tmpreg = USBx_HC(chnum)->HCCHAR;

tmpreg &= ~USB_OTG_HCCHAR_CHDIS;

tmpreg |= USB_OTG_HCCHAR_CHENA;

USBx_HC(chnum)->HCCHAR = tmpreg;

}

}

__HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_TXERR);

}

else if (__HAL_HCD_GET_CH_FLAG(hhcd, chnum, USB_OTG_HCINT_DTERR))

{

hhcd->hc[chnum].state = HC_DATATGLERR;

 

mƎALLEm
ST Technical Moderator
July 16, 2026

@Robmar 

Again, please use “Code” insertion option to paste your code:

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.