Skip to content

FNIRSI DPS-150: A Portable Programmable Supply, from Official Specs to Direct Serial Control ​

FNIRSI DPS-150 (official product photo)

A palm-sized FNIRSI DPS-150 programmable supply (0–30V / 0–5A / 150W) for which the vendor only ships a Windows PC app. The community has fully reverse-engineered its USB serial protocol, so one line of pyserial reads telemetry, sets voltage and current, and switches the output. The first half of this page collects the specs and UI from the official manual (with product photos); the second half is the reverse engineering and the pitfalls we hit (DPS-150P / firmware V1.6). The code is packaged as tool/dps150.py.

Specs at a Glance (Official Manual) ​

ItemValueItemValue
Model / screenDPS-150 · 2.8-inch 320×240Output voltage / current / power0–30V / 0–5A / 0–150W
Input voltage / currentDC 5.0–32V / 100mA–5A (supports PD / QC fast charging, can run off a power bank)Full-load efficiencyHigh (as stated in the manual; see the PDF)
Setting resolutionvoltage 10mV · current 1mASetting accuracyvoltage ≤0.1%±5mV · current ≤0.1%±3mA
Read-back accuracyinput voltage ≤0.2%±5mV · output voltage ≤0.1%±10mVLoad regulation0.49%

The manual calls it DPS-150, but the actual unit is DPS-150P (this page uses the real model throughout).

Panel and Main Screen ​

Panel overview (official manual)

The front has a 2.8-inch screen plus six buttons (the wheel slides left and right to adjust values):

Main screen (official manual)

