started work on PD negotiation
This commit is contained in:
parent
a38c71674b
commit
8adfe875cd
39
fw/main.c
39
fw/main.c
@ -3,6 +3,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fsusb.h>
|
#include <fsusb.h>
|
||||||
|
|
||||||
|
#define USBPD_IMPLEMENTATION
|
||||||
|
#include "usbpd.h"
|
||||||
|
|
||||||
#include "lib_i2c.h"
|
#include "lib_i2c.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
@ -322,6 +325,39 @@ __attribute__((noreturn)) int main(void)
|
|||||||
|
|
||||||
u8g2 = display_init();
|
u8g2 = display_init();
|
||||||
|
|
||||||
|
// Init USBPD
|
||||||
|
USBPD_VCC_e vcc = eUSBPD_VCC_3V3;
|
||||||
|
USBPD_Result_e result = USBPD_Init(vcc);
|
||||||
|
if (result != eUSBPD_OK) {
|
||||||
|
printf("USBPD_Init failed: %d\n", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// USBPD_Reset();
|
||||||
|
bool has_pd = false;
|
||||||
|
u32 start = funSysTick32();
|
||||||
|
while (eUSBPD_BUSY == (result = USBPD_SinkNegotiate())) {
|
||||||
|
u32 now = funSysTick32();
|
||||||
|
if (now - start > Ticks_from_Ms(10000)) {
|
||||||
|
printf("USBPD_SinkNegotiate timed out\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8g2_ClearBuffer(u8g2);
|
||||||
|
u8g2_SetBitmapMode(u8g2, 1);
|
||||||
|
u8g2_SetFontMode(u8g2, 1);
|
||||||
|
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
|
||||||
|
u8g2_DrawStr(u8g2, 0, 18, "waiting...");
|
||||||
|
u8g2_SendBuffer(u8g2);
|
||||||
|
}
|
||||||
|
if (result != eUSBPD_OK) {
|
||||||
|
printf("USBPD_SinkNegotiate failed: %s, state: %s\n",
|
||||||
|
USBPD_ResultToStr(result),
|
||||||
|
USBPD_StateToStr(USBPD_GetState())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
has_pd = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
static uint16_t tip_mv, vbus_mv, current_ma;
|
static uint16_t tip_mv, vbus_mv, current_ma;
|
||||||
static int16_t temp_k;
|
static int16_t temp_k;
|
||||||
@ -350,6 +386,9 @@ __attribute__((noreturn)) int main(void)
|
|||||||
u8g2_DrawStr(u8g2, x_off+25, y_off+15, u8x8_u16toa(vbus_mv, 4));
|
u8g2_DrawStr(u8g2, x_off+25, y_off+15, u8x8_u16toa(vbus_mv, 4));
|
||||||
u8g2_DrawStr(u8g2, x_off+51, y_off+7, "TEMP:");
|
u8g2_DrawStr(u8g2, x_off+51, y_off+7, "TEMP:");
|
||||||
u8g2_DrawStr(u8g2, x_off+75, y_off+7, u8x8_u16toa(temp_k, 2));
|
u8g2_DrawStr(u8g2, x_off+75, y_off+7, u8x8_u16toa(temp_k, 2));
|
||||||
|
u8g2_DrawStr(u8g2, x_off+51, y_off+15, "PD:");
|
||||||
|
u8g2_DrawStr(u8g2, x_off+65, y_off+15, has_pd ? "YES" : "NO");
|
||||||
|
|
||||||
u8g2_SendBuffer(u8g2);
|
u8g2_SendBuffer(u8g2);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
937
fw/usbpd.h
Normal file
937
fw/usbpd.h
Normal file
@ -0,0 +1,937 @@
|
|||||||
|
/* USB PD Library
|
||||||
|
* 2025-06-21 Bogdan Ionescu
|
||||||
|
* Configuration:
|
||||||
|
* - USBPD_IMPLEMENTATION: Enable USB PD implementation
|
||||||
|
* - FUNCONF_USBPD_NO_STR: Disable string conversion functions
|
||||||
|
* Notes:
|
||||||
|
* - This library is based on the USB Power Delivery Specification.
|
||||||
|
* https://www.usb.org/document-library/usb-power-delivery
|
||||||
|
* - Packed bitfield structs are used for de/serialization of USB PD messages and
|
||||||
|
* are taken directly from the spec above.
|
||||||
|
* - Not all messages are implemented.
|
||||||
|
* - Formatting macros are provided next to the struct deffinitions.
|
||||||
|
* Basic usage:
|
||||||
|
* USBPD_VCC_e vcc = eUSBPD_VCC_5V0; // set the VCC voltage
|
||||||
|
* USBPD_Result_e result = USBPD_Init( vcc ); // initialize the peripheral
|
||||||
|
*
|
||||||
|
* // wait for negotiation to complete.
|
||||||
|
* while ( eUSBPD_BUSY == ( result = USBPD_SinkNegotiate() ) );
|
||||||
|
*
|
||||||
|
* USBPD_SPR_CapabilitiesMessage_t *capabilities;
|
||||||
|
* const size_t count = USBPD_GetCapabilities( &capabilities );
|
||||||
|
* USBPD_SelectPDO( count - 1, voltage ); // select the last supply (voltage is only used for PPS)
|
||||||
|
*
|
||||||
|
* The above is not a complete example, check the funtion declarations below for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "funconfig.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifndef PACKED
|
||||||
|
#define PACKED __attribute__( ( packed ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// USB PD spec type definitions
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_PORTDATAROLE_DFP = 0, // Downstream Facing Port
|
||||||
|
eUSBPD_PORTDATAROLE_UFP = 1, // Upstream Facing Port
|
||||||
|
} USBPD_PortDataRole_e;
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_PORTPOWEROLE_SINK = 0, // Sink Power Role
|
||||||
|
eUSBPD_PORTPOWEROLE_SOURCE = 1, // Source Power Role
|
||||||
|
} USBPD_PortPowerRole_e;
|
||||||
|
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_REV_10 = 0x00u, // Revision 1.0
|
||||||
|
eUSBPD_REV_20 = 0x01u, // Revision 2.0
|
||||||
|
eUSBPD_REV_30 = 0x02u, // Revision 3.0
|
||||||
|
} USBPD_SpecificationRevision_e;
|
||||||
|
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_CTRL_MSG_GOODCRC = 0x01u,
|
||||||
|
eUSBPD_CTRL_MSG_GOTOMIN = 0x02u, // Depracated
|
||||||
|
eUSBPD_CTRL_MSG_ACCEPT = 0x03u,
|
||||||
|
eUSBPD_CTRL_MSG_REJECT = 0x04u,
|
||||||
|
eUSBPD_CTRL_MSG_PING = 0x05u, // Deprecated
|
||||||
|
eUSBPD_CTRL_MSG_PS_RDY = 0x06u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_SOURCE_CAP = 0x07u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_SINK_CAP = 0x08u,
|
||||||
|
eUSBPD_CTRL_MSG_DR_SWAP = 0x09u,
|
||||||
|
eUSBPD_CTRL_MSG_PR_SWAP = 0x0Au,
|
||||||
|
eUSBPD_CTRL_MSG_VCONN_SWAP = 0x0Bu,
|
||||||
|
eUSBPD_CTRL_MSG_WAIT = 0x0Cu,
|
||||||
|
eUSBPD_CTRL_MSG_SOFT_RESET = 0x0Du,
|
||||||
|
eUSBPD_CTRL_MSG_DATA_RESET = 0x0Eu,
|
||||||
|
eUSBPD_CTRL_MSG_DATA_RESET_COMPLETE = 0x0Fu,
|
||||||
|
eUSBPD_CTRL_MSG_NOT_SUPPORTED = 0x10u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_SOURCE_CAPEXT = 0x11u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_STATUS = 0x12u,
|
||||||
|
eUSBPD_CTRL_MSG_FR_SWAP = 0x13u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_PPS_STATUS = 0x14u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_COUNTRY_CODES = 0x15u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_SINK_CAPEXT = 0x16u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_SOURCE_INFO = 0x17u,
|
||||||
|
eUSBPD_CTRL_MSG_GET_REVISION = 0x18u,
|
||||||
|
} USBPD_ControlMessage_e;
|
||||||
|
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_DATA_MSG_SOURCE_CAP = 0x01u,
|
||||||
|
eUSBPD_DATA_MSG_REQUEST = 0x02u,
|
||||||
|
eUSBPD_DATA_MSG_BIST = 0x03u,
|
||||||
|
eUSBPD_DATA_MSG_SINK_CAP = 0x04u,
|
||||||
|
eUSBPD_DATA_MSG_BATTERY_STATUS = 0x05u,
|
||||||
|
eUSBPD_DATA_MSG_ALERT = 0x06u,
|
||||||
|
eUSBPD_DATA_MSG_GET_COUNTRY_INFO = 0x07u,
|
||||||
|
eUSBPD_DATA_MSG_ENTER_USB = 0x08u,
|
||||||
|
eUSBPD_DATA_MSG_EPR_REUEST = 0x09u,
|
||||||
|
eUSBPD_DATA_MSG_EPR_MODE = 0x0Au,
|
||||||
|
eUSBPD_DATA_MSG_SOURCE_INFO = 0x0Bu,
|
||||||
|
eUSBPD_DATA_MSG_REVISION = 0x0Cu,
|
||||||
|
eUSBPD_DATA_MSG_VENDOR_DEFINED = 0x0Fu
|
||||||
|
} USBPD_DataMessage_e;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
uint16_t data;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t MessageType : 5u; // USBPD_ControlMessage_t | USBPD_DataMessage_t
|
||||||
|
USBPD_PortDataRole_e PortDataRole : 1u;
|
||||||
|
USBPD_SpecificationRevision_e SpecificationRevision : 2u;
|
||||||
|
USBPD_PortPowerRole_e PortPowerRole : 1u;
|
||||||
|
uint16_t MessageID : 3u;
|
||||||
|
uint16_t NumberOfDataObjects : 3u; // 0: Control Message, >0: Data Message
|
||||||
|
uint16_t Extended : 1u;
|
||||||
|
};
|
||||||
|
} USBPD_MessageHeader_t;
|
||||||
|
|
||||||
|
typedef USBPD_MessageHeader_t USBPD_ControlMessage_t;
|
||||||
|
static_assert( sizeof( USBPD_MessageHeader_t ) == sizeof( uint16_t ), "USBPD_MessageHeader_t size mismatch" );
|
||||||
|
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_PDO_FIXED = 0,
|
||||||
|
eUSBPD_PDO_BATTERY = 1,
|
||||||
|
eUSBPD_PDO_VARIABLE = 2,
|
||||||
|
eUSBPD_PDO_AUGMENTED = 3,
|
||||||
|
} USBPD_PowerDataObject_e;
|
||||||
|
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_APDO_SPR_PPS = 0, // Standard Power Range Programmable Power Supply
|
||||||
|
eUSBPD_APDO_EPR_AVS = 1, // Extended Power Range Adjustable Voltage Supply
|
||||||
|
eUSBPD_APDO_SPR_AVS = 2, // Standard Power Range Adjustable Voltage Supply
|
||||||
|
eUSBPD_APDO_RESERVED = 3,
|
||||||
|
} USBPD_AugmentedPDO_e;
|
||||||
|
|
||||||
|
typedef enum PACKED
|
||||||
|
{
|
||||||
|
eUSBPD_PEAK_CURRENT_0 = 0, /* Peak Current equals IoC */
|
||||||
|
|
||||||
|
eUSBPD_PEAK_CURRENT_1 = 1, /* 150% IoC for 1ms @ 5% duty cycle
|
||||||
|
125% IoC for 2ms @ 10% duty cycle
|
||||||
|
110% IoC for 10ms @ 50% duty cycle */
|
||||||
|
|
||||||
|
eUSBPD_PEAK_CURRENT_2 = 2, /* 200% IoC for 1ms @ 5% duty cycle
|
||||||
|
150% IoC for 2ms @ 10% duty cycle
|
||||||
|
125% IoC for 10ms @ 50% duty cycle */
|
||||||
|
|
||||||
|
eUSBPD_PEAK_CURRENT_3 = 3, /* 200% IoC for 1ms @ 5% duty cycle
|
||||||
|
175% IoC for 2ms @ 10% duty cycle
|
||||||
|
150% IoC for 10ms @ 50% duty cycle */
|
||||||
|
} USBPD_PeakCurrent_e;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t data : 28u; // PDO specific data based on PDO type
|
||||||
|
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_SPR_PPS
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
|
||||||
|
} USBPD_PDOHeader_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxCurrentIn10mA : 10u;
|
||||||
|
uint32_t VoltageIn50mV : 10u;
|
||||||
|
USBPD_PeakCurrent_e PeakCurrent : 2u;
|
||||||
|
uint32_t Reserved_22bit : 1u;
|
||||||
|
uint32_t EPRModeCapable : 1u;
|
||||||
|
uint32_t UnchunkedExtendedMessage : 1u;
|
||||||
|
uint32_t DualRoleData : 1u;
|
||||||
|
uint32_t USBCommunicationsCapable : 1u;
|
||||||
|
uint32_t UnconstrainedPower : 1u;
|
||||||
|
uint32_t USBSuspendSupported : 1u;
|
||||||
|
uint32_t DualRolePower : 1u;
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_FIXED
|
||||||
|
} USBPD_SourceFixedSupplyPDO_t;
|
||||||
|
|
||||||
|
#define FIXED_SUPPLY_FMT \
|
||||||
|
"\nFixed Supply:\n" \
|
||||||
|
"\tMax Current: %d mA\n" \
|
||||||
|
"\tVoltage: %d mV\n" \
|
||||||
|
"\tPeak Current: %d\n" \
|
||||||
|
"\tEPR Mode Capable: %s\n" \
|
||||||
|
"\tUnchunked Extended Message: %s\n" \
|
||||||
|
"\tDual Role Data: %s\n" \
|
||||||
|
"\tUSB Communications Capable: %s\n" \
|
||||||
|
"\tUnconstrained Power: %s\n" \
|
||||||
|
"\tUSB Suspend Supported: %s\n" \
|
||||||
|
"\tDual Role Power: %s\n"
|
||||||
|
|
||||||
|
#define FIXED_SUPPLY_FMT_ARGS( pdo ) \
|
||||||
|
( ( pdo )->FixedSupply.MaxCurrentIn10mA * 10 ), ( ( pdo )->FixedSupply.VoltageIn50mV * 50 ), \
|
||||||
|
( ( pdo )->FixedSupply.PeakCurrent ), ( ( pdo )->FixedSupply.EPRModeCapable ? "Yes" : "No" ), \
|
||||||
|
( ( pdo )->FixedSupply.UnchunkedExtendedMessage ? "Yes" : "No" ), \
|
||||||
|
( ( pdo )->FixedSupply.DualRoleData ? "Yes" : "No" ), \
|
||||||
|
( ( pdo )->FixedSupply.USBCommunicationsCapable ? "Yes" : "No" ), \
|
||||||
|
( ( pdo )->FixedSupply.UnconstrainedPower ? "Yes" : "No" ), \
|
||||||
|
( ( pdo )->FixedSupply.USBSuspendSupported ? "Yes" : "No" ), \
|
||||||
|
( ( pdo )->FixedSupply.DualRolePower ? "Yes" : "No" )
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxCurrentIn10mA : 10u;
|
||||||
|
uint32_t MinVoltageIn50mV : 10u;
|
||||||
|
uint32_t MaxVoltageIn50mV : 10u;
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_VARIABLE
|
||||||
|
} USBPD_VariablePDO_t;
|
||||||
|
|
||||||
|
#define VARIABLE_SUPPLY_FMT \
|
||||||
|
"\nVariable Supply:\n" \
|
||||||
|
"\tMax Current: %d mA\n" \
|
||||||
|
"\tMin Voltage: %d mV\n" \
|
||||||
|
"\tMax Voltage: %d mV\n"
|
||||||
|
|
||||||
|
#define VARIABLE_SUPPLY_FMT_ARGS( pdo ) \
|
||||||
|
( ( pdo )->VariableSupply.MaxCurrentIn10mA * 10 ), ( ( pdo )->VariableSupply.MinVoltageIn50mV * 50 ), \
|
||||||
|
( ( pdo )->VariableSupply.MaxVoltageIn50mV * 50 )
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxPowerIn250mW : 10u;
|
||||||
|
uint32_t MinVoltageIn50mV : 10u;
|
||||||
|
uint32_t MaxVoltageIn50mV : 10u;
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_BATTERY
|
||||||
|
} USBPD_BatteryPDO_t;
|
||||||
|
|
||||||
|
#define BATTERY_SUPPLY_FMT \
|
||||||
|
"\nBattery Supply:\n" \
|
||||||
|
"\tMax Power: %d mW\n" \
|
||||||
|
"\tMin Voltage: %d mV\n" \
|
||||||
|
"\tMax Voltage: %d mV\n"
|
||||||
|
|
||||||
|
#define BATTERY_SUPPLY_FMT_ARGS( pdo ) \
|
||||||
|
( ( pdo )->BatterySupply.MaxPowerIn250mW * 250 ), ( ( pdo )->BatterySupply.MinVoltageIn50mV * 50 ), \
|
||||||
|
( ( pdo )->BatterySupply.MaxVoltageIn50mV * 50 )
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxCurrentIn50mA : 7u;
|
||||||
|
uint32_t Reserved_7bit : 1u; // shall be set to zero
|
||||||
|
uint32_t MinVoltageIn100mV : 8u;
|
||||||
|
uint32_t Reserved_16bit : 1u; // shall be set to zero
|
||||||
|
uint32_t MaxVoltageIn100mV : 8u;
|
||||||
|
uint32_t Reserved_25_26bit : 2u; // shall be set to zero
|
||||||
|
uint32_t PPSpowerLimited : 1u;
|
||||||
|
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_SPR_PPS
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
|
||||||
|
} USBPD_SPR_PPS_APDO_t;
|
||||||
|
|
||||||
|
#define SPR_PPS_FMT \
|
||||||
|
"\nPPS Supply:\n" \
|
||||||
|
"\tMax Current: %d mA\n" \
|
||||||
|
"\tMin Voltage: %d mV\n" \
|
||||||
|
"\tMax Voltage: %d mV\n" \
|
||||||
|
"\tPPS Power Limited: %s\n"
|
||||||
|
|
||||||
|
#define SPR_PPS_FMT_ARGS( pdo ) \
|
||||||
|
( ( pdo )->SPR_PPS.MaxCurrentIn50mA * 50 ), ( ( pdo )->SPR_PPS.MinVoltageIn100mV * 100 ), \
|
||||||
|
( ( pdo )->SPR_PPS.MaxVoltageIn100mV * 100 ), ( ( pdo )->SPR_PPS.PPSpowerLimited ? "Yes" : "No" )
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t PDPIn1W : 8u;
|
||||||
|
uint32_t MinVoltageIn100mV : 8u;
|
||||||
|
uint32_t Reserved_16bit : 1u; // shall be set to zero
|
||||||
|
uint32_t MaxVoltageIn100mV : 9u;
|
||||||
|
USBPD_PeakCurrent_e PeakCurrent : 2u;
|
||||||
|
|
||||||
|
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_EPR_AVS
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
|
||||||
|
} USBPD_EPR_AVS_APDO_t;
|
||||||
|
|
||||||
|
#define EPR_AVS_FMT \
|
||||||
|
"\nEPR AVS Supply:\n" \
|
||||||
|
"\tPDP: %d W\n" \
|
||||||
|
"\tMin Voltage: %d mV\n" \
|
||||||
|
"\tMax Voltage: %d mV\n" \
|
||||||
|
"\tPeak Current: %d\n"
|
||||||
|
|
||||||
|
#define EPR_AVS_FMT_ARGS( pdo ) \
|
||||||
|
( ( pdo )->EPR_AVS.PDPIn1W ), ( ( pdo )->EPR_AVS.MinVoltageIn100mV * 100 ), \
|
||||||
|
( ( pdo )->EPR_AVS.MaxVoltageIn100mV * 100 ), ( ( pdo )->EPR_AVS.PeakCurrent )
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxCurrent15To20VIn10mA : 10u;
|
||||||
|
uint32_t MaxCurrent9to15VIn10mA : 10u;
|
||||||
|
uint32_t Reserved_20_25bit : 6u; // shall be set to zero
|
||||||
|
USBPD_PeakCurrent_e PeakCurrent : 2u;
|
||||||
|
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_SPR_AVS
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
|
||||||
|
} USBPD_SPR_AVS_APDO_t;
|
||||||
|
|
||||||
|
#define SPR_AVS_FMT \
|
||||||
|
"\nSPR AVS Supply:\n" \
|
||||||
|
"\tMax Current 15-20V: %d mA\n" \
|
||||||
|
"\tMax Current 9-15V: %d mA\n" \
|
||||||
|
"\tPeak Current: %d\n"
|
||||||
|
|
||||||
|
#define SPR_AVS_FMT_ARGS( pdo ) \
|
||||||
|
( ( pdo )->SPR_AVS.MaxCurrent15To20VIn10mA * 10 ), ( ( pdo )->SPR_AVS.MaxCurrent9to15VIn10mA * 10 ), \
|
||||||
|
( ( pdo )->SPR_AVS.PeakCurrent )
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
USBPD_PDOHeader_t Header;
|
||||||
|
USBPD_SourceFixedSupplyPDO_t FixedSupply;
|
||||||
|
USBPD_VariablePDO_t VariableSupply;
|
||||||
|
USBPD_BatteryPDO_t BatterySupply;
|
||||||
|
USBPD_SPR_PPS_APDO_t SPR_PPS;
|
||||||
|
USBPD_EPR_AVS_APDO_t EPR_AVS;
|
||||||
|
USBPD_SPR_AVS_APDO_t SPR_AVS;
|
||||||
|
} USBPD_SourcePDO_t;
|
||||||
|
|
||||||
|
static_assert( sizeof( USBPD_SourcePDO_t ) == sizeof( uint32_t ), "USBPD_SourcePDO_t size mismatch" );
|
||||||
|
|
||||||
|
typedef enum // Do not PACK, messes up alignment
|
||||||
|
{
|
||||||
|
eUSBPD_FAST_ROLE_SWAP_NOT_SUPPORTED = 0,
|
||||||
|
eUSBPD_FAST_ROLE_SWAP_DEFAULT = 1,
|
||||||
|
eUSBPD_FAST_ROLE_SWAP_1A5 = 2, // 1.5A @ 5V
|
||||||
|
eUSBPD_FAST_ROLE_SWAP_3A = 3, // 3A @ 5V
|
||||||
|
} USBPD_FastRoleSwapRequiredCurrent_e;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t CurrentIn10mA : 10u;
|
||||||
|
uint32_t VoltageIn50mV : 10u;
|
||||||
|
uint32_t Reserved_20_22bit : 3u; // shall be set to zero
|
||||||
|
USBPD_FastRoleSwapRequiredCurrent_e FastRoleSwap : 2u;
|
||||||
|
uint32_t DualRoleData : 1u;
|
||||||
|
uint32_t USBComsCapable : 1u;
|
||||||
|
uint32_t UnconstrainedPower : 1u;
|
||||||
|
uint32_t HigherCapability : 1u;
|
||||||
|
uint32_t DualRolePower : 1u;
|
||||||
|
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_FIXED
|
||||||
|
} USBPD_SinkFixedSupplyPDO_t;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
USBPD_PDOHeader_t Header;
|
||||||
|
USBPD_SinkFixedSupplyPDO_t FixedSupply;
|
||||||
|
USBPD_VariablePDO_t VariableSupply;
|
||||||
|
USBPD_BatteryPDO_t BatterySupply;
|
||||||
|
USBPD_SPR_PPS_APDO_t SPR_PPS;
|
||||||
|
USBPD_EPR_AVS_APDO_t EPR_AVS;
|
||||||
|
USBPD_SPR_AVS_APDO_t SPR_AVS;
|
||||||
|
} USBPD_SinkPDO_t;
|
||||||
|
|
||||||
|
static_assert( sizeof( USBPD_SourcePDO_t ) == sizeof( uint32_t ), "USBPD_SourcePDO_t size mismatch" );
|
||||||
|
static_assert( sizeof( USBPD_SinkPDO_t ) == sizeof( uint32_t ), "USBPD_SinkPDO_t size mismatch" );
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
USBPD_SourcePDO_t Source[7];
|
||||||
|
USBPD_SinkPDO_t Sink[7];
|
||||||
|
} USBPD_SPR_CapabilitiesMessage_t;
|
||||||
|
|
||||||
|
static_assert( sizeof( USBPD_SPR_CapabilitiesMessage_t ) == ( 7 * sizeof( uint32_t ) ),
|
||||||
|
"USBPD_SPR_CapabilitiesMessage_t size mismatch" );
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxCurrentIn10mA : 10u;
|
||||||
|
uint32_t OperatingCurrentIn10mA : 10u;
|
||||||
|
uint32_t Reserved_20_21bit : 2u; // shall be set to zero
|
||||||
|
uint32_t ERPCapable : 1u;
|
||||||
|
uint32_t UnchunkedExtendedMessage : 1u;
|
||||||
|
uint32_t NoUSBSuspended : 1u;
|
||||||
|
uint32_t USBComsCapable : 1u;
|
||||||
|
uint32_t CapabilityMissmatch : 1u;
|
||||||
|
uint32_t Giveback : 1u; // Deprecated, shall be set to zero
|
||||||
|
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
|
||||||
|
} USBPD_FixedAndVariableRDO_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t MaxPowerIn250mW : 10u;
|
||||||
|
uint32_t OperatingPowerIn250mW : 10u;
|
||||||
|
uint32_t Reserved_20_21bit : 2u; // shall be set to zero
|
||||||
|
uint32_t ERPCapable : 1u;
|
||||||
|
uint32_t UnchunkedExtendedMessage : 1u;
|
||||||
|
uint32_t NoUSBSuspended : 1u;
|
||||||
|
uint32_t USBComsCapable : 1u;
|
||||||
|
uint32_t CapabilityMissmatch : 1u;
|
||||||
|
uint32_t Giveback : 1u; // Deprecated, shall be set to zero
|
||||||
|
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
|
||||||
|
} USBPD_BatteryRDO_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t OperatingCurrentIn50mA : 7u;
|
||||||
|
uint32_t Reserved_7_8bit : 2u; // shall be set to zero
|
||||||
|
uint32_t OutputVoltageIn20mV : 12u;
|
||||||
|
uint32_t Reserved_21bit : 1u; // shall be set to zero
|
||||||
|
uint32_t ERPCapable : 1u;
|
||||||
|
uint32_t UnchunkedExtendedMessage : 1u;
|
||||||
|
uint32_t NoUSBSuspended : 1u;
|
||||||
|
uint32_t USBComsCapable : 1u;
|
||||||
|
uint32_t CapabilityMissmatch : 1u;
|
||||||
|
uint32_t Reserved_27bit : 1u; // Deprecated, shall be set to zero
|
||||||
|
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
|
||||||
|
} USBPD_PPS_RDO_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t OperatingCurrentIn50mA : 7u;
|
||||||
|
uint32_t Reserved_7_8bit : 2u; // shall be set to zero
|
||||||
|
uint32_t OutputVoltageIn100mV : 12u; // NOTE: Output voltage in 25mV units, the least two significant bits Shall
|
||||||
|
// be set to zero making the effective voltage step size 100mV.
|
||||||
|
uint32_t Reserved_21bit : 1u; // shall be set to zero
|
||||||
|
uint32_t ERPCapable : 1u;
|
||||||
|
uint32_t UnchunkedExtendedMessage : 1u;
|
||||||
|
uint32_t NoUSBSuspended : 1u;
|
||||||
|
uint32_t USBComsCapable : 1u;
|
||||||
|
uint32_t CapabilityMissmatch : 1u;
|
||||||
|
uint32_t Reserved_27bit : 1u; // Deprecated, shall be set to zero
|
||||||
|
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
|
||||||
|
} USBPD_AVS_RDO_t;
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
USBPD_FixedAndVariableRDO_t FixedAndVariable;
|
||||||
|
USBPD_BatteryRDO_t Battery;
|
||||||
|
USBPD_PPS_RDO_t PPS;
|
||||||
|
} USBPD_RequestDataObject_t;
|
||||||
|
|
||||||
|
static_assert( sizeof( USBPD_RequestDataObject_t ) == sizeof( uint32_t ), "USBPD_RequestDataObject_t size mismatch" );
|
||||||
|
|
||||||
|
// TODO: Define the rest of the message types sections 6.4.3 -> 6.5.16
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eUSBPD_MAX_EXTENDED_MSG_LEN = 260,
|
||||||
|
eUSBPD_MAX_EXTENDED_MSG_CHUNK_LEN = 26,
|
||||||
|
eUSBPD_MAX_EXTENDED_MSG_LEGACY_LEN = 26,
|
||||||
|
} USBPD_ValueParameters_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eUSBPD_OK = 0,
|
||||||
|
eUSBPD_BUSY,
|
||||||
|
eUSBPD_ERROR,
|
||||||
|
eUSBPD_ERROR_ARGS,
|
||||||
|
eUSBPD_ERROR_NOT_SUPPORTED,
|
||||||
|
eUSBPD_ERROR_TIMEOUT,
|
||||||
|
} USBPD_Result_e;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eUSBPD_VCC_3V3 = 0,
|
||||||
|
eUSBPD_VCC_5V0 = 1,
|
||||||
|
} USBPD_VCC_e;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eUSBPD_CCNONE = 0,
|
||||||
|
eUSBPD_CC1 = 1,
|
||||||
|
eUSBPD_CC2 = 2,
|
||||||
|
} USBPD_CC_e;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
eSTATE_IDLE,
|
||||||
|
eSTATE_CABLE_DETECT,
|
||||||
|
eSTATE_SOURCE_CAP,
|
||||||
|
eSTATE_WAIT_ACCEPT,
|
||||||
|
eSTATE_WAIT_PS_RDY,
|
||||||
|
eSTATE_PS_RDY,
|
||||||
|
eSTATE_MAX,
|
||||||
|
} USBPD_State_e;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the USB PD module
|
||||||
|
* @param vcc: VCC voltage level (3.3V or 5V)
|
||||||
|
* @return USBPD_Result_e
|
||||||
|
*/
|
||||||
|
USBPD_Result_e USBPD_Init( USBPD_VCC_e vcc );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Negotiate with the USB PD Source, must be called periodically
|
||||||
|
* @param None
|
||||||
|
* @return USBPD_BUSY if negotiation is in progress, eUSBPD_OK if successful, or an error code
|
||||||
|
*/
|
||||||
|
USBPD_Result_e USBPD_SinkNegotiate( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the USB PD module
|
||||||
|
* @param None
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void USBPD_Reset( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the current state of the USB PD module
|
||||||
|
* @param None
|
||||||
|
* @return USBPD_State_e representing the current state of the module
|
||||||
|
*/
|
||||||
|
USBPD_State_e USBPD_GetState( void );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert USB PD state to string
|
||||||
|
* @param state: USBPD_State_e to convert
|
||||||
|
* @return Pointer to a string representing the state
|
||||||
|
*/
|
||||||
|
const char *USBPD_StateToStr( USBPD_State_e state );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert USB PD result to string
|
||||||
|
* @param result: USBPD_Result_e to convert
|
||||||
|
* @return Pointer to a string representing the result
|
||||||
|
*/
|
||||||
|
const char *USBPD_ResultToStr( USBPD_Result_e result );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select a new Power Data Object (PDO) to be used. No re-negotiation is needed.
|
||||||
|
* @param index: Index of the PDO to select (0-based)
|
||||||
|
* @param voltageIn100mV: Desired output voltage in 100mV units (e.g., 500 for 5V) (only applicable for PPS)
|
||||||
|
* @return USBPD_Result_e
|
||||||
|
*/
|
||||||
|
USBPD_Result_e USBPD_SelectPDO( uint8_t index, uint32_t voltageIn100mV );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the capabilities of the USB PD Source
|
||||||
|
* @param[out] capabilities: Pointer to a pointer where the capabilities message structure is stored
|
||||||
|
* @return Number of Power Data Objects (PDOs) in the capabilities message
|
||||||
|
*/
|
||||||
|
size_t USBPD_GetCapabilities( USBPD_SPR_CapabilitiesMessage_t **capabilities );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if the Power Data Object is a Programmable Power Supply (PPS)
|
||||||
|
* @param[in] pdo: Pointer to the Power Data Object to check
|
||||||
|
* @return true if the PDO is a PPS, false otherwise
|
||||||
|
*/
|
||||||
|
bool USBPD_IsPPS( const USBPD_SourcePDO_t *pdo );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the USB PD Specification Revision
|
||||||
|
* @param None
|
||||||
|
* @return USBPD_SpecificationRevision_e representing the USB PD specification revision
|
||||||
|
*/
|
||||||
|
USBPD_SpecificationRevision_e USBPD_GetVersion( void );
|
||||||
|
|
||||||
|
#if defined( USBPD_IMPLEMENTATION )
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t ccCount;
|
||||||
|
volatile USBPD_State_e state;
|
||||||
|
USBPD_SpecificationRevision_e pdVersion;
|
||||||
|
USBPD_CC_e lastCCLine;
|
||||||
|
USBPD_SPR_CapabilitiesMessage_t caps;
|
||||||
|
uint8_t messageID;
|
||||||
|
uint8_t pdoCount;
|
||||||
|
bool gotSourceGoodCRC;
|
||||||
|
} USBPD_Instance_t;
|
||||||
|
|
||||||
|
static __attribute__( ( aligned( 4 ) ) ) uint8_t s_buffer[34];
|
||||||
|
static USBPD_Instance_t s_instance = {
|
||||||
|
.pdVersion = eUSBPD_REV_30,
|
||||||
|
};
|
||||||
|
|
||||||
|
static USBPD_CC_e GetActiveCCLine( void );
|
||||||
|
static void SwitchRXMode( void );
|
||||||
|
static void SendMessage( uint8_t size );
|
||||||
|
static void ParsePacket( void );
|
||||||
|
|
||||||
|
USBPD_Result_e USBPD_Init( USBPD_VCC_e vcc )
|
||||||
|
{
|
||||||
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
|
||||||
|
RCC->AHBPCENR |= RCC_USBPD;
|
||||||
|
|
||||||
|
GPIOC->CFGHR &= ~( 0xf << ( ( 14 & 7 ) << 2 ) );
|
||||||
|
GPIOC->CFGHR |= ( GPIO_Speed_10MHz | GPIO_CNF_OUT_OD ) << ( ( 14 & 7 ) << 2 );
|
||||||
|
GPIOC->CFGHR &= ~( 0xf << ( ( 15 & 7 ) << 2 ) );
|
||||||
|
GPIOC->CFGHR |= ( GPIO_Speed_10MHz | GPIO_CNF_OUT_OD ) << ( ( 15 & 7 ) << 2 );
|
||||||
|
|
||||||
|
AFIO->CTLR |= USBPD_IN_HVT;
|
||||||
|
if ( vcc == eUSBPD_VCC_3V3 )
|
||||||
|
{
|
||||||
|
AFIO->CTLR |= USBPD_PHY_V33;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBPD->DMA = (uint32_t)s_buffer;
|
||||||
|
USBPD->CONFIG = IE_RX_ACT | IE_RX_RESET | IE_TX_END | PD_DMA_EN | PD_FILT_EN;
|
||||||
|
USBPD->STATUS = BUF_ERR | IF_RX_BIT | IF_RX_BYTE | IF_RX_ACT | IF_RX_RESET | IF_TX_END;
|
||||||
|
|
||||||
|
// disable CC comparators
|
||||||
|
USBPD->PORT_CC1 &= ~( CC_CMP_MASK | PA_CC_AI );
|
||||||
|
USBPD->PORT_CC2 &= ~( CC_CMP_MASK | PA_CC_AI );
|
||||||
|
// set CC comparator voltage
|
||||||
|
USBPD->PORT_CC1 |= CC_CMP_66;
|
||||||
|
USBPD->PORT_CC2 |= CC_CMP_66;
|
||||||
|
|
||||||
|
return eUSBPD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBPD_Result_e USBPD_SinkNegotiate( void )
|
||||||
|
{
|
||||||
|
switch ( s_instance.state )
|
||||||
|
{
|
||||||
|
case eSTATE_IDLE:;
|
||||||
|
const uint8_t ccLine = GetActiveCCLine();
|
||||||
|
if ( ccLine == eUSBPD_CCNONE )
|
||||||
|
{
|
||||||
|
s_instance.ccCount = 0;
|
||||||
|
s_instance.lastCCLine = eUSBPD_CCNONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( s_instance.lastCCLine != ccLine )
|
||||||
|
{
|
||||||
|
s_instance.lastCCLine = ccLine;
|
||||||
|
s_instance.ccCount = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_instance.ccCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( s_instance.ccCount > 10 )
|
||||||
|
{
|
||||||
|
if ( ccLine == eUSBPD_CC2 )
|
||||||
|
{
|
||||||
|
USBPD->CONFIG |= CC_SEL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
USBPD->CONFIG &= ~CC_SEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_instance.ccCount = 0;
|
||||||
|
s_instance.state = eSTATE_CABLE_DETECT;
|
||||||
|
|
||||||
|
SwitchRXMode();
|
||||||
|
// NVIC_SetPriority(USBPD_IRQn, 0x00); // TODO: Is this needed?
|
||||||
|
NVIC_EnableIRQ( USBPD_IRQn );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eSTATE_SOURCE_CAP:
|
||||||
|
USBPD_SelectPDO( 0, 0 ); // Select the first PDO by default
|
||||||
|
s_instance.state = eSTATE_WAIT_ACCEPT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eSTATE_PS_RDY: return eUSBPD_OK;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eUSBPD_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBPD_Reset( void )
|
||||||
|
{
|
||||||
|
NVIC_DisableIRQ( USBPD_IRQn );
|
||||||
|
s_instance = ( USBPD_Instance_t ){
|
||||||
|
.pdVersion = eUSBPD_REV_30,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
USBPD_State_e USBPD_GetState( void )
|
||||||
|
{
|
||||||
|
return s_instance.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FUNCONF_USBPD_NO_STR
|
||||||
|
const char *USBPD_StateToStr( USBPD_State_e state )
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *USBPD_ResultToStr( USBPD_Result_e result )
|
||||||
|
{
|
||||||
|
(void)result;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const char *USBPD_StateToStr( USBPD_State_e state )
|
||||||
|
{
|
||||||
|
switch ( state )
|
||||||
|
{
|
||||||
|
case eSTATE_IDLE: return "Idle";
|
||||||
|
case eSTATE_CABLE_DETECT: return "Cable Detected";
|
||||||
|
case eSTATE_SOURCE_CAP: return "Got Source Capabilities";
|
||||||
|
case eSTATE_WAIT_ACCEPT: return "Waiting for Accept";
|
||||||
|
case eSTATE_WAIT_PS_RDY: return "Waiting for PS_Ready";
|
||||||
|
case eSTATE_PS_RDY: return "Power Supply Ready";
|
||||||
|
default: return "Unknown State";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *USBPD_ResultToStr( USBPD_Result_e result )
|
||||||
|
{
|
||||||
|
switch ( result )
|
||||||
|
{
|
||||||
|
case eUSBPD_OK: return "OK";
|
||||||
|
case eUSBPD_BUSY: return "Busy";
|
||||||
|
case eUSBPD_ERROR: return "Error";
|
||||||
|
case eUSBPD_ERROR_ARGS: return "Error Args";
|
||||||
|
case eUSBPD_ERROR_NOT_SUPPORTED: return "Error Not Supported";
|
||||||
|
case eUSBPD_ERROR_TIMEOUT: return "Error Timeout";
|
||||||
|
default: return "Unknown Result";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // FUNCONF_USBPD_NO_STR
|
||||||
|
|
||||||
|
USBPD_Result_e USBPD_SelectPDO( uint8_t index, uint32_t voltageIn100mV )
|
||||||
|
{
|
||||||
|
if ( index >= s_instance.pdoCount )
|
||||||
|
{
|
||||||
|
return eUSBPD_ERROR_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const USBPD_SourcePDO_t *const pdo = &s_instance.caps.Source[index];
|
||||||
|
|
||||||
|
*(USBPD_MessageHeader_t *)&s_buffer[0] = ( USBPD_MessageHeader_t ){
|
||||||
|
.MessageID = s_instance.messageID,
|
||||||
|
.MessageType = eUSBPD_DATA_MSG_REQUEST,
|
||||||
|
.NumberOfDataObjects = 1u,
|
||||||
|
.SpecificationRevision = s_instance.pdVersion,
|
||||||
|
};
|
||||||
|
USBPD_RequestDataObject_t *const rdo = (USBPD_RequestDataObject_t *)&s_buffer[sizeof( USBPD_MessageHeader_t )];
|
||||||
|
|
||||||
|
if ( USBPD_IsPPS( pdo ) )
|
||||||
|
{
|
||||||
|
// Clamp voltage to min/max NOTE: Maybe we should return an error if the voltage is out of range?
|
||||||
|
const uint32_t minVoltage = pdo->SPR_PPS.MinVoltageIn100mV;
|
||||||
|
const uint32_t maxVoltage = pdo->SPR_PPS.MaxVoltageIn100mV;
|
||||||
|
voltageIn100mV = voltageIn100mV > maxVoltage ? maxVoltage : voltageIn100mV;
|
||||||
|
voltageIn100mV = voltageIn100mV < minVoltage ? minVoltage : voltageIn100mV;
|
||||||
|
|
||||||
|
*rdo = ( USBPD_RequestDataObject_t ){
|
||||||
|
.PPS =
|
||||||
|
{
|
||||||
|
.ObjectPosition = index + 1,
|
||||||
|
.OutputVoltageIn20mV = voltageIn100mV * 5,
|
||||||
|
.OperatingCurrentIn50mA = pdo->SPR_PPS.MaxCurrentIn50mA,
|
||||||
|
.NoUSBSuspended = 1u,
|
||||||
|
.USBComsCapable = 1u, // TODO: Should have these are arguments or define
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*rdo = ( USBPD_RequestDataObject_t ){
|
||||||
|
.FixedAndVariable =
|
||||||
|
{
|
||||||
|
.ObjectPosition = index + 1,
|
||||||
|
.MaxCurrentIn10mA = pdo->FixedSupply.MaxCurrentIn10mA,
|
||||||
|
.OperatingCurrentIn10mA = pdo->FixedSupply.MaxCurrentIn10mA,
|
||||||
|
.USBComsCapable = 1u,
|
||||||
|
.NoUSBSuspended = 1u,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
SendMessage( 6 );
|
||||||
|
|
||||||
|
return eUSBPD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the capabilities of the USB PD Source
|
||||||
|
* @param[out] capabilities: pointer to the capabilities message structure
|
||||||
|
* @return Number of Power Data Objects (PDOs) in the capabilities message
|
||||||
|
*/
|
||||||
|
size_t USBPD_GetCapabilities( USBPD_SPR_CapabilitiesMessage_t **capabilities )
|
||||||
|
{
|
||||||
|
if ( s_instance.pdoCount == 0 )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( capabilities )
|
||||||
|
{
|
||||||
|
*capabilities = &s_instance.caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_instance.pdoCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBPD_IsPPS( const USBPD_SourcePDO_t *pdo )
|
||||||
|
{
|
||||||
|
return ( pdo->Header.PDOType == eUSBPD_PDO_AUGMENTED ) && ( pdo->Header.AugmentedType == eUSBPD_APDO_SPR_PPS );
|
||||||
|
}
|
||||||
|
|
||||||
|
USBPD_SpecificationRevision_e USBPD_GetVersion( void )
|
||||||
|
{
|
||||||
|
return s_instance.pdVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check CC line status
|
||||||
|
* @param None
|
||||||
|
* @return USBPD_CC_t
|
||||||
|
*/
|
||||||
|
static USBPD_CC_e GetActiveCCLine( void )
|
||||||
|
{
|
||||||
|
// Switch to CC1
|
||||||
|
USBPD->CONFIG &= ~CC_SEL;
|
||||||
|
Delay_Us( 1 );
|
||||||
|
// check if CC1 is connected
|
||||||
|
if ( USBPD->PORT_CC1 & PA_CC_AI )
|
||||||
|
{
|
||||||
|
return eUSBPD_CC1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to CC2
|
||||||
|
USBPD->CONFIG |= CC_SEL;
|
||||||
|
Delay_Us( 1 );
|
||||||
|
if ( USBPD->PORT_CC2 & PA_CC_AI )
|
||||||
|
{
|
||||||
|
return eUSBPD_CC2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return eUSBPD_CCNONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch to RX mode
|
||||||
|
* @param None
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
static void SwitchRXMode( void )
|
||||||
|
{
|
||||||
|
USBPD->BMC_CLK_CNT = UPD_TMR_RX;
|
||||||
|
USBPD->CONTROL = ( USBPD->CONTROL & ~PD_TX_EN ) | BMC_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Begin transmission of PD message
|
||||||
|
* @param size: size of the message in bytes
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
static void SendMessage( uint8_t size )
|
||||||
|
{
|
||||||
|
USBPD->BMC_CLK_CNT = UPD_TMR_TX;
|
||||||
|
USBPD->TX_SEL = UPD_SOP0;
|
||||||
|
USBPD->BMC_TX_SZ = size;
|
||||||
|
USBPD->STATUS = 0;
|
||||||
|
USBPD->CONTROL |= BMC_START | PD_TX_EN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse the received packet
|
||||||
|
* @param None
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
static void ParsePacket( void )
|
||||||
|
{
|
||||||
|
bool sendGoodCRC = true;
|
||||||
|
USBPD_MessageHeader_t message = *(USBPD_MessageHeader_t *)s_buffer;
|
||||||
|
|
||||||
|
USBPD_State_e nextState = s_instance.state;
|
||||||
|
|
||||||
|
if ( message.NumberOfDataObjects == 0u )
|
||||||
|
{
|
||||||
|
switch ( (USBPD_ControlMessage_e)message.MessageType )
|
||||||
|
{
|
||||||
|
case eUSBPD_CTRL_MSG_GOODCRC:
|
||||||
|
sendGoodCRC = false;
|
||||||
|
s_instance.messageID++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eUSBPD_CTRL_MSG_ACCEPT: nextState = eSTATE_WAIT_PS_RDY; break;
|
||||||
|
|
||||||
|
case eUSBPD_CTRL_MSG_REJECT: nextState = eSTATE_SOURCE_CAP; break;
|
||||||
|
|
||||||
|
case eUSBPD_CTRL_MSG_PS_RDY: nextState = eSTATE_PS_RDY; break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch ( (USBPD_DataMessage_e)message.MessageType )
|
||||||
|
{
|
||||||
|
|
||||||
|
case eUSBPD_DATA_MSG_SOURCE_CAP:
|
||||||
|
nextState = eSTATE_SOURCE_CAP;
|
||||||
|
s_instance.pdoCount = message.NumberOfDataObjects;
|
||||||
|
s_instance.pdVersion = message.SpecificationRevision;
|
||||||
|
memcpy( &s_instance.caps, &s_buffer[2], sizeof( USBPD_SPR_CapabilitiesMessage_t ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( message.Extended || sendGoodCRC )
|
||||||
|
{
|
||||||
|
Delay_Us( 30 );
|
||||||
|
USBPD_ControlMessage_t reply = ( USBPD_ControlMessage_t ){
|
||||||
|
.MessageID = message.MessageID,
|
||||||
|
.MessageType = eUSBPD_CTRL_MSG_GOODCRC,
|
||||||
|
.SpecificationRevision = s_instance.pdVersion,
|
||||||
|
};
|
||||||
|
*(uint16_t *)&s_buffer[0] = reply.data;
|
||||||
|
SendMessage( sizeof( reply ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
s_instance.state = nextState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBPD_IRQHandler( void ) __attribute__( ( interrupt ) );
|
||||||
|
void USBPD_IRQHandler( void )
|
||||||
|
{
|
||||||
|
// Receive complete interrupt
|
||||||
|
if ( USBPD->STATUS & IF_RX_ACT )
|
||||||
|
{
|
||||||
|
// Check if we received a SOP0 packet
|
||||||
|
if ( ( ( USBPD->STATUS & BMC_AUX_MASK ) == BMC_AUX_SOP0 ) && ( USBPD->BMC_BYTE_CNT >= 6 ) )
|
||||||
|
{
|
||||||
|
ParsePacket();
|
||||||
|
}
|
||||||
|
USBPD->STATUS |= IF_RX_ACT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transmit complete interrupt (GoodCRC only)
|
||||||
|
if ( USBPD->STATUS & IF_TX_END )
|
||||||
|
{
|
||||||
|
SwitchRXMode();
|
||||||
|
USBPD->STATUS |= IF_TX_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset interrupt
|
||||||
|
if ( USBPD->STATUS & IF_RX_RESET )
|
||||||
|
{
|
||||||
|
USBPD->STATUS |= IF_RX_RESET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user