Skip to main content
Visitor II
March 19, 2021
Solved

STM32G071 hardfault in USBPD middleware when configured with 1 source and 1 sink port

  • March 19, 2021
  • 3 replies
  • 4081 views

I'm trying to get the USBPD middleware running with 2 ports: 1 source and 1 sink. I already followed the tutorial to get 1 port working as a sink. When I add the second port as a source, the chip immediately hits a hardfault after starting. I traced it back and the problem is on line 1013 of usbpd_cad_hw_if.c, where _handle->CAD_PtrStateMachine(PortNum, pEvent, pCCXX) is run. The problem is that for some reason, _handle->CAD_PtrStateMachine is never initialized and is actually a NULL pointer. Naturally, this hardfaults immediately.

The problem with the init seems to be around line 296 to 358. There are a number of #if defined (***) macros that control which functions are assigned to _handle->CAD_PtrStateMachine depending on whether _SNK, _SRC, or _DRP are defined in the project. It looks like CubeMx is defining _DRP when one of the ports is a sink and the other is a source even though neither port is actually configured for dual role. This activates the code path at line 298 but then, since neither port is actually dual role, the it fails the check on 299 and so CAD_PtrStateMachine is never set.

After the init finishes, a cable detech event is fired for both ports, which eventually causes _handle->CAD_PtrStateMachine() to be executed unconditionally.

I've pasted the snippet from usbpd_cad_hw_if.c below (note that the line numbers won't match).

Yes, it works just fine with both ports configured as sinks.

I'm using firmware V1.4.1 and CubeIDE 1.6 (although the same problem exists in CubeIDE 1.5).

 /* Set the state machine according the SW configuration */
#if !defined(USBPDCORE_LIB_NO_PD)
#if defined(_DRP)
 if (Ports[PortNum].settings->CAD_RoleToggle == USBPD_TRUE)
 {
 _handle->CAD_PtrStateMachine = CAD_StateMachine_DRP;
 _handle->CAD_Accessory_SRC = Ports[PortNum].settings->CAD_AccesorySupport;
#if defined(USBPDCORE_VPD)
 _handle->CAD_VPD_SRC = Ports[PortNum].settings->CAD_VPDSupport;
#endif /* USBPDCORE_VPD */
 }
 else
#endif /* !USBPDCORE_LIB_NO_PD */
 {
#if defined(_SRC)
 if (USBPD_PORTPOWERROLE_SRC == Ports[PortNum].settings->PE_DefaultRole)
 {
 _handle->CAD_PtrStateMachine = CAD_StateMachine_SRC;
 _handle->CAD_Accessory_SRC = Ports[PortNum].settings->CAD_AccesorySupport;
#if defined(USBPDCORE_VPD)
 _handle->CAD_VPD_SRC = Ports[PortNum].settings->CAD_VPDSupport;
#endif /* USBPDCORE_VPD */
 }
 else
#endif /* _SRC */
 {
#if defined(_SNK)
 _handle->CAD_PtrStateMachine = CAD_StateMachine_SNK;
 _handle->CAD_Accessory_SNK = Ports[PortNum].settings->CAD_AccesorySupport;
#if defined(USBPDCORE_VPD)
 _handle->CAD_VPD_SNK = Ports[PortNum].settings->VPDSupport;
#endif /* USBPDCORE_VPD */
#endif /* _SNK */
 }
 }
#else /* USBPDCORE_LIB_NO_PD */
#if defined(USBPD_TYPE_STATE_MACHINE)
#if defined(_SRC)
 if (USBPD_PORTPOWERROLE_SRC == Ports[PortNum].settings->PE_DefaultRole)
 {
 _handle->CAD_PtrStateMachine = CAD_StateMachine_SRC;
#if !defined(USBPDCORE_LIB_NO_PD)
 _handle->CAD_Accessory_SRC = Ports[PortNum].settings->CAD_AccesorySupport;
#endif /* !USBPDCORE_LIB_NO_PD */
#if defined(USBPDCORE_VPD)
 _handle->CAD_VPD_SRC = Ports[PortNum].settings->CAD_VPDSupport;
#endif /* USBPDCORE_VPD */
 }
 else
