Two nominally identical shunt amplifier channels on Ulna-60-30 V1.2 read 25.6 mV/A and 22.0 mV/A over 0 to 3 A, a 16 percent spread, and the cause is in the copper, not the parts. The differential sense traces leave the shunt pads on the same side as the high current connections, so each channel amplifies the shunt plus a different stub of track. Both channels are linear to within half a millivolt, which means the error is a per channel gain term we can calibrate out in firmware on this revision and remove in the layout on the next. The rest of the first board came up clean: rails on target, the debugger talks, CAN at 1 Mbit and RS485 at 115200 ran their soak tests with zero errors.
What the board is
Ulna-60-30 is our GaN 3 phase inverter for humanoid joint motors, a round board that sits behind the motor. V1.2 is the first revision we handed to an external test bench rather than checking ourselves, with a scripted sequence: inspection, continuity, power on, rails, thermal, SWD, a minimal firmware, then each communication interface in turn. This entry is the first half of that sequence. Motor running tests follow in the next one.
Power on and rails
Nothing clever here, and that is the point. Bench supply at 12 V with a 0.2 A limit, only the supply cable connected, microcontroller unprogrammed. Quiescent draw was 40 mA and stayed there. The rails measured on a 6.5 digit true RMS meter:
| Rail | Measured | Where |
|---|---|---|
| VIN | 11.997 V | input, set to 12 V for this test |
| +5 V | 4.99 V | C11 |
| +3.3 V | 3.32 V | C15 |
AC coupled scope captures on the same three nodes show the switching regulator ripple riding on the +5 V rail at about 20 mV per division full scale and the +3.3 V rail at 5 mV per division, with narrow spikes at the switching edges on VIN. Nothing that worries us at this stage, but we will revisit those edges with a 20 MHz bandwidth limit and a short ground spring once the GaN stage is switching, because that is when ripple on the logic rails starts to matter for the current sense ADC.
The thermal camera found the 3.3 V regulator to be the warmest part on the board at a steady 30 °C with no load on the power stage. The transient protection device on the input stayed at ambient.
Clock: a 50 MHz crystal oscillator the MCU cannot use
One real mistake on the schematic. The external oscillator fitted is 50 MHz, which is above the HSE input range the microcontroller accepts [1]. The bench firmware therefore runs the core at 170 MHz from the internal 16 MHz RC through the PLL. That works for bring up, and the internal oscillator is good enough for CAN at 1 Mbit as the soak test below shows, but it is not good enough for the timing we want on the motor control timers and on FD data rates. V1.3 gets an oscillator inside the specified range. We are noting it here so nobody else copies a part number off our board.
The first firmware was deliberately trivial: a 1 kHz, 50 percent duty square wave on PB7 from TIM3, prescaler 169 and period 999 off the 170 MHz clock, captured on the scope at 1.00097 kHz. Programmable, clock tree sane, pin map correct.
Communications soak tests
CAN, TCAN3414 transceiver. The firmware accepts only ID 0x200 through a hardware filter, rejects everything else, and answers each request with an 8 byte frame on ID 0x100 carrying an incrementing counter. The PC side was a USB-CAN-B adapter. At 1000 kbit per second, 10,000 request frames were sent and 10,000 responses came back with no errors. The log is in D1CANFDV2.csv. This was classic CAN framing with bit rate switching off; FD data phase testing waits for the crystal fix above.
RS485, THVD1450 transceiver. The firmware listens for TEST\n at 115200 baud and replies with RS485DebugCounter=n. Requests went out every 100 ms for 10 minutes, about 1,000 frames, no missing or corrupted responses. The scope capture of the A and B lines shows clean edges and the driver enable timing we expected from the hardware DE control.
10,000 of 10,000 CAN frames answered at 1 Mbit. About 1,000 of 1,000 RS485 frames answered at 115200 baud. Zero errors on either bus.
The current sense result, and why it matters
Each phase current is measured across a milliohm class shunt, marked R001 on the silkscreen, by a differential shunt amplifier referenced to mid rail. With no current the two channels, U4 and U5, both sit at 1658 mV. That is the good news: the zero is shared and stable. Then a known DC current was pushed through each shunt in steps up to 3 A and the amplifier output logged.
| Channel | Output at 0 A | Output at 3 A | Fitted slope | Max residual |
|---|---|---|---|---|
| U4 | 1658 mV | 1581 mV | 25.6 mV/A | 0.46 mV |
| U5 | 1658 mV | 1592 mV | 22.0 mV/A | under 0.1 mV |
Two channels built from the same parts, on the same board, differ by 16 percent in gain. Both are straight lines, so this is not a saturation or an offset problem.
The layout review explains it. The sense traces for each channel are tapped from the shunt pads on the same side as the high current copper, instead of from the far side of the pads where no load current flows. So the amplifier sees the shunt in series with a short length of plated copper and via, and that length differs between the two channels because the two shunts sit at different distances from their amplifiers. At a shunt value of one milliohm, a few hundred microohms of stray copper is a double digit percentage. In a true Kelvin connection the sense taps carry no load current and the stray resistance drops out of the measurement entirely.
Why we care at joint level. The current loop in a field oriented controller trusts these two channels to reconstruct the third phase and to produce torque. A 16 percent gain mismatch between phases shows up as a torque ripple at electrical frequency, and a gain error common to both shows up as a torque scale error. Neither is acceptable in a joint that has to be backdrivable and repeatable.
What we are doing about it
On V1.2 boards the error is deterministic and linear, so it is calibrated out. Each board gets a per channel gain constant measured the same way, DC current through the shunt against ADC counts, stored with the board. The microcontroller side is one multiply per sample. The temperature coefficient of copper, about 0.4 percent per kelvin, means the stray term will drift with board temperature, so the calibration constant is only exact at the temperature it was taken. We will characterise that drift when the power stage is running and the board is warm.
On V1.3 the shunt footprints get true four terminal pads, sense traces routed as a tight differential pair from the inside edge of the pads, and the stray term disappears. It costs nothing but attention at layout time. We knew the rule. The round board is tight around the power stage and the taps were placed where they fit rather than where they belong, and the bench numbers above are the price of that choice.
Next entry
Phase current waveforms with the GaN stage switching, the ripple on the logic rails under load, and the calibrated current sense against a reference current probe.
References
- STMicroelectronics, microcontroller datasheet for the fitted part, HSE oscillator characteristics. The 50 MHz oscillator exceeds the specified external clock input range.
- External bench test report, Ulna-60-30 V1.2, sections A1 to D2, October 2026. Aleph-B internal.
- Current sense characterisation, channels U4 and U5, 0 to 3 A DC, and layout review note, October 2026. Aleph-B internal.
