cookbook code and circuit solutions

software-driven voltage buck down converter

this circuit and code efficiently provides (poorly) regulated 3.3V output from the "wild" power output by an Adafruit Solar Charger/LiPo battery supply. the Solar Charger output is "load shared", meaning that while the sun is charging (or has power provided via USB or other DC input) it both charges the attached LiPo battery and provides load power output on it's LOAD pins. the problem is that the voltage varies from 3V (discharged LiPo, not charging) to over 6V (charging under full sunlight) or 5V when plugged into USB.

all of my loads (Adafruit sound card, nRF24L01+ radio module, 2.5W class D audio amplifier) require 3.3V, and though the sound card and amp will run at 5V, the radio will not, and the 6V+ from the solar charger exceeds absolute maximum for most 3.3V devices. the usual solution is to use a linear regulator (eg. the one on the Arduino) but that's wasteful, especially under precious solar power, and limited to 150mA (which produces a great deal of heat).


the circuit below is a crappy buck regulator. it's reasonably efficient (uncharacterized but 90%-ish) and importantly, will regulate down to 100mV higher input voltage. it's crappy because transient response sucks and it's noisy, but for most digital loads it's more than fine.

this circuit contains one clever trick that generates the series-pass MOSFET's gate drive, which needs to be higher than the drain input voltage. it uses a charge pump capacitor to provide output drive of approximately 7 volts, from a 3.3V/8MHz Arduino Pro Mini. the catch with the charge pump (you know there had to be a catch) is that the PWM duty cycle cannot be 0, nor 100%. in practice this isn't a limitation, as 255/256ths is pretty damn close to 1.

above is the core gate drive circuit. when the output pin is driven low, capacitor C charges through the shottky diode; simultaneously, the small MOSFET (2N7000) is turned on (it's gate at Vcc, source at ground) pulling the output rapidly to ground (gate drive output: 0V). obviously after a few microseconds C has Vcc, 3.3V, stored across it. when the output pin goes high, the bottom of C is now at Vcc (3.3V), the top of C is driven to VIN + Vcc, minus the shottky voltage. this is sufficient to drive the series-pass MOSFET gate on. risetime is reasonably fast; the only load is the series-pass gate's charge storage.

because the gate energy source is a capacitor, the duty cycle of the gate drive pulse cannot be always on or always off, though in practice it doesn't matter. the code limits the Arduino analogWrite() PWM value to 1..254.

above is the complete schematic for the working circuit driven by an Arduino Pro Mini, 3.3V. the Arduino itself is fed from the raw, wild, VIN voltage output by the Solar Charger; the Arduino and it's LEDs consumes only a few mA therefore the loss from the linear regulator is ignorable. code and circuit assume an ATMEGA328 and digital pin 3 in the Arduino system because TIMER2 is changed to increase the analogWrite() PWM frequency from the default crappy 490 Hz to less-unreasonable 31KHz, allowing for a smaller inductor and easier filtering. other CPUs can be used, you just have to RTFM timer configuration. YMMV.

output voltage feedback is through a 3.9:1 voltage divider feeding analog input A0. this divider reduces the target 3.3V (3300 mV) to 846mV at the analog input; the code configures for the internal 1.1V ADC reference using analogReference (INTERNAL). i am moving all my designs to eventually operate on "wild" (unregulated) supplies hence the internal, fixed reference is ultimately more reliable. again YMMV.


the initial, test hack code is on my github repository the code has been turned into a nice C++ library for Arduino but i haven't documented and packaged it yet.