#endif /* _SRC */
 {
#if defined(_SNK)
 _handle->CAD_PtrStateMachine = CAD_StateMachine_SNK;
#if !defined(USBPDCORE_LIB_NO_PD)
 _handle->CAD_Accessory_SNK = Ports[PortNum].settings->CAD_AccesorySupport;
#endif /* !USBPDCORE_LIB_NO_PD */
#if defined(USBPDCORE_VPD)
 _handle->CAD_VPD_SNK = Ports[PortNum].settings->CAD_VPDSupport;
#endif /* USBPDCORE_VPD */
#endif /* _SNK */
 }
#endif /* USBPD_TYPE_STATE_MACHINE */
#endif /* USBPDCORE_LIB_NO_PD */

    This topic has been closed for replies.
    Best answer by Yohann M.

    Hi @NathanWolcott​ 

    I reproduced your setup and I confirm the same problem.

    Unfortunately, we should enable also _DRP switch with _SRC and _SNK switches. In case of _DRP is not enabled, in your configuration, ANAMODE is set to 1 in both configuration linked to this code:

    void CAD_Init(uint8_t PortNum, USBPD_SettingsTypeDef *pSettings, USBPD_ParamsTypeDef *pParams, void (*WakeUp)(void))
    {
    (...)
    #if defined(_SRC) || defined(_DRP)
     /* Initialize usbpd interrupt */
     if (USBPD_PORTPOWERROLE_SRC == Ports[PortNum].params->PE_PowerRole)
     {
     USBPDM1_AssertRp(PortNum);
     }
    #endif /* _SRC || _DRP */
    #if defined(_DRP)
     else
    #endif /* _DRP */
    #if defined(_SNK) || defined(_DRP)
     {
     USBPDM1_AssertRd(PortNum);
     }
    #endif /* _SNK || _DRP */

    Apologize again regarding this constraint :(

    In meanwhile, if you want a reference to source application, we have the following one (based on STM32G081B-EVAL board in STM32CubeG0 package):

    https://github.com/STMicroelectronics/STM32CubeG0/tree/master/Projects/STM32G081B-EVAL/Applications/USB-PD/USB-PD_Provider_1port

    There are no STM32CubeMx application for dual role but demonstration of STM32G081B-EVAL board shows this configuration on port_1 DRP:

    https://github.com/STMicroelectronics/STM32CubeG0/tree/master/Projects/STM32G081B-EVAL/Demonstrations/DemoUCPD

    Regards,

    Yohann

    3 replies

    ST Employee
    March 22, 2021

    Dear @NathanWolcott​ 

    We may have an issue with code generation done by CubeMx.

    Can you try to enable _SRC and _SNK compilation switches in your STM32CubeIDE project? And remove the compilation switch _DRP.

    regards,

    Yohann

    Visitor II
    March 25, 2021

    Hi @Yohann M.​ ,

    I can't seem to get the USBPD middleware to work with both a sink and a source port enabled at the same time. While the app no longer crashes with your fix, when I test the Source functionality, it doesn't work correctly. There is still some kind of configuration error because when I check the configuration register, the port is configured as a Sink and not a Source. In my configuration, UCPD1 is a sink and UCPD2 is a source (although I have tried the other way and it doesn't change anything). If I start debugging and then halt and check the registers, UCPD2->CR->ANAMODE is set to 1 (Sink) for both ports. I tracked this problem down after noticing that both CC1 and CC2 lines on the Source port were at 0V, instead of being pulled up.

    If I configure the project for only 1 port in Source mode, it works properly, the GUI shows a power contract if I connect to another Sink, etc.

    I have also tried running the X-CUBE-TCPP project SNK1M1_Sink as you suggested and just adding a source port to the cube config and regenerating, but this fails too. In this case, the code generator isn't working correctly because the Preprocessor symbols only have _SNK defined and USBPD_PORT_COUNT=1, so the code for the second port is not generated at all.

    It doesn't look like is any support in the examples and tutorials for Source, or Dual Role mode. Has any of this stuff been tested?

    Thanks,

    Nathan

    Visitor II
    March 22, 2021

    Hi @Yohann M.​ 

    I made the change as you suggested and this appears to work. The code no longer hardfaults at startup and I am able to attach the CubeMonitorUCPD app to the board and see the trace on the sink port.

    I have not yet actually tested the source port, so I don't know if it works, but it is at least stable while running idle.

    Thanks for the help. I will add the results of the source port test once I run it.

    Yohann M.Answer
    ST Employee
    March 26, 2021

    Hi @NathanWolcott​ 

    I reproduced your setup and I confirm the same problem.

    Unfortunately, we should enable also _DRP switch with _SRC and _SNK switches. In case of _DRP is not enabled, in your configuration, ANAMODE is set to 1 in both configuration linked to this code:

    void CAD_Init(uint8_t PortNum, USBPD_SettingsTypeDef *pSettings, USBPD_ParamsTypeDef *pParams, void (*WakeUp)(void))
    {
    (...)
    #if defined(_SRC) || defined(_DRP)
     /* Initialize usbpd interrupt */
     if (USBPD_PORTPOWERROLE_SRC == Ports[PortNum].params->PE_PowerRole)
     {
     USBPDM1_AssertRp(PortNum);
     }
    #endif /* _SRC || _DRP */
    #if defined(_DRP)
     else
    #endif /* _DRP */
    #if defined(_SNK) || defined(_DRP)
     {
     USBPDM1_AssertRd(PortNum);
     }
    #endif /* _SNK || _DRP */

    Apologize again regarding this constraint :(

    In meanwhile, if you want a reference to source application, we have the following one (based on STM32G081B-EVAL board in STM32CubeG0 package):

    https://github.com/STMicroelectronics/STM32CubeG0/tree/master/Projects/STM32G081B-EVAL/Applications/USB-PD/USB-PD_Provider_1port

    There are no STM32CubeMx application for dual role but demonstration of STM32G081B-EVAL board shows this configuration on port_1 DRP:

    https://github.com/STMicroelectronics/STM32CubeG0/tree/master/Projects/STM32G081B-EVAL/Demonstrations/DemoUCPD

    Regards,

    Yohann

    Visitor II
    March 26, 2021

    Thanks for the update @Yohann M.​ .

    Unfortunately, I've run into a weird problem and haven't been able to test your fix.

    After regenerating the code, I now get a bunch of undefined reference errors when trying to compile.

    I actually started a brand new project, configured it the same as usual (1 sink and 1 source port, trace, gui, etc) and I get the same error. Does this have anything to do with importing that other project from the X-CUBE_TCPP package? I wouldn't think that would have any impact on the other projects in the workspace.

    This is the error. When I do a global search, I can't find the function definitions in the firmware repo folder at all. Very strange.

    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: Middlewares/ST/STM32_USBPD_Library/Core/src/usbpd_trace.o: in function `USBPD_TRACE_Init':
    C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../Middlewares/ST/STM32_USBPD_Library/Core/src/usbpd_trace.c:113: undefined reference to `USBPD_PE_SetTrace'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: USBPD/usbpd_dpm_core.o: in function `PE_Task':
    C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:368: undefined reference to `USBPD_PE_StateMachine_DRP'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: USBPD/usbpd_dpm_core.o: in function `USBPD_CAD_Task':
    C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:391: undefined reference to `USBPD_CAD_Process'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: USBPD/usbpd_dpm_core.o: in function `DPM_ManageAttachedState':
    C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:464: undefined reference to `USBPD_PE_IsCableConnected'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: USBPD/usbpd_dpm_core.o: in function `USBPD_DPM_CADCallback':
    C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:427: undefined reference to `USBPD_PE_IsCableConnected'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: USBPD/usbpd_dpm_core.o: in function `USBPD_DPM_InitCore':
    C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:167: undefined reference to `USBPD_PE_CheckLIB'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:175: undefined reference to `USBPD_PE_GetMemoryConsumption'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:197: undefined reference to `USBPD_CAD_Init'
    c:\st\stm32cubeide_1.6.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_1.5.0.202011040924\tools\arm-none-eabi\bin\ld.exe: C:/Users/D-Rock/STM32CubeIDE/workspace_1.6.0/stm32g071_nucleo_usbCC_test3/Debug/../USBPD/usbpd_dpm_core.c:201: undefined reference to `USBPD_PE_Init'
    <snipped...>

    ST Employee
    March 29, 2021

    Dear @NathanWolcott​ 

    All these functions are included in the USB-PD stack library.

    Can you check that the library is well included in your project?

    0693W000008y83oQAA.jpg 

    Regards,

    Yohann