cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G0 USB-PD Source stack periodically sends hard resets when compiler optimizations are enabled.

NathanWolcott
Associate III

I'm using a Cube IDE generated project (latest version) with the latest version of the G0 SDK. This problem originally showed up on a custom board but I have reproduced the problem using a Nucleo-G071RB dev board wired up to a USB-C breakout jack with voltage divider to sample VBus and a mosfet to switch VBus.

The system runs fine when compiled at -O0. The Source port establishes a contract with a Sink device and stays connected indefinitely. However, as soon as any level of optimizations are turned on (even just -Og) the stack will start sending hard resets to a connected Sink roughly every 15 seconds. Sometimes this only happens 1 or 2 times after the initial contract is established, sometimes it repeats for several minutes and then stops, sometimes it repeats forever.

I can set a breakpoint to stop when the reset message is sent but the hard reset signal call chain originates inside the ST stack library code. I can't see what is causing the problem because there is no source code.

I have attached the cubeIDE project that reproduces the problem. There is 1 sink and 1 source port configured so that the project matches our custom board configuration. Only the source port is actually connected to a physical USB connector. The tracer is redirected to a custom serial print log system because that is what we use on the custom board.

How can I fix this? I can't just turn off optimizations because the code for the custom boards gets too big to fit in the flash.

1 ACCEPTED SOLUTION

Accepted Solutions
Yohann M.
ST Employee

Dear @NathanWolcott​ 

Thanks to do the effort to provide us the log...

HardReset is sent by our stack due to expiration of PPS timeout used to check that port partner sends regularly a request message.

This timer is set to 14s:

#define PE_TPPSTIMEOUT                   14000u /*!< tPPSTimeout: min 12s to max 15s                           */

But the contract has not been negotiated in PPS.

Actually, this timer is started from our side due to the 'PtrPowerObject' variable returned by the function:

