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_
#define USER_BSP_PD_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_ */

View File

@@ -8,15 +8,5 @@
#include "BSP_PD.h"
#include "Model_Config.h"
#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

View File

@@ -8,19 +8,5 @@
#include "BSP_PD.h"
#include "Model_Config.h"
#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

View File

@@ -5,8 +5,10 @@
* Author: Ralim
*/
#include "BSP_PD.h"
#include "configuration.h"
#include "pd.h"
#include "policy_engine.h"
/* The current draw when the output is disabled */
#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 */
/* Look at the PDOs to see if one matches our desires */
// Look against USB_PD_Desired_Levels to select in order of preference
for (uint8_t desiredLevel = 0; desiredLevel < USB_PD_Desired_Levels_Len; desiredLevel++) {
for (uint8_t i = 0; i < numobj; i++) {
/* If we have a fixed PDO, its V equals our desired V, and its I is
* at least our desired I */
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
// This is a fixed PDO entry
int voltage = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i]));
int current = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]);
uint16_t desiredVoltage = USB_PD_Desired_Levels[(desiredLevel * 2) + 0];
uint16_t desiredminCurrent = USB_PD_Desired_Levels[(desiredLevel * 2) + 1];
// 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);
uint8_t bestIndex = 0xFF;
int bestIndexVoltage = 0;
int bestIndexCurrent = 0;
for (uint8_t i = 0; i < numobj; i++) {
/* If we have a fixed PDO, its V equals our desired V, and its I is
* at least our desired I */
if ((capabilities->obj[i] & PD_PDO_TYPE) == PD_PDO_TYPE_FIXED) {
// This is a fixed PDO entry
// Evaluate if it can produve sufficient current based on the tipResistance (ohms*10)
// V=I*R -> V/I => minimum resistance, if our tip resistance is >= this then we can use this supply
/* GiveBack disabled */
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);
// We support usb comms (ish)
request->obj[0] |= PD_RDO_USB_COMMS;
/* Update requested voltage */
_requested_voltage = voltage;
return true;
}
int voltage_mv = PD_PDV2MV(PD_PDO_SRC_FIXED_VOLTAGE_GET(capabilities->obj[i])); // voltage in mV units
int current_a_x100 = PD_PDO_SRC_FIXED_CURRENT_GET(capabilities->obj[i]); // current in 10mA units
int min_resistance_ohmsx10 = voltage_mv / current_a_x100;
if (min_resistance_ohmsx10 <= tipResistance) {
// This is a valid power source we can select as
if (bestIndex == 0xFF) {
// This is the first valid source, so select to be safe
bestIndex = i;
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 */
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;
/* GiveBack disabled */
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);
// We support usb comms (ish)
request->obj[0] |= PD_RDO_USB_COMMS;
/* Update requested voltage */
_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) {
@@ -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);
/* Get the current we want */
uint16_t current = USB_PD_Desired_Levels[1] / 10; // In centi-amps
uint16_t voltage = USB_PD_Desired_Levels[0]; // in mv
uint16_t voltage = USB_PD_VMAX * 1000; // in mv
if (_requested_voltage != 5000) {
voltage = _requested_voltage;
}
uint16_t current = (voltage) / tipResistance; // In centi-amps
/* 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);

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;
/* PD 3.0 collision avoidance */
// if (PolicyEngine::isPD3_0()) {
// /* If we're starting an AMS, wait for permission to transmit */
// evt = waitForEvent((uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS,
// 0);
// if ((uint32_t) evt
// & (uint32_t) Notifications::PDB_EVT_PRLTX_START_AMS) {
// while (fusb_get_typec_current() != fusb_sink_tx_ok) {
// osDelay(1);
// }
// }
// }
if (PolicyEngine::isPD3_0()) {
/* If we're starting an AMS, wait for permission to transmit */
ProtocolTransmit::Notifications evt = waitForEvent((uint32_t)Notifications::PDB_EVT_PRLTX_START_AMS, 0);
if ((uint32_t)evt & (uint32_t)Notifications::PDB_EVT_PRLTX_START_AMS) {
while (fusb_get_typec_current() != fusb_sink_tx_ok) {
osDelay(1);
}
}
}
messageSending = true;
/* Send the message to the PHY */
fusb_send_message(&temp_msg);