cancel
Showing results for 
Search instead for 
Did you mean: 

USB Host Audio MIC Device Input - incomplete code

Dear STM Team,

dear STM Community,

please, who can help for intended project: "USB MIC Device on STM Board as USB Host Audio with Input Steaming"?

The code, provided in CubeHAL (drivers, STM USB Middleware) as well as the generated code by CubeMX tool seems to be incomplete:

How to extend the USBH (host) Audio Class for 'microphone' input streaming?

Which code where to add?

Issues:

  • I have used CubeMX code generator for my board (NUCLEO-H745ZI-Q) with USB Host and Audio Class selected
  • It generates code (properly), it is 'compile clean' but nothing works (on USB)
  • OK, sure - it cannot: the generated code does not setup. does not enable any USB interrupt
  • OK, I could manually add/fix the USB OTG Interrupt handler: now, the USB Enumeration for the USB MIC works, STM board requests properly the MIC device descriptors and generates (properly) the SOF signal (on GPIO pin), obviously to enable power for USB MIC properly
  • it sets the right parameters in the USB Middleware driver (e.g. a 'microphone' as connected, 288 byte Endpoint size after MIC Enumeration etc.)

What is missing?

If I see the code, the audio data from MIC (every 1 ms an USB packet, via Endpoint 0x81) is not coming (no interrupts anymore, nothing stored in memory)

It cannot, because the code is missing!

The function 'USBH_AUDIO_InputSteam()' is empty (and optimized to do nothing, no code at all at the end).

So, I think, I had to add code to get IN, Input, EP 0x81 input data. If a Pipe for it is already configured (just not triggered) - I cannot say right now (but the EP 0x81 seems to be known by the driver).

Even, I do not know (sorry):

  • is there a need to send a command from STM Host to MIC Device in order to trigger that MIC will send an USB packet with Audio data (288 bytes for 2 channels, 24bit, 48 KHz in my case)?
  • Can I place a function call in the SOF generator function (every 1 ms) in order to receive anything from the USB MIC Device (or anywhere else - where)?
  • Do I have to use a (HW) Pipe as well? Is this Pipe already setup (just not kicked off)? Where will be the data in memory and how to access this USB packet/frame? (assuming USB DMA is involved - a need for cache coherency operations?) Is there a need to enable additional USB OTG (Endpoint) interrupts?
  • How to trigger an InputStream function, how to know if received and where the MIC Device data is stored? (ready to process it?)

I think, this STM USB Host Audio Class for a MIC Input was never implemented (never tested and never used- sorry). It should be missing on all STM boards and projects (USB Middleware). The counterpart, the 'headphone' Host Audio Class, seems to be complete, just the opposite direction looks like never used and never implemented (sorry).

Please, how to extend the code to bring-up an USB MIC Device on an STM board with STM USB Middleware as USB Host Audio Class Input device?

Thank you.

Best regards

Torsten

3 REPLIES 3

As I see right now in some manuals - the Host Audio (MIC) Input is not officially supported (just Host Audio Output to a speaker).

how to add/extend for Audio Microphone?

0690X00000BviJKQAZ.jpg

OK, just a need to add a call of USBH_IsocReceiveData() function with pipe as AUDIO_Handle->microphone.pipe. This can be done synchronized with the SOF process (in SOF handler or using helper flags to sync with code in the USBH_Process() and its sub-functions called).

But new issue!

It works for few seconds, in a random way how long it will be working. After a short while (0.5 up to few seconds), the 'idle' code, the code in main() with the function USBH_Process() is never called again. Instead, the code runs only and all the time in the USB Interrupt handler. It means: there seems to be a pending, still active USB interrupt (not cleared) so that the USB INT handler is entered immediately again.

Potentially, there is an INT condition which is not cleared and it triggers again immediately an interrupt. No chance for the main() 'thread' to run.

No idea yet where the problem is. But it is related to calling the USBH_IsocReceiveData() function. If I do not do this call, this condition does not happen. If I do the call, after a short period of time the entire code keeps running only in the interrupt handler code, never back to main().

Or: maybe one IN data reception is missing, after sending the URB request nothing is sent from the external USB MIC device. Maybe this Even/Odd frame indication gets out of sync. Or the clock drift is an issue (MIC internal clock is asynchronous to the host clock, but actually the SOF should be there to cope with).

If I call this USBH_IsocReceiveData() function inside the SOF handler (which is part of the INT handler) - it works to update my memory/buffer with the MIC USB PCM packets. But the same issue: endlessly running in the INT handlers, even this USBH_IsocReceiveData() fetches still new IN data from MIC. The main() 'thread' is 'dead'.

YES! I can confirm:

  • 1. There is an error condition (Babble Error, BBERR) which can come (on/from USB bus or the USB host device internally)
  • 2. and there is code missing to handle this error: USB_OTG_HCINT_BBERR flag in HCINTx is never checked (not used) and never cleared!
  • 3. It results in a pending, never cleared interrupt and after once this error happened (no idea why) - firmware keeps looping endlessly in the INT handlers only, main() thread is dead forever!

Details:

Debugging the USB stack (host, ISO IN streaming) I found that HCINT flag in GINTSTS is always set (remains set), never cleared. The reason is that one channel (channel 2 for my ISO IN), has seen a BBERR. This error condition is set in register OTG_HCINT(2) but never checked and never cleared.

(BTW: this BBERR interrupt flag is enabled in file stm32h7xx_ll_usb.c and therefore it 'must' be handled as well somewhere else - 'forgotten to implement consistent code?')

Adding code in file stm32h7xx_hal_hcd.c, in function HCD_HC_IN_IRQHandler() as:

  /**
   * ATT: add handling of BBERR !!
   */
  if ((USBx_HC(ch_num)->HCINT & USB_OTG_HCINT_BBERR) == USB_OTG_HCINT_BBERR)
  {
    __HAL_HCD_CLEAR_HC_INT(ch_num, USB_OTG_HCINT_BBERR);
  }

solves the problem.

Now, my Audio ISO IN from USB microphone works w/o issues. The main() thread, in function USBH_AUDIO_InputStream(), called from USBH_AUDIO_Process() in file usbh_audio.c, does the USBH_IsocReceiveData() function call to get my audio with PCM words from the USB mic. COOL!

Here the function to get the USB IN audio: the flag is used in combination with the function USBH_AUDIO_SOFProcess() in order to synchronize with the SOF interrupt (and signal).

static USBH_StatusTypeDef USBH_AUDIO_InputStream(USBH_HandleTypeDef *phost)
{
  USBH_StatusTypeDef status = USBH_OK;
  AUDIO_HandleTypeDef *AUDIO_Handle;
 
  if (flag == 0)
	  flag = 1;
 
  if (flag == 2)
  {
	  flag = 1;
	  /* actually, size is AUDIO_Handle->microphone.EpSize */
	  AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
	  /**
	   * this function should return if the in data was received
	   */
	  status = USBH_IsocReceiveData(phost, audioInBuffer, sizeof(audioInBuffer), AUDIO_Handle->microphone.Pipe);
	  cnt++;
	  if ((cnt % 500) == 0)
		  BSP_LED_Toggle(LED1);
  }
  else
	  status = USBH_BUSY;
  return status;
}