Skip to main content
Visitor II
October 6, 2020
Question

USB PD Sink Configuration for a wide input range charger?

  • October 6, 2020
  • 5 replies
  • 2016 views

We are designing a USB PD LiPo charger that can receive power from a variety of USB PD sources. It is based around a charger IC designed to handle a wide range of input voltages with internal control of the current draw. For example, our design can draw 3A at 20V if the USB PD Source can handle it. However, our design can also just pull 1.5A at 12V if that's all the USB PD Source can supply. We are using the STM32G071RB with integrated USB PD peripheral and the USB PD stack provided by ST. How should we configure the PORT0_PDO_ListSNK[] array so the stack will always ask for the highest voltage and current available from the source (we can easily handle 20V 5A, but our device will accept 5V 1A if that's all the source can provide)? Also, where is the best location to configure this array. We are currently hard coding the values in the USBPD_PWR_IF_Init() function.

Here is a snippet of code we have been testing with:

USBPD_StatusTypeDef USBPD_PWR_IF_Init(void)
{
/* USER CODE BEGIN USBPD_PWR_IF_Init */
 USBPD_StatusTypeDef _status = USBPD_OK;
 
 /* Set links to PDO values and number for Port 0 (defined in PDO arrays in H file).
 */
 
 PWR_Port_PDO_Storage[USBPD_PORT_0].SinkPDO.ListOfPDO = (uint32_t *)PORT0_PDO_ListSNK;
 PWR_Port_PDO_Storage[USBPD_PORT_0].SinkPDO.NumberOfPDO = &USBPD_NbPDO[0];
 
 
 //Hard coded config values
 PORT0_PDO_ListSNK[0] = _PWR_SNKFixedPDO(1.5,5,1,0,0,0,0);
 PORT0_PDO_ListSNK[1] = _PWR_SNKVariablePDO(20,5,1.25);
 PORT0_PDO_ListSNK[2] = _PWR_SNKVariablePDO(20,5,1.5);
 PORT0_PDO_ListSNK[3] = _PWR_SNKVariablePDO(20,5,2);
 PORT0_PDO_ListSNK[4] = _PWR_SNKVariablePDO(20,5,2.25);
 PORT0_PDO_ListSNK[5] = _PWR_SNKVariablePDO(20,5,2.5);
 PORT0_PDO_ListSNK[6] = _PWR_SNKVariablePDO(20,5,3);
 USBPD_NbPDO[0]=7;

This works fine (successfully establishes a contract with the highest power available from the source) if we plug our device into a 100W or 60W USB PD charger, but it doesn't work if we plug into a USB PD charger that is only 18W (12V @ 1.5A).

Below is the request that gets made to the 18W charger, but the request gets rejected.

 0693W000004Ir4cQAC.png

 0693W000004Ir4mQAC.png

Thank you in advance for any help you can provide.

    This topic has been closed for replies.

    5 replies

    ST Employee
    October 6, 2020

    Hello Tim,

    It seems your request is not correct. You request too much current ? (the bit "Capability mismatch" is set)

    Can you have a look at our wiki ? There is a specific section about this kind of error.

    Then, instead of sharing the picture of the trace, can you share the .cpd file ? (The trace files are saved in c:\Users\%username%\AppData\Local\Temp\STM32CubeMonitor-UCPD\Acquisition\ with ".cpd" extension.)

    See also this wiki section related to PDO building policy.

    Thanks.

    Nicolas

    Tim1Author
    Visitor II
    October 6, 2020

    .cpd file attached. Can we adjust our SNK configuration to solve this problem? The only thing we have modified in the ST example project is the SNK configuration shown above. The logic to request the current is done by code provided by the ST example.

    Tim1Author
    Visitor II
    October 6, 2020

    I believe the capabilities mismatch may be caused by this section of code in usbpd_dpm_conf.h

    USBPD_USER_SettingsTypeDef DPM_USER_Settings[USBPD_PORT_COUNT] =
    {
     {
     .PE_VconnSwap = USBPD_FALSE, /* support VCONN swap */
     .DPM_SNKRequestedPower = /*!< Requested Power by the sink board */
     {
     .MaxOperatingCurrentInmAunits = USBPD_CORE_PDO_SNK_FIXED_MAX_CURRENT,
     .OperatingVoltageInmVunits = USBPD_BOARD_REQUESTED_VOLTAGE_MV,
     .MaxOperatingVoltageInmVunits = USBPD_BOARD_MAX_VOLTAGE_MV,
     .MinOperatingVoltageInmVunits = USBPD_BOARD_MIN_VOLTAGE_MV,
     .OperatingPowerInmWunits = (USBPD_CORE_PDO_SNK_FIXED_MAX_CURRENT * USBPD_BOARD_REQUESTED_VOLTAGE_MV)/1000,
     .MaxOperatingPowerInmWunits = (USBPD_CORE_PDO_SNK_FIXED_MAX_CURRENT * USBPD_BOARD_MAX_VOLTAGE_MV)/1000
     },
    #if defined(USBPDCORE_SNK_CAPA_EXT)
     .DPM_SNKExtendedCapa = /*!< SRC Extended Capability */
     {
     .VID = USBPD_VID, /*!< Vendor ID (assigned by the USB-IF) */
     .PID = USBPD_PID, /*!< Product ID (assigned by the manufacturer) */
     .XID = USBPD_XID, /*!< Value provided by the USB-IF assigned to the product */
     .FW_revision = 1, /*!< Firmware version number */
     .HW_revision = 2, /*!< Hardware version number */
     .SKEDB_Version = USBPD_SKEDB_VERSION_1P0, /*!< SKEDB Version (not the specification Version)
     based on @ref USBPD_SKEDB_VERSION */
     .LoadStep = USBPD_SKEDB_LOADSTEP_150MA, /*!< Load Step based on @ref USBPD_SKEDB_LOADSTEP */
     .SinkLoadCharac.b = /*!< Sink Load Characteristics */
     {
     .PercentOverload = 0, /*!< Percent overload in 10% increments Values higher than 25
     (11001b) are clipped to 250%. 00000b is the default. */
     .OverloadPeriod = 0, /*!< Overload period in 20ms when bits 0-4 non-zero. */
     .DutyCycle = 0, /*!< Duty cycle in 5% increments when bits 0-4 are non-zero. */
     .VBusVoltageDrop = 0, /*!< Can tolerate VBUS Voltage drop. */
     },
     .Compliance = 0, /*!< Compliance based on combination of @ref USBPD_SKEDB_COMPLIANCE */
     .Touchtemp = USBPD_SKEDB_TOUCHTEMP_NA, /*!< Touch Temp based on @ref USBPD_SKEDB_TOUCHTEMP */
     .BatteryInfo = 0, /*!< Battery info */
     .SinkModes = 0, /*!< Sink Modes based on combination of @ref USBPD_SKEDB_SINKMODES */
     .SinkMinimumPDP = 0, /*!< The Minimum PDP required by the Sink to operate without
     consuming any power from its Battery(s) should it have one */
     .SinkOperationalPDP = 0, /*!< The PDP the Sink requires to operate normally. For Sinks with
     a Battery, it is the PDP Rating of the charger supplied with
     it or recommended for it. */
     .SinkMaximumPDP = 0, /*!< The Maximum PDP the Sink can consume to operate and
     charge its Battery(s) should it have one. */
     },
    #endif /* USBPDCORE_SNK_CAPA_EXT */

    " .OperatingPowerInmWunits = (USBPD_CORE_PDO_SNK_FIXED_MAX_CURRENT * USBPD_BOARD_REQUESTED_VOLTAGE_MV)/1000" is assuming the board draws constant power. But our device can draw dynamic power based on what is available from the source. Should we just set this to a low value (18W for example)?

    ST Employee
    October 7, 2020

    Dear @Tim​ 

    USBPD_CORE_PDO_SNK_FIXED_MAX_CURRENT has been fixed to 5A and it seems that your power supply does not accept our request with a max current to 5A:

    ---> 0000008915 P0 SOP s:006 PD3 H:0x1082 REQUEST DATA:f4b10414

             PDO position     :(1)

             NoUSBSuspend     : 0

             USB Capable      : 0

             GiveBack       : 0

             Capa Mismatch     : 1

             Operating current   : 3000 mA

             Maxi Operating current: 5000 mA

             UnchunkMode Support  : 0

     <--- 0000008918 P0 SOP s:002 PD3 H:0x03a4 REJECT

    Can you just try to sent this defined to 3A?

    (usbpd_pdo_def.h)
    #define USBPD_CORE_PDO_SNK_FIXED_MAX_CURRENT 3000

    Yohann

    Tim1Author
    Visitor II
    October 7, 2020

    Hi Yohann, I made the change you suggested and the request was accepted. This seems to fix the problem. Thank you for your help.

    Do you agree with the following SNK configuration? We are trying to ensure it will always select the highest available power from the USB PD Source?

     //located in USBPD_PWR_IF_Init
     PORT0_PDO_ListSNK[0] = _PWR_SNKFixedPDO(3,5,1,0,0,0,0);
     PORT0_PDO_ListSNK[1] = _PWR_SNKVariablePDO(20,5,1.25);
     PORT0_PDO_ListSNK[2] = _PWR_SNKVariablePDO(20,5,1.5);
     PORT0_PDO_ListSNK[3] = _PWR_SNKVariablePDO(20,5,2);
     PORT0_PDO_ListSNK[4] = _PWR_SNKVariablePDO(20,5,2.25);
     PORT0_PDO_ListSNK[5] = _PWR_SNKVariablePDO(20,5,2.5);
     PORT0_PDO_ListSNK[6] = _PWR_SNKVariablePDO(20,5,3);
     USBPD_NbPDO[0]=7;

    ST Employee
    October 7, 2020

    Hi Tim,

    As described in the wiki page, the construction of the request is done through the 'USBPD_DPM_SNK_EvaluateMatchWithSRCPDO' function.

    According to our PDO selection algorithm, variable Sink PDO will be selected only if the source provides in its list a variable PDO, which matches with our sink capabilities.

    Up to you to change this algorithm to match with your needs.

    Yohann