2018-08-22 09:41 AM
I'm working on extending the capabilities of the STM32CubeMX Library to support higher data rate isochronous IN data (e.g. UAC audio). Currently I have host code that requests and receives isochronous data every 1ms frame (not every micro-frame).
Is there any way to configure the STM32 CubeMX USB Host Library to request data every micro-frame?
Control transfers all appear correct and enumeration happens happily - the bus is running at high-speed (confirmed with USB protocol analyser).
The device is capable (USB protocol analyser shows it receiving 1 packet every micro-frame with a Windows drivers, but only every 8 micro-frames with the modified code I have).
I'm using version 3.2.2 of the STM32 USB Host Library and 1.2.4 of the STM32F7xx HAL Drivers (I've checked the changes to 1.2.5 but there is no differences in the USB drivers).
2018-08-22 09:43 AM
I have patches in place to fix the noted Isochronous receive issue (see https://community.st.com/s/question/0D50X00009XkWbkSAF/usb-isochronous-in-host-example)
2018-08-28 09:29 AM
USB_CoreInit() in stm32f7xx_ll_usb.c calls USB_HS_PHYCInit() if USB_HS_PHYC is defined (e.g. the STM32F733 has an embedded high speed phy, so USB_HS_PHYC is defined in stm32f733xx.h) and phy_itface == USB_OTG_HS_EMBEDDED_PHY.
HCD_Port_IRQHandler in stm32f7xx_hal_hcd_c has a section of code to 'Check whether Port Enable Changed' which tests for phy_itface == USB_OTG_EMBEDDED_PHY, then calls USB_InitFSLSPClkSel() to set HFIR to 6000 for low speed and 48000 otherwise.
If phy_itface != USB_OTG_EMBEDDED_PHY and speed == HCD_SPEED_FULL, HFIR is set to 60000.
In the STM32F733 it is possible to set:
hhcd_USB_OTG_HS.Init.speed = USB_OTG_SPEED_HIGH;
hhcd_USB_OTG_HS.Init.dma_enable = ENABLE;
hhcd_USB_OTG_HS.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY;
In this case I can't see HFIR being set. Have I read this wrongly?
What value should HFIR be set to for the STM32F733 when the embedded phy is being used at high speed? My guess would be 384,000 (8 * 48000) but that is too large for a 16 bit register.
To see this question in a code context, if there are values for WHAT_VALUE and ANOTHER_VALUE for the STM32F733 (see 32.15.18 and 32.15.19 of reference manual RM0431) e.g.:
diff --git a/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_hcd.c b/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_hcd.c
index 85c19ea..71fc5ef 100644
--- a/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_hcd.c
+++ b/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_hcd.c
@@ -1209,6 +1209,15 @@ static void HCD_Port_IRQHandler (HCD_HandleTypeDef *hhcd)
USB_InitFSLSPClkSel(hhcd->Instance ,HCFG_48_MHZ );
}
}
+#ifdef USB_HS_PHYC
+ else if (hhcd->Init.phy_itface == USB_OTG_HS_EMBEDDED_PHY)
+ {
+ if(hhcd->Init.speed == HCD_SPEED_HIGH)
+ {
+ USB_InitFSLSPClkSel(hhcd->Instance, WHAT_VALUE);
+ }
+ }
+#endif
else
{
if(hhcd->Init.speed == HCD_SPEED_FULL)
diff --git a/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_ll_usb.c b/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_ll_usb.c
index 87bd84a..86c54cd 100644
--- a/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_ll_usb.c
+++ b/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_ll_usb.c
@@ -1315,6 +1315,12 @@ HAL_StatusTypeDef USB_InitFSLSPClkSel(USB_OTG_GlobalTypeDef *USBx , uint8_t freq
{
USBx_HOST->HFIR = (uint32_t)48000;
}
+#ifdef USB_HS_PHYC
+ else if (freq == WHAT_VALUE)
+ {
+ USBx_HOST->HFIR = (uint32_t)ANOTHER_VALUE;
+ }
+#endif
else if (freq == HCFG_6_MHZ)
{
USBx_HOST->HFIR = (uint32_t)6000;
2018-08-29 08:14 AM
I have tried the above (attempted) fix with WHAT_VALUE set to HCFG_48_MHZ and ANOTHER_VALUE set to 48000 (e.g. the values used for full speed) and see different behaviour on the USB protocol analyser. I see SOFs every ~800us (I was hoping for every 125 us) rather than 8 SOFs every 1ms
So with this hack I can get isochronous data every SOF, but the SOF timing is all wrong.
The USB clock is set to 48MHz in the STM32 Cube MX clock configuration view.
What is the correct way to set the USB Host Library up to request Isochronous data every 125us SOF?
2018-09-21 03:39 AM
Although I'm in danger of talking to myself ...
It is possible to get isochronous data at 1 (or more) packet per micro-frame, but stm32f7xx_hal_hcd.c needs modifying.
In addition to adding 'else if(hhcd->hc[ch_num].ep_type == EP_TYPE_ISOC)' (from https://community.st.com/s/question/0D50X00009XkWbkSAF/usb-isochronous-in-host-example) to handle isochronous data in the HCD_HC_IN_IRQHandler interrupt routine (specifically in the part where we handle the transfer complete interrupt, signalled by USB_OTG_HCINT_XFRC in the host channel interrupt register) and notifying the USB stack with HAL_HCD_HC_NotifyURBChange_Callback(), you need to get the size of the USB packet copied by the USB DMA (e.g. 'uint32_t data_length = hhcd->hc[ch_num].xfer_count'), call (your own) function to provide another address for the USB DMA to transfer received data to (you'll not be able to do anything with the data in 125us) and then call USBH_IsocReceiveData() to set up the next USB DMA transfer.
The code I had before was trying to do this in my USBH_VIDEO_Receive function (which the USBH_VIDEO_Process calls in response to the IRQs HAL_HCD_HC_NotifyURBChange_Callback) - it is too slow there and needs to be in the IRQ.
Hopefully this will be of some help to anyone else trying to add UVC support to the STM32 processor.
Now the challenge is doing anything with the data before running out of space to DMA into / overwriting data being read out!
Note: STM32Cube F7 1.9.0 and STM32Cube F7 1.12.0 both state they contain version 3.2.2 of the STM32 USB Host Library, but STM32Cube F7 1.11.0 & STM32Cube F7 1.12.0 both contain version 3.3.0 of the STM32 USB Host Library - this makes it look like the USB middleware has not changed when in fact it has.
Also note: Version 1.2.5 of the STM32F7xx HAL Drivers DOES have USB driver changes - it contains the addition of two functions (HAL_HCD_PortEnabled_Callback & HAL_HCD_PortDisabled_Callback) which need 'real' versions adding to usbh_conf.c to call USBH_LL_PortEnabled / USBH_LL_PortDisabled - otherwise upgrading from STM32Cube F7 1.9.0 to a later version will break the USB stack (without using STM32CubeMX to auto-generate code and re-applying any hacks you've needed to add outside the USER CODE BEGIN / USER CODE END comment markers).
2019-10-31 03:46 AM
In reply to a community members question on whether I managed to get data every microframe I wrote:
I was only using the USB stack to receive data - I never tried to send data.
I was able to receive data every microframe - the trick was to provide the next buffer for the isochronous data in the ISR itself.
My original method (based on ST's standard driver) was to post a message (using HAL_HCD_HC_NotifyURBChange_Callback) to the USB stack, that then calculated an address for the next free buffer and called USBH_IsocReceiveData to provide that address to the hardware (so the DMA engine has somewhere to put the next packet).
This was far too slow and resulted in dropped packets and processing packets every ~1ms.
I modified stm32f7xx_hal_hcd.c (else if(hhcd->hc[ch_num].ep_type == EP_TYPE_ISOC) section in HCD_HC_IN_IRQHandler() to call a user function (to calculate the next buffer address) then called USBH_IsocReceiveData in the ISR.
I found I needed to call HAL_HCD_HC_NotifyURBChange_Callback in the ISR about every millisecond to keep the USB stack happy.
With isochronous video data I was always getting a 12 byte header. If that was the only data I got I ignored it and provided the same (8 byte aligned) address. When I got more data I marked the buffer as 'full' and calculated the next 8 byte aligned address (for the USB DMA engine to DMA the data to).
Hopefully this makes sense.