diff --git a/Firmware/.gitignore b/Firmware/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/Firmware/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/Firmware/.vscode/c_cpp_properties.json b/Firmware/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..ada839e --- /dev/null +++ b/Firmware/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Pico", + "includePath": [ + "${workspaceFolder}/**", + "${env:PICO_SDK_PATH}/**" + ], + "defines": [], + "compilerPath": "${env:PICO_INSTALL_PATH}/gcc-arm-none-eabi/bin/arm-none-eabi-gcc.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "linux-gcc-arm", + "configurationProvider": "ms-vscode.cmake-tools" + } + ], + "version": 4 +} diff --git a/Firmware/.vscode/cmake-kits.json b/Firmware/.vscode/cmake-kits.json new file mode 100644 index 0000000..4b24eb7 --- /dev/null +++ b/Firmware/.vscode/cmake-kits.json @@ -0,0 +1,7 @@ +[ + { + "name": "Pico ARM GCC", + "description": "Pico SDK Toolchain with GCC arm-none-eabi", + "toolchainFile": "${env:PICO_SDK_PATH}/cmake/preload/toolchains/pico_arm_gcc.cmake" + } +] diff --git a/Firmware/.vscode/extensions.json b/Firmware/.vscode/extensions.json new file mode 100644 index 0000000..03ba0af --- /dev/null +++ b/Firmware/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "marus25.cortex-debug", + "ms-vscode.cmake-tools", + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "ms-vscode.vscode-serial-monitor" + ] +} diff --git a/Firmware/.vscode/launch.json b/Firmware/.vscode/launch.json new file mode 100644 index 0000000..c370c53 --- /dev/null +++ b/Firmware/.vscode/launch.json @@ -0,0 +1,58 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Pico Debug (Cortex-Debug)", + "cwd": "${workspaceFolder}", + "executable": "${command:cmake.launchTargetPath}", + "request": "launch", + "type": "cortex-debug", + "servertype": "openocd", + "gdbPath": "arm-none-eabi-gdb", + "device": "RP2040", + "configFiles": [ + "interface/cmsis-dap.cfg", + "target/rp2040.cfg" + ], + "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", + "runToEntryPoint": "main", + "openOCDLaunchCommands": [ + "adapter speed 5000" + ] + }, + { + "name": "Pico Debug (Cortex-Debug with external OpenOCD)", + "cwd": "${workspaceFolder}", + "executable": "${command:cmake.launchTargetPath}", + "request": "launch", + "type": "cortex-debug", + "servertype": "external", + "gdbTarget": "localhost:3333", + "gdbPath": "arm-none-eabi-gdb", + "device": "RP2040", + "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", + "runToEntryPoint": "main" + }, + { + "name": "Pico Debug (C++ Debugger)", + "type": "cppdbg", + "request": "launch", + "cwd": "${workspaceFolder}", + "program": "${command:cmake.launchTargetPath}", + "MIMode": "gdb", + "miDebuggerPath": "arm-none-eabi-gdb", + "miDebuggerServerAddress": "localhost:3333", + "debugServerPath": "openocd", + "debugServerArgs": "-f interface/cmsis-dap.cfg -f target/rp2040.cfg -c \"adapter speed 5000\"", + "serverStarted": "Listening on port .* for gdb connections", + "filterStderr": true, + "stopAtEntry": true, + "hardwareBreakpoints": { + "require": true, + "limit": 4 + }, + "preLaunchTask": "Flash", + "svdPath": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd" + } + ] +} diff --git a/Firmware/.vscode/settings.json b/Firmware/.vscode/settings.json new file mode 100644 index 0000000..c11e238 --- /dev/null +++ b/Firmware/.vscode/settings.json @@ -0,0 +1,30 @@ +{ + // These settings tweaks to the cmake plugin will ensure + // that you debug using cortex-debug instead of trying to launch + // a Pico binary on the host + "cmake.statusbar.advanced": { + "debug": { + "visibility": "hidden" + }, + "launch": { + "visibility": "hidden" + }, + "build": { + "visibility": "hidden" + }, + "buildTarget": { + "visibility": "hidden" + } + }, + "cmake.buildBeforeRun": true, + "cmake.configureOnOpen": true, + "cmake.configureSettings": { + "CMAKE_MODULE_PATH": "${env:PICO_INSTALL_PATH}/pico-sdk-tools" + }, + "cmake.generator": "Ninja", + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "files.associations": { + "cc_charger.h": "c", + "stdlib.h": "c" + } +} diff --git a/Firmware/.vscode/tasks.json b/Firmware/.vscode/tasks.json new file mode 100644 index 0000000..a437c2f --- /dev/null +++ b/Firmware/.vscode/tasks.json @@ -0,0 +1,29 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Flash", + "type": "shell", + "command": "openocd", + "args": [ + "-f", + "interface/cmsis-dap.cfg", + "-f", + "target/rp2040.cfg", + "-c", + "adapter speed 1000; program {${command:cmake.launchTargetPath}} verify reset exit" + ], + "problemMatcher": [] + }, + { + "label": "Build", + "type": "cmake", + "command": "build", + "problemMatcher": "$gcc", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} diff --git a/Firmware/CC_Charger.c b/Firmware/CC_Charger.c new file mode 100644 index 0000000..2713cbd --- /dev/null +++ b/Firmware/CC_Charger.c @@ -0,0 +1,219 @@ +#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_CC_timing() { + + gpio_put(DIODE_ON_PIN, false); //Turn off ideal diode + + gpio_put(CC_CHARGER_EN_PIN, false); //Disable CC Charger gate driver + + 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); + gpio_set_function(3, 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_chan_level(v_i_set_pwm_slice, pwm_gpio_to_channel(CC_I_LIMIT_PIN), charger_current); + pwm_set_chan_level(v_i_set_pwm_slice, pwm_gpio_to_channel(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_chan_level(bias_pwm_slice_num, pwm_gpio_to_channel(GATE_BIAS_CLK_PIN), 1250); + + pwm_set_enabled(bias_pwm_slice_num, true); +} \ No newline at end of file diff --git a/Firmware/CC_Charger.h b/Firmware/CC_Charger.h new file mode 100644 index 0000000..1d5dc65 --- /dev/null +++ b/Firmware/CC_Charger.h @@ -0,0 +1,50 @@ +#ifndef CC_CHARGER_H_INCLUDED +#define CC_CHARGER_H_INCLUDED + +#include "pico/stdlib.h" + +extern bool caps_charged; + +/*! \brief Disable Constant Current Charger timing outputs, effectively turns off CC charger + \ingroup CC_Charger +*/ +void disable_CC_timing(); + +/*! \brief Enable Constant Current Charger timing outputs, effectively turns on CC charger + \ingroup CC_Charger +*/ +void enable_CC_timing(); + +/*! \brief Sets the CC charger clock period, indirectly sets the switching frequency of the CC charger + \ingroup CC_Charger + + \param period Clock period = 3 * (1 + period) / Sys_clock (default 125MHz) +*/ +void CLK_set_period(uint32_t period); + +/*! \brief Sets the timing for the PWM limiting output + \ingroup CC_Charger + + \param wait_time output low time = 2 * (1 + wait_time) / Sys_clock (default 125MHz) + \param on_time output high time = (1 + 2 * (1 * on_time)) / Sys_clock (default 125MHz) +*/ +void LIMIT_set_timing(uint32_t wait_time, uint32_t on_time, bool enabled); + +/*! \brief Sets the timing for the PWM limiting output + \ingroup CC_Charger + + \param wait_time output low time = 2 * (1 + wait_time) / Sys_clock (default 125MHz) + \param on_time output high time = (1 + 2 * (1 * on_time)) / Sys_clock (default 125MHz) +*/ +void BLANKING_set_timing(uint32_t wait_time, uint32_t on_time, bool enabled); + +/*! \brief Setup the CC charger + \ingroup CC_Charger +*/ +void CC_Charger_init(int charger_current, int cap_voltage); + +/*! \brief Whether or not the output caps are at the set voltage + \ingroup CC_charger +*/ + +#endif \ No newline at end of file diff --git a/Firmware/CLK.pio b/Firmware/CLK.pio new file mode 100644 index 0000000..e07b67e --- /dev/null +++ b/Firmware/CLK.pio @@ -0,0 +1,36 @@ +.program CLK +.side_set 1 opt + + irq clear 0 side 1 ; Set IRQ for other signals to reference off of + mov y, isr ; ISR contains PWM period. Y used as counter. + irq 0 +countloop: + jmp x!=y noset ; Set pin high if X == Y, keep the two paths length matched + jmp skip side 0 +noset: + nop ; Single dummy cycle to keep the two paths the same length +skip: + jmp y-- countloop ; Loop until Y hits 0, then pull a restart the counter + + + +% c-sdk { +static inline void CLK_program_init(PIO pio, uint sm, uint offset, uint pin) { + pio_sm_config c = CLK_program_get_default_config(offset); + + // Map the state machine's OUT pin group to one pin, namely the `pin` + // parameter to this function. + sm_config_set_out_pins(&c, pin, 1); + // Set this pin's GPIO function (connect PIO to the pad) + pio_gpio_init(pio, pin); + // Set the pin direction to output at the PIO + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + + sm_config_set_sideset_pins(&c, pin); + + // Load our configuration, and jump to the start of the program + pio_sm_init(pio, sm, offset, &c); + // Set the state machine running + //pio_sm_set_enabled(pio, sm, true); +} +%} \ No newline at end of file diff --git a/Firmware/CMakeLists.txt b/Firmware/CMakeLists.txt new file mode 100644 index 0000000..2102235 --- /dev/null +++ b/Firmware/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.13) + +include(pico_sdk_import.cmake) + +project(main) + +pico_sdk_init() + +add_executable(main) + +pico_generate_pio_header(main ${CMAKE_CURRENT_LIST_DIR}/CLK.pio) +pico_generate_pio_header(main ${CMAKE_CURRENT_LIST_DIR}/TIMING.pio) + +target_sources( main + PRIVATE main.c + CC_Charger.c + pulse_generator.c) + +# pull in common dependencies +target_link_libraries( main + pico_stdlib + hardware_pio + hardware_adc + hardware_pwm + pico_time) + +pico_enable_stdio_uart(main 1) +pico_enable_stdio_usb(main 0) + +# create map/bin/hex file etc. +pico_add_extra_outputs(main) \ No newline at end of file diff --git a/Firmware/TIMING.pio b/Firmware/TIMING.pio new file mode 100644 index 0000000..61bf072 --- /dev/null +++ b/Firmware/TIMING.pio @@ -0,0 +1,40 @@ +.program TIMING +.side_set 1 opt + +offStart: + wait 0 irq 0 side 0 ; Wait for clock rising edge + + mov y, isr ; Wait time stored in ISR, Y register used as counter + +waitloop: + jmp !y onStart ; When the timer runs out turn on the output pin and begin on time loop + jmp y-- waitloop ; If the off time hasn't elapsed, keep looping + +onStart: + mov y, osr side 1 ; On time stored in OSR, Y register used as a counter + +onloop: + jmp !y offStart ; When the timer runs out turn off the output pin and wait for clock edge + jmp y-- onloop ; If the on time hasn't yet elapsed, keep looping + + +% c-sdk { +static inline void TIMING_program_init(PIO pio, uint sm, uint offset, uint pin) { + pio_sm_config c = TIMING_program_get_default_config(offset); + + // Map the state machine's OUT pin group to one pin, namely the `pin` + // parameter to this function. + sm_config_set_out_pins(&c, pin, 1); + // Set this pin's GPIO function (connect PIO to the pad) + pio_gpio_init(pio, pin); + // Set the pin direction to output at the PIO + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + + sm_config_set_sideset_pins(&c, pin); + + // Load our configuration, and jump to the start of the program + pio_sm_init(pio, sm, offset, &c); + // Set the state machine running + //pio_sm_set_enabled(pio, sm, true); +} +%} \ No newline at end of file diff --git a/Firmware/main.c b/Firmware/main.c new file mode 100644 index 0000000..59a35ec --- /dev/null +++ b/Firmware/main.c @@ -0,0 +1,87 @@ +#include +#include "pico/stdlib.h" +#include "pico/time.h" +#include "hardware/pwm.h" + +#include "CC_Charger.h" +#include "pulse_generator.h" + +//Pinout definitions +#define CUT_nEN_PIN 0 + +//OUTPUT PULSE PARAMETERS (times in usecs) +#define OUTPUT_ON_TIME 20 +#define OUTPUT_OFF_TIME 80 +#define ISO_PULSE false +#define CAP_VOLTAGE_SETPOINT 65 //Don't set higher than 65 + +//CC Charger Parameters (don't change unless you know what you're doing) +#define CHARGER_CURRENT 850 + +//Math stuff DO NOT EDIT +#define CAP_VOLTAGE_PWM_LEVEL CAP_VOLTAGE_SETPOINT * 303 / 48 + +bool tripped = false; + +void cut_on_off_irq(void) { + + if(gpio_get_irq_event_mask(CUT_nEN_PIN) & GPIO_IRQ_EDGE_FALL) { + + gpio_acknowledge_irq(CUT_nEN_PIN, GPIO_IRQ_EDGE_FALL); + + cutting_enabled = true; + begin_output_pulses(OUTPUT_ON_TIME, OUTPUT_OFF_TIME, ISO_PULSE); + } + + if(gpio_get_irq_event_mask(CUT_nEN_PIN) & GPIO_IRQ_EDGE_RISE) { + + gpio_acknowledge_irq(CUT_nEN_PIN, GPIO_IRQ_EDGE_RISE); + + cutting_enabled = false; + } +} + +void default_gpio_callback(uint gpio, uint32_t event_mask) { + gpio_acknowledge_irq(gpio, event_mask); + return; +} + +int main() { + + // stdio_init_all(); //Start the Serial console + + // gpio_init(CUT_nEN_PIN); + // gpio_set_dir(CUT_nEN_PIN, GPIO_IN); + // gpio_set_pulls(cut_NEN, true, false); + + sleep_ms(1000); + + // while(gpio_get(23)) {} + + CC_Charger_init(CHARGER_CURRENT, CAP_VOLTAGE_PWM_LEVEL); //Setup the CC Charger Outputs + + pulse_generator_init(10); + + gpio_init(CUT_nEN_PIN); + gpio_set_dir(CUT_nEN_PIN, GPIO_IN); + gpio_set_pulls(CUT_nEN_PIN, true, false); + + gpio_init(1); + gpio_set_dir(1, GPIO_OUT); + gpio_put(1, false); + + irq_set_enabled(IO_IRQ_BANK0, true); + + sleep_ms(1000); + + gpio_set_irq_enabled(CUT_nEN_PIN, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true); + gpio_add_raw_irq_handler(CUT_nEN_PIN, &cut_on_off_irq); + + while (true) { + + // sleep_us(10); + // gpio_put(3, true); + // sleep_us(10); + // gpio_put(3, false); + } +} \ No newline at end of file diff --git a/Firmware/pico_sdk_import.cmake b/Firmware/pico_sdk_import.cmake new file mode 100644 index 0000000..65f8a6f --- /dev/null +++ b/Firmware/pico_sdk_import.cmake @@ -0,0 +1,73 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG master + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE}) diff --git a/Firmware/pulse_generator.c b/Firmware/pulse_generator.c new file mode 100644 index 0000000..2c265fd --- /dev/null +++ b/Firmware/pulse_generator.c @@ -0,0 +1,149 @@ +#include "pico/stdlib.h" +#include "pulse_generator.h" +#include "CC_Charger.h" +#include "hardware/pwm.h" + +#define OUTPUT_EN_PIN 2 +#define OUTPUT_CURRENT_TRIP_PIN 10 +#define SPARK_THRESHOLD_PWM_PIN 14 + +bool cutting_enabled = true; +bool off_time_insufficient = false; + +//Enum to keep track of where we are in the pulse sequence +enum pulse_state{ WAITING_FOR_IGNITION, + SPARK_ON, + SPARK_OFF}; + +enum pulse_state output_state = SPARK_OFF; + +//Pulse definition waveforms +uint32_t pulse_on_time = 0; +uint32_t pulse_off_time = 0; +bool iso_pulse_mode = false; +uint32_t pulse_timeout_time = 0; //time in us + +//Prototype functions +int64_t begin_off_time(alarm_id_t id, void *user_data); + +//Set the CC timing to the standard charging parameters +int64_t change_CC_timing(alarm_id_t id, void *user_data){ + + LIMIT_set_timing(185, 7, true); + + return 0; + +} + +void output_current_trip_irq(void) { + + if (gpio_get_irq_event_mask(OUTPUT_CURRENT_TRIP_PIN) & GPIO_IRQ_EDGE_RISE) { + + gpio_acknowledge_irq(OUTPUT_CURRENT_TRIP_PIN, GPIO_IRQ_EDGE_RISE); + + gpio_set_irq_enabled(OUTPUT_CURRENT_TRIP_PIN, GPIO_IRQ_EDGE_RISE, false); //Turn off the interrupt on the ignition sense + + output_state = SPARK_ON; //Update the pulse generator state + + add_alarm_in_us(pulse_on_time, begin_off_time, NULL, true); //Set alarm to turn off the pulse after the pulse on time + + } + +} + +int64_t begin_on_time(alarm_id_t id, void *user_data){ + + disable_CC_timing(); //Turn off the CC Charger + + if(cutting_enabled) { //Check that cutting is still enabled + + if(iso_pulse_mode) { //Check pulse mode is iso-pulse + + output_state = WAITING_FOR_IGNITION; //Update pulse generator state + + gpio_put(OUTPUT_EN_PIN, true); //Turn on output FET + + add_alarm_in_us(pulse_timeout_time, begin_off_time, NULL, true); //Set the alarm in case of pulse timeout + + gpio_set_irq_enabled(OUTPUT_CURRENT_TRIP_PIN, GPIO_IRQ_EDGE_RISE, true);//Configure detection of the spark + gpio_add_raw_irq_handler(OUTPUT_CURRENT_TRIP_PIN, &output_current_trip_irq); + + } else { //If pulse mode is iso-tonic + + output_state = SPARK_ON; //Update pulse generator state + + gpio_put(OUTPUT_EN_PIN, true); //Turn on output FET + add_alarm_in_us(pulse_on_time-3, begin_off_time, NULL, true); //Set alarm for the off transition + } + } + + return 0; + +} + + +int64_t begin_off_time(alarm_id_t id, void *user_data){ + + if(output_state == WAITING_FOR_IGNITION || iso_pulse_mode == false) { //Spark has timed out or if iso pulse is off, restart pulse cycle + + gpio_put(OUTPUT_EN_PIN, false); //Turn off output MOSFET + + output_state = SPARK_OFF; //Update pulse generator state + + gpio_set_irq_enabled(OUTPUT_CURRENT_TRIP_PIN, GPIO_IRQ_EDGE_RISE, false); //Disable the ignition sense irq + + LIMIT_set_timing(97, 7, false); //Limit CC Charger PWM duty cycle to avoid inrush (was 97) + + enable_CC_timing(); //Start CC Charger + + add_alarm_in_us(15, change_CC_timing, NULL, true); //Setup the alarm to correct CC charger timing + add_alarm_in_us(pulse_off_time-11, begin_on_time, NULL, true); //Setup the alarm to turn on the output MOSFET after the off time + + } else if(output_state == SPARK_ON && iso_pulse_mode == true) { //Spark is already ignited, ignore this timer callback + + //Do nothing + + } + + return 0; + +} + +void first_begin_off_time() { + + LIMIT_set_timing(97, 7, false); //Set the CC Charger PWM max duty cycle lower to prevent inrush + + enable_CC_timing(); //Start the CC Charger + + add_alarm_in_us(15-4, change_CC_timing, NULL, true); //Setup the alarm to correct CC charger timing + add_alarm_in_us(pulse_off_time-8, begin_on_time, NULL, true); //Setup the alarm to turn on the output MOSFET after the off time +} + +void begin_output_pulses(uint32_t on_time, uint32_t off_time, bool iso_pulse) { + + //Load in the pulse parameters + pulse_on_time = on_time; + pulse_off_time = off_time; + pulse_timeout_time = pulse_on_time / 2; + iso_pulse_mode = iso_pulse; + + //Update pulse state based on pulse mode + if(iso_pulse_mode) { + output_state = WAITING_FOR_IGNITION; + } else { + output_state = SPARK_OFF; + } + + first_begin_off_time(); + +} + +void pulse_generator_init(uint32_t trip_current) { + + gpio_init(OUTPUT_EN_PIN); + gpio_set_dir(OUTPUT_EN_PIN, GPIO_OUT); + + gpio_init(OUTPUT_CURRENT_TRIP_PIN); + gpio_set_dir(OUTPUT_CURRENT_TRIP_PIN, GPIO_IN); + +} \ No newline at end of file diff --git a/Firmware/pulse_generator.h b/Firmware/pulse_generator.h new file mode 100644 index 0000000..d6fac5f --- /dev/null +++ b/Firmware/pulse_generator.h @@ -0,0 +1,19 @@ +#ifndef PULSE_GENERATOR_H_INCLUDED +#define PULSE_GENERATOR_H_INCLUDED + +#include "pico/stdlib.h" + +extern bool cutting_enabled; +extern bool off_time_insufficient; + +/*! \brief Start the EDM machine, ie, begin cutting + \ingroup pulse_generator +*/ +void begin_output_pulses(uint32_t on_time, uint32_t off_time, bool iso_pulse); + +/*! \brief Setup pins/dirs for the pulse generator + \ingroup pulse_generator +*/ +void pulse_generator_init(uint32_t trip_current); + +#endif \ No newline at end of file diff --git a/Powercore-V2.0 Motherboard/KiCAD/.gitignore b/Powercore-V2.0 Motherboard/KiCAD/.gitignore new file mode 100644 index 0000000..b406b04 --- /dev/null +++ b/Powercore-V2.0 Motherboard/KiCAD/.gitignore @@ -0,0 +1 @@ +POWERCORE-V2.0_MOTHERBOARD-backups/ \ No newline at end of file diff --git a/Powercore-V2.0 Motherboard/KiCAD/Gerbers/POWERCORE-V2.0_MOTHERBOARD-F_Paste.zip b/Powercore-V2.0 Motherboard/KiCAD/Gerbers/POWERCORE-V2.0_MOTHERBOARD-F_Paste.zip new file mode 100644 index 0000000..e22de00 Binary files /dev/null and b/Powercore-V2.0 Motherboard/KiCAD/Gerbers/POWERCORE-V2.0_MOTHERBOARD-F_Paste.zip differ diff --git a/Powercore-V2.0 Motherboard/KiCAD/Powercore-V2.0_Motherboard.kicad_prl b/Powercore-V2.0 Motherboard/KiCAD/Powercore-V2.0_Motherboard.kicad_prl index 5f66ff5..fdd76fb 100644 --- a/Powercore-V2.0 Motherboard/KiCAD/Powercore-V2.0_Motherboard.kicad_prl +++ b/Powercore-V2.0 Motherboard/KiCAD/Powercore-V2.0_Motherboard.kicad_prl @@ -63,7 +63,7 @@ 36, 40 ], - "visible_layers": "8081100_ffffffff", + "visible_layers": "8081100_ffffffe0", "zone_display_mode": 0 }, "meta": {