I wired up a first prototype converter last night and coded up a quick test this morning. So far, it "works," but not great.
The converter is based around a PIC12LF1571 that drives a simple MOSFET/inductor/diode circuit. Here's the schematic:
The PIC code (attached at the end of this log) generates a 17us pulse every 94us to magnetize the inductor by switching on the MOSFET. When the magnetic field decays in the coil, the voltage rises to maintain the same current flow, charging C1 through the Schottky diode.
I chose this topology because I had better NMOS transistors in stock than PMOS. I first saw the IRLML6244 when @Elliot Williams used it in his version of
#TritiLED, and it has quickly become one of my go-to parts. I might end up substituting something else later, but for now, this seems fine. Two output pins from the PIC are paralleled to increase the drive current and promote faster switching in the FET.
I originally modeled the circuit with a BAT54 diode, because everyone has a million of them, but the 1N5817 is more efficient in this circuit due to the large current pulses. The downside to the 1N5817 is the larger reverse leakage (up to 500uA, even 1mA at 20V on some datasheets). Quick estimates make it more efficient, but I'll have to examine this in more detail.
I wanted a low-ESR capacitor, and the best I could come up with was 10x 10uF 1206 ceramic caps in parallel. I'll probably add another few hundred uF of low-ESR polymer caps when I find the missing bag of them around here. This large capacitance averages out the current drawn from the cell so that it doesn't see the hundreds of mA drawn by the inductor during the pulses. There are some other miscellaneous bypass caps on the board, but they probably don't do anything interesting :-)
I didn't have any beefy inductors of around 100uH in the junk box, so I hand-wound one on a core salvaged from an old power supply. Nearest I can figure, the core is a T131-26 (yellow/white paint). I wound 35 turns of 20AWG wire on there, which ends up measuring out to 115uH, as predicted by the formulas (113.9).
I've only had a chance to test the converter briefly, and so far it "works," charging a 10F capacitor to 1V in a little less than 2 minutes, while drawing 43mA from a CR2032. A quick calculation shows that this is 15.5J out of the cell, with 5J stored in the capacitor for an efficiency of around 33%. I need to at least double that to hit my goal of 67F charged to 14V. In the circuit's defense, I didn't precisely time the charging, so the measurement might be off. Another possibility is that my 10F capacitor is more than 10F. It came from the junk box, and isn't marked with a tolerance, so who knows.
Next, I need to instrument the circuit to see what's going on - I'll add a 0.1-ohm resistor in series with the inductor so I can see the current waveforms, which will probably be the most interesting.
I also need to add an over-voltage crowbar to the output. With the 67F capacitor, there probably won't be any danger of over-charging, but the smaller capacitors I have to play with for now could easily be damaged by a few minutes of inattention. My plan is to add an adjustable shunt regulator, a TL431, directly across the output. The power output of the converter is low enough so that the TL431 can just dissipate it all once the target voltage has been reached.
Here's the trivial code running on the PIC:
;;; ;;; coin_cell_cap_charger.asm: DC-DC converter for charging supercapacitors ;;; from coin cells ;;; ;;; Copyright (C) 2017 Theodore C. Yapo ;;; Licensed under MIT license (see file) ;;; LIST P=12LF1571 #include <p12lf1571.inc> ERRORLEVEL -302 ERRORLEVEL -305 ;;; ;;; I/O pin configuration ;;; GATE_DRIVE_A equ 4 GATE_DRIVE_B equ 5 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_HI & _LPBOREN_OFF & _LVP_ON ;;; ;;; variables in Common RAM (accessable from all banks) ;;; CBLOCK 0x70 delay_counter reset_counter ENDC ORG 0 RESET_VEC: movlw .255 movwf reset_counter BANKSEL ANSELA movlw b'00000000' ; all digital I/O movwf ANSELA BANKSEL LATA clrf LATA BANKSEL TRISA ;; set gate driver lines as output movlw ((0xff ^ (1 << GATE_DRIVE_A)) ^ (1 << GATE_DRIVE_B)) movwf TRISA BANKSEL OSCCON movlw b'01101010' ; 4 MHz HF osc movwf OSCCON MAIN_LOOP: BANKSEL LATA movlw (1 << GATE_DRIVE_A) | (1 << GATE_DRIVE_B) movwf LATA ;start inductor ramp-up nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop clrf LATA ;end inductor ramp-up movlw .26 call DELAY_3W decfsz reset_counter goto MAIN_LOOP reset ;;; delay 3x value in W (W must be >= 3; minimum 9 cycle delay) DELAY_3W: addlw -.2 movwf delay_counter DELAY_3W_LOOP: decfsz delay_counter bra DELAY_3W_LOOP return ;; fill remainder of program memory with reset instructions fill (reset), 0x0400-$-2 END