Skip to content

fix USB-PD implementation - #936

Merged
cnlohr merged 2 commits into
cnlohr:masterfrom
NyxCode:fix-usb-pd
Jul 27, 2026
Merged

fix USB-PD implementation#936
cnlohr merged 2 commits into
cnlohr:masterfrom
NyxCode:fix-usb-pd

Conversation

@NyxCode

@NyxCode NyxCode commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Hey! This PR fixes usbpd.h in examples_x035/usbpd_sink.
What I wanted to get working was just a simple PD sink requesting 12V or 9V from a charger, but no chargers successfully negotiated.
With these fixes, negotiation works. I tested this on an iPad Pro charger and a ThinkPad T14 power brick.

Disclosure: This PR was assisted by Claude Code. Should be reviewed by someone familiar with the PD protocol.

Comment on lines +782 to +783
__asm volatile( "" ::: "memory" );

@NyxCode NyxCode Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the barrier (and the volatile field above), negotiation always failed when compiled with LTO

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

Comment on lines +886 to +887
case eUSBPD_CTRL_MSG_WAIT: nextState = eSTATE_CABLE_DETECT; break;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ThinkPad power brick sent the WAIT command, and only negotiated successfully with this

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

@NyxCode

NyxCode commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

For reference, here is my code that negotiates 12V or 9V:

#define NEGOTIATE_TIMEOUT_CYCLES \
    ((uint32_t)((uint64_t)FUNCONF_SYSTEM_CORE_CLOCK * 10000 / 1000))
#define SETTLE_MS 500

// kept around for diagnostics
static uint8_t s_last_state;

int32_t usb_pd_negotiate(void) {
    USBPD_Init(eUSBPD_VCC_3V3);
    USBPD_Reset();

    uint32_t start = (uint32_t)SysTick->CNTL;
    USBPD_Result_e result;
    while ((result = USBPD_SinkNegotiate()) == eUSBPD_BUSY) {
        if ((uint32_t)SysTick->CNTL - start >= NEGOTIATE_TIMEOUT_CYCLES) {
            s_last_state = (uint8_t)USBPD_GetState();
            return -1;
        }
    }
    s_last_state = (uint8_t)USBPD_GetState();
    if (result != eUSBPD_OK)
        return -2;

    USBPD_SPR_CapabilitiesMessage_t *caps;
    size_t n = USBPD_GetCapabilities(&caps);

    int     best_idx = -1;
    int32_t best_mv  = 0;
    for (size_t i = 0; i < n; i++) {
        const USBPD_SourcePDO_t *pdo = &caps->Source[i];
        if (pdo->Header.PDOType != eUSBPD_PDO_FIXED) continue;
        int32_t mv = (int32_t)(pdo->FixedSupply.VoltageIn50mV * 50u);
        if ((mv == 12000 || mv == 9000) && mv > best_mv) {
            best_mv  = mv;
            best_idx = (int)i;
        }
    }

    if (best_idx < 0)
        return -(3 + (int32_t)n);

    USBPD_SelectPDO((uint8_t)best_idx, 0);
    Delay_Ms(SETTLE_MS);
    return best_mv;
}

@cnlohr
cnlohr merged commit f23b10d into cnlohr:master Jul 27, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants