cancel
Showing results for 
Search instead for 
Did you mean: 

What is the means to reset just the internal USB OTG PHY of the STM32?

RhSilicon
Lead

Hi,

I noticed that there are debug messages advising to disconnect the device from the USB port.

  • 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.
  • It has also happened that the USB device does not respond after resetting the STM32F407VGT6.

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.

  • Apparently the USB device is reset when the STM32 is reprogrammed via STlink. I noticed this because I added keyboard LED activation routines, and the LEDs go off when reprogramming the STM32, in this case I didn't use power manager, the keyboard was always powered with 5V, so it wasn't a power reset.
  • (When I did the keyboard reset test via Linux PC, using usbreset cmd line, the keyboard LEDs didn't go out)
  • Perhaps as a starting point for researching what happens to the device when the STM32 is reprogrammed via STlink, I will try to monitor the USB port data lines with logic analyzer.

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?

  • What would be the way to accomplish this, would you have to de-initialize PHY, stop the PHY clock, and then change the CSR registers?

Please USBH.png

1 ACCEPTED SOLUTION

Accepted Solutions

> 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

View solution in original post

3 REPLIES 3

> 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

Pavel A.
Evangelist III

@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.

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