Ramblings of an aging IT geek
← Ramblings of an aging IT geek
hardware

reverse-engineering a usb-c charger that lied to me

A weekend spent sniffing USB Power Delivery negotiation to work out why a charger advertised 65W and delivered 15.

A soldering iron and a circuit board on a cluttered workbench

The short version: I bought a "65W" USB-C charger, my laptop charged at the pace of a sundial, and rather than return it like a sensible adult I spent a Saturday working out exactly how it was lying. The answer turned out to be more interesting than the refund would have been.

What PD actually does

USB Power Delivery is a negotiation, not a setting. When you plug a sink (your laptop) into a source (the charger), they do not just agree on "lots of watts". The source advertises a list of Power Data Objects, the PDOs, each one a fixed voltage and a maximum current it can supply at that voltage. A typical source might offer 5V/3A, 9V/3A, 15V/3A and 20V/3.25A. The sink looks at that menu, picks the highest one it can use, and sends a Request. The source either accepts and ramps the voltage, or rejects it.

All of this happens over the CC line as a serial protocol called BMC, biphase mark coding, at around 300kbps. Critically, it is a real conversation with real messages, which means you can listen to it.

Listening in

I have a Saleae-style logic analyser and, more usefully, a cheap USB-C breakout board that brings the CC1 and CC2 pins out to header pins. The CC line sits at a sane logic level, so you can probe it directly. The trick is just knowing which CC pin is active, because in a given cable orientation only one of the two is doing the talking.

A close-up of a small circuit board with breakout headers

I captured the negotiation between the charger and a known-good sink. Decoding BMC by hand is tedious but the structure is forgiving: a preamble, then 5b/4b encoded symbols, then the actual PD messages with a header and a CRC. What I was after was the Source Capabilities message, the one carrying the PDO menu. That message is the charger telling the truth about itself, whatever the box claims.

Here is the menu it actually advertised, once I had decoded the PDOs:

PDO 1: Fixed  5.00V  3.00A  (15.0W)
PDO 2: Fixed  9.00V  1.67A  (15.0W)
PDO 3: Fixed 12.00V  1.25A  (15.0W)

Three profiles. Every single one of them capped at 15W. There was no 20V profile at all, and the 9V and 12V profiles were current-limited so hard that they could never exceed the 5V figure. The "65W" on the box was, as far as the PD engine was concerned, fiction. My laptop was behaving perfectly: it asked for the best thing on offer, the best thing on offer was 15W, and so 15W is what it took.

Why the laptop "agreed" to be slow

This is the part that fooled me for an hour. My laptop's USB-C charge indicator was perfectly happy. No error, no warning, just slow. That is by design. PD has no concept of "this charger is disappointing." The sink requests an Objects Position from the advertised list, the source accepts, and as far as both ends are concerned the contract is honoured. A weak menu is still a valid menu. The charger was not failing the protocol, it was succeeding at advertising almost nothing.

I confirmed it with a USB-C power meter inline, one of the little inline displays that show negotiated voltage and live current. It read 9.0V at about 1.6A under load and never moved. That matched the decoded PDO exactly, which was a quietly satisfying moment: the bytes I had pulled off the CC line predicted the meter to two significant figures.

The takeaway, and the small lesson

A few things I will carry forward:

  • The wattage on a USB-C charger's box is marketing. The wattage in its Source Capabilities message is the truth. If you have a PD trigger board or an inline meter, you can see the real menu in seconds, and you do not need the logic analyser unless you enjoy it. I enjoy it, which is the only reason the logic analyser came out.
  • A PD "trigger" board is the cheap version of this whole exercise. You set it to demand a specific voltage and it either gets it or it does not. Mine never got more than 12V out of this charger, which was the confirmation I needed.
  • Slow charging with no error is almost always a source problem, not a sink problem, and almost always a current cap rather than a cable fault. A bad cable tends to fail the negotiation outright or drop the link; a stingy charger negotiates cleanly and then gives you very little.

The charger went back after all. But I kept the breakout board and the meter on the bench, because the next time something charges slowly I would like to know within thirty seconds whether to blame the brick, the cable, or myself. It is rarely the laptop, and it is more often than I would like the cheap brick that promised the world and shipped 15 watts.