The main screen is dense (matching the manual's numbered callouts): input voltage, internal temperature, run state, live V/A/W and accumulated energy (Wh/Ah), voltage setpoint (0.01V steps), current setpoint (0.001A steps), preset group number, panel lock state and output mode.

There are seven run states; any of them other than OK turns the output off automatically and sounds the buzzer:

StateMeaning
OVP / OCP / OPPover-voltage / over-current / over-power protection
OTPover-temperature protection
REPreverse-polarity protection
LVPunder-voltage protection (the output cannot be turned on in this state)

Preset groups: the device stores 6 presets (M1–M6), each with its own voltage and current-limit setpoint; a short press switches between them — handy when powering several devices in turn.

Output modes: constant voltage CV or constant current CC.

Operating Essentials ​

  • Adjusting values: click the settings key to enter the highlighted field, then slide the wheel left/right to change it; click again to switch between the voltage and current setpoints, short-press to save and exit
  • Menu items (Power Settings / System Settings / About): the OVP/OCP/OPP/OTP/LVP thresholds are each configurable, plus language, standard ↔ industrial UI style, backlight brightness, volume and metering on/off
  • Saving a preset: open the data group page → click to highlight a field → adjust with the wheel → short-press to save
  • ⚠️ Once the PC app is connected the control panel locks itself (the lock icon turns white) and only unlocks when the serial session ends — the control tool we wrote later triggers this too

Menu screens (official manual)

Advanced Features Built into the PC App ​

Besides basic monitoring and waveform logging (the voltage/current curves zoom with the wheel and can be saved or deleted), the official Windows app has three advanced "run the output like a program" features:

FeatureWhat it does
Sequence outputsteps through preset V/I values on a timer, within a step range and loop count; supports manual single-stepping, pause/resume
Current sweepvoltage fixed, current sweeps from start to end as "step current + delay" (common in CC mode)
Voltage sweepcurrent fixed, voltage sweeps from start to end as "step voltage + delay" (common in CV mode)

PC app basic functions (official manual)

PC app advanced functions (official manual)

Firmware Upgrade (Two Routes) ​

  • USB-drive method: hold the upgrade key while plugging in the data cable; a USB drive shows up on the computer, copy the firmware in and the device upgrades itself
  • PC app method: once connected, click "Firmware Upgrade → BOOT/restart"; the same USB drive appears for copying the firmware

Firmware upgrade screen (official manual)

⚠️ Note: firmware upgrade uses DFU mode. Don't confuse it with 0xC0 in our serial protocol — that's the "enter DFU" command byte, and sending it by mistake drops the serial port entirely (see the dangerous byte at the end).

Device Identification ​

It connects over the Micro-USB data port and enumerates as a USB CDC virtual serial port (the internal MCU is an Artery AT32):

bash
system_profiler SPUSBDataType | grep -A6 "AT32 Virtual Com Port"   # 识别设备
ls /dev/cu.usbmodem*                                               # 串口设备节点

Protocol Overview (Community Reverse Engineering) ​

The frame is minimal — 1 header byte + command + register + length + data + checksum:

0xF1CommandRegisterLengthData (0..N)Checksum
HeaderCmdRegLenData…Sum

Checksum = (寄存器 + 长度 + Σ数据) & 0xFF (header and command are excluded); the device replies with header 0xF0; all values are IEEE754 float32 little-endian.

Command bytes:

CommandPurpose
0xA1read register
0xB1write register
0xB0set baud rate
0xC1session connect / disconnect
0xC0⚠️ enter DFU flash mode — never send this (the CDC port disappears; replug to recover)

Key registers:

RegisterTypeMeaning
0xC1float32voltage setpoint
0xC2float32current setpoint
0xDBuint8output switch (0/1)
0xC0float32input voltage
0xC33×float32measured output V/A/W
0xDCuint8protection status (0=OK,1=OVP…6=REP)
0xDDuint80=CC / 1=CV
0xFF139Bfull status dump (6 presets, protection thresholds, Ah/Wh)

Control Loop Measured ​

One command sets the values and turns the output on; the soft start ramps up in about 1.5 s:

CapabilityMeasured
Read model / firmware / hardwareDPS-150P · V1.6 · V1.0
Read telemetryinput 20.08V, temperature 30.5°C, output V/A/W, full 139-byte status
Write setpoints5.000V / 0.500A, read back identical
Output on/offon → 5.000V (soft start ~1.5s); off → discharges to zero in ~1.2s

Common operations:

bash
python3 tool/dps150.py status                               # 读全状态
python3 tool/dps150.py set --voltage 12.0 --current 2.0     # 设 12V/2A(不开启)
python3 tool/dps150.py set --on                             # 开输出
python3 tool/dps150.py set --off                            # 关输出

Pitfall Archive ​

SymptomRoot causeSolution
Register reads come back scrambled, only 12 bytesthe device pushes telemetry frames unsolicited (0xC3 etc.) into the response streamfilter the read-back by register number and drop non-target frames
Reading 0xE2/0xE3 on their own returns 0the capability registers only carry values in the pushed framestake max V/I from offsets 0x6F/0x73 of the full status dump
Setting 30V doesn't stickbuck architecture: the output ceiling is clamped below the input voltage (20V in → 19.88V max)raise the input voltage if you need more output
Right after enabling, the voltage reads only a fraction of a voltthe soft start is still rampingwait ≥1.5s before reading
Panel buttons stop workingconnecting the PC app auto-locks the panelend the serial session to unlock

One dangerous byte

0xC0 isn't a reboot — it enters DFU flash mode: the USB CDC port vanishes and you must physically replug to recover. The device has no soft-reboot command.

Reproduction and Sources ​

  • Control tool: tool/dps150.py in the fnirsi-dps150 skill (only depends on pyserial)
  • Protocol source: community reverse engineering nasheed-x/dps150_api (PROTOCOL.md, cross-checked against four implementations in JS/C/Python/Rust plus a decompiled official .NET app)
  • Official resources: FNIRSI official product page · official manual PDF (all specs and UI images here come from that manual, archived on this site)
  • For the full register map, the 139-byte layout and the preset group formulas, see the fnirsi-dps150 skill reference docs
Something unclear here, or want to talk about similar work?Message me →