1
0
forked from me/IronOS

Clean up PD voltage selection for flexibility

This commit is contained in:
Ben V. Brown
2021-04-04 22:58:53 +10:00
parent 77fd9f6a2d
commit 5fd969ada7
5 changed files with 70 additions and 81 deletions

View File

@@ -8,9 +8,5 @@
#ifndef USER_BSP_PD_H_ #ifndef USER_BSP_PD_H_
#define USER_BSP_PD_H_ #define USER_BSP_PD_H_
#include "BSP.h" #include "BSP.h"
/*
* An array of all of the desired voltages & minimum currents in preferred order
*/
extern const uint16_t USB_PD_Desired_Levels[];
extern const uint8_t USB_PD_Desired_Levels_Len;
#endif /* USER_BSP_PD_H_ */ #endif /* USER_BSP_PD_H_ */

View File

@@ -8,15 +8,5 @@
#include "BSP_PD.h" #include "BSP_PD.h"
#include "Model_Config.h" #include "Model_Config.h"
#ifdef POW_PD #ifdef POW_PD
/*
* An array of all of the desired voltages & minimum currents in preferred order
*/
const uint16_t USB_PD_Desired_Levels[] = {
// mV desired input, mA minimum required current
12000, 2400, // 12V @ 2.4A
9000, 2000, // 9V @ 2A
5000, 100, // 5V @ whatever
};
const uint8_t USB_PD_Desired_Levels_Len = 3;
#endif #endif

View File

@@ -8,19 +8,5 @@
#include "BSP_PD.h" #include "BSP_PD.h"
#include "Model_Config.h" #include "Model_Config.h"
#ifdef POW_PD #ifdef POW_PD
/*
* An array of all of the desired voltages & minimum currents in preferred order
*/
const uint16_t USB_PD_Desired_Levels[] = {
// mV desired input, mA minimum required current
// Tip is ~ 7.5 ohms
20000, 2666, // 20V, 2.6A
18000, 2400, // 18V, 2.4A
15000, 2000, // 15V 2A
12000, 1600, // 12V @ 1.6A
9000, 1200, // 9V @ 1.2A
5000, 100, // 5V @ whatever
};
const uint8_t USB_PD_Desired_Levels_Len = 6;
#endif #endif

View File

