2025-07-22 6:29 AM - edited 2025-07-22 7:26 AM
I have been testing the USBPD firmware examples SNK1M1_Sink and DRP1M1_DRP (the board is the NUCLEO-G474RE). When a PD source is connected to the board running either example and then the board is reset, it will then renegotiate the contract with the source.
I have my own project (STM32G0B1RE) with two ports, a UFP (sink) and a DRP (sink/source). When I connect a source to either port and then reset the board, it doesn't renegotiate the contract like the firmware examples. I need to get this behaviour so that the board will behave correctly if it has to reset.
Can anyone help me to work out why? I have tried resetting the board with the debugger attached, and confirmed that USBPD_DPM_UserCableDetection() gets called with State=USBPD_CAD_EVENT_ATTACHED on the connected port after reset (so the source is detected).
For now I am focussing only on the UFP, so please ignore any DRP/tcpp03 code below.
Here are the parts that I've changed from the defaults. Please let me know if you need any other code.
Code: https://pastebin.com/cyBgLdFK
Thanks in advance,
Richard
2025-07-23 8:34 AM
I managed to capture a renegotiation after the MCU was reset with the SNK1M1_Sink project (sometimes STM32CubeMon-UCPD disconnects after a board reset...). It appears that the protocol engine is sending a hard reset after a tTypeCSinkWaitCap timeout (that is, no source capabilities were received in time).
I am working on getting a capture for my board to see what's different.
2025-07-23 8:51 AM - edited 2025-07-23 8:54 AM
And this is the capture for my board when it is reset with a 20V/3A contract already negotiated (same setup as with the SNK1M1_Sink project above). The protocol engine doesn't seem to time out and send the Hard Reset like in the other project. Does anyone know why the protocol engine might fail to send a Hard Reset in this situation? (Spec 8.3.3.3.3: "When the SinkWaitCapTimer times out, the will perform a Hard Reset").
When it is powered up without a pre-existing contract (when the USB C cable is removed and reattached), the power supply sends the capabilities when it should and everything works:
Edit: I am seeing the same behaviour with multiple PD sources by the way. These captures were made with an Apple 60W power supply.
2025-07-23 9:55 AM - edited 2025-07-23 10:06 AM
I solved it. I think it's a CubeMX bug.
In the SNK1M1_Sink and DRP1M1_DRP examples, USBPD_DPM_TimerCounter() is called in SysTick_Handler(). On my board, I'm using CMSIS V2 and STM32CubeMX didn't generate this code. Instead, my SysTick_Handler() is provided by cmsis_os2.c and doesn't call USBPD_DPM_TimerCounter() at any time (nor is it called by any other function, I searched the whole project).
After HAL_TIM_PeriodElapsedCallback as below, I get the correct behaviour (TIM16 is my HAL timebase source).
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM16)
{
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
// Modify to use your system timebase source, as found in CubeMX -> SYS -> Timebase Source
if (htim->Instance == TIM16)
{
USBPD_DPM_TimerCounter();
}
/* USER CODE END Callback 1 */
}
Edit: This seems to be a known problem: https://wiki.st.com/stm32mcu/wiki/Introduction_to_USB_Power_Delivery_with_STM32#Why_is_the_PD_message_not_sent_by_the_stack--
2025-07-27 6:02 AM
Unless you are running PPS or your Rd releases a SRC won't notice that your SNK has reset. That's not abnormal. If SRC was providing 20V it's going to keep doing that.
First thing I do as a SNK after a connection is send reset if the voltage is greater than VSafe5V. Also, SNK sends reset if no SrcCaps received in x seconds.