Supercapacitor Rapid Charger

A 6 Amp supercapacitor charger, and a small tutorial on charging

Public Chat
Similar projects worth following
How to charge up a supercapacitor? Use an ATtiny13A and a MP18021 Half-Bridge Gate Driver, that's how!

I wanted to learn more about supercapacitor charging.  I had made a few boards using purpose-built ICs, but wanted to make it up of simple blocks that I could tweak and test.  Also, I blew up a few of the purpose-built ICs, and wanted to slow the whole thing down.

First, I designed an ATtiny13A eval board with a 20 MHz external clock.  Then, I designed a "testbed" with the basic parts - input capacitor, half-bridge, inductor, and output current sensor.

I learned a lot, so let me share!

I placed the steps in the project logs.  Cheers!


WRL file for the ATTINY13A. Again, a simple WRL file for KiCAD to help visualize the board.

Virtual Reality Modeling Language - 375.00 bytes - 09/18/2020 at 02:49



WRL file for the SIRA20DP transistor. I make my own simple wrl files for KiCAD to help visualize the board.

Virtual Reality Modeling Language - 374.00 bytes - 09/18/2020 at 02:48


  • 1 × ATtiny13A Microprocessors, Microcontrollers, DSPs / ARM, RISC-Based Microcontrollers
  • 1 × MP18021 Interface and IO ICs / Peripheral Drivers and Actuators
  • 1 × TPLH-3R0/450SS35X71 450 F supercapacitor, Tecate
  • 1 × KC5032A20.0000CMGE00 Frequency Control / Oscillators

  • WRL files posted

    sciencedude19903 days ago 0 comments

    Hi!  I posted a couple example WRL files that I made for KiCAD for the PCB rendering.  They are simple, and slightly transparent to help visualize the board.

  • Now what? Well, celebrate with video games...

    sciencedude19904 days ago 0 comments

    Now that you have a supercapacitor all charged up, what do you do?

    Celebrate with video games!!!

  • Video showing the supercapacitor charger with a wire

    sciencedude19906 days ago 0 comments
  • Video showing the charging of a 450 F supercapacitor

    sciencedude19906 days ago 0 comments
  • Code

    sciencedude19907 days ago 0 comments

    Here is the code to the controller.  Note in the charging phase there are three steps.  First, have the high side transistor on (to increase the inductor current), second have the low side transistor on (at the start, you actually don't turn on the lower transistor), and lastly, dead time.  The dead time is super important because at the start, you want to gradually increase the lower transistor on time so that you don't discharge the supercapacitor if it has an initial charge.  Since the switching node of the controller is okay with going a bit negative, you use the body diode of the lower transistor and the dead time to decrease the inductor current until the loops converge.  When the loop converges, you shed the dead time in favor of the lower transistor on time.

    #include <avr/io.h>
    #define F_CPU 20000000UL // Use external 20 MHz clock, set to external oscillator in the fuses
    #include <util/delay.h>
    const uint8_t MAX_CAP_VOLTAGE = 212; // When charging is done
    const uint8_t START_CAP_VOLTAGE = 180; // When to start charging - separate these two numbers to give hysteresis
    const uint8_t COUNT_FET_DEFAULT = 0; // When starting to charge, the lower FET on time
    const uint8_t COUNT_LOW_DEFAULT = 200; // The starting count for the low side on time
    const uint8_t CHARGING_LOOP_COUNT = 8; // The number of charging loop cycles between checking the ADC reading and the comparator
    // Enumerated type for the state machine
    typedef enum {IDLE, CHARGING} state_var;
    int main(void) { // Main routine
    	// Variable to hold the state
    	volatile state_var the_state = IDLE;
    	// The low side on time
    	uint8_t count_fet = COUNT_FET_DEFAULT;
    	// The idle time when everything is low
    	uint8_t count_low = COUNT_LOW_DEFAULT;
    	// Setup the ADC, bit 6 set to 1 for internal 1.1V reference, left adjusted (so only read ADCH), and select channel 2 (PB4, ADC2)
    	ADMUX = (1 << 6) + (1 << 5) + (2);
    	// Enable ADC, start it up, auto trigger, no interrupt flag, no interrupt, divide by 128
    	ADCSRA = (1 << 7) + (1 << 6) + (1 << 5) + (0 << 4) + (0 << 3) + 7;
    	// No analog comparator mux, free running mode
    	ADCSRB = 0;
    	// Analog comparator control, enabled, bandgap turned on
    	ACSR = (1 << 6);
    	// Allow the ADC to settle, and allow for system programming
    	// Output pins, PB0 for high side FET, PB1 for current sense (comparator), PB2 for low side FET, PB3 for CLKI, PB4 for capacitor voltage monitor
    	DDRB = (1 << 0) + (1 << 2);
    	// Set the output pins to low
    	PORTB = 0;
        while (1) { // Main loop
    		if (the_state == IDLE) {  // Idle state
    			// Wait to let the ADC readings settle
    			if (ADCH < START_CAP_VOLTAGE) { // Begin charging
    				// Initialize lower FET on time
    				count_fet = COUNT_FET_DEFAULT;
    				count_low = COUNT_LOW_DEFAULT;
    				// Update state variable
    				the_state = CHARGING;
    		else if (the_state == CHARGING) { // Charging state
    			// Charging loop
    			for (uint8_t ii = 0; ii < CHARGING_LOOP_COUNT; ii++) {
    				// Turn on the high side FET
    				PORTB = 1;
    				PORTB = 1;
    				PORTB = 1;
    				PORTB = 1;
    				PORTB = 1;
    				PORTB = 1;
    				// Turn off the high side FET
    				PORTB = 0;
    				PORTB = 0;
    				PORTB = 0;
    				// Turn on the low side FET				
    				for (uint8_t jj = 0; jj < count_fet; jj++) {
    					PORTB = 4;
    				// Turn off the low side FET
    				PORTB = 0;
    				for (uint8_t jj = 0; jj < count_low; jj++) {
    					PORTB = 0;
    			if (ADCH > MAX_CAP_VOLTAGE) {
    				// Done charging, set to IDLE
    				the_state = IDLE;					
    			if ((ACSR & (1 << 5)) == 0) { // Current too high
    				if (count_fet < 255) {
    					count_fet = count_fet + 1;
    			else { // Current too low
    				if (count_fet > 0) {
    					count_fet = count_fet - 1;
    				if (count_low > 0) {
    					count_low = count_low - 1;					

  • Adapter PCB for supercapacitor

    sciencedude19907 days ago 0 comments

    Just for reference, I made a small adapter PCB for the supercapacitor.  This let's you attach wires to the supercapacitor and use the strain relief of the supercapacitor mounting pins.

    Then you can place twist on connectors to the wires to prevent accidental shorting.

  • Results

    sciencedude19907 days ago 0 comments

    So, the first thing to test is a piece of wire.  Yes, crazy, but it makes it easier to debug.

    Here is the scope view:

    The yellow trace shows when the high transistor is on (briefly to add a bit of current to the inductor).  Then, it shows that the low transistor is on for a long time (it takes a long time to reduce the inductor current).  The inductor current is middle of the scope and shows the fast rise when the high transistor is on, and the long decay when the low transistor is one.  The voltage is purple, and just ripples of voltage (remember, the is just driving a wire).

    Next, I connected a supercapacitor, and started the charging.

    Here is the scope view...

    So, it worked!  It keeps the inductor current hovering around 1.2V (i.e., the 1.2V of the comparator), and the capacitor voltage is slowly increasing.

    Total capacitance, 450 F, total charge time from 0.7V to 2.8V, 2 minutes, 53 seconds.  So with the untuned controller, the average current was around 5.5 Amps.  Next step would be adjust the controller code to tighten up the current ripple (it gets a little sloppy when the capacitor voltage increases past 1 V).

    In still air, the hottest component on the board was the low transistor at 50C. 

  • Testbed

    sciencedude19907 days ago 0 comments

    Here is the PCB rendering in KiCAD

    Here is the PCB

    On the left are the screw terminals to apply the 12V.  C1-C6 are the input capacitors.  The transistors are SIRA20DP.  They are controlled by a MP18021.  Why the MP18021?  It can handle -5V on the switching node.  It also has the integrated diode for high side driver.  The inductor is a 1uH SRP1265A.  The output current is measured using a 0.001 Ohm sense resistor, with Kelvin connections to the INA180 current sensor.  There is a small output capacitor.  Then, to connect to the supercapacitor (and make sure I don't have ~200 Amps in the event of a short while probing), I used a 15A 0ZRN1500FF1A polymeric fuse.  The terminals on the right are for the load.  The 8-pin JST connector connects to the controller.

  • Controller

    sciencedude19907 days ago 0 comments

    Here is the controller I designed.  It is an ATtiny13A, 20 MHz external clock, and RC filters/resistor voltage dividers for the comparator and ADC inputs.  I used the comparator to control the inductor current.

    With 6 amps of charging current, 0.001 Ohm sense resistor, 200 V/V gain the current sensor, I get 1.2 V at the comparator input.  With the ATtiny13A, I selected the 1.2V internal reference.  So, based on the output of the comparator, you can tell if the current is too high or too low, and adjust the on-time of the lower transistor to compensate.

    For the supercapacitor voltage, the max is 3V.  I used a voltage divider to bring that under 1.2V, and used the ADC to measure the supercapacitor voltage, relative to the 1.2V internal reference.

    Here is the rendering from KiCAD:

    Here is the circuit populated:

    PB0 is used to drive the high side transistor.  PB2 is used to drive the low side transistor.  PB1 is the comparator input to sense the input current.  PB4 is the ADC input to sense the supercapacitor voltage.  PB3 is busy receiving the 20 MHz external clock.  The board accepts anything from ~5V up to 20V using an LDO (which also has reverse protection!)...yah SPX3819.

  • Schematic

    sciencedude19907 days ago 0 comments

    The basic way to charge the capacitor is to switch an inductor.  But watch out, there are lots of ways to blow things up!

    Here is a basic schematic:

    The input voltage is something like 12V.  The transistors start with being off, so the input capacitor, C_IN, is also at 12V.  You have to balance the selection of C_IN to reduce the ripple at the input, but it can't be too big, or else your 12V supply will be unstable.

    Next, you *need* to protect your switching node, SW.  If you aren't careful, this node will go extremely negative.  This can happen if the inductor has current flowing through it, and you shut off the transistors.  The body diode in the lower FET will turn on and the drop will pull SW negative.  Some purpose-built ICs are allergic to this and will break.  You can protect with a low drop Schottky, but watch out if you are trying to push a lot of current through the inductor.

    You also have to be careful of having both transistors on at the same time.  This causes crazy shorts.  This can happen when you are programming the controller using the ISP (since this toggles most of the pins on the ATtiny13A - so you have to isolate the ATtiny13A during programming).

    Also, note that C_BIG, is well, a pretty big capacitor.  If you turn on the lower transistor T_low, and you don't have current flowing in to the capacitor, then current will definitely flow out of the capacitor back through the inductor, through T_low, to ground.  The capacitor is not shy about dumping 287 amps through your circuit.

    So, what is the big-picture idea for charging a supercapacitor?  Here are the steps as I understand them.  First, have the input capacitor charged up.  Next, turn on T_high so that current starts to flow in the inductor to the supercapacitor.    Next, turn off T_high, and then quickly (but not too quickly) turn on T_low so that the current can continue to flow through the inductor.  Once the inductor current has decreased a bit, you turn off T_low, and then turn T_high back on so that the inductor current increases to make up for the decrease you just had.  Then, you repeat, adjusting the on-time of the transistors to keep the current steady-ish.

    Here is what happens when you first turn T_high, and just leave it on for a long time (5 us).

    The input voltage local to the input capacitor starts to drop as the current builds in the inductor.  Now, what I think is cool is that for a relatively small drop in the input voltage, you can get ~50A flowing in the inductor.  In reality, you only want the transistor on for a bit so that each pass you slowly increase the inductor current to the set point.

    Now, for the next step, and this is wacky.  Let us say the supercapacitor has 0V (i.e., brand new, out of the bag, shipped with terminals shorted).  If you turn on T_low, and just leave it on, this is what will happen:

    The inductor current just decreases nice and gently over ~200 us, slowly charging up the supercapacitor to ~1 uV.  Now, contrast this with when the supercapacitor is already nearly charged (say at ~3V).

    If you leave T_low on for longer than ~2us, then the supercapacitor will start to discharge (i.e., the current flow through the inductor becomes negative).  I designed my controller to dither the on-time of the low transistor, so the controller has to be able to adapt to these two different time scales.

View all 11 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

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