/** ****************************************************************************** * @file usbpd_pwr_if.c * @author MCD Application Team * @brief This file contains power interface control functions. ****************************************************************************** * @attention * *

© Copyright (c) 2018 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ #define __USBPD_PWR_IF_C /* Includes ------------------------------------------------------------------*/ #include "stm32g0xx.h" #include "usbpd_core.h" #include "usbpd_pwr_if.h" #include "usbpd_hw_if.h" #include "usbpd_dpm_core.h" #include "usbpd_dpm_conf.h" #include "usbpd_pdo_defs.h" #if defined (_TRACE) #include "usbpd_trace.h" #endif /* _TRACE */ #include "string.h" #include #include "cmsis_os.h" #include "main.h" /* Private typedef -----------------------------------------------------------*/ #ifdef _TRACE #define POWER_IF_TRACE(_PORT_,_MSG_,_SIZE_) USBPD_TRACE_Add(USBPD_TRACE_DEBUG,_PORT_,0,(uint8_t *)_MSG_, _SIZE_); #else #define POWER_IF_TRACE(_PORT_,_MSG_,_SIZE_) #endif /* Private define ------------------------------------------------------------*/ #define ABS(__VAL__) ((__VAL__) < 0 ? - (__VAL__) : (__VAL__)) /* Private macros ------------------------------------------------------------*/ #define _PWR_UPDATE_VOLTAGE_MIN(_PDO_VOLT_, _SNK_VOLT_) \ if ((_PDO_VOLT_) < (_SNK_VOLT_)) \ { \ /* Update min voltage */ \ (_SNK_VOLT_) = (_PDO_VOLT_); \ } #define _PWR_UPDATE_VOLTAGE_MAX(_PDO_VOLT_, _SNK_VOLT_) \ if ((_PDO_VOLT_) > (_SNK_VOLT_)) \ { \ /* Update min voltage */ \ (_SNK_VOLT_) = (_PDO_VOLT_); \ } #define _PWR_UPDATE_CURRENT_MAX(_PDO_CURRENT_, _SNK_CURRENT_) \ if ((_PDO_CURRENT_) > (_SNK_CURRENT_)) \ { \ /* Update min current */ \ (_SNK_CURRENT_) = (_PDO_CURRENT_); \ } #define _PWR_UPDATE_POWER_MAX(_PDO_POWER_, _SNK_POWER_) \ if ((_PDO_POWER_) > (_SNK_POWER_)) \ { \ /* Update min POWER */ \ (_SNK_POWER_) = (_PDO_POWER_); \ } #define _PWR_CHECK_VOLTAGE_MIN(_PDO_VOLT_, _SNK_VOLT_) \ if ((_PDO_VOLT_) != (_SNK_VOLT_)) \ { \ /* Disalignment between PDO and DPM_SNKRequestedPower structure */ \ _status = USBPD_ERROR; \ } #define _PWR_CHECK_VOLTAGE_MAX(_PDO_VOLT_, _SNK_VOLT_) \ if ((_PDO_VOLT_) != (_SNK_VOLT_)) \ { \ /* Disalignment between PDO and DPM_SNKRequestedPower structure */ \ _status = USBPD_ERROR; \ } #define _PWR_CHECK_CURRENT_MAX(_PDO_CURRENT_, _SNK_CURRENT_) \ if ((_PDO_CURRENT_) != (_SNK_CURRENT_)) \ { \ /* Disalignment between PDO and DPM_SNKRequestedPower structure */ \ _status = USBPD_ERROR; \ } #define _PWR_CHECK_POWER_MAX(_PDO_POWER_, _SNK_POWER_) \ if ((_PDO_POWER_) != (_SNK_POWER_)) \ { \ /* Disalignment between PDO and DPM_SNKRequestedPower structure */ \ _status = USBPD_ERROR; \ } /* Private variables ---------------------------------------------------------*/ /** * @brief USBPD Port safty data */ uint8_t safety_contract = 0; USBPD_PDO_TypeDef safety_pdo; USBPD_SNKRDO_TypeDef safety_rdo; /** * @brief USBPD Port PDO Storage array declaration */ /**** PDO ****/ USBPD_PWR_Port_PDO_Storage_TypeDef PWR_Port_PDO_Storage[USBPD_PORT_COUNT]; /* Private function prototypes -----------------------------------------------*/ /* Functions to initialize Source PDOs */ uint32_t _PWR_SRCFixedPDO(float _C_, float _V_, USBPD_CORE_PDO_PeakCurr_TypeDef _PK_, USBPD_CORE_PDO_DRDataSupport_TypeDef DRDSupport, USBPD_CORE_PDO_USBCommCapable_TypeDef UsbCommCapable, USBPD_CORE_PDO_ExtPowered_TypeDef ExtPower, USBPD_CORE_PDO_USBSuspendSupport_TypeDef UsbSuspendSupport, USBPD_CORE_PDO_DRPowerSupport_TypeDef DRPSupport); uint32_t _PWR_SRCVariablePDO(float _MAXV_, float _MINV_, float _C_); uint32_t _PWR_SRCBatteryPDO(float _MAXV_,float _MINV_,float _PWR_); /* Functions to initialize Sink PDOs */ uint32_t _PWR_SNKFixedPDO(float _C_, float _V_, USBPD_CORE_PDO_DRDataSupport_TypeDef DRDSupport, USBPD_CORE_PDO_USBCommCapable_TypeDef UsbCommCapable, USBPD_CORE_PDO_ExtPowered_TypeDef ExtPower, USBPD_CORE_PDO_HigherCapability_TypeDef HigherCapab, USBPD_CORE_PDO_DRPowerSupport_TypeDef DRPSupport); uint32_t _PWR_SNKVariablePDO(float _MAXV_,float _MINV_,float _C_); uint32_t _PWR_SNKBatteryPDO(float _MAXV_,float _MINV_,float _PWR_); uint32_t _PWR_ProgrammablePowerSupplyAPDO(float _MAXC_,float _MINV_,float _MAXV_); /* Private functions ---------------------------------------------------------*/ void USBPD_PWR_IF_MonitorSafety(void const *argument); /** * @brief Initialize structures and variables related to power board profiles * used by Sink and Source, for all available ports. * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_Init(void) { USBPD_StatusTypeDef _status = USBPD_OK; uint32_t index; /* Definition of Sink PDO for Port 0 */ uint32_t PORT0_PDO_USER_ListSNK[USBPD_MAX_NB_PDO] = { /* PDO 1 */ ( ((PWR_A_10MA(3)) << USBPD_PDO_SRC_FIXED_MAX_CURRENT_Pos) | ((PWR_V_50MV(5)) << USBPD_PDO_SRC_FIXED_VOLTAGE_Pos) | USBPD_PDO_SNK_FIXED_FRS_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_DRD_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_USBCOMM_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_EXT_POWER_NOT_AVAILABLE | USBPD_PDO_SNK_FIXED_HIGHERCAPAB_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_DRP_NOT_SUPPORTED | USBPD_PDO_TYPE_FIXED ), /* PDO 2 */ ( ((PWR_A_10MA(3)) << USBPD_PDO_SRC_FIXED_MAX_CURRENT_Pos) | ((PWR_V_50MV(9)) << USBPD_PDO_SRC_FIXED_VOLTAGE_Pos) | USBPD_PDO_SNK_FIXED_FRS_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_DRD_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_USBCOMM_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_EXT_POWER_NOT_AVAILABLE | USBPD_PDO_SNK_FIXED_HIGHERCAPAB_SUPPORTED | USBPD_PDO_SNK_FIXED_DRP_NOT_SUPPORTED | USBPD_PDO_TYPE_FIXED ), /* PDO 3 */ ( ((PWR_A_10MA(3)) << USBPD_PDO_SRC_FIXED_MAX_CURRENT_Pos) | ((PWR_V_50MV(12)) << USBPD_PDO_SRC_FIXED_VOLTAGE_Pos) | USBPD_PDO_SNK_FIXED_FRS_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_DRD_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_USBCOMM_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_EXT_POWER_NOT_AVAILABLE | USBPD_PDO_SNK_FIXED_HIGHERCAPAB_SUPPORTED | USBPD_PDO_SNK_FIXED_DRP_NOT_SUPPORTED | USBPD_PDO_TYPE_FIXED ), /* PDO 4 */ ( ((PWR_A_10MA(3)) << USBPD_PDO_SRC_FIXED_MAX_CURRENT_Pos) | ((PWR_V_50MV(15)) << USBPD_PDO_SRC_FIXED_VOLTAGE_Pos) | USBPD_PDO_SNK_FIXED_FRS_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_DRD_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_USBCOMM_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_EXT_POWER_NOT_AVAILABLE | USBPD_PDO_SNK_FIXED_HIGHERCAPAB_SUPPORTED | USBPD_PDO_SNK_FIXED_DRP_NOT_SUPPORTED | USBPD_PDO_TYPE_FIXED ), /* PDO 5 */ ( ((PWR_A_10MA(3)) << USBPD_PDO_SRC_FIXED_MAX_CURRENT_Pos) | ((PWR_V_50MV(20)) << USBPD_PDO_SRC_FIXED_VOLTAGE_Pos) | USBPD_PDO_SNK_FIXED_FRS_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_DRD_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_USBCOMM_NOT_SUPPORTED | USBPD_PDO_SNK_FIXED_EXT_POWER_NOT_AVAILABLE | USBPD_PDO_SNK_FIXED_HIGHERCAPAB_SUPPORTED | USBPD_PDO_SNK_FIXED_DRP_NOT_SUPPORTED | USBPD_PDO_TYPE_FIXED ), /* PDO 6 */ (0x00000000U), /* PDO 7 */ (0x00000000U) }; uint8_t num_of_user_sink_pdo = 5; /* Reset PDO values */ memset(PWR_Port_PDO_Storage, 0, sizeof(PWR_Port_PDO_Storage)); for (index = 0; index < USBPD_MAX_NB_PDO; index++) { /* SRC PDO for Port 0 */ PWR_Port_PDO_Storage[USBPD_PORT_0].SourcePDO.ListOfPDO[index] = PORT0_PDO_ListSRC[index]; #ifdef _GUI_INTERFACE /* SNK PDO for Port 0 */ PWR_Port_PDO_Storage[USBPD_PORT_0].SinkPDO.ListOfPDO[index] = PORT0_PDO_ListSNK[index]; #else /* SNK PDO for Port 0 */ PWR_Port_PDO_Storage[USBPD_PORT_0].SinkPDO.ListOfPDO[index] = PORT0_PDO_USER_ListSNK[index]; #endif } #ifdef _GUI_INTERFACE PWR_Port_PDO_Storage[USBPD_PORT_0].SinkPDO.NumberOfPDO = USBPD_NbPDO[0]; #else PWR_Port_PDO_Storage[USBPD_PORT_0].SinkPDO.NumberOfPDO = num_of_user_sink_pdo; #endif PWR_Port_PDO_Storage[USBPD_PORT_0].SourcePDO.NumberOfPDO = USBPD_NbPDO[1]; //_status |= USBPD_PWR_IF_CheckUpdateSNKPower(USBPD_PORT_0); return _status; } USBPD_StatusTypeDef USBPD_PWR_IF_StartMonitoring(void) { osThreadDef(SAFE, USBPD_PWR_IF_MonitorSafety, osPriorityLow, 0, 100); if(NULL == osThreadCreate(osThread(SAFE), NULL)) { return USBPD_ERROR; } return USBPD_OK; } /** * @brief Sets the required power profile, now it works only with Fixed ones * @param PortNum Port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_SetProfile(uint8_t PortNum) { USBPD_StatusTypeDef _ret = USBPD_ERROR; USBPD_PDO_TypeDef _pdo; USBPD_SNKRDO_TypeDef _rdo; static USBPD_SNKRDO_TypeDef _rdo_previous = { .d32 = 0 }; uint32_t _vbusTargetInmv = 0; uint32_t _PowerProfileSelected = DPM_Ports[PortNum].DPM_RDOPosition - 1; uint8_t counter = 0; /* Check if valid port */ /* Check if profile nb is valid for this port */ if (( !USBPD_PORT_IsValid(PortNum) ) || (_PowerProfileSelected >= PWR_Port_PDO_Storage[PortNum].SourcePDO.NumberOfPDO) || (0 == PWR_Port_PDO_Storage[PortNum].SourcePDO.NumberOfPDO)) { return _ret; } safety_pdo.d32 = _pdo.d32 = PWR_Port_PDO_Storage[PortNum].SourcePDO.ListOfPDO[_PowerProfileSelected]; safety_rdo.d32 = _rdo.d32 = DPM_Ports[PortNum].DPM_RcvRequestDOMsg; switch(_pdo.GenericPDO.PowerObject) { case USBPD_CORE_PDO_TYPE_FIXED : { _vbusTargetInmv = _pdo.SRCFixedPDO.VoltageIn50mVunits * 50; uint32_t _OperatingCurrent = _rdo.FixedVariableRDO.OperatingCurrentIn10mAunits * 10; uint32_t _MaxOperatingCurrent = _rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits * 10; _ret = BSP_PWR_VBUSSetVoltage_Fixed(PortNum, _vbusTargetInmv, _OperatingCurrent, _MaxOperatingCurrent) == PWR_OK ? USBPD_OK: USBPD_ERROR; break; } case USBPD_CORE_PDO_TYPE_VARIABLE : { _vbusTargetInmv = _pdo.SRCVariablePDO.MinVoltageIn50mVunits * 50; uint32_t _vbusTargetMaxInmv = _pdo.SRCVariablePDO.MaxVoltageIn50mVunits * 50; uint32_t _OperatingCurrent = _rdo.FixedVariableRDO.OperatingCurrentIn10mAunits * 10; uint32_t _MaxOperatingCurrent = _rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits * 10; _ret = BSP_PWR_VBUSSetVoltage_Variable(PortNum, _vbusTargetInmv, _vbusTargetMaxInmv, _OperatingCurrent, _MaxOperatingCurrent) == PWR_OK ? USBPD_OK: USBPD_ERROR; break; } case USBPD_CORE_PDO_TYPE_APDO : { _vbusTargetInmv = _rdo.ProgRDO.OutputVoltageIn20mV * 20; uint32_t _OperatingCurrent = _rdo.ProgRDO.OperatingCurrentIn50mAunits * 50; int32_t _delta = 0; if(_rdo.ProgRDO.ObjectPosition == _rdo_previous.ProgRDO.ObjectPosition) { _delta = (_rdo_previous.ProgRDO.OutputVoltageIn20mV - _rdo.ProgRDO.OutputVoltageIn20mV) * 20; } _ret = BSP_PWR_VBUSSetVoltage_APDO(PortNum, _vbusTargetInmv, _OperatingCurrent, _delta) == PWR_OK ? USBPD_OK: USBPD_ERROR; break; } case USBPD_CORE_PDO_TYPE_BATTERY : default : { /* not yet implemented */ return _ret; } } /* save the previous rd, mainly for APDO management */ _rdo_previous.d32 = _rdo.d32; if (_ret != USBPD_OK) { _rdo_previous.d32 = 0; return _ret; } else { /* before sending PS_READY if the power is at the expected level */ int32_t _delta; uint32_t _vbusOriginInmv; uint8_t _exit = 0; uint32_t _precision; if (USBPD_CORE_PDO_TYPE_APDO == _pdo.GenericPDO.PowerObject) /* Set the power, precision should be 20mV */ _precision = 20; else /* Set the power, the precision must be at 4% for a fixed PDO */ _precision = (_vbusTargetInmv * 4) / 100; do { counter++; if (USBPD_CORE_PDO_TYPE_APDO == _pdo.GenericPDO.PowerObject) USBPD_DPM_WaitForTime(1); else USBPD_DPM_WaitForTime(5); _vbusOriginInmv = BSP_PWR_VBUSGetVoltage(PortNum); _delta = _vbusOriginInmv - _vbusTargetInmv; if((ABS(_delta)) < _precision) { _exit = 1; } }while((_exit == 0) && (counter < 22)); } if (22 == counter) return USBPD_FAIL; else { safety_contract = 1; return USBPD_OK; } } /** * @brief Resets the Power Board * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_PowerResetGlobal(void) { int i = 0; /* Resets all the ports */ for(i = 0; i < USBPD_PORT_COUNT; i++) { USBPD_PWR_IF_PowerReset(i); } return USBPD_OK; } /** * @brief Resets the Power on a specified port * @param PortNum Port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_PowerReset(uint8_t PortNum) { /* check for valid port */ if (!USBPD_PORT_IsValid(PortNum)) { return USBPD_ERROR; } /* Put the usbpd port into ready to start the application */ return USBPD_PWR_IF_InitPower(PortNum); } /** * @brief Checks if the power on a specified port is ready * @param PortNum Port number * @param Vsafe Vsafe status based on @ref USBPD_VSAFE_StatusTypeDef * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_SupplyReady(uint8_t PortNum, USBPD_VSAFE_StatusTypeDef Vsafe) { USBPD_StatusTypeDef status = USBPD_ERROR; /* check for valid port */ if (!USBPD_PORT_IsValid(PortNum)) { return USBPD_ERROR; } if (USBPD_VSAFE_0V == Vsafe) { /* Vsafe0V */ status = ((BSP_PWR_VBUSGetVoltage(PortNum) < BSP_PWR_HIGH_VBUS_THRESHOLD)? USBPD_OK: USBPD_ERROR); } else { /* Vsafe5V */ status = ((BSP_PWR_VBUSGetVoltage(PortNum) > BSP_PWR_HIGH_VBUS_THRESHOLD)? USBPD_OK: USBPD_ERROR); } return status; } /** * @brief Enables VBUS power on a specified port * @param PortNum Port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_VBUSEnable(uint8_t PortNum) { USBPD_StatusTypeDef _status = USBPD_ERROR; /* check for valid port */ if (USBPD_PORT_IsValid(PortNum)) { POWER_IF_TRACE(PortNum, "EN_VBUS", 7); /* Set the new state */ #ifdef _TRACE char str[20]; sprintf(str, "CC:%d VCONN:%d", DPM_Params[PortNum].VconnCCIs, DPM_Params[PortNum].VconnStatus); POWER_IF_TRACE(PortNum, (uint8_t*)str, strlen(str)); #endif /* _TRACE */ //_status = (USBPD_StatusTypeDef)HW_IF_PWR_Enable(PortNum, USBPD_ENABLE, DPM_Params[PortNum].VconnCCIs, DPM_Params[PortNum].VconnStatus, USBPD_PORTPOWERROLE_SRC); } return _status; } /** * @brief Disbale VBUS/VCONN the power on a specified port * @param PortNum Port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_VBUSDisable(uint8_t PortNum) { USBPD_StatusTypeDef _status = USBPD_ERROR; /* check for valid port */ if (USBPD_PORT_IsValid(PortNum)) { POWER_IF_TRACE(PortNum, "DIS VBUS", 8); /* Set the new state */ /* Set the new state */ //_status = (USBPD_StatusTypeDef)HW_IF_PWR_Enable(PortNum, USBPD_DISABLE, DPM_Params[PortNum].VconnCCIs, DPM_Params[PortNum].VconnStatus, USBPD_PORTPOWERROLE_SRC); DPM_Params[PortNum].VconnStatus = USBPD_FALSE; } /* Safety add On */ if(0 == PortNum) { safety_contract = 0; } return _status; } /** * @brief Disable the SNK to stop current consumption * @param PortNum Port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_SNKDisable(uint8_t PortNum) { USBPD_StatusTypeDef _status = USBPD_ERROR; /* check for valid port */ if (USBPD_PORT_IsValid(PortNum)) { /* Set the new state */ _status = (USBPD_StatusTypeDef)HW_IF_PWR_Enable(PortNum, USBPD_DISABLE, DPM_Params[PortNum].VconnCCIs, DPM_Params[PortNum].VconnStatus, USBPD_PORTPOWERROLE_SNK); } return _status; } /** * @brief Initialize power on a specified port * @param PortNum Port number * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_InitPower(uint8_t PortNum) { return USBPD_OK; } /** * @brief Checks if the power on a specified port is enabled * @param PortNum Port number * @retval USBPD_ENABLE or USBPD_DISABLE */ USBPD_FunctionalState USBPD_PWR_IF_VBUSIsEnabled(uint8_t PortNum) { /* Get the Status of the port */ return USBPD_PORT_IsValid(PortNum) ? (USBPD_FunctionalState)HW_IF_PWR_VBUSIsEnabled(PortNum) : USBPD_DISABLE; } /** * @brief Reads the voltage and the current on a specified port * @param PortNum Port number * @param pVoltage: The Voltage in mV * @param pCurrent: The Current in mA * @retval USBPD_ERROR or USBPD_OK */ USBPD_StatusTypeDef USBPD_PWR_IF_ReadVA(uint8_t PortNum, uint16_t *pVoltage, uint16_t *pCurrent) { /* check for valid port */ if (!USBPD_PORT_IsValid(PortNum)) { return USBPD_ERROR; } /* USBPD_OK if at least one pointer is not null, otherwise USBPD_ERROR */ USBPD_StatusTypeDef ret = USBPD_ERROR; /* Get values from HW_IF */ if (pVoltage != NULL) { *pVoltage = HW_IF_PWR_GetVoltage(PortNum); ret = USBPD_OK; } if (pCurrent != NULL) { *pCurrent = HW_IF_PWR_GetCurrent(PortNum); ret = USBPD_OK; } return ret; } /** * @brief Create SRC Fixed PDO object * @param _C_: Current in A * @param _V_: voltage in V * @param _PK_: The peak of current * @param DRDSupport: Data Role Swap support indication * @param UsbCommCapable: USB communications capability indication * @param ExtPower: Port externally powered indication * @param UsbSuspendSupport: USB Suspend support indication * @param DRPSupport: Dual Role Power support indication * @retval PDO object value (expressed on u32) */ uint32_t _PWR_SRCFixedPDO(float _C_, float _V_, USBPD_CORE_PDO_PeakCurr_TypeDef _PK_, USBPD_CORE_PDO_DRDataSupport_TypeDef DRDSupport, USBPD_CORE_PDO_USBCommCapable_TypeDef UsbCommCapable, USBPD_CORE_PDO_ExtPowered_TypeDef ExtPower, USBPD_CORE_PDO_USBSuspendSupport_TypeDef UsbSuspendSupport, USBPD_CORE_PDO_DRPowerSupport_TypeDef DRPSupport) { USBPD_PDO_TypeDef pdo; pdo.d32 = 0; pdo.SRCFixedPDO.MaxCurrentIn10mAunits = PWR_A_10MA(_C_); pdo.SRCFixedPDO.VoltageIn50mVunits = PWR_V_50MV(_V_); pdo.SRCFixedPDO.PeakCurrent = _PK_; pdo.SRCFixedPDO.DataRoleSwap = DRDSupport; pdo.SRCFixedPDO.USBCommunicationsCapable = UsbCommCapable; pdo.SRCFixedPDO.ExternallyPowered = ExtPower; pdo.SRCFixedPDO.USBSuspendSupported = UsbSuspendSupport; pdo.SRCFixedPDO.DualRolePower = DRPSupport; pdo.SRCFixedPDO.FixedSupply = USBPD_CORE_PDO_TYPE_FIXED; return pdo.d32; } /** * @brief Create SRC Variable PDO object * @param _MAXV_ Max voltage in V * @param _MINV_ Min voltage in V * @param _C_: Max current in A * @retval PDO object value (expressed on u32) */ uint32_t _PWR_SRCVariablePDO(float _MAXV_, float _MINV_, float _C_) { USBPD_PDO_TypeDef pdo; pdo.d32 = 0; pdo.SRCVariablePDO.MaxCurrentIn10mAunits = PWR_A_10MA(_C_); pdo.SRCVariablePDO.MaxVoltageIn50mVunits = PWR_V_50MV(_MAXV_); pdo.SRCVariablePDO.MinVoltageIn50mVunits = PWR_V_50MV(_MINV_); pdo.SRCVariablePDO.VariableSupply = USBPD_CORE_PDO_TYPE_VARIABLE; return pdo.d32; } /** * @brief Create SRC Battery PDO object * @param _MAXV_ Max voltage in V * @param _MINV_ Min voltage in V * @param _PWR_ Max allowable power in W * @retval PDO object value (expressed on u32) */ uint32_t _PWR_SRCBatteryPDO(float _MAXV_,float _MINV_,float _PWR_) { USBPD_PDO_TypeDef pdo; pdo.d32 = 0; pdo.SRCBatteryPDO.MaxAllowablePowerIn250mWunits = PWR_W(_PWR_); pdo.SRCBatteryPDO.MinVoltageIn50mVunits = PWR_V_50MV(_MINV_); pdo.SRCBatteryPDO.MaxVoltageIn50mVunits = PWR_V_50MV(_MAXV_); pdo.SRCBatteryPDO.Battery = USBPD_CORE_PDO_TYPE_BATTERY; return pdo.d32; } /** * @brief Create SNK Fixed PDO object * @param _C_ Current in A * @param _V_ voltage in V * @param DRDSupport: Data Role Swap support indication * @param UsbCommCapable: USB communications capability indication * @param ExtPower: Port externally powered indication * @param HigherCapab: Sink needs more than vSafe5V to provide full functionality indication * @param DRPSupport: Dual Role Power support indication * @retval PDO object value (expressed on u32) */ uint32_t _PWR_SNKFixedPDO(float _C_, float _V_, USBPD_CORE_PDO_DRDataSupport_TypeDef DRDSupport, USBPD_CORE_PDO_USBCommCapable_TypeDef UsbCommCapable, USBPD_CORE_PDO_ExtPowered_TypeDef ExtPower, USBPD_CORE_PDO_HigherCapability_TypeDef HigherCapab, USBPD_CORE_PDO_DRPowerSupport_TypeDef DRPSupport) { USBPD_PDO_TypeDef pdo; pdo.d32 = 0; pdo.SNKFixedPDO.OperationalCurrentIn10mAunits = PWR_A_10MA(_C_); pdo.SNKFixedPDO.VoltageIn50mVunits = PWR_V_50MV(_V_); pdo.SNKFixedPDO.DataRoleSwap = DRDSupport; pdo.SNKFixedPDO.USBCommunicationsCapable = UsbCommCapable; pdo.SNKFixedPDO.ExternallyPowered = ExtPower; pdo.SNKFixedPDO.HigherCapability = HigherCapab; pdo.SNKFixedPDO.DualRolePower = DRPSupport; pdo.SNKFixedPDO.FixedSupply = USBPD_CORE_PDO_TYPE_FIXED; return pdo.d32; } /** * @brief Create SNK Variable PDO object * @param _MAXV_ Max voltage in V * @param _MINV_ Min voltage in V * @param _C_: Max current in A * @retval PDO object value (expressed on u32) */ uint32_t _PWR_SNKVariablePDO(float _MAXV_,float _MINV_,float _C_) { USBPD_PDO_TypeDef pdo; pdo.d32 = 0; pdo.SRCVariablePDO.MaxCurrentIn10mAunits = PWR_A_10MA(_C_); pdo.SRCVariablePDO.MaxVoltageIn50mVunits = PWR_V_50MV(_MAXV_); pdo.SRCVariablePDO.MinVoltageIn50mVunits = PWR_V_50MV(_MINV_); pdo.SRCVariablePDO.VariableSupply = USBPD_CORE_PDO_TYPE_VARIABLE; return pdo.d32; } /** * @brief Create SNK Battery PDO object * @param _MAXV_ Max voltage in V * @param _MINV_ Min voltage in V * @param _PWR_ Max allowable power in W * @retval PDO object value (expressed on u32) */ uint32_t _PWR_SNKBatteryPDO(float _MAXV_,float _MINV_,float _PWR_) { USBPD_PDO_TypeDef pdo; pdo.d32 = 0; pdo.SRCBatteryPDO.MaxAllowablePowerIn250mWunits = PWR_W(_PWR_); pdo.SRCBatteryPDO.MinVoltageIn50mVunits = PWR_V_50MV(_MINV_); pdo.SRCBatteryPDO.MaxVoltageIn50mVunits = PWR_V_50MV(_MAXV_); pdo.SRCBatteryPDO.Battery = USBPD_CORE_PDO_TYPE_BATTERY; return pdo.d32; } /** * @brief Create Programmable Power Supply APDO object * @param _MAXC_ Max Current in A * @param _MINV_ Min voltage in V * @param _MAXV_ Max voltage in V * @retval PDO object value (expressed on u32) */ uint32_t _PWR_ProgrammablePowerSupplyAPDO(float _MAXC_,float _MINV_,float _MAXV_) { USBPD_PDO_TypeDef apdo; apdo.d32 = 0; apdo.SRCSNKAPDO.MaxCurrentIn50mAunits = PWR_A_50MA(_MAXC_); /*!< Maximum Current in 50mA increments */ apdo.SRCSNKAPDO.MinVoltageIn100mV = PWR_V_100MV(_MINV_); /*!< Minimum Voltage in 100mV increments */ apdo.SRCSNKAPDO.MaxVoltageIn100mV = PWR_V_100MV(_MAXV_); /*!< Maximum Voltage in 100mV increments */ apdo.SRCSNKAPDO.PPS_APDO = USBPD_CORE_PDO_TYPE_APDO; return apdo.d32; } #if defined(_VCONN_SUPPORT) /** * @brief Enables the VConn on the port. * @param PortNum Port number * @param CC Specifies the CCx to be selected based on @ref CCxPin_TypeDef structure * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_Enable_VConn(uint8_t PortNum, CCxPin_TypeDef CC) { PWR_StatusTypeDef _status = PWR_OK; POWER_IF_TRACE(PortNum, "VCONN ON", 8); _status = BSP_PWR_VCONNOn(PortNum, CC); if(PWR_OK == _status) { DPM_Params[PortNum].VconnStatus = USBPD_TRUE; } return _status == PWR_OK? USBPD_OK: USBPD_ERROR; } /** * @brief Disable the VConn on the port. * @param PortNum Port number * @param CC Specifies the CCx to be selected based on @ref CCxPin_TypeDef structure * @retval USBPD status */ USBPD_StatusTypeDef USBPD_PWR_IF_Disable_VConn(uint8_t PortNum, CCxPin_TypeDef CC) { PWR_StatusTypeDef _status = PWR_OK; POWER_IF_TRACE(PortNum, "VCONN OFF", 9); _status = BSP_PWR_VCONNOff(PortNum, CC); if(PWR_OK == _status) { DPM_Params[PortNum].VconnStatus = USBPD_FALSE; } return _status == PWR_OK? USBPD_OK:USBPD_ERROR; } #endif /* _VCONN_SUPPORT */ /** * @brief Allow PDO data reading from PWR_IF storage. * @param PortNum Port number * @param DataId Type of data to be read from PWR_IF * This parameter can be one of the following values: * @arg @ref USBPD_CORE_DATATYPE_SRC_PDO Source PDO reading requested * @arg @ref USBPD_CORE_DATATYPE_SNK_PDO Sink PDO reading requested * @param Ptr Pointer on address where PDO values should be written (u8 pointer) * @param Size Pointer on nb of u32 written by PWR_IF (nb of PDOs) * @retval None */ void USBPD_PWR_IF_GetPortPDOs(uint8_t PortNum, USBPD_CORE_DataInfoType_TypeDef DataId, uint8_t *Ptr, uint32_t *Size) { uint32_t nbpdo, index, nb_valid_pdo = 0; uint32_t *ptpdoarray = NULL; USBPD_PDO_TypeDef pdo_first; USBPD_PDO_TypeDef pdo; /* Check if valid port */ if (USBPD_PORT_IsValid(PortNum)) { /* According to type of PDO to be read, set pointer on values and nb of elements */ switch (DataId) { case USBPD_CORE_DATATYPE_SRC_PDO: nbpdo = PWR_Port_PDO_Storage[PortNum].SourcePDO.NumberOfPDO; ptpdoarray = PWR_Port_PDO_Storage[PortNum].SourcePDO.ListOfPDO; /* Save the 1st PDO */ pdo_first.d32 = *ptpdoarray; /* Reset unchunked bit if current revision is PD2.0*/ if (USBPD_SPECIFICATION_REV2 == DPM_Params[PortNum].PE_SpecRevision) { pdo_first.SRCFixedPDO.UnchunkedExtendedMessage = USBPD_PDO_SRC_FIXED_UNCHUNK_NOT_SUPPORTED; } break; case USBPD_CORE_DATATYPE_SNK_PDO: nbpdo = PWR_Port_PDO_Storage[PortNum].SinkPDO.NumberOfPDO; ptpdoarray = PWR_Port_PDO_Storage[PortNum].SinkPDO.ListOfPDO; /* Save the 1st PDO */ pdo_first.d32 = *ptpdoarray; /* Reset FRS bit if current revision is PD2.0*/ if (USBPD_SPECIFICATION_REV2 == DPM_Params[PortNum].PE_SpecRevision) { pdo_first.SNKFixedPDO.FastRoleSwapRequiredCurrent = USBPD_PDO_SNK_FIXED_FRS_NOT_SUPPORTED; } break; default: nbpdo = 0; break; } /* Copy PDO data in output buffer */ for (index = 0; index < nbpdo; index++) { pdo.d32 = *ptpdoarray; /* Copy only PDO (and not APDO in case of current revision is PD2.0) */ if ((USBPD_SPECIFICATION_REV2 == DPM_Params[PortNum].PE_SpecRevision) && (pdo.GenericPDO.PowerObject == USBPD_CORE_PDO_TYPE_APDO)) { } else { /* Copy 1st PDO as potentially FRS or UNCHUNKED bits have been reset */ if (0 == index) { (void)memcpy(Ptr, (uint8_t*)&pdo_first.d32, 4u); } else { (void)memcpy((Ptr + (nb_valid_pdo * 4u)), (uint8_t*)ptpdoarray, 4u); } nb_valid_pdo++; } ptpdoarray++; } /* Set nb of read PDO (nb of u32 elements); */ *Size = nb_valid_pdo; } } /** * @brief Find out SRC PDO pointed out by a position provided in a Request DO (from Sink). * @param PortNum Port number * @param RdoPosition RDO Position in list of provided PDO * @param Pdo Pointer on PDO value pointed out by RDO position (u32 pointer) * @retval Status of search * USBPD_OK : Src PDO found for requested DO position (output Pdo parameter is set) * USBPD_FAIL : Position is not compliant with current Src PDO for this port (no corresponding PDO value) */ USBPD_StatusTypeDef USBPD_PWR_IF_SearchRequestedPDO(uint8_t PortNum, uint32_t RdoPosition, uint32_t *Pdo) { if((RdoPosition == 0) || (RdoPosition > PWR_Port_PDO_Storage[PortNum].SourcePDO.NumberOfPDO)) { /* Invalid PDO index */ return USBPD_FAIL; } *Pdo = PWR_Port_PDO_Storage[PortNum].SourcePDO.ListOfPDO[RdoPosition - 1]; return USBPD_OK; } /** * @brief the function is called in case of critical issue is detected to switch in safety mode. * @param None * @retval None */ void USBPD_PWR_IF_Alarm() { /* Disable the power on SRC */ BSP_PWR_VBUSOff(0); /* Remove the resitor */ USBPD_CAD_EnterErrorRecovery(0); #if USBPD_PORT_COUNT == 2 USBPD_CAD_EnterErrorRecovery(1); #endif /* USBPD_PORT_COUNT == 2 */ /* Stop RTOS scheduling */ vTaskSuspendAll (); /* Display the error */ //DEMO_Display_Error(0); /* disable all interrupt to lock the system */ __disable_irq(); while(1); } /** * @brief Function to check validity between SNK PDO and power user settings * @param PortNum Port number * @retval USBPD Status */ USBPD_StatusTypeDef USBPD_PWR_IF_CheckUpdateSNKPower(uint8_t PortNum) { USBPD_StatusTypeDef _status = USBPD_OK; USBPD_PDO_TypeDef pdo; uint32_t _max_power = 0; uint16_t _voltage = 0, _current = 0, _power = 0; uint16_t _min_voltage = 0xFFFF, _max_voltage = 0, _max_current = 0; for (uint32_t _index = 0; _index < PWR_Port_PDO_Storage[PortNum].SinkPDO.NumberOfPDO; _index++) { pdo.d32 = PWR_Port_PDO_Storage[PortNum].SinkPDO.ListOfPDO[_index]; switch (pdo.GenericPDO.PowerObject) { case USBPD_CORE_PDO_TYPE_FIXED: /*!< Fixed Supply PDO */ _voltage = PWR_DECODE_50MV(pdo.SNKFixedPDO.VoltageIn50mVunits); _PWR_UPDATE_VOLTAGE_MIN(_voltage, _min_voltage); _PWR_UPDATE_VOLTAGE_MAX(_voltage, _max_voltage); _current = PWR_DECODE_10MA(pdo.SNKFixedPDO.OperationalCurrentIn10mAunits); _PWR_UPDATE_CURRENT_MAX(_current, _max_current); break; case USBPD_CORE_PDO_TYPE_BATTERY: /*!< Battery Supply PDO */ _voltage = PWR_DECODE_50MV(pdo.SNKBatteryPDO.MinVoltageIn50mVunits); _PWR_UPDATE_VOLTAGE_MIN(_voltage, _min_voltage); _voltage = PWR_DECODE_50MV(pdo.SNKBatteryPDO.MaxVoltageIn50mVunits); _PWR_UPDATE_VOLTAGE_MAX(_voltage, _max_voltage); _power = PWR_DECODE_MW(pdo.SNKBatteryPDO.OperationalPowerIn250mWunits); _PWR_UPDATE_POWER_MAX(_power, _max_power); break; case USBPD_CORE_PDO_TYPE_VARIABLE: /*!< Variable Supply (non-battery) PDO */ _voltage = PWR_DECODE_50MV(pdo.SNKVariablePDO.MinVoltageIn50mVunits); _PWR_UPDATE_VOLTAGE_MIN(_voltage, _min_voltage); _voltage = PWR_DECODE_50MV(pdo.SNKVariablePDO.MaxVoltageIn50mVunits); _PWR_UPDATE_VOLTAGE_MAX(_voltage, _max_voltage); _current = PWR_DECODE_10MA(pdo.SNKVariablePDO.OperationalCurrentIn10mAunits); _PWR_UPDATE_CURRENT_MAX(_current, _max_current); break; case USBPD_CORE_PDO_TYPE_APDO: /*!< Augmented Power Data Object (APDO) */ _voltage = PWR_DECODE_100MV(pdo.SRCSNKAPDO.MinVoltageIn100mV); _PWR_UPDATE_VOLTAGE_MIN(_voltage, _min_voltage); _voltage = PWR_DECODE_100MV(pdo.SRCSNKAPDO.MaxVoltageIn100mV); _PWR_UPDATE_VOLTAGE_MAX(_voltage, _max_voltage); _current = PWR_DECODE_50MA(pdo.SRCSNKAPDO.MaxCurrentIn50mAunits); _PWR_UPDATE_CURRENT_MAX(_current, _max_current); break; default: break; } } _PWR_CHECK_VOLTAGE_MIN(_min_voltage, DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.MinOperatingVoltageInmVunits); _PWR_CHECK_VOLTAGE_MAX(_max_voltage, DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.MaxOperatingVoltageInmVunits); _PWR_CHECK_CURRENT_MAX(_max_current, DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.MaxOperatingCurrentInmAunits); _max_power = (_max_voltage * _max_current) / 1000; _PWR_CHECK_POWER_MAX(_max_power, DPM_USER_Settings[PortNum].DPM_SNKRequestedPower.MaxOperatingPowerInmWunits); return _status; } /** * @brief Manage the Safety to avoid material issue, it the current execed the limitation an alarm is set * @param None * @retval None */ void USBPD_PWR_IF_MonitorSafety(void const *argument) { uint32_t _MaxOperatingCurrent = 1000; int32_t isense_safety[2]; for(;;) /* infinite loop to monitore the current from port 0 */ { /* Monitor the current for the SRC power PORT0 */ isense_safety[USBPD_PORT_0] = BSP_PWR_VBUSGetCurrent(USBPD_PORT_0); if ((DPM_Params[USBPD_PORT_0].PE_IsConnected == USBPD_TRUE) && (USBPD_PORTPOWERROLE_SRC == DPM_Params[USBPD_PORT_0].PE_PowerRole) && (1 == safety_contract)) { /* check if we are aligned with the limitation done by the SINK */ switch(safety_pdo.GenericPDO.PowerObject) { case USBPD_CORE_PDO_TYPE_FIXED : case USBPD_CORE_PDO_TYPE_VARIABLE : { _MaxOperatingCurrent = safety_rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits * 10; break; } #if defined(USBPD_REV30_SUPPORT) case USBPD_CORE_PDO_TYPE_APDO : { _MaxOperatingCurrent = safety_rdo.ProgRDO.OperatingCurrentIn50mAunits * 50; break; } #endif default : { } } } if(ABS(isense_safety[USBPD_PORT_0]) > (_MaxOperatingCurrent*1.1 +100)) { USBPD_PWR_IF_Alarm(); } #if USBPD_PORT_COUNT == 2 /* Monitor the current for the SNK power PORT1 */ isense_safety[USBPD_PORT_1] = BSP_PWR_VBUSGetCurrent(USBPD_PORT_1); /* check if we are aligned with the limitation done by the SINK */ if (ABS(isense_safety[USBPD_PORT_1]) > 1000) { USBPD_PWR_IF_Alarm(); } #endif osDelay(1); } } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/