Low-Cost Programmable Power Supply

Chinese "LM2596 DC/DC buck converter with voltmeter" + "some wires" + "Forth" = "programmable power supply"

Similar projects worth following
Programmable power supplies are important for test automation. This project turns a $1.60 Chinese DC/DC converter with µC-based voltmeter into hobby lab equipment. The price per unit is less than $2, and the conversion can be done in about 15 minutes!

So far, the following features have been implemented:
* modification instructions for a cheap DC/DC converter
* programmable output voltage and ON/OFF
* input and output voltage measurement (e.g. for display, safety, or closed loop control)
* Full programmability in an embedded scripting language
* U=f(t) time sequencing,
* character I/O with 2 keys and 3 digit 7S-LED display for user interface
* remote control, and interactive scripting through RS232

Code from the Hackaday "eForth for cheap STM8S Value Line gadgets" project is used, mastering of which will give you bragging rights. It's also possible to use this hack for simple automation, battery charging, or lighting.

Hackable DC/DC Converters

A quick search for "LM2596 DC 4.0-40 to 1.3-37V Adjustable Step-Down" on AliExpress presents a range of cheap DC/DC converters with voltmeter from $1.50. I discovered that the voltmeter uses a STM8S003F3P6, the low-cost µC that's the target of my first Hackaday project. The first specimen I hacked didn't have the most promising hardware design: it was necessary to solder patch wires to pins of a 0.65mm TSSOP package *).

The second one I ordered looked like this:

The first obvious thing, already visible on the vendor's pictures, is that the 7S-LED display nicely covers the voltmeter part including all the passive components.

*) Of course, it's still possible to remove the 7S-LED display, and use the pin as a breakout for no less than 11 GPIOs!

Under the Hood

Underneath the LED display we find this nice arrangement:

The LM317 in TO92 package is directly connected to the voltage divider R4/R3 (the LM317 lacks the recommended capacitor Cout, Cin is shared with the LM2596). C13 is connected to Vcap (STM8 1.8V core supply circuit). R1/R2-C4 and R8/R9-C5 are the "voltmeter inputs" (PC4 Vin, and PD3 Vout). R5 is connected to the green power LED.

PC3 is connected to LED "in", and PB4 to LED "out" without current limiting resistor (the same as the 7S-LED display). Like in the first variant, the "design" relies on the limited current driving capability, and on the surprising robustness of the STM8S outputs. The LED power dissipation is limited by a 4% duty cycle (there is a small risk of accelerated aging).

Isn't there anything else missing? Yes, a bypass capacitor for the STM8S003F3P6! A 100nF capacitor should be added to prevent communication errors (see instructions). Any doubts about the robustness of the STM8S are unfounded: it will tolerate circuit bending practices on a mass production scale ;-)

I first assumed that the GPIOs used for the 7S-LED display are the same as in the first variant, but they're not (the STM8S003F3P6 is rotated by 90º).

The LEDs "in" and "out" are now connected to dedicated GPIOs (which is good for us), but the keys still share a GPIO with LED segments like in a 70s pocket calculator (PC5/SegE and PD2/SegG). It would have been really easy to use PB5 for reading the keys but well ...

As mentioned in one of my previous posts there is a thing I learned about the STM8 ICP interface: connecting the NRST pin isn't needed unless SWIM has been disabled in the device configuration, and if the port pin is in input mode at least sometimes. Since PD1/SWIM is connected to pin4 of the display, iIt's possible to get a new firmware onto the µC without removing the 7S-LED display! Programing usually fails on the first attempt but that's OK for our needs: once there is a Forth console we can use IAP (in application programming).

Which variant to buy

I only plan to provide full board support for the variant in the pictures above. Other variants are either more expensive, or they don't have GPIOs on the LED pads that can be re-used easily. If you want to buy a unit, on AliExpress search for "LM2596 DC 4.0-40 to 1.3-37V Adjustable Step-Down" or simply post a comment here. I've seen a green and a blue variant, and both are easy to identify ("CN2596-2" is written on the back, LM317 is in TO92 package, it has only few passive components near the 7S-LED display). The green variant is better, since the ICP pins (NRST & SWIM) are broken out to pads.

Modding Options

The board has some quirks, but we can work around them:

  • for reading ADC values, the display should be dark (the anode, and the cathode outputs should be off - due to the required low duty cycle that's no problem
  • ADC Vin ADC is easily accessible on the backside of the PCB (after cutting the copper trace it can be used for measuring something else)
  • ADC Vout can be used for an output voltage control loop (or, after modification, for measuring the output current)
  • PC3 can be exposed by removing LED "in"...
Read more »


Try-It snapshot (the latest version is on )

ihx - 16.33 kB - 01/31/2017 at 19:35


  • 1 × 100nF ceramics capacitor 0603 or 0805 (47nF to 10µF should work, too)
  • 1 × 10µF ceramics capacitor 0603 or 0805 (4.7µF*47R should work, too)
  • 1 × 47R 0805, replaces LED "IN" (33R*10µF should work, too)
  • 1 × 1K8 0805, replaces LED "OUT" (any value from 220R to 4k7 should work)
  • 1 × some wire

View all 6 components

  • STM8 eForth 2.2.20 tested with the Low-Cost Programmable Power Supply

    Thomas12/23/2017 at 22:51 0 comments

    I just tested one of my green boards with the latest STM8 eForth 2.2.20:

    • the improved e4thcom support works great, even though the communication uses the DP segment
    • #require loads aliases for unlinked words from the folder out/DCDC/target
    • even loading Manfred Mahlow's STM8 eForth VOC extension, which patches the core, works without problems

    The packaging method with automated builds (Travis-CI) used in the W1209 data logging thermostat project works well, and I plan to use it for providing pre-build "programmable power supply" binaries.

  • STM8EF v2.2.15: e4thcom 2-wire mode improves DC/DC usabiliy

    Thomas09/17/2017 at 18:29 0 comments

    The latest STM8EF release v2.2.15 contains a CN2596 DC/DC board binary that works great with the latest e4thcom STM8EF plug-in.

    Here is a demo (asciinema garbled the console key input a bit):

    Please note that the coding examples can now use the e4thcom Forth code #include & #require features. It's also possible to create binaries from the same code using the STM8S simulation feature of uCsim.

  • Script it: Forth Intro

    Thomas06/01/2017 at 17:05 0 comments

    Forth is a very simple language, ideal for scripting, and therefore the Forth Intro in the GitHub Wiki also was simplified.

    Check it out - feedback is welcome!


    Thomas05/19/2017 at 17:29 0 comments

    Nice, this little project seems to catch the attention of many of you!

    It's really easy and cheap to hack the CN2596 DC/DC modules, and I can't wait to see on of these boards running your code, to do something useful, or to confuse a cat, I don't care :-) In any case, if you have questions just ask!

  • A Bug!

    Thomas05/06/2017 at 08:40 0 comments

    @RigTig found a bug in tg9541/stm8ef that also affects this project: emiting a "Z" to the 7S-LED display shows an "S" while he's doing fancy things with the W1209. My bad. Bug fixed, but right now only in the develop branch. In other words, the base software is otherwise rather stable.

    It's a bit quiet here because I'm currently bringing Forth to the HC12 wireless RS232 bridge. Robust communication to "smart things" in-house, on-premises or at > 500m in free space for about $3 and with very low power-consumption in stand-by mode.

  • Wiki Page on GitHub Updated

    Thomas04/19/2017 at 18:22 0 comments

    The eForth for STM8 Wiki page on the CN2596-2 board has been updated. On this page I try to consolidate information dispersed here over comments and log entries.

    If you think that something important is missing, please let me know!


    Thomas03/31/2017 at 05:38 0 comments

    Nice, 100 people show interest in what was meant as a showcase project for the STM8 Value Line eForth project!

    It's true, Forth differs a lot from procedural programing languages like Java, C++, C, Pascal, or Fortran. If you put the religious wars about programing languages aside, you'll see properties of scripting (Bash, BASIC, Perl, Python), REPL (LISP, Clojure), and ... assembly. It's not a panacea, but for some things it's very good.

    I'd like to encourage you to get one or two of the green DCDC boards, an ST-LINK V2 adapter, and a serial interface adapter. With budget delivery, this will cost you about $4. It would be really nice to some companions on this journey, and to get some feedback about which features are needed most, or which points need better docs :-)

    EDIT: 102 people now. Thanks guys! I forgot to mention the two capacitors and the two resistors. If you don't have an assortment in your lab anyway, here and here are examples for what you'd need for this, and for other projects (you may also ask a friend for some of these half-a-penny items).

    Does someone know of a Hackaday page with recommendations for an "electronics starter kit"?

  • Cold Cranking (automotive ECU testing, homebrew style)

    Thomas03/26/2017 at 11:24 0 comments

    Programmable power supplies are a necessary (and very expensive) test equipment in the automotive industry. The price tag for a single test channel can be several $1000 (and sometimes more). You'll never hear me say that one can fully replace such a piece of equipment on-the-cheap, but it's always possible to use cheap equipment for doing a tests that support the development, and thus to reduce the risk that the thing you develop won't pass tests. Also it's sufficient for "explorative testing", a method that's used in validating requirements (i.e. find out if known requirements are sufficient for higher level goals, like robustness or functional safety).

    One of the common power supply tests for networked ECUs (electronic control units, e.g. motor control, body controller, brake control) is the cold cranking test. The "test pulse" (i.e. the effect on the power supply) looks like this:

    Please note that the time scale in the first part of the function is in the order of miliseconds, and later in the order of seconds! The first part often induces a reset of an ECU (even if the requirements say that it shouldn't). Since no ECU I know of can power valves (or other actuators) from 3V, the 50 ms slope that follows stresses diagnostic routines. The 10s plateau then requires the ECU to rest in a degraded mode from which it has to recover somewhere in the 10s slope leading to normal operating conditions. Of course, the test pulse is just an acceptance test. For the supplier, developing a robust ECU is the main objective, not meeting the exact requirement.

    The pulse can be generated by simply defining the output voltage as a function of time. I took the values from the chart and made a table for @inter which maps time in ms to voltage in mV.

    Creating a test pulse is very simple, all it takes is a background task, that maps TIM value (ms ticks) through the mapping function and sets the output voltage:

    CREATE cctab 6 , 12000 0 , , 3000 5 , , 3000 20 , , 6000 70 , , 6000 10070 , ,12000 20070 , ,
    : coldcrank TIM cctab @inter mV ; ' coldcrank BG ! HAND

    CREATE defines the new word cctab, which returns the address of the following cells. In the following lines, the , take numbers from the data stack, and create a table by storing them in the dictionary memory (i.e. right after the word cctab. The word coldcrank gets the timer ticker value and the address of the table on the stack and uses @inter to get the value corresponding to the value of the 16bit ticker (in ms), and uses mV from the last log entry to set the output voltage. Negative values, and values > 20070 ms result in the saturation value 12000 mV (just like in the diagram). The pulse is thus repeated ever 65.536 s.

    On my >20 years old damaged scope, the result looks like this:

    If the picture doesn't look like the the diagram above it's because of the two time scale . It's hopeless to see a 70ms voltage drop to 3V at a 5s/DIV timescale. The rising slope looks good (it appears to be linear!), and also the two constant voltages (6V and 12V) are accurate. Discharging capacitors to 3V in just 5ms without additional effort won't work (at 330R load the output voltage drops to 5V after 60 ms from where it rises to the plateau of 6V in about 20ms). However, this result was reached with a very quick open loop control hack, and it took much longer to write this log, than to make this showcase application!

    These guys from FIG were right, Forth is very effective, especially for building test equipment. For decades I only used C and assembly for embedded programming, and I had missed out on a very good tool.

    EDIT: for discharging the output capacitor of the CN2596-2 board (220µF) from 12V to 3V in 5ms about 22R load is required. If the DuT (device under test = the test load) has a power rating of more than about 6.5W@12V that would always be the case. If the power rating is lower it depends: if the DuT has an ideal 3,17W DC/DC converter the 5ms slope in the test pulse spec could be met, too....

    Read more »

  • Linearized output

    Thomas03/26/2017 at 08:58 0 comments

    With the interpolation routine from the last log entry linearizing the DCDC converter output is simple. It doesn't really matter how the function looks like: the grid point density can be adjusted to match the second derivative. In a first example, I simply used a voltmeter and the interactive Forth console to map PMW values to the output voltage. It turned out that between 0 and 1V the function is less smooth, and I inserted an extra grid point. Also, below 20mV I couldn't reliably control the output voltage (after all, a bias to the feedback ground of an LM2596 is a hack :-) ), so I set the last grid point to 469/20mV.

    I decided to represent the voltage in units of mV, and created the following table with 14 grid points:

    CREATE vptab
    14 ,
    469 20 , , 451 500 , , 434 1010 , , 401 2000 , ,
    367 3010 , , 333 3990 , , 297 5010 , , 261 5990 , ,
    222 7010 , , 183 7990 , , 141 8990 , , 97 9990 , ,
    50 11000 , , 0 12000 , ,

    The mapping of output voltage to PWM is simple:

    : mV vptab @inter pwm ;

    By typing eg. 7500 mV I get an output voltage of 7.53V, which is more accurate than I had ever expected. I observed some drift, but as there is nothing like reference voltage source, what can you expect?

    Here are more examples:

    5000 mV -> 5.02V
    3700 mV -> 3.73V
    3300 mV -> 3.35V
    2800 mV -> 2.83V

    Through the saturation feature of @inter the following works, too:

    15000 mV -> 12.00V
    -10000 mV -> 0.03V

    Once more: level up!

  • Interpolation routine wanted (solved)

    Thomas03/23/2017 at 06:25 10 comments

    This project calls for a robust and easy to use interpolation function, preferably one that accepts a list of (Xn,Yn) points sorted for ascending value of X. The result should be (Y0) for X < X0, and Ylast for X > Xlast.

    If anybody has some code lying around or knows of some code that's been published under a permissive Open Source license, I would love to hear about it. Otherwise you'll just have to wait until a sufficient number of neurons in my brain isn't already fully satisfied by working on work related problems ;-)


    I brewed something up. @inter includes the table search and the interpolation function @K.C. Lee referred to, and a limiting function that works by comparing the pointers to value pairs. It can be used for arbitrary y=f(x) with saturation, which is what's needed for many control and linearizion tasks.

    : @dif ( a -- n )     \ delta of value pairs
      dup 2+ 2+ @ swap @ - ;
    : @inter ( x a -- y ) \ find value pairs, interpolate
      dup @ 1- >R 2+ dup begin 
        3 pick over @ < not while 
        nip dup 2+ 2+ next 
          drop dup
        else R> drop then \ eForth LEAVE idiom
      over = if           \ pointers equal: saturation 
        2+ @ nip 
        dup rot over @ - over 2+ @dif 
        rot @dif */ swap 2+ @ + then ;

    @inter does a table lookup with interpolation. The input is the value and the address of a table with n value pairs (Xn, Yn) ordered by ascending values of X, and preceded by the number of n. @dif looks up two values returns the difference (X1-X0 or Y1-Y0 depending on the offset). A C program would be a bit longer, I guess. Compiled this code requires 177 bytes.

    Here is an example:

    500 1000 400 800 300 600 200 400 100 200 50 100 6 ok
    create pairs , , , , , , , , , , , , , ok
    : p pairs @inter . ; ok
    450 p 225 ok
    90 p 50 ok
    1500 p 500 ok

    pairs is an arbitraty list of 6 x/y value pairs: [6, [100, 50], [200, 100], [400, 200], [600, 300], [800, 400], [1000, 500] ]

    Test values:

    450 is between (400/200) and (600/300) -> result 225
    90 is below X0, and following the requirements above Y0 is returned -> 50
    1500 is above X(n-1) and Y(n-1) is returned -> 500

View all 22 project logs

  • 1
    Step 1

    Note: the picture in this log entry shows a fully modified board.

    Prepare the board:

    1. remove LED "IN"
    2. remove LED "OUT"
    3. interrupt the connection between LM2596 pin 5 (!ON/OFF) and GND (i.e. cut the pin in the middle, and de-solder the lower half)
    4. carefully cut the copper trace between the LM2596 heat sink GND and the 330R next to the trimmer.
    5. cut the copper trace between LM317 pin2 and anode pad of LED "IN". Expose some of the copper of the trace near said pad.
  • 2
    Step 2

    Add new components:

    1. solder a C 100nF between LM317 pin 2 and GND on the backside of the PCB
    2. solder a 10µF ceramics capacitor 0603 or 0805 over the now cut copper trace between the LM2596 heat sink GND and the adjacent pad of the 330R next to the trimmer
    3. solder a 47R 0805 resistor to the pads of LED "IN"
    4. solder a 1k8 0805 resistor to the pads of LED "OUT"
  • 3
    Step 3

    Make new connections for controlling the LM2596:

    1. add a wire between the cathode pad of LED "OUT" (PB4) and LM2596 pin 5
    2. add a wire between the copper trace near the anode pad of LED "IN" (PC3) to the 330R pad, where also the 10µF capacitor is connected
    3. connect (pin 2 || pin 3) of the trimmer to pin 1 of the voltage adjust trimmer on the board

View all 6 instructions

Enjoy this project?



richard wrote 09/18/2017 at 04:01 point

I've ordered a couple of these to play with. I'll be using a nominal 24 volt supply so If I set the output voltage to 20V when PWM=0 I'm hoping this gives me a 0-20V adjustable supply.

  Are you sure? yes | no

Thomas wrote 09/18/2017 at 05:05 point

This will most likely work. Expect, however, reduced control performance, especially from the lower 25% on. Performance will most likely leave a lot to wish for below 1V (but you can disable the converter, and for static loads you can create an "outer control loop" using the ADC). The LM2596 datasheet recommends selecting the inductor depending on the design power, and the required voltage transformation (-> discontinuous mode -> higher noise). Noise can be reduced by adding a inductor/capacitor network at the output.

  Are you sure? yes | no

richard wrote 09/18/2017 at 06:58 point

I don't have lab quality expectations. After all, there is only so much you're terrific Forth implementation can do to overcome the dodgy $2 hardware.

I was weighing up using the W1209 and an external DAC driving a linear regulator. But I had so many choices in the junk box that I was spinning my wheels. I still might explore that option but I think the LM2596 will suffice.

  Are you sure? yes | no

Thomas wrote 09/18/2017 at 19:02 point

OK, for automated robustness tests (e.g. automotive, machine control, etc) even a dodgy hardware is good (one might argue "if the circuit still works with that much noise it already passes the first test").
Considering the price, the LM2596 is OK. Efficiency-wise the XL4005 is maybe a better choice (but the control offset is just 0.8V, which requires a lower PWM duty cycle than what's needed for the 1.2V of the LM2596). If no 7S-LED display is needed a single STM8S003F3 can control up to 6 DC/DC converters.

  Are you sure? yes | no

Elliot Williams wrote 04/10/2017 at 19:10 point

I love the idea of a simple/cheap programmable power supply as a demo project for your Fortheries, so I ordered two of these things a few weeks ago.  As luck would have it, I got the "first variant" versions of the boards (or maybe something else, who knows?).  

To anyone following along: the big difference in board appearance is that the "first variant" board has more discrete components visible -- three resistors next to the TO92 package and two on either side of the display.  Don't get that board if you want to retain the display.

So I popped the display off and soldered some wires on.  Of the SWIM and UART lines, the only one that's not broken out into a through-hole is the NRST, which you may not need.  I gently lifted the pin and fly-wired it anyway. 

On my board, the chip needed unlocking, so I ran stm8flash with the -u flag first, and then uploaded a version of Thomas' stm8ef that didn't need to use the half-duplex hack, because without the LED you have clear access to both the TX and RX lines.  

So far, so easy.  Next I'm going to hack on Thomas' control routines for the  LM25596.  I'm half tempted to see if some minor code changes can turn this into a solar-cell MPPT device.  We'll see.

  Are you sure? yes | no

Thomas wrote 04/11/2017 at 05:36 point

Hi Elliot, the MPPT idea sounds great!

If you want to continue with the "first DC/DC PCB type", most of what I know about it is described in the log entries below. I also have half-baked code to control the LED display. If necessary I can refactor it to meet the improved "board framework" conventions but as you live in Germany I can also send you one of my a "green" DC/DC boards by mail.

If no LED display is required, an MPPT might also be feasible using plain DC/DC boards, and a STM8S breakout board. So far I didn't find out whether measuring the current is necessary for an optimal MPPT.

Here are log entries on the first DC/DC board variants:

Here is a bit on getting a PWM out of TIM1:

  Are you sure? yes | no

Elliot Williams wrote 04/11/2017 at 08:26 point

Thanks!  I was looking through those links late last night.  And no need to send me a green one -- ebay is already on the case. My impatience costs me only 2€.

Summarizing the voltage control routine to see if I've got it right: you inject an offset voltage into the voltage divider between the output and feedback pins by disconnecting a resistor to ground and replacing ground with a filtered-PWM voltage.  

You then look the PWM up in a table?  Why not close the loop on output and vary the PWM until it produces the desired output?  Is it unstable?  Have you tried?  Some combo of the lookup table PWM plus fine-adjustment should get the voltage "accurate" down to the resolution of the ADC.  (Of course, no voltage reference, etc.)

For MPPT: yeah, current is also necessary. But without the LED, I've got a lot of free pins. :)    

  Are you sure? yes | no

Thomas wrote 04/11/2017 at 17:05 point

You're of course right in all points:
* injecting an offset lowers the output voltage, but it also reduces the DC/DC control loop gain by a factor of (1-offset/1.25V)

* the lookup table acts as a open-loop-control component for the DC/DC converter's closed-loop-control set-point, and it greatly improves stability and responsiveness of this hack. However, a feedback component can help to reduce the residual control error. I guess that a PID controller would be a good addition, even though the voltmeter resolution is just about 50mV. Also, the lookup-table can be "self-learning".

* Removing the LED-display from any variant of the DC/DC converter turns the display's solder pads into a STM8S003F3 breakout. Who needs a display if the power supply is networked and automated, and the visualization (if needed) can be done with a central "dashboard"? Really a smart idea!

EDIT: the Wiki page on the CN2596 board now contains some info on STM8S003F3 and LED display connections:

  Are you sure? yes | no

K.C. Lee wrote 02/04/2017 at 12:24 point

>it was necessary to solder patch wires to pins of a 0.5mm TSSOP package.\

It is actually 0.65mm pitch.

  Are you sure? yes | no

Thomas wrote 02/04/2017 at 13:34 point

Thanks! Fixed.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates