cancel
Showing results for 
Search instead for 
Did you mean: 

USB PD Sink Configuration for a wide input range charger?

Tim1
Associate II

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.

6 REPLIES 6
Nicolas P.
ST Employee

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

.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.

Tim1
Associate II

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)?

Yohann M.
ST Employee

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

Tim1
Associate II

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;

Yohann M.
ST Employee

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