From e19a626945deeebb2375166c904c420ff10d360b Mon Sep 17 00:00:00 2001 From: Peter McGoron Date: Tue, 4 Apr 2023 15:10:32 -0400 Subject: [PATCH] dac, adc switch and documentation --- creole | 2 +- firmware/rtl/base/base.v.m4 | 23 ++++++++++++++++ software/src/access.c | 53 ++++++++++++++++++++++++++++++------- software/src/access.h | 10 +++++++ 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/creole b/creole index c7fc965..0ead095 160000 --- a/creole +++ b/creole @@ -1 +1 @@ -Subproject commit c7fc965fcfa72f26456f5221a6480de52f7d776a +Subproject commit 0ead095044c93825c7db8cec0a6b92769bac7a7d diff --git a/firmware/rtl/base/base.v.m4 b/firmware/rtl/base/base.v.m4 index d07c5b0..796b4d2 100644 --- a/firmware/rtl/base/base.v.m4 +++ b/firmware/rtl/base/base.v.m4 @@ -2,9 +2,22 @@ m4_changequote(`⟨', `⟩') m4_changecom(⟨/*⟩, ⟨*/⟩) m4_define(generate_macro, ⟨m4_define(M4_$1, $2)⟩) m4_include(../control_loop/control_loop_cmds.m4) + +/* Since yosys only allows for standard Verilog (no system verilog), + * arrays (which would make everything much cleaner) cannot be used. + * A preprocessor is used instead, and M4 is used because it is much + * cleaner than the Verilog preprocessor (which is bad). + */ + /*********************************************************/ /********************** M4 macros ************************/ /*********************************************************/ + +/* This macro is used in the module declaration. + * The first argument is the number of wires the select switch must + * support (2 for most DACs, 3 for the control loop DAC). + * The second argument is the DAC number. + */ m4_define(m4_dac_wires, ⟨ input [$1-1:0] dac_sel_$2, output dac_finished_$2, @@ -27,12 +40,20 @@ m4_define(m4_dac_wires, ⟨ input wf_ram_valid_$2 ⟩) +/* Same thing but for ADCs */ + m4_define(m4_adc_wires, ⟨ output adc_finished_$2, input adc_arm_$2, output [$1-1:0] from_adc_$2 ⟩) +/* This is used in the body of the module. It declares the interconnect + * for each DAC. The first argument is the amount of switch ports the + * DAC requires (2 for most DACs, 3 for the control loop DAC). The + * second argument is the DAC number. + */ + m4_define(m4_dac_switch, ⟨ wire [$1-1:0] mosi_port_$2; wire [$1-1:0] miso_port_$2; @@ -111,6 +132,8 @@ m4_define(m4_dac_switch, ⟨ ) ⟩) +/* Same thing but for ADCs */ + m4_define(m4_adc_switch, ⟨ spi_master_ss_no_write #( .WID($1), diff --git a/software/src/access.c b/software/src/access.c index c93c538..ad70f41 100644 --- a/software/src/access.c +++ b/software/src/access.c @@ -18,6 +18,10 @@ LOG_MODULE_REGISTER(access); +/* The values from converters are not aligned to an 8-bit byte. + * These values are still in twos compliment and have to be + * manually sign-extended. + */ static inline uint32_t sign_extend(uint32_t in, unsigned len) { @@ -74,6 +78,7 @@ dac_read_write(int dac, creole_word send, k_timeout_t timeout, int e = dac_take(dac, timeout); if (e != 0) return e; + dac_switch(dac, DAC_SPI_PORT, K_NO_WAIT); *to_dac[dac] = send; *dac_arm[dac] = 1; @@ -94,6 +99,19 @@ dac_read_write(int dac, creole_word send, k_timeout_t timeout, return 0; } +int +dac_switch(int dac, int setting, k_timeout_t timeout) +{ + int e = dac_take(dac, timeout); + if (e != 0) + return e; + + *dac_sel[dac] = setting; + + dac_release(dac); + return 0; +} + /********************** * adc read *********************/ @@ -132,6 +150,25 @@ adc_release(int adc) return e; } +int +adc_switch(int adc, int setting, k_timeout_t timeout) +{ + /* As of now, only one ADC (the CLOOP adc) is used + * by two modules at the same time. + */ + if (adc != 0) + return -ENOENT; + + int e = adc_take(adc, timeout); + if (e != 0) + return e; + + *adc_sel_0 = setting; + + adc_release(adc); + return 0; +} + int adc_read(int adc, k_timeout_t timeout, creole_word *wrd) { @@ -139,6 +176,7 @@ adc_read(int adc, k_timeout_t timeout, creole_word *wrd) if ((e = adc_take(adc, timeout)) != 0) return e; + adc_switch(adc, ADC_SPI_PORT, K_NO_WAIT); *adc_arm[adc] = 1; /* Recursive locks should busy wait. */ @@ -173,15 +211,10 @@ cloop_take(k_timeout_t timeout) int cloop_release(void) { - /* If being unlocked for the last time. */ - if (cloop_locked == 1) { - *cl_cmd = CONTROL_LOOP_WRITE_BIT | CONTROL_LOOP_STATUS; - cl_word_out[0] = 0; - cl_word_out[1] = 0; - *cl_start_cmd = 1; - while (!*cl_finish_cmd); - *cl_start_cmd = 0; - } + /* Do not attempt to reset the CLOOP interface. + * Other scripts will fight to modify the CLOOP constants + * while the loop is still running. + */ int e = k_mutex_unlock(&cloop_mutex); if (e == 0) { cloop_locked--; @@ -320,6 +353,8 @@ waveform_arm(int slot, bool halt_on_finish, uint32_t wait, k_timeout_t timeout) return 0; } + dac_switch(slot, DAC_WF_PORT, K_NO_WAIT); + *wf_halt_on_finish[slot] = halt_on_finish; *wf_time_to_wait[slot] = wait; *wf_arm[slot] = 1; diff --git a/software/src/access.h b/software/src/access.h index 3a42ba8..24bfc5c 100644 --- a/software/src/access.h +++ b/software/src/access.h @@ -7,10 +7,20 @@ int dac_release(int dac); int dac_read_write(int dac, creole_word send, k_timeout_t timeout, creole_word *recv); +/* These ports are defined in firmware/rtl/base/base.v.m4 */ +#define DAC_SPI_PORT 0 +#define DAC_WF_PORT 1 +#define DAC_CLOOP_PORT 2 +int dac_switch(int dac, int setting, k_timeout_t timeout); + int adc_take(int adc, k_timeout_t timeout); int adc_release(int adc); int adc_read(int adc, k_timeout_t timeout, creole_word *wrd); +#define ADC_SPI_PORT 0 +#define ADC_CLOOP_PORT 1 +int adc_switch(int adc, int setting, k_timeout_t timeout); + int cloop_take(k_timeout_t timeout); int cloop_read(int code, uint32_t *high_reg, uint32_t *low_reg, k_timeout_t timeout);