USBPD_StatusTypeDef USBPD_DPM_EvaluateRequest(uint8_t PortNum, USBPD_CORE_PDO_Type_TypeDef *PtrPowerObject)
{
/* USER CODE BEGIN USBPD_DPM_EvaluateRequest */
  DPM_USER_DEBUG_TRACE(PortNum, "ADVICE: update USBPD_DPM_EvaluateRequest: %p", PtrPowerObject);
  if(PtrPowerObject != NULL)
  {
	  DPM_USER_DEBUG_TRACE(PortNum, "USBPD_DPM_EvaluateRequest: got PDO: 0x%08X", *(uint32_t *)PtrPowerObject);
	  // TODO: add PDO evaluation logic here.
	  // For now, just accept.
	  return USBPD_ACCEPT;
  }
  else
  {
	  DPM_USER_DEBUG_TRACE(PortNum, "USBPD_DPM_EvaluateRequest: ERR: NULL PDO");
	  return USBPD_REJECT;
  }

In your code, you do not initialize it and unfortunately, with the optimization, this value may be equal to USBPD_CORE_PDO_TYPE_APDO whereas it must be in your case set to USBPD_CORE_PDO_TYPE_PDO.

A temporary workaround is to initialize it to:

*PtrPowerObject = USBPD_CORE_PDO_TYPE_FIXED;

Please let me know if it fixes your issue!

Regards

Yohann

View solution in original post

7 REPLIES 7
Yohann M.
ST Employee

Dear @NathanWolcott​ 

Could you please enable your debug trace in your environment?

Please refer to the following wiki page.

For Nucleo-G071RB, you have to

  • enable the USART2 IP (pin PA2 & PA3) and activate the DMA channels for UART_TX and UART_RX (already done in your project)
  • enable TRACER_EMB module in Utilities panel in selecting USART2
  • Check 'Tracer Source (TRACER_EMB) in your Middleware->USBPD panel

Normally you should be able to evacuate trace in STM32CubeMonUCPD.

When you reproduced the issue, close STM32CubeMonUCPD and please provide the .cpd file available in your "c:\Users\%username%\AppData\Local\Temp\STM32CubeMonitor-UCPD\Acquisition" folder.

In the other hand, can you try to keep -O0 only for '\Middlewares\ST\STM32_USBPD_Library\Devices' and keep the rest of the project with your optimization?

Regards,

Yohann

NathanWolcott
Associate III

Good morning @Yohann M.​ ,

Sorry but I forgot to attach my log printout to the original question. As I mentioned earlier, I currently have the project configured to use my custom printf subsystem and have redirected all of the various Trace macros within the PD source code to point to it. This is necessary on the custom board because the ST debug trace interferes with the serial port which we are using for other things. It can be shared with log prints but the trace control cannot have full control of the port. I kept this configuration on the dev board test project so that the configuration was as similar as possible to the custom board. However, now that I have reproduced the problem, that configuration is no longer necessary.

I will try to switch everything back and activate the ST debug trace driver later this afternoon and will upload the cpd file as soon as possible.

For the moment, I have attached the log file output from yesterday's run.

I don't know how to configure different optimization settings for each resource. Is that possible from inside CubeIDE? What is the procedure?

Thanks,

Nathan

NathanWolcott
Associate III

Good afternoon @Yohann M.​ ,

I think I have a capture for you.

It took a lot of tinkering to make it work. No offence intended, but the ST Trace module is fragile and difficult to work with.

After enabling the module, regenerating the code, and disabling my custom print module, the tracer would only print a single log entry and then never output anything again. I put a breakpoint in the tracer code and found that the call to TRACER_EMB_AllocateBufer was failing. Eventually, I found that this was because the USART wasn't sending the data and so the buffer was full. After tinkering with the USART settings for quite a while, I eventually discovered that I had to switch the USART driver to LL mode instead of HAL in the project manager settings in CUBE and then it magically started working. This is not documented and was not included in your instructions. Anyway, enough of my rant about the Tracer Module.

After getting the tracer working, at first I was not able to reproduce the issue. I set the project to -Og optimizations but the PD contract stayed up and running. Eventually, I set -O1 and got it to fail once after several different runs. That is the cpd file I have attached.

As you can see, the stack sends a hard reset to the attached sink after the link has been up for around 14 seconds.

Just be aware that when running without the ST Trace EMB, this failure repeats periodically at any optimization level other than -O0. I couldn't see any additional information in the text output of the trace beyond what I was already seeing with my custom print module. It just looks like the stack decides to send a hard reset after being connected for around 15 seconds.

I haven't tested the suggestion to set different compile optimizations for the driver code vs the application code yet.

NathanWolcott
Associate III

After cleaning the project and rebuilding with -Og optimizations, I was able the reproduce the issue again.

Here is the cpd file.

Also, while adjusting the settings for this run I realized that the first capture file from my previous post was captured with -Os and not -O1.

Yohann M.
ST Employee

Dear @NathanWolcott​ 

Thanks to do the effort to provide us the log...

HardReset is sent by our stack due to expiration of PPS timeout used to check that port partner sends regularly a request message.

This timer is set to 14s:

#define PE_TPPSTIMEOUT                   14000u /*!< tPPSTimeout: min 12s to max 15s                           */

But the contract has not been negotiated in PPS.

Actually, this timer is started from our side due to the 'PtrPowerObject' variable returned by the function:

USBPD_StatusTypeDef USBPD_DPM_EvaluateRequest(uint8_t PortNum, USBPD_CORE_PDO_Type_TypeDef *PtrPowerObject)
{
/* USER CODE BEGIN USBPD_DPM_EvaluateRequest */
  DPM_USER_DEBUG_TRACE(PortNum, "ADVICE: update USBPD_DPM_EvaluateRequest: %p", PtrPowerObject);
  if(PtrPowerObject != NULL)
  {
	  DPM_USER_DEBUG_TRACE(PortNum, "USBPD_DPM_EvaluateRequest: got PDO: 0x%08X", *(uint32_t *)PtrPowerObject);
	  // TODO: add PDO evaluation logic here.
	  // For now, just accept.
	  return USBPD_ACCEPT;
  }
  else
  {
	  DPM_USER_DEBUG_TRACE(PortNum, "USBPD_DPM_EvaluateRequest: ERR: NULL PDO");
	  return USBPD_REJECT;
  }

In your code, you do not initialize it and unfortunately, with the optimization, this value may be equal to USBPD_CORE_PDO_TYPE_APDO whereas it must be in your case set to USBPD_CORE_PDO_TYPE_PDO.

A temporary workaround is to initialize it to:

*PtrPowerObject = USBPD_CORE_PDO_TYPE_FIXED;

Please let me know if it fixes your issue!

Regards

Yohann

Good afternoon @Yohann M.​ ,

I'm happy to confirm that this fixed the problem.

I would like to point out that the documentation never mentioned that I was supposed to assign a value to that variable. The documentation for that function just says that it should return Accept, Reject, Wait, or GotoMin. The functions comments list that parameter as "Pointer on the power data object". I thought that it was just a pointer to the requested PDO, so the code could take a look at it and accept or reject.

Is there an updated document (I'm using UM2552 and UM2785) that includes this information?

Are there other functions with undocumented requirements waiting to cause problems in the future?

Thanks for your help.

Nathan

Thanks for your remark. We will take it in considerations and will update documentation accordingly and also update the function in cubeMX to highlight this point.

Regards

Yohann