cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L475 USB host w/ memory stick doesn't work first insert

JGerb
Associate III

I'm using an STM32L475RC with USB host and using FAT FS to read a memory stick. This worked fine in previous hardware build, but since new hardware and update of CubeMX (now at MCU pkg 1.17.2) and updated USB host, an odd bug has appeared. When I run the init, the first attempt always fails. Init is only ever run when a USB stick is detected in the socket, to save power. There is a fair bit of other code involved, but this is the basics:

 

/* Init host Library, add supported class and start the library. */
MX_USB_HOST_Init();
 
PRINTDBG("Host stack init, waiting for USB stick",PRINT_NOTIME);
gTimeTick = 0;
while ((USBH_MSC_IsReady(&hUsbHostFS) == 0) && (gTimeTick < USB_STICK_TIMEOUT))
{
     /* USB Host Background task */
     USBH_Process(&hUsbHostFS);
}
//Not shown - do USB stuff if no timeout
//Shutdown
PRINTDBG("Shutting down USB stack",PRINT_TIMESTAMP);
//stop the USB
USBH_Stop(&hUsbHostFS);
/* De-Init */
USBH_DeInit(&hUsbHostFS);
 
On first insert after a micro reset/power up, it always fails, but on subsequent inserts it works fine. I can work around it by always calling init and then de-init, and then on second init it is fine. Anyone have any idea what is going on? I took a snapshop of the registers on the first and second run, with first run being the connect fail, and 2nd run the connect success. I would prefer not to have to use the workaround, and rather understand what is going on.
 
10 REPLIES 10

In "connect fail" picture, GRSTCTL.CSRST=1, i.e. the module is "hanging" in reset, maybe due to missing PHY (48MHz) clock.

JW


@JGerb wrote:

... new hardware and update of CubeMX (now at MCU pkg 1.17.2) and updated USB host ...


That's a lot of things to change all at once!

Can you go back and update just one thing at a time?

I guess I wasn't expecting it to not work. Eclipse and I are not friends, and the last time I did this it took a week out of my project timelines with fault finding and head scratching. I guess I could try create a new project and start from scratch with a simplistic build, but odds are it will not replicate.

Thanks, that would make sense, it's a good tip. I switch to 48MHz MSI clock just before init'ing the stack and drop back to 4MHz once done. But it seems the clock switch always works ok. I have even tried adding a 1s delay after clock switch and before calling the init, but it makes no difference. It seems to need the following code before calling MX_USB_HOST_Init(), because this was in the older product's code too:

//restore this bit
PWR->CR2 |= PWR_CR2_USV;
//restore the clock
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
//and to ensure it's fully reset, we perform a reset of the OTG
SET_BIT(RCC->AHB2RSTR, RCC_AHB2RSTR_OTGFSRST);
asm("nop");
asm("nop");
CLEAR_BIT(RCC->AHB2RSTR, RCC_AHB2RSTR_OTGFSRST);
//make sure MSI is selected as USB clock
MODIFY_REG(RCC->CCIPR, RCC_CCIPR_CLK48SEL_Msk, RCC_CCIPR_CLK48SEL_0 | RCC_CCIPR_CLK48SEL_1);

 

I do the clock switch before this code usually, though I have tried it after too. Always the first insert fails, subsequent ones succeed.

 

Try to single-step the whole sequence up to the point where GRSTCTL.CSRST is set (it has to auto-clear), while observing the registers written and related registers, whether their content matches expectations; perhaps comparing them to the "working" case.

JW

STM32CubeIDE doesn't show the OTG registers in the SFR box, I had to add an expression after careful searching in the code.

So on the first call, it seems the CSRST bit is set during USBH_Init(). Diving deeper into USBH_Init I see both CSRST and AHDIDL are being set by USBH_LL_Init(phost). Stepping further into that, we get to HAL_HCD_Init(), and into that, we get to (HAL_HCD_MspInit(hhcd) - which sets the AHBIDL and) USB_CoreInit() which sets CSRST.

Digging into USB_CoreInit, I get to:

ret = USB_CoreReset(USBx); 

Digging into USB_CoreReset, which is in stm32l4xx_ll_usb.c, I get to the following code:

static HAL_StatusTypeDef USB_CoreReset(USB_OTG_GlobalTypeDef *USBx)
{
  __IO uint32_t count = 0U;

  /* Wait for AHB master IDLE state. */
  do
  {
    count++;
    if (count > 200000U)
    {
      return HAL_TIMEOUT;
    }
  } while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);

  /* Core Soft Reset */
  count = 0U;
  USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST;

  do
  {
    count++;
    if (count > 200000U)
    {
      return HAL_TIMEOUT;
    }
  } while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST);
  return HAL_OK;
}

It is timing out on the last statement, the core soft reset, as one would expect. I tried increasing the count to 400000U with no effect. When it is run again on a second attempt, it goes through this routine with no problems.

I checked the clock tree out - I am using the MSI as system clock, either on 4MHz (when idle) or 48MHz (doing USB). I am using MSIPLLEN = 1 to lock the PLL onto my 32khz LSE for improved accuracy.