@@ -5,8 +5,10 @@
* Author: Ralim * Author: Ralim
*/ */
#include "BSP_PD.h" #include "BSP_PD.h"
#include "configuration.h"
#include "pd.h" #include "pd.h"
#include "policy_engine.h" #include "policy_engine.h"
/* The current draw when the output is disabled */ /* The current draw when the output is disabled */
#define DPM_MIN_CURRENT PD_MA2PDI(50) #define DPM_MIN_CURRENT PD_MA2PDI(50)
/* /*
@@ -54,52 +56,65 @@ bool PolicyEngine::pdbs_dpm_evaluate_capability(const union pd_msg *capabilities
/* Make sure we have configuration */ /* Make sure we have configuration */
/* Look at the PDOs to see if one matches our desires */ /* Look at the PDOs to see if one matches our desires */
// Look against USB_PD_Desired_Levels to select in order of preference // Look against USB_PD_Desired_Levels to select in order of preference
for (uint8_t desiredLevel = 0; desiredLevel < USB_PD_Desired_Levels_Len; desiredLevel++) { uint8_t bestIndex = 0xFF;
for (uint8_t i = 0; i < numobj; i++) { int bestIndexVoltage = 0;
/* If we have a fixed PDO, its V equals our desired V, and its I is int bestIndexCurrent = 0;
* at least our desired I */ for (uint8_t i = 0; i < numobj; i++) {
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) { /* If we have a fixed PDO, its V equals our desired V, and its I is
// This is a fixed PDO entry * at least our desired I */
int voltage = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
int current = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); // This is a fixed PDO entry
uint16_t desiredVoltage = USB_PD_Desired_Levels[(desiredLevel * 2) + 0]; // Evaluate if it can produve sufficient current based on the tipResistance (ohms*10)
uint16_t desiredminCurrent = USB_PD_Desired_Levels[(desiredLevel * 2) + 1]; // V=I*R -> V/I => minimum resistance, if our tip resistance is >= this then we can use this supply
// As pd stores current in 10mA increments, divide by 10
desiredminCurrent /= 10;
if (voltage == desiredVoltage) {
if (current >= desiredminCurrent) {
/* We got what we wanted, so build a request for that */
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
/* GiveBack disabled */ int voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); // voltage in mV units
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(current) | PD_RDO_FV_CURRENT_SET(current) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1); int current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); // current in 10mA units
// We support usb comms (ish) int min_resistance_ohmsx10 = voltage_mv / current_a_x100;
request->obj[0] |= PD_RDO_USB_COMMS; if (min_resistance_ohmsx10 <= tipResistance) {
// This is a valid power source we can select as
/* Update requested voltage */ if (bestIndex == 0xFF) {
_requested_voltage = voltage; // This is the first valid source, so select to be safe
bestIndex = i;
return true; bestIndexVoltage = voltage_mv;
} bestIndexCurrent = current_a_x100;
} else if (voltage_mv > bestIndexVoltage) {
// Higher voltage and valid, select this instead
bestIndex = i;
bestIndexVoltage = voltage_mv;
bestIndexCurrent = current_a_x100;
} }
} }
} }
} }
if (bestIndex != 0xFF) {
/* We got what we wanted, so build a request for that */
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
/* Nothing matched (or no configuration), so get 5 V at low current */ /* GiveBack disabled */
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1); request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(bestIndexCurrent) | PD_RDO_FV_CURRENT_SET(bestIndexCurrent) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(bestIndex + 1);
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(1); // We support usb comms (ish)
/* If the output is enabled and we got here, it must be a capability request->obj[0] |= PD_RDO_USB_COMMS;
* mismatch. */
if (pdNegotiationComplete) { /* Update requested voltage */
request->obj[0] |= PD_RDO_CAP_MISMATCH; _requested_voltage = bestIndexVoltage;
return true;
} else {
/* Nothing matched (or no configuration), so get 5 V at low current */
request->hdr = hdr_template | PD_MSGTYPE_REQUEST | PD_NUMOBJ(1);
request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_FV_CURRENT_SET(DPM_MIN_CURRENT) | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(1);
/* If the output is enabled and we got here, it must be a capability
* mismatch. */
if (pdNegotiationComplete) {
request->obj[0] |= PD_RDO_CAP_MISMATCH;
}
request->obj[0] |= PD_RDO_USB_COMMS;
/* Update requested voltage */
_requested_voltage = 5000;
return false;
} }
request->obj[0] |= PD_RDO_USB_COMMS;
/* Update requested voltage */
_requested_voltage = 5000;
return false;
} }
void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) { void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
@@ -112,8 +127,12 @@ void PolicyEngine::pdbs_dpm_get_sink_capability(union pd_msg *cap) {
cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(5000)) | PD_PDO_SNK_FIXED_CURRENT_SET(DPM_MIN_CURRENT); cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(5000)) | PD_PDO_SNK_FIXED_CURRENT_SET(DPM_MIN_CURRENT);
/* Get the current we want */ /* Get the current we want */
uint16_t current = USB_PD_Desired_Levels[1] / 10; // In centi-amps uint16_t voltage = USB_PD_VMAX * 1000; // in mv
uint16_t voltage = USB_PD_Desired_Levels[0]; // in mv if (_requested_voltage != 5000) {
voltage = _requested_voltage;
}
uint16_t current = (voltage) / tipResistance; // In centi-amps
/* Add a PDO for the desired power. */ /* Add a PDO for the desired power. */
cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(voltage)) | PD_PDO_SNK_FIXED_CURRENT_SET(current); cap->obj[numobj++] = PD_PDO_TYPE_FIXED | PD_PDO_SNK_FIXED_VOLTAGE_SET(PD_MV2PDV(voltage)) | PD_PDO_SNK_FIXED_CURRENT_SET(current);

View File

@@ -104,17 +104,15 @@ ProtocolTransmit::protocol_tx_state ProtocolTransmit::protocol_tx_construct_mess
temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT; temp_msg.hdr |= (_tx_messageidcounter % 8) << PD_HDR_MESSAGEID_SHIFT;
/* PD 3.0 collision avoidance */ /* PD 3.0 collision avoidance */
// if (PolicyEngine::isPD3_0()) { if (PolicyEngine::isPD3_0()) {
// /* If we're starting an AMS, wait for permission to transmit */ /* If we're starting an AMS, wait for permission to transmit */
// evt = waitForEvent((uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS, ProtocolTransmit::Notifications evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PRLTX_START_AMS, 0);
// 0); if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_START_AMS) {
// if ((uint32_t) evt while (fusb_get_typec_current() != fusb_sink_tx_ok) {
// & (uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS) { osDelay(1);
// while (fusb_get_typec_current() != fusb_sink_tx_ok) { }
// osDelay(1); }
// } }
// }
// }
messageSending = true; messageSending = true;
/* Send the message to the PHY */ /* Send the message to the PHY */
fusb_send_message(&temp_msg); fusb_send_message(&temp_msg);