Powercore-V2.0/Powercore-V2.0 Firmware/CC_Charger.c

221 lines
8.2 KiB
C

#include "pico/stdlib.h"
#include "hardware/pio.h"
#include "hardware/pwm.h"
#include "CC_Charger.h"
// Our assembled programs:
#include "CLK.pio.h"
#include "TIMING.pio.h"
//Pinout Definitions
//CC_Charger Timing:
#define CLK_PIN 6
#define LIMIT_PIN 9
#define BLANKING_PIN 15
//CC_Charger Control:
#define CC_CHARGER_EN_PIN 5
//Ideal Diode Controls:
#define DIODE_ON_PIN 4
//Gate Bias PWM:
#define GATE_BIAS_CLK_PIN 3
//PWM Voltage Sets:
#define CC_I_LIMIT_PIN 13
#define V_CAP_SET_PIN 12
//Telemetry:
#define VSENSE_TRIP_PIN 11
#define CAP_VSENSE_PIN 27
PIO pio;
int sm, sm_clk, sm_limit, sm_blanking;
uint offset_clk, offset_timing;
uint32_t default_clk_period = 133; //3.216usec
uint32_t default_limit_wait_time = 185; //3.024usec
uint32_t default_limit_on_time = 7; //0.136usec
uint32_t default_blanking_wait_time = 185; //0.112usec
uint32_t default_blanking_on_time = 12; //3.032usec
bool caps_charged = false;
void VSENSE_TRIP_callback(void) {
if(gpio_get_irq_event_mask(VSENSE_TRIP_PIN) & GPIO_IRQ_EDGE_RISE) {
gpio_acknowledge_irq(VSENSE_TRIP_PIN, GPIO_IRQ_EDGE_RISE);
//Flag that the caps have been charged
caps_charged = true;
//Turn off the CC_Charger
disable_CC_timing();
}
if(gpio_get_irq_event_mask(VSENSE_TRIP_PIN) & GPIO_IRQ_EDGE_FALL) {
gpio_acknowledge_irq(VSENSE_TRIP_PIN, GPIO_IRQ_EDGE_FALL);
//Flag that the caps are not fully charged
caps_charged = false;
}
}
void disable_gate_driver() {
gpio_put(CC_CHARGER_EN_PIN, false);
}
void disable_CC_timing() {
gpio_put(DIODE_ON_PIN, false); //Turn off ideal diode
pio_sm_set_enabled(pio, sm_clk, false); //Disable CC Charger Clock
pio_sm_exec(pio, sm_clk, pio_encode_nop() | pio_encode_sideset_opt(1, 0)); //Set Clock output to 0
pio_sm_exec(pio, sm_clk, pio_encode_irq_set(false, 0));
pio_sm_set_enabled(pio, sm_limit, false); //Disable PWM limit SM
pio_sm_exec(pio, sm_limit, pio_encode_nop() | pio_encode_sideset_opt(1, 1)); //Set PWM limit to 1 (keeps !CLR on Flip Flop low)
pio_sm_set_enabled(pio, sm_blanking, false); //Disable Slope blanking/reset
pio_sm_exec(pio, sm_blanking, pio_encode_nop() | pio_encode_sideset_opt(1, 1)); //Set Slope blanking to (Allows the compensated current limit to decay to 0)
}
void enable_CC_timing() {
//Don't start the charger if the caps are already charged
if(caps_charged == false){
//Reset all PIOs to the start of the program:
pio_sm_exec(pio, sm_clk, pio_encode_jmp(offset_clk ));
pio_sm_exec(pio, sm_blanking, pio_encode_jmp(offset_timing));
pio_sm_exec(pio, sm_limit, pio_encode_jmp(offset_timing));
//Renable PIOs
pio_sm_set_enabled(pio, sm_limit, true);
pio_sm_set_enabled(pio, sm_blanking, true);
pio_sm_set_enabled(pio, sm_clk, true);
gpio_put(CC_CHARGER_EN_PIN, true); //Enable the CC Charger gate driver
gpio_put(DIODE_ON_PIN, true); //Turn on the ideal diode
}
}
void CLK_set_period(uint32_t period) {
pio_sm_put_blocking(pio, sm_clk, period); //Load new period into FIFO
pio_sm_exec(pio, sm_clk, pio_encode_pull(false, false)); //Pull new period into OSR
pio_sm_exec(pio, sm_clk, pio_encode_out(pio_isr, 32)); //Shift new period from OSR to ISR
pio_sm_put_blocking(pio, sm_clk, period/2); //Load new on time into FIFO
pio_sm_exec(pio, sm_clk, pio_encode_pull(false, false)); //Pull new on time into OSR
pio_sm_exec(pio, sm_clk, pio_encode_out(pio_x, 32)); //Shift new on time into X register
}
void SM_set_timing(PIO pio, uint sm, uint32_t wait_time, uint32_t on_time, bool enabled) {
pio_set_sm_mask_enabled(pio, sm_clk | sm_blanking | sm_limit, false);
// pio_sm_set_enabled(pio, sm, false); //Temporarily freeze SM
pio_sm_put_blocking(pio, sm, wait_time); //Load new wait time into FIFO
pio_sm_exec(pio, sm, pio_encode_pull(false, false)); //Pull new wait time into OSR
pio_sm_exec(pio, sm, pio_encode_out(pio_isr, 32)); //Shift new wait time into ISR
pio_sm_put_blocking(pio, sm, on_time); //Load new on time into FIFO
pio_sm_exec(pio, sm, pio_encode_pull(false, false)); //Pull new wait time into OSR
// pio_sm_set_enabled(pio, sm, enabled); //Renable SM
pio_set_sm_mask_enabled(pio, sm_clk | sm_blanking | sm_limit, enabled);
}
void LIMIT_set_timing(uint32_t wait_time, uint32_t on_time, bool enabled) {
SM_set_timing(pio, sm_limit, wait_time, on_time, enabled); //Update timing registers in SM
}
void BLANKING_set_timing(uint32_t wait_time, uint32_t on_time, bool enabled) {
SM_set_timing(pio, sm_blanking, wait_time, on_time, enabled); //Update timing registers in SM
}
void CC_Charger_init(int charger_current, int cap_voltage) {
//Select a PIO bank
pio = pio0;
//Load programs into PIO memory
offset_clk = pio_add_program(pio, &CLK_program);
offset_timing = pio_add_program(pio, &TIMING_program);
//Select state machines for each output
sm_clk = pio_claim_unused_sm(pio, true);
sm_limit = pio_claim_unused_sm(pio, true);
sm_blanking = pio_claim_unused_sm(pio, true);
//Initialize each state machine
CLK_program_init (pio, sm_clk, offset_clk, CLK_PIN );
TIMING_program_init (pio, sm_limit, offset_timing, LIMIT_PIN );
TIMING_program_init (pio, sm_blanking, offset_timing, BLANKING_PIN );
//Load in default timing
CLK_set_period (default_clk_period);
LIMIT_set_timing (default_limit_wait_time, default_limit_on_time, false);
BLANKING_set_timing (default_blanking_wait_time, default_blanking_on_time, false);
//Setup VSENSE_TRIP pin
gpio_init(VSENSE_TRIP_PIN);
gpio_set_dir(VSENSE_TRIP_PIN, GPIO_IN);
gpio_set_pulls(VSENSE_TRIP_PIN, false, true);
gpio_set_irq_enabled(VSENSE_TRIP_PIN, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true);
gpio_add_raw_irq_handler(VSENSE_TRIP_PIN, &VSENSE_TRIP_callback);
//Setup CC_CHARGER_EN pin
gpio_init(CC_CHARGER_EN_PIN);
gpio_set_dir(CC_CHARGER_EN_PIN, GPIO_OUT);
gpio_put(CC_CHARGER_EN_PIN, false);
//Setup PWM -> Analog pins
gpio_set_function(CC_I_LIMIT_PIN, GPIO_FUNC_PWM);
gpio_set_function(V_CAP_SET_PIN, GPIO_FUNC_PWM);
uint v_i_set_pwm_slice = pwm_gpio_to_slice_num(V_CAP_SET_PIN);
pwm_set_wrap(v_i_set_pwm_slice, 1000);
pwm_set_gpio_level(CC_I_LIMIT_PIN, charger_current);
pwm_set_gpio_level(V_CAP_SET_PIN, cap_voltage);
pwm_set_enabled(v_i_set_pwm_slice, true);
//Setup Ideal Diode driver
gpio_init(DIODE_ON_PIN);
gpio_set_dir(DIODE_ON_PIN, GPIO_OUT);
gpio_put(DIODE_ON_PIN, false);
//Setup Gate Bias Charge Pump
gpio_set_function(GATE_BIAS_CLK_PIN, GPIO_FUNC_PWM);
uint bias_pwm_slice_num = pwm_gpio_to_slice_num(GATE_BIAS_CLK_PIN);
pwm_set_wrap(bias_pwm_slice_num, 2500);
pwm_set_gpio_level(GATE_BIAS_CLK_PIN, 1250);
pwm_set_enabled(bias_pwm_slice_num, true);
}