I struggled to see any difference between the 2 states, other than the CSRST bit, but not knowing USB that well, I don't know what to look for. I also tried USB_CoreReset code before the init code, in case a double reset would fix it, but no luck.

As I've said, this is usually symptom of missing 48MHz PHY clock.

> I don't know what to look for.

You are looking for differences between working and non-working state. A minimal set of registers to look at would include OTG_PCGCCTL, RCC_AHB2ENR.OTGFSEN, RCC_CCIPR.CLK48SEL, and whatever RCC registers are involved in generating the 48MHz clock itself.

JW

It cannot be missing the 48MHz clock, as I am using the MSI, and also am running the micro on the same clock (SW =0 in RCC_CFGR).

 

I cannot access OTG_PCGCCTL as the debugger will not show it, even when I add the expression USBx_PCGCCTL (as copied from stm32l4xx_ll_usb.c) into the window. However, this register is only referenced (as far as i can see from the code) in device mode, and I am in host mode, so I presume you meant some other register.

 

I've attached the expression window for the "fail" condition, but the only difference between fail and success is again USB_OTG_FS->GRSTCTL bit 0 (CSRST).

JGerb_0-1706257090002.png

I have reviewed the clock bits before and after on both fail and success conditions, and they are both correct and unchanged. My impression is that this is more likely to be a USB variables issue inside the stack. If this is the only bug in the USB stack this time, I can live with that. On older versions of the stack some editing of the stack code was required, this version simply needs to be run a 2nd time to work. I can even do the first run after reset during my init code, and it works ok. Here's what I do after detecting a memory stick now:

 

//restore this bit
	PWR->CR2 |= PWR_CR2_USV;
	//restore the clock
	RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
	//and to ensure it's fully released the pins, we perform a reset of the OTG
	SET_BIT(RCC->AHB2RSTR, RCC_AHB2RSTR_OTGFSRST);
	asm("nop");
	asm("nop");
	CLEAR_BIT(RCC->AHB2RSTR, RCC_AHB2RSTR_OTGFSRST);
	//make sure MSI is selected as USB clock
	MODIFY_REG(RCC->CCIPR, RCC_CCIPR_CLK48SEL_Msk, RCC_CCIPR_CLK48SEL_0 | RCC_CCIPR_CLK48SEL_1);
	//power to the USB is enabled by the stack
	//disable pullups on GPIOA 11 and 12 (DM and DP)
	CLEAR_BIT(GPIOA->PUPDR, GPIO_PUPDR_PUPD11_Msk | GPIO_PUPDR_PUPD12_Msk);
	//set GPIOA 11 and 12 back as alternate function inputs
	SET_BIT(GPIOA->MODER, GPIO_MODER_MODE11_Msk | GPIO_MODER_MODE12_Msk);
	PRINTDBG("Initialising USB host stack",PRINT_NOTIME);
	//SET_BIT(USB_OTG_FS->GAHBCFG, USB_OTG_GAHBCFG_GINT);
	//SET_BIT(USB_OTG_FS->GOTGCTL,USB_OTG_GOTGCTL_VBVALOVAL | USB_OTG_GOTGCTL_AVALOEN);
	//msDelay(1000);
	//seems to need this extra run, otherwise stick only works on 2nd insert
	MX_USB_HOST_Init();
	//stop the USB
	USBH_Stop(&hUsbHostFS);
	/* De-Init */
	USBH_DeInit(&hUsbHostFS);
	
	/* Init host Library, add supported class and start the library. */
	MX_USB_HOST_Init();

	PRINTDBG("Host stack init, waiting for USB stick",PRINT_NOTIME);
	gTimeTick = 0;
	while ((USBH_MSC_IsReady(&hUsbHostFS) == 0) && (gTimeTick < USB_STICK_TIMEOUT))
	{
		/* USB Host Background task */
		USBH_Process(&hUsbHostFS);
		//check if main regulator has dipped or vbatt is too low
		//grab the battery voltage
		baseBoardReadWrite(BASE_IDX_BATT_SENSE, ADC_OVRSMP_16X, false);
		if ((extPowerOk == false) && (adcData[BASE_IDX_BATT_SENSE].resultf < USB_MIN_RUN_VOLTAGE))
		{
			gTimeTick = USB_STICK_TIMEOUT; //force an early abort
		}
	}

 

 

 

 

The 48MHz clock may be on and running, but there may be gates between RCC and the PHY which would stop it to reach PHY. Also, there may be some other reason why the core reset won't self-clear, but my experience is that it's usually the PHY clock missing.

I am not ST and I was suffering from the chaos surrounding the Synopsys IP, contributed both from Synopsys and ST, although on 'F4 rather than 'L4, and the details may/do differ. So, not knowing where to look, I recommend to look everywhere. If the debugger does not have a symbol built in, you usually can read given register simply as some memory area. And, at the end of the day, you can also read it from program. I mentioned OTG_PCGCCTL  because it appears to be related to clocks AND low-power modes (although the descriptions are far from being clear), and that's what you appear to be pursuing, too.

Of course, gates may also be hidden from user; but that is supposedly the task of the resets to settle them into an initial state.

As the next step, apparently, the core reset (CSRST) gets cleared at one point, as you report "next attempt working". So, you may want to find out, where exactly does that happen.

JW