High voltage generation from 3.3-5V

This post describes my standard DC-DC HV converter

You know, to power up geiger tubes or photomultipliers there the need of high voltage at very low current drain. How to generate 400, 1000 or more volts from a single 5V supply or better 3,3V? Simple, let’s build a boost converter (Wikipedia). In this post I’ll describe my standard building block, the PWM drived, voltage multiplied boost converter. I’ve used it in many circuits, as notable example please take a look at my HV converter project page.

How does it works? Let’s look at the following picture. In my implementation the active element of the circuit, a N-type mosfet called BSP300, is capable to handle 800V and it only needs a proper PWM waveform generated by an MCU like Atmega328 from an Arduino or STM32F103 or other MCU’s to work.

My boost converter circuit

Briefly speaking, the input supply (5V) “charges” the magnetic field around the inductor L1 when the mosfet Q4 is energized by a positive PWM waveform (5V). The PWM signal is applied on the BSP300 gate. When the PWM signal reach the low state (0V) of it’s duty cycle, the mosfet disrupt the circuit causing the generation of an overvoltage across the inductor leads. Please visit Wikipedia for more info on PWM.

Duty cycle example

This overvoltage is caused by the magnetic field collapsing aroun the inductor. The overvoltage is rectified by a Shottky diode or, in my case by a voltage multiplier network. This voltage multiplier network is formed by D1/D2/D3/D4 and C2/C3/C4 and multiply input voltage by a factor of 4. The voltage multiplier network is a standard Cockcroft-Walton design.

Voltage multiplier basic circuit

At the output of the diode or the network usually you’ll add a capacitor to filter out the voltage ripple and then you have your high voltage ready to be used. The V_ADC output goes to an ADC input of the choosed MCU and makes possible to the MCU to know the output voltage then regulate it varying the PWM waveform duty cycle. The series of R1-R2-R3-R4 forms a 40Mohm resistor. With R5 that is 100kohm, this series of resistors is a voltage divider network. The voltage across R5 is 400 times smaller than the voltage across the complete resistor series. Mathematically Vr5=[Vin/(R1+R2+R3+R4)]*R5 so with 1600Vin you’ll get aprox. 4V. If your MCU runs from 5V and your ADC’s reference voltage is 5V you’ll stay in it’s input range. If you’ll use different reference voltage you’ll need to change the voltage divider ratio.

I’ve found this boost converter components calculator from Adafruit but I’ve found more usefull to use a standard MC34053 calculator and use it’s output inductor value as reference.

Adafruit calculator

How to generate the PWM signal? Take a look at this little “Arduino” code. It’s self explaining and it’s easy to be ported to whatever MCU and language you use.

Some notes about components selection

  • L1 must be a 3.3mH ferrite core inductor with the lowest internal resistance avaiable. It’s value is experimental, I’ve found that my circuit works best with this value. The inductor used is this ELC-11D332F
  • Diodes must be Shottky and rated minimum for 400V reverse voltage. Low leakage current fast recovery type are a must! Suggested model: BYG21M-E3/TR
  • Capacitors of the voltage multiplier must be rated minimum for 400V and they value is 4.7nF.
  • The BSP300 couldn’t be substituted. That mosfet is specifically designed to be drived by a PWM waveform from a MCU and it’s high voltage capability it’s essential. It’s also cheap and easy to found.

Some notes about my Arduino code

  • In this code I’m using A7 ADC pin to sample the generated voltage.
  • Pin 9 is PWM output to the BSP300 gate
  • A2-3-4-5 pins have internal pull up resistor enabled. This four pins are connected to a dip switch to select desired output voltage. The dip switch shorts to ground the selected line, the MCU read it as input.
  • The software calculate the desired output voltage via a simple function “read_jumper()”.
  • I’m also using a custom function called analogWrite16() because this function makes a 3Khz PWM output. The standard Arduino’s analogWrite() barely reach 900Hz frequency.
  • The frequency is very important because changing frequency you’ll need to change the value of the L1 inductor and also the capacitors of the voltage multiplier.
  • The circuit is designed to work at 3Khz.
//MadExp PMT adapter firmware v0.1
//Copyright 2018(C) Papadopol Lucian Ioan
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

//Define some pins
const int analogInPin = A7; // Analog input pin

//Voltage conversion constant
const float conversionFactor = 0.00488;

//Global variable
int Output;

//Startup setup code
void setup() {

//Jumper pullups
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);

//Main LOOP
void loop() {

//Reading voltage set point and reading actual converter output voltage
int Setpoint = read_jumper();
int sensorValue = analogRead(analogInPin);
int Input = sensorValue * conversionFactor * 400;

//Some calculation for PWM correction (more voltage? less PWM exc...)
int k = 0 ; //Costante di correzione

if (Input < Setpoint) {
k = (Setpoint - Input) / Input;
Output = Output + 2 + k;
if (Input > Setpoint) {
k = (Input - Setpoint) / 10;
Output = Output - 2 - k;
analogWrite16(9, Output);

int setpoint_minus_delta = Setpoint - 20;
int setpoint_plus_delta = Setpoint + 20;
if (Input <= setpoint_plus_delta && Input >= setpoint_minus_delta) {
if (Input > setpoint_plus_delta || Input < setpoint_minus_delta) {


//PWM @ 16bit resolution! From 0 a 4095 not 0-255 like stupid arduino library!!!
/* Configure digital pins 9 and 10 as 16-bit PWM outputs. */
void setupPWM16() {
DDRB |= _BV(PB1) | _BV(PB2); /* set pins as outputs */
TCCR1A = _BV(COM1A1) | _BV(COM1B1) /* non-inverting PWM */
| _BV(WGM11); /* mode 14: fast PWM, TOP=ICR1 */
TCCR1B = _BV(WGM13) | _BV(WGM12)
| _BV(CS10); /* no prescaling */
ICR1 = 0x0fff; /* TOP counter value 4095 12bit */
/* Comments about the setup
Changing ICR1 will effect the amount of bits of resolution.
ICR1 = 0xffff; (65535) 16-bit resolution
ICR1 = 0x7FFF; (32767) 15-bit resolution
ICR1 = 0x3FFF; (16383) 14-bit resolution etc....

Changing the prescaler will effect the frequency of the PWM signal.
Frequency[Hz}=CPU/(ICR1+1) where in this case CPU=16 MHz
16-bit PWM will be>>> 16000000/(65535+1)=244,14Hz
a 12 bit fa 16Mhz/(4095+1)= 3.9Khz
/* 16-bit version of analogWrite(). Works only on pins 9 and 10. */

void analogWrite16(uint8_t pin, uint16_t val)
switch (pin) {
case 9: OCR1A = val; break;
case 10: OCR1B = val; break;

//Read jumper function
int read_jumper() {
int point;
int jumper_presel = 0;
int jumper_state1 = digitalRead(A2);
int jumper_state2 = digitalRead(A3);
int jumper_state3 = digitalRead(A4);
int jumper_state4 = digitalRead(A5);

if (jumper_state1 == 0) {
jumper_presel = jumper_presel + 8;
if (jumper_state2 == 0) {
jumper_presel = jumper_presel + 4;
if (jumper_state3 == 0) {
jumper_presel = jumper_presel + 2;
if (jumper_state4 == 0) {
jumper_presel = jumper_presel + 1;

point = (jumper_presel * 50) + 500;
return point;

5V to 900V step-up converter module


This project response to my need of an universal high voltage power supply to be used with mostly all type of geiger tubes that I have in my collection.

I’ve needed a selectable output voltage between 300V and 900-1000V, low power output, on board pulse counter and maybe a display. All powered by 5V


I’ve started the design of this voltage converter scrapping my “Madexp PMT adapter” power supply section. For more info visit www.madexp.com
In that old project I’ve generated 900-1600V out with a single 5V source from USB via a simple TTL variable duty cycle oscillator.
I’ve replaced that oscillator with an Atmega328P MCU so I was capable to add programmable voltage output via 4 bit parallel interface, pulse counting and if I need, an 0.96″ OLED display.
Into this schematic there is a missing 100pF capacitor from pin INT0 to ground. The oled display have also two 1K pull up resistors on I2C lines
On the first prototype I’ve easily reached 1650V of output but into the second (current) production prototype I could not exced 900V because of the insufficent spacing between HV multiplier and the MCU. This is not an issue because  mostly all geiger tubes works with less than 900V.
The board is thinked to be used as a module of a bigger project or stand alone.
As module of a bigger project, you can simply omit the OLED display and connect the 8 pin connetor to your project. The 4 bit parallel interface selects voltage output and the ACK pin goes HIGH when the output voltage selected is reached/stabilized.
If you wish to use the module as stand alone, you can connect the OLED and a geiger on the + and OUT pins, 5V supply from a battery (voltage regulator NOT included) and you can see the voltage, pulses per minute (CPM) and last minute reading on the display. The output voltage is selected by make a soldering bridge on voltage selection jumpers. It permit you to made a pocket size geiger counter with very low effort.
If you wish to made a geiger clicker without display you cold simply connect a little speaker between pin 1 of the 8 pin connector marked as “^” and GND, omit OLED.
The 3 pin output connector have a geiger katode connection marked as “OUT” and also permit you to exclude the pulse counting and conditioning section connecting the powered item directly between HV and GND.

There is also a JTAG connector for uploading new firmware via a USBAsp programmer. During operation the jtag pins 3 and 4 becomes RX/TX uart. Pin 1 is GND.

The voltage selection jumpers are made to select output voltage when the board is used stand-alone. Make a solder bridge according with the table below and you’ll get the corresponding output voltage out.


The firmware is in currently developement but it’s already stable, counts pulses, display voltage and also send info like pulses/voltage via UART.


This project was published on Kickstarter and was active for pledges during all the month of September. I’ve realy appreciated the 30 pledges (one was for two boards) received, that made me capable of buy all the tooling needed to build the boards and further inprove their design.

At the moment the boards are travelling around the globe to reach their owners. I’ve send most of them to USA and Australia but also to Japan, Germany, Switzerland, Canada, Spain, Russia, Ireland and UK. I’m very happy about this result. This make me feel like a multi national corporate, it stimulate my hungry for new projects. Thank you again and stay tuned, you’ll see some new crazy project soon!


Here you cand download the board manual complete with schematic MadexpHV manual 0.3