From d979344624da2130cdf41dfd5064202083fbad83 Mon Sep 17 00:00:00 2001 From: Peter McGoron Date: Mon, 12 Jun 2023 15:46:12 -0400 Subject: [PATCH] change constants, bring back automated control loop tests, validate --- firmware/Makefile | 2 + firmware/rtl/Makefile | 4 +- firmware/rtl/control_loop/Makefile | 4 +- firmware/rtl/control_loop/control_loop.v.m4 | 6 +- .../rtl/control_loop/control_loop_math.v.m4 | 13 +- .../control_loop/control_loop_math_sim.cpp | 3 +- .../rtl/control_loop/control_loop_sim.cpp | 150 ++++----------- .../control_loop_sim_interactive.cpp | 172 ++++++++++++++++++ 8 files changed, 226 insertions(+), 128 deletions(-) create mode 100644 firmware/rtl/control_loop/control_loop_sim_interactive.cpp diff --git a/firmware/Makefile b/firmware/Makefile index 9550a1a..fba4245 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -11,6 +11,8 @@ csr.json build/digilent_arty/digilent_arty.bit: soc.py clean: rm -rf build csr.json overlay.config overlay.dts pin_io.h arty.dts arty.dtb cd rtl && make clean +test: + cd rtl && make test arty.dts: csr.json litex_json2dts_linux csr.json > arty.dts diff --git a/firmware/rtl/Makefile b/firmware/rtl/Makefile index b65e1c4..a88a6c8 100644 --- a/firmware/rtl/Makefile +++ b/firmware/rtl/Makefile @@ -1,5 +1,7 @@ -all: make_base make_spi make_control_loop make_waveform +all: make_base make_spi make_control_loop +test: + cd control_loop && make test make_base: cd base && make codegen make_spi: diff --git a/firmware/rtl/control_loop/Makefile b/firmware/rtl/control_loop/Makefile index 9330851..ab9694b 100644 --- a/firmware/rtl/control_loop/Makefile +++ b/firmware/rtl/control_loop/Makefile @@ -14,8 +14,8 @@ CONSTS_FRAC=43 E_WID=21 test: obj_dir/Vcontrol_loop_sim_top obj_dir/Vcontrol_loop_math - # obj_dir/Vcontrol_loop_math - + obj_dir/Vcontrol_loop_math + obj_dir/Vcontrol_loop_sim_top obj_dir/Vcontrol_loop_math.mk: control_loop_math_sim.cpp ${COMMON} \ ${control_loop_math_verilog} verilator --cc --exe -Wall --trace --trace-fst \ diff --git a/firmware/rtl/control_loop/control_loop.v.m4 b/firmware/rtl/control_loop/control_loop.v.m4 index 08dd3a5..d9db131 100644 --- a/firmware/rtl/control_loop/control_loop.v.m4 +++ b/firmware/rtl/control_loop/control_loop.v.m4 @@ -168,9 +168,7 @@ control_loop_math #( .CONSTS_SIZ(CONSTS_SIZ), .ADC_WID(ADC_WID), .DAC_WID(DAC_DATA_WID), - .CYCLE_COUNT_WID(CYCLE_COUNT_WID), - .SEC_PER_CYCLE('b10101011110011000), - .ADC_TO_DAC({32'b01000001100, 32'b01001001101110100101111000110101}) + .CYCLE_COUNT_WID(CYCLE_COUNT_WID) ) math ( .clk(clk), .rst_L(rst_L), @@ -252,7 +250,7 @@ end * the main loop is clearing the dirty bit. */ -wire write_control = state == CYCLE_START || !running; +wire write_control = state == WAIT_ON_DAC || !running; reg dirty_bit = 0; always @ (posedge clk) begin diff --git a/firmware/rtl/control_loop/control_loop_math.v.m4 b/firmware/rtl/control_loop/control_loop_math.v.m4 index 53d3273..9301f0a 100644 --- a/firmware/rtl/control_loop/control_loop_math.v.m4 +++ b/firmware/rtl/control_loop/control_loop_math.v.m4 @@ -32,10 +32,17 @@ m4_define(M4_CONSTS_WID, (CONSTS_WHOLE + CONSTS_FRAC)) parameter ADC_WID = 18, parameter [M4_CONSTS_WID-1:0] SEC_PER_CYCLE = 'b10101011110011000, - /* The conversion between the ADC bit (20/2**18) and DAC bit (20.48/2**20) - * is 0.256. + /* To calculate this value: + * Load doc/fixedpoint.py + * run bin(string_to_fixed_point(str((ADC_RANGE/2**ADC_WID)/(DAC_RANGE/2**DAC_WID)), CONSTS_FRAC)) + * This value is the value to put below. + * This value uses ADC_RANGE=20.48, DAC_RANGE=30 + * The ranges are the range of values REPRESENTABLE by the ADC and DAC, + * not the values you expect to get! */ - parameter [M4_CONSTS_WID-1:0] ADC_TO_DAC = 64'b0100000110001001001101110100101111000110101, + parameter [M4_CONSTS_WID-1:0] ADC_TO_DAC = +/* 64'b0100000110001001001101110100101111000110101, */ +64'b0101110111000000000000000000000000000000000, parameter CYCLE_COUNT_WID = 18, parameter DAC_WID = 20 m4_define(M4_E_WID, (DAC_WID + 1)) diff --git a/firmware/rtl/control_loop/control_loop_math_sim.cpp b/firmware/rtl/control_loop/control_loop_math_sim.cpp index ba284d9..6543ed3 100644 --- a/firmware/rtl/control_loop/control_loop_math_sim.cpp +++ b/firmware/rtl/control_loop/control_loop_math_sim.cpp @@ -25,13 +25,14 @@ static void init(int argc, char **argv) { Verilated::traceEverOn(true); mod = new ModType; mod->clk = 0; + mod->rst_L = 1; } #define MASK(n) ((1 << (n)) - 1) using V = int64_t; constexpr V per100 = 0b010101011110011000; -constexpr V adc_to_dac = 0b0100000110001001001101110100101111000110101; +constexpr V adc_to_dac = 0b0101110111000000000000000000000000000000000; static void calculate() { /* Multiplication adds an extra CONSTS_FRAC bits to the end, diff --git a/firmware/rtl/control_loop/control_loop_sim.cpp b/firmware/rtl/control_loop/control_loop_sim.cpp index 55d415a..fe262ca 100644 --- a/firmware/rtl/control_loop/control_loop_sim.cpp +++ b/firmware/rtl/control_loop/control_loop_sim.cpp @@ -7,14 +7,12 @@ #include #include -// Other classes implemented (Verilator) #include #include "control_loop_math_implementation.h" #include "control_loop_cmds.h" #include "Vcontrol_loop_sim_top.h" using ModType = Vcontrol_loop_sim_top; -// Clock uint32_t main_time = 0; double sc_time_stamp() { return main_time; @@ -35,6 +33,7 @@ static void init(int argc, char **argv) { Verilated::traceEverOn(true); mod = new ModType; mod->clk = 0; + mod->rst_L = 1; } static void set_value(V val, unsigned name) { @@ -48,125 +47,42 @@ static void set_value(V val, unsigned name) { } int main(int argc, char **argv) { + printf("sim top\n"); init(argc, argv); + Transfer func = Transfer{150, 0, 2, 1.1, 10, -1}; - int Con, // Continue option for user - P = 3, // Default P value - I = 0, // Default I value - Delay = 20, // Default Delay value - SetPt = 10000, // Default SetPt value - Status = 1, // Default Status value - Option_Picked; // Option user picked - - do - { + set_value(0b11010111000010100011110101110000101000111, CONTROL_LOOP_P); + /* Constant values must be sized to 64 bits, or else the compiler + * will think they are 32 bit and silently mess things up + */ + set_value((V)6 << CONSTS_FRAC, CONTROL_LOOP_I); + set_value(20, CONTROL_LOOP_DELAY); + set_value(10000, CONTROL_LOOP_SETPT); + set_value(1, CONTROL_LOOP_STATUS); + mod->curset = 0; - mod = new ModType; - Transfer func = Transfer{150, 0, 2, 1.1, 10, -1}; - - mod->clk = 0; - - // Testing this char for P value - char Data_Change_S = '0b11010111000010100011110101110000101000111'; - - // Default value for P, some type of error where it won't accept any string, int | Try char next time - set_value(0b11010111000010100011110101110000101000111, CONTROL_LOOP_P); - - // Default value - set_value((V)6 << CONSTS_FRAC, CONTROL_LOOP_I); - set_value(Delay, CONTROL_LOOP_DELAY); - set_value(SetPt, CONTROL_LOOP_SETPT); - set_value(Status, CONTROL_LOOP_STATUS); - - // Menu - do - { - printf("%15s\n", "Menu"); - printf("1) Set Control loop P Current value: %d\n", P); - printf("2) Set Control loop I Current value: %d\n", I); - printf("3) Set Delay Current value: %d\n", Delay); - printf("4) Set setpoint Current value: %d\n", SetPt); - printf("5) Set status Current value: %d\n", Status); - printf("6) Continue\n"); - - // Checks for what option user picks - scanf("%d", &Option_Picked); - - // Clears unix screen - system("clear"); - - switch (Option_Picked) - { - case 1: - // This case doesn't work for some reason? Need further time to figure it out - printf("Please input new Control Loop P value: "); - scanf("%d", &P); - set_value(P, CONTROL_LOOP_P); - break; - case 2: - printf("Please input new Control Loop I value: "); - scanf("%d", &I); - set_value(I, CONTROL_LOOP_I); - break; - case 3: - printf("Please input new delay value: "); - scanf("%d", &Delay); - set_value(Delay, CONTROL_LOOP_DELAY); - break; - case 4: - printf("Please input new setpoint value: "); - scanf("%d", &SetPt); - set_value(SetPt, CONTROL_LOOP_SETPT); - break; - case 5: - printf("Please input new status value: "); - scanf("%d", &Status); - set_value(Status, CONTROL_LOOP_STATUS); - break; - } - - } while (Option_Picked != 6); - - - - - mod->curset = 0; - - // Resets Con to 1 to activate for loop - Con = 1; - - for (int tick = 0; Con == 1; tick++) { - run_clock(); - if (mod->request && !mod->fulfilled) { - /* Verilator values are not sign-extended to the - * size of type, so we have to do that ourselves. - */ - V ext = sign_extend(mod->curset, 20); - V val = func.val(ext); - printf("setting: %ld, val: %ld\n", ext, val); - mod->measured_value = val; - mod->fulfilled = 1; - } else if (mod->fulfilled && !mod->request) { - mod->fulfilled = 0; - } - - if (mod->finish_cmd) { - mod->start_cmd = 0; - } - - // After 100000 ticks shows user prompt, might make tick to be changable for user. - if (tick % 100000 == 0 && tick != 0) - { - printf("Continue? (0 for exit, 1 for yes, 2 to return to menu)\n"); - scanf("%d", &Con); - } + for (int tick = 0; tick < 1000;) { + run_clock(); + if (mod->request && !mod->fulfilled) { + /* Verilator values are not sign-extended to the + * size of type, so we have to do that ourselves. + */ + V ext = sign_extend(mod->curset, 20); + V val = func.val(ext); + printf("setting: %ld, val: %ld\n", ext, val); + mod->measured_value = val; + mod->fulfilled = 1; + } else if (mod->fulfilled && !mod->request) { + mod->fulfilled = 0; + tick++; } - // Clears unix screen - system("clear"); - mod->final(); - delete mod; - } while (Con == 2); - + if (mod->finish_cmd) { + mod->start_cmd = 0; + } + } + + mod->final(); + delete mod; return 0; } diff --git a/firmware/rtl/control_loop/control_loop_sim_interactive.cpp b/firmware/rtl/control_loop/control_loop_sim_interactive.cpp new file mode 100644 index 0000000..55d415a --- /dev/null +++ b/firmware/rtl/control_loop/control_loop_sim_interactive.cpp @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// Other classes implemented (Verilator) +#include +#include "control_loop_math_implementation.h" +#include "control_loop_cmds.h" +#include "Vcontrol_loop_sim_top.h" +using ModType = Vcontrol_loop_sim_top; + +// Clock +uint32_t main_time = 0; +double sc_time_stamp() { + return main_time; +} + +ModType *mod; + +static void run_clock() { + for (int i = 0; i < 2; i++) { + mod->clk = !mod->clk; + mod->eval(); + main_time++; + } +} + +static void init(int argc, char **argv) { + Verilated::commandArgs(argc, argv); + Verilated::traceEverOn(true); + mod = new ModType; + mod->clk = 0; +} + +static void set_value(V val, unsigned name) { + mod->cmd = CONTROL_LOOP_WRITE_BIT | name; + mod->word_into_loop = val; + mod->start_cmd = 1; + + do { run_clock(); } while (!mod->finish_cmd); + mod->start_cmd = 0; + run_clock(); +} + +int main(int argc, char **argv) { + init(argc, argv); + + int Con, // Continue option for user + P = 3, // Default P value + I = 0, // Default I value + Delay = 20, // Default Delay value + SetPt = 10000, // Default SetPt value + Status = 1, // Default Status value + Option_Picked; // Option user picked + + do + { + + mod = new ModType; + Transfer func = Transfer{150, 0, 2, 1.1, 10, -1}; + + mod->clk = 0; + + // Testing this char for P value + char Data_Change_S = '0b11010111000010100011110101110000101000111'; + + // Default value for P, some type of error where it won't accept any string, int | Try char next time + set_value(0b11010111000010100011110101110000101000111, CONTROL_LOOP_P); + + // Default value + set_value((V)6 << CONSTS_FRAC, CONTROL_LOOP_I); + set_value(Delay, CONTROL_LOOP_DELAY); + set_value(SetPt, CONTROL_LOOP_SETPT); + set_value(Status, CONTROL_LOOP_STATUS); + + // Menu + do + { + printf("%15s\n", "Menu"); + printf("1) Set Control loop P Current value: %d\n", P); + printf("2) Set Control loop I Current value: %d\n", I); + printf("3) Set Delay Current value: %d\n", Delay); + printf("4) Set setpoint Current value: %d\n", SetPt); + printf("5) Set status Current value: %d\n", Status); + printf("6) Continue\n"); + + // Checks for what option user picks + scanf("%d", &Option_Picked); + + // Clears unix screen + system("clear"); + + switch (Option_Picked) + { + case 1: + // This case doesn't work for some reason? Need further time to figure it out + printf("Please input new Control Loop P value: "); + scanf("%d", &P); + set_value(P, CONTROL_LOOP_P); + break; + case 2: + printf("Please input new Control Loop I value: "); + scanf("%d", &I); + set_value(I, CONTROL_LOOP_I); + break; + case 3: + printf("Please input new delay value: "); + scanf("%d", &Delay); + set_value(Delay, CONTROL_LOOP_DELAY); + break; + case 4: + printf("Please input new setpoint value: "); + scanf("%d", &SetPt); + set_value(SetPt, CONTROL_LOOP_SETPT); + break; + case 5: + printf("Please input new status value: "); + scanf("%d", &Status); + set_value(Status, CONTROL_LOOP_STATUS); + break; + } + + } while (Option_Picked != 6); + + + + + mod->curset = 0; + + // Resets Con to 1 to activate for loop + Con = 1; + + for (int tick = 0; Con == 1; tick++) { + run_clock(); + if (mod->request && !mod->fulfilled) { + /* Verilator values are not sign-extended to the + * size of type, so we have to do that ourselves. + */ + V ext = sign_extend(mod->curset, 20); + V val = func.val(ext); + printf("setting: %ld, val: %ld\n", ext, val); + mod->measured_value = val; + mod->fulfilled = 1; + } else if (mod->fulfilled && !mod->request) { + mod->fulfilled = 0; + } + + if (mod->finish_cmd) { + mod->start_cmd = 0; + } + + // After 100000 ticks shows user prompt, might make tick to be changable for user. + if (tick % 100000 == 0 && tick != 0) + { + printf("Continue? (0 for exit, 1 for yes, 2 to return to menu)\n"); + scanf("%d", &Con); + } + } + // Clears unix screen + system("clear"); + + mod->final(); + delete mod; + } while (Con == 2); + + return 0; +}