Building a USB Power Delivery Trigger HAT
Overview
This tutorial walks through a Raspberry Pi HAT that uses a USB-C Power Delivery trigger controller to request a fixed voltage from a USB-C charger. The HAT keeps the Raspberry Pi header available for control and status signals, then routes the negotiated output to screw terminals for powering motors, LED strips, test fixtures, or another downstream board.
Circuit Requirements
The trigger HAT needs to:
- Accept power from a USB-C charger or power bank
- Negotiate a fixed USB Power Delivery voltage
- Expose the negotiated voltage on a clearly marked terminal block
- Let the Raspberry Pi read a power-good signal
- Add local input and output capacitors so load steps do not reset the trigger controller
This tutorial uses a CH224K-style trigger controller because it is small, inexpensive, and common on hobbyist PD trigger modules. The same layout approach works with similar fixed-voltage PD trigger ICs; always check the controller datasheet before fabricating.
Component Choices
| Reference | Part | Purpose |
|---|---|---|
| J1 | USB-C receptacle | Input from a PD charger |
| U1 | CH224K-style PD trigger | Negotiates the requested voltage |
| R1 | Voltage-select resistor | Selects the requested PD profile |
| C1 | 100 nF ceramic capacitor | Local high-frequency bypassing |
| C2 | 22 uF ceramic capacitor | Output bulk capacitance |
| D1, R2 | Green status LED and resistor | Shows power-good status |
| J2 | 2-pin terminal block | Exposes VOUT and GND |
Building the Circuit Step by Step
Step 1: Add the HAT and USB-C Connector
Start with the Raspberry Pi HAT board and place a USB-C connector on the edge of the board. Keep the USB-C connector close to the board edge so the cable can plug in without hitting the Raspberry Pi case.
Step 2: Add the PD Trigger Controller
The trigger controller watches CC1 and CC2, advertises the requested voltage profile, then exposes the negotiated charger voltage on VBUS. The PG pin is useful because it lets the Raspberry Pi detect when negotiation has completed.
Step 3: Select the Requested Voltage
Many PD trigger ICs use one or more configuration pins to select 5 V, 9 V, 12 V, 15 V, or 20 V. In this example, R1 pulls the VSEL pin to ground. Change this resistor network to match the table in your exact controller datasheet.
| Target output | Typical use |
|---|---|
| 5 V | Logic, small LED strings, USB-powered boards |
| 9 V | Small motors, audio modules, compact test loads |
| 12 V | Fans, relays, light strips, instrumentation |
| 15 V | Higher-voltage analog rails or bench fixtures |
| 20 V | Laptop-style adapters and high-power loads |
Step 4: Add Filtering and the Output Terminal
Place a 100 nF capacitor close to U1 and a larger ceramic capacitor near the terminal block. The terminal block should have clear silkscreen labels for VOUT and GND, especially if you plan to change the requested voltage later.
import { RaspberryPiHatBoard } from "@tscircuit/common"
export default () => (
<RaspberryPiHatBoard name="HAT1">
<chip
name="J1"
footprint="usb_c_receptacle"
manufacturerPartNumber="USB-C Receptacle"
pinLabels={{
pin1: ["VBUS"],
pin2: ["GND"],
pin3: ["CC1"],
pin4: ["CC2"],
}}
pcbX={-18}
pcbY={0}
/>
<chip
name="U1"
footprint="sot23_6"
manufacturerPartNumber="CH224K USB PD trigger"
pinLabels={{
pin1: ["CC1"],
pin2: ["CC2"],
pin3: ["GND"],
pin4: ["VSEL"],
pin5: ["PG"],
pin6: ["VBUS"],
}}
pcbX={-4}
pcbY={0}
/>
<capacitor name="C1" capacitance="100nF" footprint="0402" pcbX={2} pcbY={-8} />
<capacitor name="C2" capacitance="22uF" footprint="1206" pcbX={8} pcbY={-6} />
<chip
name="J2"
footprint="terminalblock_1x02"
manufacturerPartNumber="Output terminal block"
pinLabels={{
pin1: ["VOUT"],
pin2: ["GND"],
}}
pcbX={24}
pcbY={0}
/>
<trace from=".J1 .VBUS" to=".U1 .VBUS" />
<trace from=".J1 .GND" to=".U1 .GND" />
<trace from=".U1 .VBUS" to=".C1 > .pin1" />
<trace from=".C1 > .pin2" to=".J1 .GND" />
<trace from=".U1 .VBUS" to=".C2 > .pin1" />
<trace from=".C2 > .pin2" to=".J1 .GND" />
<trace from=".U1 .VBUS" to=".J2 .VOUT" />
<trace from=".J1 .GND" to=".J2 .GND" />
</RaspberryPiHatBoard>
)
Step 5: Add Power-Good Status
Use the power-good pin as both a visual status indicator and a Raspberry Pi input. The example LED is wired to 3.3 V through a resistor and sinks through the PG pin, which matches open-drain power-good outputs on many trigger ICs.
import { RaspberryPiHatBoard } from "@tscircuit/common"
export default () => (
<RaspberryPiHatBoard name="HAT1">
<chip
name="U1"
footprint="sot23_6"
manufacturerPartNumber="CH224K USB PD trigger"
pinLabels={{
pin1: ["CC1"],
pin2: ["CC2"],
pin3: ["GND"],
pin4: ["VSEL"],
pin5: ["PG"],
pin6: ["VBUS"],
}}
pcbX={-4}
pcbY={0}
/>
<resistor name="R2" resistance="2.2k" footprint="0402" pcbX={10} pcbY={5} />
<led name="D1" color="green" footprint="0603" pcbX={16} pcbY={5} />
<trace from=".HAT1_chip .V3_3_1" to=".R2 > .pin1" />
<trace from=".R2 > .pin2" to=".D1 > .pin1" />
<trace from=".D1 > .pin2" to=".U1 .PG" />
<trace from=".U1 .PG" to=".HAT1_chip .GPIO_23" />
</RaspberryPiHatBoard>
)
PCB Layout
Route the USB-C VBUS and output path as a short, wide trace. For higher-current loads, use a polygon pour or multiple traces in parallel and size the terminal block for the expected current. Keep the CC traces short and away from noisy switching loads.
import { RaspberryPiHatBoard } from "@tscircuit/common"
export default () => (
<RaspberryPiHatBoard name="HAT1">
<chip
name="J1"
footprint="usb_c_receptacle"
manufacturerPartNumber="USB-C Receptacle"
pinLabels={{
pin1: ["VBUS"],
pin2: ["GND"],
pin3: ["CC1"],
pin4: ["CC2"],
}}
pcbX={-18}
pcbY={0}
/>
<chip
name="U1"
footprint="sot23_6"
manufacturerPartNumber="CH224K USB PD trigger"
pinLabels={{
pin1: ["CC1"],
pin2: ["CC2"],
pin3: ["GND"],
pin4: ["VSEL"],
pin5: ["PG"],
pin6: ["VBUS"],
}}
pcbX={-4}
pcbY={0}
/>
<resistor name="R1" resistance="10k" footprint="0402" pcbX={-4} pcbY={-10} />
<capacitor name="C1" capacitance="100nF" footprint="0402" pcbX={2} pcbY={-8} />
<capacitor name="C2" capacitance="22uF" footprint="1206" pcbX={8} pcbY={-6} />
<resistor name="R2" resistance="2.2k" footprint="0402" pcbX={10} pcbY={5} />
<led name="D1" color="green" footprint="0603" pcbX={16} pcbY={5} />
<chip
name="J2"
footprint="terminalblock_1x02"
manufacturerPartNumber="Output terminal block"
pinLabels={{
pin1: ["VOUT"],
pin2: ["GND"],
}}
pcbX={24}
pcbY={0}
/>
<trace from=".J1 .VBUS" to=".U1 .VBUS" />
<trace from=".J1 .GND" to=".U1 .GND" />
<trace from=".J1 .CC1" to=".U1 .CC1" />
<trace from=".J1 .CC2" to=".U1 .CC2" />
<trace from=".U1 .VSEL" to=".R1 > .pin1" />
<trace from=".R1 > .pin2" to=".J1 .GND" />
<trace from=".U1 .VBUS" to=".C1 > .pin1" />
<trace from=".C1 > .pin2" to=".J1 .GND" />
<trace from=".U1 .VBUS" to=".C2 > .pin1" />
<trace from=".C2 > .pin2" to=".J1 .GND" />
<trace from=".U1 .VBUS" to=".J2 .VOUT" />
<trace from=".J1 .GND" to=".J2 .GND" />
<trace from=".HAT1_chip .V3_3_1" to=".R2 > .pin1" />
<trace from=".R2 > .pin2" to=".D1 > .pin1" />
<trace from=".D1 > .pin2" to=".U1 .PG" />
<trace from=".U1 .PG" to=".HAT1_chip .GPIO_23" />
</RaspberryPiHatBoard>
)
Bring-Up Test
Before plugging the HAT into a Raspberry Pi, test it by itself:
- Set the voltage-select resistor network for the voltage you want.
- Connect a current-limited USB-C PD charger.
- Measure
VOUTandGNDat the terminal block. - Confirm that the output voltage matches the expected PD profile.
- Attach a small load, such as a resistor or lamp, before connecting the real load.
- Check that the status LED changes state when the charger negotiates successfully.
After the standalone check passes, install the HAT and read the PG signal from Raspberry Pi GPIO 23:
from gpiozero import DigitalInputDevice
from signal import pause
pd_good = DigitalInputDevice(23, pull_up=True)
def ready():
print("USB PD output is ready")
def lost():
print("USB PD output was removed")
pd_good.when_activated = ready
pd_good.when_deactivated = lost
pause()
Safety Notes
- Do not connect the PD output directly to the Raspberry Pi 5 V rail unless you have checked back-powering requirements for your exact Pi model.
- Label the selected voltage on the silkscreen or with a removable sticker.
- Use a fuse or current-limited power switch if users will connect external loads.
- Keep 20 V outputs away from low-voltage GPIO signals on connectors and test points.
Next Steps
- Add a jumper block for selecting 5 V, 9 V, 12 V, 15 V, or 20 V without changing resistors
- Add a resettable fuse between the PD output and the terminal block
- Add an ADC divider so the Raspberry Pi can measure the negotiated voltage
- Add an EEPROM if you want the board to identify itself as a full Raspberry Pi HAT