Overview
This is a precision bidirectional current source I designed and built from scratch — schematic, PCB, and firmware. The goal was to drive a resistive-inductive load with controlled current in both directions, smoothly crossing through zero, which is what makes it a true 4-quadrant converter. The whole thing is aimed at magnet power supply research at CERN, where you need to push current one way, pull it back the other way, and do it accurately.
The power stage is a full H-bridge built from four STP110N10F7 N-channel MOSFETs rated at 100 V / 110 A — way overspec'd for the ~4 A continuous I'm targeting, but that's intentional. At these current levels the FETs barely get warm, so I don't even need heatsinks on them. The bridge runs off a 48 V bus through a fused, TVS-protected input and switches at 100 kHz with center-aligned PWM.
Current regulation is handled by a TI C2000 F280049C microcontroller running a PI loop at the PWM rate. The controller reads current through an INA240A2 sense amplifier (50 V/V gain) connected to a 10 mΩ shunt sitting between the two switch nodes — that placement is key, because it lets you measure current regardless of which direction it's flowing. A hardware comparator (MCP6567) on the INA240 output provides a fast overcurrent trip that bypasses firmware entirely: if the current exceeds ±3 A, the FAULT line drops and the C2000 kills the PWM within a switching cycle.
Power Stage
The H-bridge has two legs — Leg A (QH_A, QL_A) and Leg B (QH_B, QL_B) — with the load connected between their switch nodes SW_A and SW_B. By varying the duty cycle of each leg differentially, you control the net voltage across the load: both legs at 50% means zero volts across the load, shifting them apart pushes current one way or the other. A 220 µH inductor in series with the load smooths the PWM into a controlled DC current.
Each MOSFET gate is driven through a 10 Ω series resistor with a BAT54 Schottky diode in anti-parallel. The resistor slows down turn-on to limit dV/dt stress and reduce EMI, while the diode bypasses it during turn-off so the gate discharges fast. That asymmetry — slow on, fast off — is deliberate. It's a simple way to minimize the window where cross-conduction could happen during the dead time. Pull-down resistors (10 kΩ) on every gate ensure the FETs stay off if the controller ever tri-states its outputs.
Gate Drivers
Each half-bridge leg gets its own UCC27211A gate driver from TI. These take the 3.3 V logic-level PWM from the C2000 and level-shift it up to the 12 V needed to properly enhance the MOSFETs. The high-side driver uses a bootstrap topology — a 1 µF ceramic cap charges through the UCC27211A's internal bootstrap diode when the low-side FET is on, then floats up with the switch node to drive the high-side gate. I upgraded C1 and C3 from 0.1 µF to 10 µF each, using 1206-size 100 V-rated X7S MLCCs, and stacked two caps per leg on the same pads to push more capacitance into the same footprint. The 100 V rating matters because MLCC capacitance drops hard under DC bias: at 48 V (about 48% of rated voltage), published curves for similar X7S parts put effective capacitance around 60-80% of nominal, so each 10 µF part behaves more like 6-8 µF in operation, and two stacked per leg still lands around 12-16 µF effective. That's still a major jump over the original 0.1 µF parts and gives the switching loop noticeably stiffer local decoupling.
One thing that saved me a component: the UCC27211A has an integrated bootstrap diode, so there's no external Schottky needed in the boot path. Fewer parts, tighter layout.
Current Sensing
The shunt resistor (10 mΩ, 1 W, 2512 package) sits in the load path between SW_A and the inductor — not on the low-side return, which is where you'd typically put it in a unidirectional converter. The bidirectional placement means the INA240A2 always sees the actual load current, positive or negative, without needing to deal with common-mode transients referenced to the power ground.
The INA240A2 outputs a voltage centered at 1.65 V (its internal reference) with a gain of 50 V/V on the shunt voltage. So for a ±3 A range, the output swings between roughly 0.15 V and 3.15 V — fits nicely within the C2000's 3.3 V ADC range. After the amplifier there's a simple R-C anti-alias filter (10 Ω + 100 nF) with a cutoff around 159 kHz. That's above the signal bandwidth but well below the ADC's Nyquist limit, which keeps switching noise out of the samples.
Hardware Overcurrent Protection
I added a MCP6567 dual comparator watching the INA240 output against two thresholds set by resistor dividers: 3.15 V on the upper side and 0.15 V on the lower side. The divider math is straightforward — 10 kΩ / 470 Ω gives you 3.152 V and swapping them gives 0.148 V, close enough to the ±3 A trip point. I used 1% tolerance resistors in those divider networks because threshold accuracy is the whole game here: if the divider drifts, the overcurrent trip either fires too early and kills usable current range or too late and lets extra stress into the power stage. If the INA output crosses either threshold, the comparator pulls FAULT_OUT low and the C2000's trip-zone hardware instantly disables all four PWM outputs. No firmware latency in the protection path — that's the whole point.
Input Power
The 48 V bus enters through a screw terminal (J3), passes through a 25 A mini fuse, and hits the main DC rail. Bulk storage is a 470 µF / 63 V electrolytic in parallel with a 1 µF / 160 V WIMA film cap. The electrolytic handles energy storage; the film cap handles the high-frequency transient current that the electrolytic is too slow for. A SMCJ58A TVS diode clamps any spikes above ~64 V. The 12 V rail for the gate drivers comes in on a separate screw terminal (J4) with its own 10 µF bulk cap.
PCB Layout
The board is a 4-layer design: top copper for components and power routing, inner layer 1 as a solid PGND plane, inner layer 2 split between VIN_48V and +12V power planes, and bottom copper for signals and sense traces. The layout follows a three-zone strategy — power stage at the top, gate drivers in the middle, sensing and connector at the bottom — with the switching loop kept as tight as possible. The PGND and SGND domains connect at a single star point near the shunt resistor.
I routed traces to leave pads at 90° instead of 45° to avoid creating acute-angle acid traps during etching. The fab rules allow power-polygon clearances down to 0.2 mm, but I kept mine mostly around 1-2 mm for comfortable margin and shaped the copper pours more rectangular for cleaner geometry. The 90° corners here are not a performance concern in this design envelope: for DC power flow they are effectively irrelevant, and at these switching frequencies they are still a practical non-issue compared with larger discontinuities you already accept, like every via transition in the loop.
Controller Interface
The C2000 LaunchPad connects through a 2×5 pin header carrying four PWM signals, the analog current measurement, enable, FAULT_OUT, power, and both ground domains. I also swapped the header positions of I_MEAS_ADC_RAW and +3.3 V from my earlier pin order so the raw ADC line is no longer sitting directly beside the PWM switching lines; using the constant 3.3 V rail between them gives the analog path a cleaner buffer from switching noise. The FAULT_OUT line has a pull-up to 3.3 V so it reads high during normal operation — a low means the hardware comparator tripped and the controller should latch into a fault state.
| Pin 1 | PWM_AH | Pin 2 | PWM_AL |
| Pin 3 | PWM_BH | Pin 4 | PWM_BL |
| Pin 5 | +3.3V | Pin 6 | ENABLE |
| Pin 7 | I_MEAS_ADC_RAW | Pin 8 | FAULT_OUT |
| Pin 9 | SGND | Pin 10 | PGND |