2023-06-17 07:50 AM
Hi,
I noticed that there are debug messages advising to disconnect the device from the USB port.
I've tried de-initializing and initializing the USBH via the HALL functions, and it seems to have helped to get it working again, but it didn't completely resolve it. Completely resetting the STM32 using the "NVIC_SystemReset()" command re-established communication most of the time.
I thought of programmatically resetting the value of all CSR registers (Core global control and status registers - Ref.: RM0090). Could this work as a reset of the OTG PHY module?
Solved! Go to Solution.
2023-06-18 11:41 AM - edited 2023-06-18 11:41 AM
> But it has happened to me that the USB port remains stuck even after removing the device (keyboard) and reconnecting. I had to reset the MCU in this case.
Why do you think this has anything to do with the PHY?
Most probably that's a bug in the USBH software. Debug it as usually - develop understanding of how does it work, and then find out at which step does it fail to enumerate the device.
> I've tried de-initializing and initializing the USBH via the HALL function
Did you check what do those functions actually do? Did you reset the OTG module using its respective reset bit in RCC?
JW
2023-06-18 11:41 AM - edited 2023-06-18 11:41 AM
> But it has happened to me that the USB port remains stuck even after removing the device (keyboard) and reconnecting. I had to reset the MCU in this case.
Why do you think this has anything to do with the PHY?
Most probably that's a bug in the USBH software. Debug it as usually - develop understanding of how does it work, and then find out at which step does it fail to enumerate the device.
> I've tried de-initializing and initializing the USBH via the HALL function
Did you check what do those functions actually do? Did you reset the OTG module using its respective reset bit in RCC?
JW
2023-06-19 01:53 AM
@RhSilicon When you do USB device reset remotely (ex. with this usbreset utility), the host signals the reset to the device. This requires that the device side USB controller is alive and functioning, that's, the firmware is at least partially working.
2023-06-19 04:51 PM - edited 2023-06-20 05:44 PM
Oddly DeInit doesn't seem to DeInitialize completely, this does not use the USBH_LL_DeInit function:
/**
* @brief HCD_Init
* De-Initialize the Host portion of the driver.
* phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
{
(void)DeInitStateMachine(phost);
/* Restore default Device connection states */
phost->device.PortEnabled = 0U;
phost->device.is_connected = 0U;
phost->device.is_disconnected = 0U;
phost->device.is_ReEnumerated = 0U;
phost->device.RstCnt = 0U;
phost->device.EnumCnt = 0U;
if (phost->pData != NULL)
{
(void)USBH_LL_Stop(phost);
}
#if (USBH_USE_OS == 1U)
#if (osCMSIS < 0x20000U)
/* Free allocated resource for USBH process */
(void)osThreadTerminate(phost->thread);
(void)osMessageDelete(phost->os_event);
#else
/* Free allocated resource for USBH process */
(void)osThreadTerminate(phost->thread);
(void)osMessageQueueDelete(phost->os_event);
#endif /* (osCMSIS < 0x20000U) */
#endif /* (USBH_USE_OS == 1U) */
return USBH_OK;
}
I modified the way of managing timeout and port reset as well, it was a bit better.
But with the reset commands via RCC the USB module seems to have managed to recover every time it crashed, I hope I'm not celebrating too soon.
UART output:
App start
MCU-ID 10076413
USB Device Connected
USB Device Reset Completed
Recovering USB module
USB Device Connected
USB Device Reset Completed
Recovering USB module
USB Device Connected
USB Device Reset Completed
PID: 318h
VID: 513h
Address (#1) assigned.
Manufacturer : N/A
Product : N/A
Serial Number : N/A
Enumeration done.
This device has only 1 configuration.
Default configuration set.
Device remote wakeup enabled
USBH_HID_InterfaceInit
Switching to Interface (#0)
Class : 3h
SubClass : 1h
Protocol : 1h
KeyBoard device found!
max_ep: 1
Interface 0, endpoint #0: address 0x81, attributes 0x03
Switching to Interface (#1)
Class : 3h
SubClass : 1h
Protocol : 2h
Mouse device found!
max_ep: 1
Interface 1, endpoint #0: address 0x82, attributes 0x03
Switching to Interface (#0)
HID class started.
File usbh_core.h:
/**
* @brief HCD_DeInit
* De-Initialize the Host portion of the driver.
* phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost) {
(void) DeInitStateMachine(phost);
/* Restore default Device connection states */
phost->device.PortEnabled = 0U;
phost->device.is_connected = 0U;
phost->device.is_disconnected = 0U;
phost->device.is_ReEnumerated = 0U;
phost->device.RstCnt = 0U;
phost->device.EnumCnt = 0U;
if (phost->pData != NULL) {
(void) USBH_LL_Stop(phost);
(void) USBH_LL_DeInit(phost);
}
#if (USBH_USE_OS == 1U)
#if (osCMSIS < 0x20000U)
/* Free allocated resource for USBH process */
(void)osThreadTerminate(phost->thread);
(void)osMessageDelete(phost->os_event);
#else
/* Free allocated resource for USBH process */
(void)osThreadTerminate(phost->thread);
(void)osMessageQueueDelete(phost->os_event);
#endif /* (osCMSIS < 0x20000U) */
#endif /* (USBH_USE_OS == 1U) */
#ifdef HOST_HS
if (phost->id == HOST_HS) {
// stm32f4xx_hal_rcc_ex.h
__HAL_RCC_USB_OTG_HS_FORCE_RESET();
__HAL_RCC_USB_OTG_HS_RELEASE_RESET();
}
#endif
#ifdef HOST_FS
if (phost->id == HOST_FS) {
// stm32f4xx_hal_rcc_ex.h
__HAL_RCC_USB_OTG_FS_FORCE_RESET();
__HAL_RCC_USB_OTG_FS_RELEASE_RESET();
}
#endif
return USBH_OK;
}
void USBH_RecoveryPhost(USBH_HandleTypeDef *phost) {
USBH_UsrLog("Recovering USB module");
USBH_HandleTypeDef phost_bkp;
phost_bkp.id = phost->id;
phost_bkp.pUser = phost->pUser;
phost_bkp.ClassNumber = phost->ClassNumber;
for (uint8_t i = 0; i < phost->ClassNumber; i++) {
phost_bkp.pClass[i] = phost->pClass[i];
}
(void) USBH_Stop(phost);
(void) USBH_DeInit(phost);
(void) USBH_Init(phost, phost_bkp.pUser, phost_bkp.id);
for (uint8_t i = 0; i < phost_bkp.ClassNumber; i++) {
(void) USBH_RegisterClass(phost, phost_bkp.pClass[i]);
}
(void) USBH_Start(phost);
}
/**
* @brief USBH_Process
* Background process of the USB Core.
* phost: Host Handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) {
__IO USBH_StatusTypeDef status = USBH_FAIL;
uint8_t idx = 0U;
/* check for Host pending port disconnect event */
if (phost->device.is_disconnected == 1U) {
phost->gState = HOST_DEV_DISCONNECTED;
}
switch (phost->gState) {
case HOST_IDLE:
if ((phost->device.is_connected) != 0U) {
if (phost->resetPortPhase == 0U) {
USBH_UsrLog("\nUSB Device Connected");
phost->resetPortTimer = USBH_GetTick();
phost->resetPortPhase = 1U;
} else if (phost->resetPortPhase == 1U) {
/* Wait for 275 ms after connection */
/* https://www.usbmadesimple.co.uk/ums_5.htm */
if ((USBH_GetTick() - phost->resetPortTimer) > 275U) {
phost->resetPortPhase = 2U;
}
} else if (phost->resetPortPhase == 2U) {
/* RESET 31 ms */
(void) USBH_LL_ResetPort_Start(phost);
phost->resetPortTimer = USBH_GetTick();
phost->resetPortPhase = 3U;
} else if (phost->resetPortPhase == 3U) {
/* RESET 31 ms */
if ((USBH_GetTick() - phost->resetPortTimer) > 15U) {
(void) USBH_LL_ResetPort_End(phost);
phost->resetPortTimer = USBH_GetTick();
phost->resetPortPhase = 4U;
}
} else if (phost->resetPortPhase == 4U) {
if ((USBH_GetTick() - phost->resetPortTimer) > 10U) {
phost->resetPortPhase = 5U;
}
} else if (phost->resetPortPhase == 5U) {
phost->resetPortPhase = 0U;
phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT;
/* Make sure to start with Default address */
phost->device.address = USBH_ADDRESS_DEFAULT;
phost->Timeout = USBH_GetTick(); //0U;
case HOST_DEV_DISCONNECTED:
phost->device.is_disconnected = 0U;
(void) DeInitStateMachine(phost);
/* Re-Initilaize Host for new Enumeration */
if (phost->pActiveClass != NULL) {
phost->pActiveClass->DeInit(phost);
phost->pActiveClass = NULL;
}
if (phost->pUser != NULL) {
phost->pUser(phost, HOST_USER_DISCONNECTION);
}
USBH_UsrLog("USB Device disconnected");
if (phost->device.is_ReEnumerated == 1U) {
phost->device.is_ReEnumerated = 0U;
/* Start the host and re-enable Vbus */
(void) USBH_Start(phost);
} else {
/* Device Disconnection Completed, start USB Driver */
(void) USBH_LL_Start(phost);
}
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_PORT_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, 0U);
#endif
#endif
break;
case HOST_ABORT_STATE:
USBH_RecoveryPhost(phost);
break;
default:
break;
}
return USBH_OK;
}
If anyone needs it, better navigate through the IDE to see the changes, I also managed to get two HID interfaces recognized (with the help of another example project that implements USB HUB), to operate with the (built-in Touchpad) Keyboard, and to control the keyboard LEDs (still need to finish Touchpad decoding part):
https://github.com/rtek1000/STM32F4HUB_modified/tree/main/Project-STM32CubeIDE_USBH_ASC