Close

Code

A project log for Supercapacitor Rapid Charger

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

sciencedude1990sciencedude1990 09/14/2020 at 03:420 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
	_delay_ms(2000);
		
	// 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
			_delay_ms(3);
			
			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;					
				}
			}			
		}
    }
}

Discussions