First things first, we would like to thank Nick Bild for his article about PSU-EXT. It was the first public reference to the project. We appreciate both the attention and the clear, thoughtful way he presented what PSU-EXT does.
The ProblemMany bench power supplies are electrically useful but difficult to automate. They may have no remote interface, limited logging, or software that only works with one product family. Replacing a working supply with a programmable model is expensive, and it still leaves the automation workflow tied to that instrument.
PSU-EXT takes a different approach. It is an external control and measurement module that upgrades the supply already on the bench.
What PSU-EXT Does?- Measures input voltage, output voltage, output current, and output power
- Switches the output path with an onboard relay
- Applies configurable over-voltage protection (OVP) and over-current protection (OCP), plus a separate hard current cutoff
- Exposes Standard Commands for Programmable Instruments (SCPI) over USB Communications Device Class (USB CDC) and raw TCP on port
5025 - Supports two external trigger inputs and on-device ten-step timer queues
Today, In scope of hackster.io project, I would like to primarily talk bout hardware and firmware, rather than software.
Hardware ArchitecturePSU-EXT sits in the physical power path between a bench power supply and the load or device under test. The output path passes through PSU-EXT’s relay-controlled connection, while an isolated acquisition front end continuously measures voltage and current.
The isolated measurement and control domain is powered by an RFM-0505S isolated DC-DC converter.
The ESP32-S3 processes measurement samples using circular buffers and averaging. It also stores calibration values used to convert raw measurements into reported voltage and current values.
This article focuses four parts of the current prototype architecture:
- The overall acquisition front-end and power-path layout
- The current measurement design
- The RFM-0505S isolated DC-DC power supply
- Firmware circular buffers, averaging, and calibration storage
Higher quality PSU-EXT architecture diagram is available on GitHub
Front-End Power PathThe positive power path runs from the bench supply, through the 10 mΩ shunt resistor and normally open relay, to the load. Closing the relay completes this path. Opening it disconnects the load's positive connection from the supply and current-sense path.
The load output is not completely disconnected from the measurement electronics when the relay is open. Its voltage divider remains connected, and a 10 Ω/220nF series snubber remains across the relay contacts (snubber values and placement are under evaluation and might change in the final product). The output is therefore a high-impedance measured node rather than a strictly floating node.
The circuit uses three ground domains:
PGNDis the shared power return for the bench supply and load.GNDSis the signal ground for the isolated analog circuitry.GNDis the USB and ESP32-S3 control-side ground.
A 0Ω link joins PGND and GNDS inside the isolated measurement domain. They remain isolated from the USB-side GND.
The ADS1115 uses three of its four analog channels. One measures the supply input voltage, one measures the load output voltage, and one reads the INA240A2 current-sense output. The fourth channel is unused.
The ADS1115, INA240A2, and their supporting circuits operate from the isolated 3.3 V rail. An RFM-0505S isolated DC-DC converter creates the isolated 5 V supply, and an LD1117S33 regulator produces 3.3 V for the analog circuitry. The ISO1540 transfers the I²C clock and data signals across the isolation boundary to the ESP32-S3.
Voltage Measurement and ADC FiltersThe input- and output-voltage channels use the same divider. Two 160 kΩ resistors in series form the high side, and a 20 kΩ resistor connects the divider node to PGND. This gives a nominal 17:1 ratio. Splitting the 320 kΩ high-side resistance between two parts also shares the applied voltage between the resistors.
Each voltage divider feeds its ADS1115 channel through a 1 kΩ resistor, with a 1nF capacitor at the ADC input. Together with the divider's source resistance, this produces an 8 kHz low-pass filter. It reduces fast switching and radio-frequency noise, while its approximately 100 µs settling time allows the ADS1115 to switch channels without slowing the 100-sample-per-second acquisition loop. The ADS1115 digital filter and firmware averaging handle lower-frequency noise.
The current channel uses a separate 100Ω/1nF network between the INA240A2 output and its ADS1115 channel. These values are part of the current prototype and remain subject to review before production. Final selection will verify ADC settling, noise rejection, and operation with the production PCB layout.
Input Protection and PolarityAn SMBJ36A TVS diode is connected across the supply input, ahead of the shunt and relay. It clamps positive transients but does not provide reverse-polarity protection.
The prototype relies on correct supply polarity. A reverse connection can forward-bias the diode, and there is no onboard fuse or current limiter. The additional protection diodes shown in the schematic are do-not-populate parts and are not fitted.
Current MeasurementMany commercial bench power supplies use 30 V and 3 A as a standard channel rating. This established the initial front-end target: measure 0 A to 3 A and use as much as practical of an ADC input operating from 3.3 V.
The first idea is a direct 0 A to 3 A mapping into approximately 0 V to 3.3 V. This requires a current-channel sensitivity of:
Required sensitivity = 3.3 V / 3 A = 1.1 V/AProducing that voltage directly across a shunt would require 1.1 Ω. At 3 A, that resistor would drop 3.3 V and dissipate 9.9 W. That loss is too high for an inline measurement module, so the design uses a much smaller shunt followed by an amplifier.
A 10 mΩ shunt drops only 30 mV and dissipates 90 mW at 3 A. The amplifier gain required to expand 30 mV to 3.3 V is:
Required gain = 3.3 V / 0.03 V = 110 V/VThe INA240 was selected because it can measure a small differential voltage while its inputs sit at the bench supply's higher common-mode voltage. Its specified common-mode range extends from −4 V to 80 V, which covers the 30 V design target. The device is available with fixed gains of 20, 50, 100, and 200 V/V.
The 100 V/V version is closest to the initial 110 V/V target. With the 10 mΩ shunt, it would produce 1 V/A, or 3 V at 3 A. This nearly fills a 3.3 V ADC input, but it leaves little analog headroom and requires the ADS1115's ±4.096 V setting.
The implemented circuit instead uses the INA240A2 with a gain of 50 V/V:
Current sensitivity = 50 V/V × 0.01 Ω = 0.5 V/A
Output change at 3 A = 0.5 V/A × 3 A = 1.5 VThe lower amplifier gain allows the firmware to select the ADS1115's ±2.048 V range. The 1.5 V current signal at 3 A fits with about 548 mV of range headroom before accounting for the output offset described below. The ADS1115 returns a signed 16-bit value, so one step at this setting is:
ADC step = 4.096 V total span / 65,536 codes = 62.5 µV per codeThe current represented by one ADC code is:
Current step = 62.5 µV / 0.5 V/A= 125 µA per codeThis is the same nominal current step that a 100 V/V amplifier would provide with the ±4.096 V ADS1115 range. That combination gives a 125 µV ADC step and 1 V/A sensitivity, which also equals 125 µA per code.
The implemented 50 V/V and ±2.048 V combination therefore preserves nominal current resolution while providing more analog headroom. The 0 A to 3 A span uses about 24, 000 codes.
These calculations describe nominal conversion resolution, not current accuracy. Amplifier and resistor tolerances, noise, temperature, layout, and calibration determine the useful measurement resolution.
The shunt Kelvin-sense paths each include a 4.7 Ω series resistor. These resistors place a small impedance between the external banana-plug connections and the INA240 inputs. They limit current from fast connection transients without adding a significant error to the shunt measurement. They are not intended to set the measurement bandwidth.
Board Revision 1.2.1 adds a small INA240A2 output offset. With both reference pins grounded, the amplifier operates close to its lower output limit, and currents below about 3 mA could not be measured reliably. The revised circuit uses a 20 kΩ/2 kΩ divider and an LM321 buffer to produce about 300 mV from the isolated 3.3 V rail. This voltage is applied to one reference pin while the other remains grounded. The INA240 averages the two reference inputs, so the nominal zero-current output is about 150 mV. Moving the output away from its lower limit fixes this low-current dead zone. At 3 A, the expected ADC input is about 1.65 V, leaving about 398 mV of headroom inside the ±2.048 V range.
The reference input also provides a path to bidirectional current measurement. If the effective zero-current output is set to 1 V, forward current moves the output above 1 V and reverse current moves it below 1 V.
High quality, full project schematic is available on GitHub.
Why an Unconnected Input Can Show a VoltageThe isolated analog circuitry can be powered from USB while no bench supply is connected. In that state, the INA240 inputs have no low-impedance connection to PGND. They are therefore free to move together as a floating common-mode node.
The INA240 input-bias current depends on this common-mode voltage. Figure 7-14 in the INA240 datasheet shows that the typical bias current changes as the input voltage rises and approaches zero in the low-voltage region. With no external source driving the input, the bias current charges the floating node until it reaches an equilibrium. A connected multimeter supplies the small return path that defines the measured voltage.
For example, a typical digital multimeter has a 10 MΩ input resistance. A reading of 1.3 V means that the meter draws only:
Meter current = 1.3 V / 10 MΩ = 130 nAThe two INA240 inputs share this load, so each input supplies approximately 65 nA. The measured voltage is the point where their combined input-bias current balances the multimeter current. In simplified form, this condition is:
2 × |IB(VCM)| = Vmeter / RmeterThe datasheet curve shows typical behavior at a 5 V supply, while PSU-EXT powers the INA240 from 3.3 V. It does not guarantee an exact floating-input voltage. Component variation, temperature, and multimeter input resistance can also move the result. However, a reading around 1.2 V to 1.4 V with a 10 MΩ meter is consistent with the datasheet behavior. A lower-resistance meter loads the node more heavily and can show a lower voltage.
This is a high-impedance bias voltage, sometimes called a ghost voltage. It cannot provide useful power and collapses when the input is connected to the bench supply or another low-impedance load. Measurements relative to USB ground can be even more confusing because USB ground and the isolated analog ground are intentionally separate.
Switching Regulator NoiseThe measurement circuit needs isolated power, but an isolated switching converter can introduce noise. The RFM-0505S converts the USB-side 5 V supply into an isolated, unregulated 5-ish volts supply. It switches between 50 kHz and 100 kHz, with 80 kHz listed as typical. Its datasheet specifies up to 100 mV peak-to-peak of output ripple under the stated measurement conditions.
The converter is not in the bench supply's main power path, so this ripple is not applied directly to the load. However, the isolated analog ground is connected to the bench supply and load return. Switching current could therefore appear as noise in the measurement reference or couple into the load through ground impedance and parasitic capacitance.
The design addresses this in several stages. A 47 µF (100 µF in the current prototype) capacitor is fitted on each side of the RFM. On the input side, capacitor works together with a 10 µF capacitor to supply the converter's pulsed current locally. The second 47 µF capacitor is connected across the isolated output to reduce ripple and support short load-current changes. The isolated 5 V output then feeds an LD1117S33 linear regulator instead of powering the analog circuitry directly. The regulator produces the 3.3 V rail used by the ADS1115 and INA240A2. A 100 nF capacitor at the regulator input and a 10 µF capacitor at its output handle higher-frequency noise and load transients.
Two 330 pF, 1 kV ceramic capacitors provide defined high-frequency return paths across the isolation barrier. One connects the two 5 V rails, and the other connects GND and GNDS. They block DC and do not remove galvanic isolation. Their purpose is to return fast switching currents through known paths instead of uncontrolled converter and PCB capacitance. The 1 kV rating is required because the capacitors bridge the isolation boundary. This is a component rating, not a safety-certification claim for the complete product.
Current prototype, isolated 3.3 V rail measured 3 - 6 mV peak-to-peak ripple noise under home-lab conditions.
The firmware separates AD access, calibration, storage, averaging, and the Standard Commands for Programmable Instruments (SCPI) interface. A background FreeRTOS task performs the conversions continuously. SCPI queries read the resulting history instead of stopping the task to request a new conversion.
PSU-EXT exposes two logical measurement channels:
| Channel | ADS1115 input | Measurement |
|--- |--- |--- |
| `CH0` | `AIN0` | Supply input voltage |
| `CH1` | `AIN1` | Load output voltage |
| `CH1` | `AIN2` | Output current from the INA240A2 |
| — | `AIN3` | Unused |ADS1115 Configuration
The ADS1115 is connected over a 400 kHz I²C bus at address 0x48. All three inputs are measured as single-ended signals against the isolated analog ground. The programmable gain amplifier is set to the ±2.048 V range, which gives a nominal ADC step of 62.5 µV.
The firmware uses single-shot mode at 860 samples per second. Each read selects one input, starts a conversion, polls the conversion-ready bit, and reads the result. The comparator output is disabled. Access is protected by a mutex so that only one task can change the ADC multiplexer at a time.
The first conversion after every multiplexer change is discarded. The firmware then performs a second conversion and keeps that result. This allows the analog input and the ADC's switched-capacitor input to settle after moving to a different channel. At the maximum configured rate of 100 measurements per second for each of the three active inputs, this requires up to 600 conversions per second, which fits within the selected 860-sample-per-second ADC rate.
The background rate is configurable from 10 Hz to 100 Hz per active input. The production application sets it to 100 Hz. Raw ADC readings are converted into unsigned fixed-point values scaled by 10, 000. Negative ADC readings are clamped to zero in the present unidirectional measurement path.
Calibration
Calibration is applied to every sample before it enters the history buffer. The firmware maintains separate tables for CH0 voltage, CH1 voltage, and CH1 current. Each table contains between two and eight calibration points. Every point stores the raw measurement and the corresponding value reported by the reference instrument.
For a reading between two calibration points, the firmware uses piecewise-linear interpolation:
calibrated = actual0 + (raw - raw0) × (actual1 - actual0) / (raw1 - raw0)The first or last table segment is also used for readings outside the calibrated span. This provides linear extrapolation rather than abruptly stopping at the endpoint. The calculation uses fixed-point integer arithmetic with rounding and saturation. Calibration points must increase in both raw and reference value, which prevents reversed or zero-width segments.
Calibration is transactional. A command opens a staging table, and each point starts a fresh capture from the selected logical channel and physical ADC input. The capture ignores the first two matching samples, then collects 16 signed ADS1115 codes. It adds the codes with a 64-bit accumulator and checks that the peak-to-peak spread is no more than 16 ADC codes. An unstable window is discarded, including its settling samples, and capture starts again within the same five-second deadline.
Once a stable window is available, the firmware calculates the signed mean and rounds it once. Only then does it convert the averaged native ADC code into the unsigned fixed-point format used by the calibration table. This avoids losing information by rounding every ADC sample to fixed point before averaging. The averaged raw value is stored with the reference value supplied by the calibration command.
The active calibration remains unchanged until the complete staged table is validated, written to nonvolatile storage, and committed. An abort discards the staged changes. Generation checks also prevent a delayed capture from writing into an aborted or replaced transaction. This keeps an interrupted calibration session from replacing a working table.
Committed tables are stored in the ESP32's nonvolatile storage (NVS). Each versioned record contains a format identifier, the point count, all calibration pairs, and a CRC-32 integrity check. The firmware loads independent records for both voltage channels and the current channel at startup. Missing or invalid records fall back to the nominal two-point conversion, and the loader can migrate the earlier two-point storage format.
Circular Measurement Histories
Four circular buffers are allocated in external pseudo-static RAM (PSRAM):
CH0input voltageCH1output voltageCH1output currentCH1output power
Each buffer holds 1, 000 records. A record contains a 32-bit device-uptime timestamp in milliseconds and a 32-bit calibrated value scaled by 10, 000. The four histories therefore use 32, 000 bytes for sample records. When a buffer is full, the next sample replaces the oldest one.
Power is not read from another ADC input. The service pairs calibrated CH1 voltage and current events and calculates power as voltage × current. The derived value is timestamped and stored in its own circular buffer.
At the production application's 100 Hz rate, each buffer contains about ten seconds of history. If the rate is reduced to 10 Hz, the same buffer contains about 100 seconds. SCPI data queries can select a record count and an oldest-relative starting offset. Records are returned from oldest to newest as a definite-length binary block.
Measurement Averaging
A scalar voltage, current, or power query returns the arithmetic mean of the newest calibrated samples in its history buffer. Voltage, current, and power have independent averaging counts. Each count can be set from one to 100, defaults to 50, and is retained in NVS across restarts.
At 100 Hz with the default averaging count of 50, a scalar result covers approximately half a second of measurements. Increasing the count reduces random noise but makes the reported result respond more slowly. Setting the count to one returns the latest calibrated sample. Binary history queries remain available when an application needs the individual timestamped samples instead of the averaged scalar value.
This scalar-query averaging is separate from calibration capture. Calibration always uses its own fresh 16-code stability window. Changing MEAS:VOLT:AVER:COUN, MEAS:CURR:AVER:COUN, or MEAS:POWER:AVER:COUN does not change how calibration points are collected.
Scalar readings are formatted with four fractional digits. This is the fixed-point reporting format, not an accuracy specification. Accuracy still depends on the analog front end, calibration reference, operating point, temperature, and validation procedure.
SCPI Over USB and TCPSCPI provides a text-based control interface that is familiar in test and measurement systems. PSU-EXT exposes the same command set over two transports:
- USB CDC for a direct cable connection
- Raw TCP on port
5025after the ESP32-S3 connects to Wi-Fi
A minimal session can identify the device, read the output voltage and current, and operate the relay:
*IDN?
MEAS:VOLT? CH1
MEAS:CURR? CH1
OUTP? CH1
OUTP CH1,1
OUTP CH1,0Only queries ending in ? return a response after success. Invalid commands, invalid arguments, and runtime failures return a line beginning with ERR.
Full PSU-EXT SCPI reference is available on GitHub. The SCPI interface covers:
- Input- and output-voltage measurement
- Output-current and output-power measurement
- Binary measurement history
- Relay state
- OVP and OCP settings and trip status
- Timer queue management
- External-trigger configuration
- Wi-Fi configuration and status
- Runtime date and time mapping
A browser cannot normally open a raw serial port or arbitrary TCP socket in a portable way. The PSU-EXT software stack uses a local backend bridge between the browser and SCPI devices.
The software has three main parts:
- A Spring Boot WebSocket proxy that connects browser clients to USB or TCP SCPI devices
- A React frontend for device configuration, live dashboards, charts, protection controls, and a SCPI monitor
- A PC-side script runner for managed JavaScript automation
The dashboard is built from configurable widgets. A widget can query a value, control a state, display a chart, or expose protection and trigger settings. Multiple widgets that request the same device and query share one scheduled data source instead of opening independent polling loops.
The software is not limited to PSU-EXT. The public documentation includes configuration examples for a Siglent SPD4323X power supply and a Rigol DM858E digital multimeter over TCP. Compatibility still depends on the commands and response formats supported by each instrument.
We encourage you to try our software with other instruments you own and provide feedback to us on GitHub. We've developed an easy 2 step installation process for the software and distributions available for Linux, Mac and Windows
Scripted Hardware TestsThe script runner executes JavaScript on the PC, not on the ESP32-S3. A script can query and control configured SCPI devices, write timestamped measurements, report progress, and stream logs back to the browser interface.
The runtime is restricted. Scripts do not receive general filesystem, network, or host access. PSU-EXT provides specific bindings for device communication, results, progress, logging, timing, cancellation, and operator input.
A small script can read voltage and current and save both values:
(() => {
const voltage = query("PSUEXT1", "MEAS:VOLT? CH1");
const current = query("PSUEXT1", "MEAS:CURR? CH1");
record(new Date(), "voltage", "V", voltage);
record(new Date(), "current", "A", current);
log("INFO", "Measured " + voltage + " V, " + current + " A");
progress(1.0);
return { voltage, current };
})();The public repository includes example scripts for identification, voltage and current measurement, looping, operator confirmation before enabling an output, and power and energy logging.
Building PSU-EXT From the Published SourcesPSU-EXT is currently open source and can be reproduced from the complete source files. The hardware repository includes the editable KiCad schematic and PCB projects, Gerbers, drill files, bill of materials (BOM), component-placement list (CPL), and schematic PDF. It also includes the editable FreeCAD enclosure project and printable exports.
The firmware and complete PC-side software stack are published in their own repositories. Anyone reproducing the product should use matching hardware, firmware, manufacturing, and enclosure revisions and observe the documented electrical limits.
Specifications- Measurement rate: 100 samples per second
- Operating range: 0–25 V and 0–2.5 A
- DC voltage accuracy: ±(0.1% of reading + 2 mV) from 1 V to 24 V; ±(0.5% of reading + 2 mV) below 1 V
- DC current accuracy: work in progress.
- Protection response: 10ms nominal protection-evaluation interval
- Terminal Spacing: 19.05 mm (3/4 in) center-to-center spacing for 4 mm banana receptacles
- PCB dimensions: About 100 × 50 mm (3.94 × 1.97 in)
- Weight: 82 g
The voltage-accuracy figures are preliminary measurements taken under laboratory conditions after calibration.
Product StatusPSU-EXT is a developed open-hardware product with a working enclosed unit, firmware, backend services, browser interface, automation tools, manufacturing outputs, and automated tests. The complete project is published across the public repositories.
The current hardware is an engineering validation test (EVT) prototype. All functions described in this article are working on the enclosed prototype, including isolated voltage and current measurement, calibration, relay control, protection, SCPI over USB and TCP, measurement history, the backend bridge, the browser interface, and automation tools.
The project is reproducible and manufacturable in its current prototype form. The public release includes editable KiCad and FreeCAD sources, Gerbers, drill files, a bill of materials (BOM), a component placement list (CPL), enclosure exports, firmware, application software, and automated tests. These files support ordering the PCB, assembling the hardware, building the firmware, and running the complete software stack.
EVT status means that the architecture and described functions have been implemented and exercised on real hardware. It does not present the current unit as a production-qualified or safety-certified instrument. Revision identification and visible prototype rework remain part of the project record.
Open Hardware and SoftwareThe project is open source now, across four repositories in the PSU-EXT GitHub Organization:
- Hardware sources and manufacturing files
- ESP-IDF firmware
- Backend, frontend, script runner, and installer
Original hardware design sources use the CERN Open Hardware Licence Version 2, Strongly Reciprocal (CERN-OHL-S v2). The firmware and control software use the Apache License, Version 2.0. Bundled third-party assets and dependencies retain their own notices and licenses.
The release includes editable source projects, not only fabrication exports. The KiCad schematic and PCB projects allow electrical review and modification. The FreeCAD project provides the editable enclosure design. Gerbers, drill files, the BOM, the CPL, printable enclosure files, firmware, backend, frontend, and test sources support reproduction of the complete system.
What Do You Think About PSU-EXT?Please share your questions, use cases, and ideas in the comments. We welcome feedback on the hardware, firmware and software while PSU-EXT continues to develop. We encourage you to try our software, report problems or propose improvements by opening an issue in the PSU-EXT project repository.
Follow PSU-EXT on Crowd SupplyPSU-EXT is live on Crowd Supply. Follow the project there to receive campaign and launch updates.


_4YUDWziWQ8.png?auto=compress%2Cformat&w=48&h=48&fit=fill&bg=ffffff)



_Ujn5WoVOOu.png?auto=compress%2Cformat&w=40&h=40&fit=fillmax&bg=fff&dpr=2)


Comments