diff --git a/src/client/julia/src/EEPROM.jl b/src/client/julia/src/EEPROM.jl index 3ac6c47f..f6388e46 100644 --- a/src/client/julia/src/EEPROM.jl +++ b/src/client/julia/src/EEPROM.jl @@ -1,4 +1,4 @@ -export calibDACOffset, calibDACOffset!, calibADCScale, calibADCScale!, calibADCOffset, calibADCOffset!, updateCalib!, calibDACScale!, calibDACScale, calibFlags +export calibDACOffset, calibDACOffset!, calibADCScale, calibADCScale!, calibADCOffset, calibADCOffset!, updateCalib!, calibDACScale!, calibDACScale, calibFlags, calibDACLowerLimit, calibDACLowerLimit!, calibDACUpperLimit, calibDACUpperLimit!, calibDACLimit! """ calibDACOffset!(rp::RedPitaya, channel::Integer, val) @@ -43,6 +43,60 @@ calibDACScale(rp::RedPitaya, channel::Integer) = query(rp, scpiCommand(calibDACS scpiCommand(::typeof(calibDACScale), channel::Integer) = string("RP:CALib:DAC:CH", Int(channel) - 1, ":SCA?") scpiReturn(::typeof(calibDACScale)) = Float64 +""" + calibDACLowerLimit!(rp::RedPitaya, channel::Integer) + +Store calibration DAC lower limit `val` for given channel into the RedPitayas EEPROM. +This value is used by the server to limit the output voltage. +""" +function calibDACLowerLimit!(rp::RedPitaya, channel::Integer, val) + return query(rp, scpiCommand(calibDACLowerLimit!, channel, val), scpiReturn(calibDACLowerLimit!)) +end +scpiCommand(::typeof(calibDACLowerLimit!), channel::Integer, val) = string("RP:CALib:DAC:CH", Int(channel) - 1, ":LIM:LOW $(Float32(val))") +scpiReturn(::typeof(calibDACLowerLimit!)) = Bool +""" + calibDACLowerLimit(rp::RedPitaya, channel::Integer) + +Retrieve the calibration DAC lower limit for given channel from the RedPitayas EEPROM. +""" +calibDACLowerLimit(rp::RedPitaya, channel::Integer) = query(rp, scpiCommand(calibDACLowerLimit, channel), scpiReturn(calibDACLowerLimit)) +scpiCommand(::typeof(calibDACLowerLimit), channel::Integer) = string("RP:CALib:DAC:CH", Int(channel) - 1, ":LIM:LOW?") +scpiReturn(::typeof(calibDACLowerLimit)) = Float64 + +""" + calibDACUpperLimit!(rp::RedPitaya, channel::Integer) + +Store calibration DAC upper limit `val` for given channel into the RedPitayas EEPROM. +This value is used by the server to limit the output voltage. +""" +function calibDACUpperLimit!(rp::RedPitaya, channel::Integer, val) + return query(rp, scpiCommand(calibDACUpperLimit!, channel, val), scpiReturn(calibDACUpperLimit!)) +end +scpiCommand(::typeof(calibDACUpperLimit!), channel::Integer, val) = string("RP:CALib:DAC:CH", Int(channel) - 1, ":LIM:UP $(Float32(val))") +scpiReturn(::typeof(calibDACUpperLimit!)) = Bool +""" + calibDACUpperLimit(rp::RedPitaya, channel::Integer) + +Retrieve the calibration DAC upper limit for given channel from the RedPitayas EEPROM. +""" +calibDACUpperLimit(rp::RedPitaya, channel::Integer) = query(rp, scpiCommand(calibDACUpperLimit, channel), scpiReturn(calibDACUpperLimit)) +scpiCommand(::typeof(calibDACUpperLimit), channel::Integer) = string("RP:CALib:DAC:CH", Int(channel) - 1, ":LIM:UP?") +scpiReturn(::typeof(calibDACUpperLimit)) = Float64 + +""" + calibDACLimit!(rp::RedPitaya, channel, val) + +Applies `val` with a positive sign as the upper and with a negative sign as the lower calibration DAC limit. + +See also [calibDACUpperLimit!](@ref), [calibDACLowerLimit!](@ref) +""" +function calibDACLimit!(rp::RedPitaya, channel::Integer, val) + val = abs(val) + result = calibDACLowerLimit!(rp, channel, -val) + result &= calibDACUpperLimit!(rp, channel, val) + return result +end + """ calibADCOffset!(rp::RedPitaya, channel::Integer, val) diff --git a/src/fpga/bd/bd.tcl b/src/fpga/bd/bd.tcl index 5c24f765..c59f741d 100644 --- a/src/fpga/bd/bd.tcl +++ b/src/fpga/bd/bd.tcl @@ -901,6 +901,8 @@ proc create_hier_cell_signal_compose1 { parentCell nameHier } { connect_bd_net -net offset_1 [get_bd_pins offset] [get_bd_pins signal_composer_0/seq] connect_bd_net -net rst_ps7_0_125M_peripheral_aresetn [get_bd_pins aresetn] [get_bd_pins signal_ramp_0/aresetn] [get_bd_pins waveform_awg1/aresetn] [get_bd_pins waveform_gen_0/aresetn] [get_bd_pins waveform_gen_1/aresetn] [get_bd_pins waveform_gen_2/aresetn] [get_bd_pins waveform_gen_3/aresetn] connect_bd_net -net signal_calib_0_signal_out [get_bd_pins S] [get_bd_pins signal_calib_0/signal_out] + connect_bd_net -net signal_cfg_slice_0_calib_limit_lower [get_bd_pins signal_calib_0/calib_limit_lower] [get_bd_pins signal_cfg_slice_0/calib_limit_lower] + connect_bd_net -net signal_cfg_slice_0_calib_limit_upper [get_bd_pins signal_calib_0/calib_limit_upper] [get_bd_pins signal_cfg_slice_0/calib_limit_upper] connect_bd_net -net signal_cfg_slice_0_calib_offset [get_bd_pins signal_calib_0/calib_offset] [get_bd_pins signal_cfg_slice_0/calib_offset] connect_bd_net -net signal_cfg_slice_0_calib_scale [get_bd_pins signal_calib_0/calib_scale] [get_bd_pins signal_cfg_slice_0/calib_scale] connect_bd_net -net signal_cfg_slice_0_comp_0_amp [get_bd_pins signal_cfg_slice_0/comp_0_amp] [get_bd_pins waveform_gen_0/amplitude] @@ -1093,6 +1095,8 @@ proc create_hier_cell_signal_compose { parentCell nameHier } { connect_bd_net -net offset_1 [get_bd_pins offset] [get_bd_pins signal_composer_0/seq] connect_bd_net -net ramping_enable_1 [get_bd_pins enable_ramping] [get_bd_pins signal_ramp/enableRamping] connect_bd_net -net signal_calib_0_signal_out [get_bd_pins S] [get_bd_pins signal_calib_0/signal_out] + connect_bd_net -net signal_cfg_slice_0_calib_limit_lower [get_bd_pins signal_calib_0/calib_limit_lower] [get_bd_pins signal_cfg_slice_0/calib_limit_lower] + connect_bd_net -net signal_cfg_slice_0_calib_limit_upper [get_bd_pins signal_calib_0/calib_limit_upper] [get_bd_pins signal_cfg_slice_0/calib_limit_upper] connect_bd_net -net signal_cfg_slice_0_calib_offset [get_bd_pins signal_calib_0/calib_offset] [get_bd_pins signal_cfg_slice_0/calib_offset] connect_bd_net -net signal_cfg_slice_0_calib_scale [get_bd_pins signal_calib_0/calib_scale] [get_bd_pins signal_cfg_slice_0/calib_scale] connect_bd_net -net signal_cfg_slice_0_comp_0_amp [get_bd_pins signal_cfg_slice_0/comp_0_amp] [get_bd_pins waveform_gen_0/amplitude] @@ -3413,6 +3417,7 @@ proc create_root_design { parentCell } { # Restore current instance current_bd_instance $oldCurInst + validate_bd_design save_bd_design } # End of create_root_design() @@ -3425,5 +3430,3 @@ proc create_root_design { parentCell } { create_root_design "" -common::send_gid_msg -ssname BD::TCL -id 2053 -severity "WARNING" "This Tcl script was generated from a block design that has not been validated. It is possible that design <$design_name> may result in errors during validation." - diff --git a/src/fpga/hdl/reset_manager.v b/src/fpga/hdl/reset_manager.v index b1769238..7e891778 100644 --- a/src/fpga/hdl/reset_manager.v +++ b/src/fpga/hdl/reset_manager.v @@ -212,7 +212,7 @@ begin end else begin - triggerState <= trigger_in_int || sata_trigger_int; + triggerState <= trigger_in_int; end masterTriggerState_pre <= reset_cfg[5] & counter_trigger; // counter_trigger must always be high if not enabled diff --git a/src/fpga/hdl/signal_cfg_slice.v b/src/fpga/hdl/signal_cfg_slice.v index 9e38a60c..47df5ec9 100644 --- a/src/fpga/hdl/signal_cfg_slice.v +++ b/src/fpga/hdl/signal_cfg_slice.v @@ -6,6 +6,8 @@ module signal_cfg_slice( output [15:0] offset, output [15:0] calib_scale, output [15:0] calib_offset, + output [15:0] calib_limit_lower, + output [15:0] calib_limit_upper, output [47:0] comp_0_cfg, output [15:0] comp_0_amp, output [47:0] comp_0_freq, @@ -35,13 +37,15 @@ assign calib_scale[15:0] = cfg_data[191:176]; assign comp_0_phase[47:0] = cfg_data[239:192]; assign calib_offset[15:0] = cfg_data[255:240]; +// 0 bit gap assign comp_1_cfg[47:0] = cfg_data[303:256]; assign comp_1_amp[15:0] = cfg_data[319:304]; assign comp_1_freq[47:0] = cfg_data[367:320]; -// 15 bit gap +assign calib_limit_lower[15:0] = cfg_data[383:368]; assign comp_1_phase[47:0] = cfg_data[431:384]; +assign calib_limit_upper[15:0] = cfg_data[447:432]; -// 15 bit gap +// 0 bit gap assign comp_2_cfg[47:0] = cfg_data[495:448]; assign comp_2_amp[15:0] = cfg_data[511:496]; assign comp_2_freq[47:0] = cfg_data[559:512]; diff --git a/src/fpga/hdl/signal_limit.v b/src/fpga/hdl/signal_limit.v new file mode 100644 index 00000000..fb005086 --- /dev/null +++ b/src/fpga/hdl/signal_limit.v @@ -0,0 +1,26 @@ +`timescale 1ns / 1ps + + +module signal_limit( + input clk, + input signed [15:0] signal_in, + input signed [15:0] limit_upper, + input signed[15:0] limit_lower, + output [15:0] limited_signal + ); + +reg signed [15:0] signal_result; + +always @(posedge clk) +begin + if (signal_in > limit_upper) begin + signal_result <= limit_upper; + end else if (signal_in < limit_lower) begin + signal_result <= limit_lower; + end else begin + signal_result <= signal_in; + end +end + +assign limited_signal = signal_result; +endmodule diff --git a/src/lib/rp-daq-lib.c b/src/lib/rp-daq-lib.c index 51844e31..6d176bdd 100644 --- a/src/lib/rp-daq-lib.c +++ b/src/lib/rp-daq-lib.c @@ -463,6 +463,39 @@ int setCalibDACOffset(float value, int channel) { return 0; } +int setCalibDACLowerLimit(float value, int channel) { + if (channel < 0 || channel > 1) { + return -3; + } + + int16_t limit = (int16_t)(value*8191.0); + if (limit < -8191 || limit >= 8192) { + return -2; + } + // Config lower limit is stored in second component freq + uint64_t register_value = *(dac_cfg + COMPONENT_START_OFFSET + FREQ_OFFSET + COMPONENT_OFFSET*1 + CHANNEL_OFFSET*channel); + register_value = (register_value & MASK_LOWER_48) | ((((int64_t) limit) << 48) & ~MASK_LOWER_48); + *(dac_cfg + COMPONENT_START_OFFSET + FREQ_OFFSET + COMPONENT_OFFSET*1 + CHANNEL_OFFSET*channel) = register_value; + return 0; +} + + +int setCalibDACUpperLimit(float value, int channel) { + if (channel < 0 || channel > 1) { + return -3; + } + + int16_t limit = (int16_t)(value*8191.0); + if (limit < -8191 || limit >= 8192) { + return -2; + } + // Config upper limit is stored in second component phase + uint64_t register_value = *(dac_cfg + COMPONENT_START_OFFSET + PHASE_OFFSET + COMPONENT_OFFSET*1 + CHANNEL_OFFSET*channel); + register_value = (register_value & MASK_LOWER_48) | ((((int64_t) limit) << 48) & ~MASK_LOWER_48); + *(dac_cfg + COMPONENT_START_OFFSET + PHASE_OFFSET + COMPONENT_OFFSET*1 + CHANNEL_OFFSET*channel) = register_value; + return 0; +} + int setArbitraryWaveform(float* values, int channel) { uint32_t *awg_cfg = NULL; if (channel == 0) { @@ -1392,6 +1425,10 @@ rp_calib_params_t getDefaultCalib(){ calib.adc_ch1_offs = 0.0; calib.adc_ch2_fs = 1.0/8192.0; calib.adc_ch2_offs = 0.0; + calib.dac_ch1_lower = -1.0; + calib.dac_ch1_upper = 1.0; + calib.dac_ch2_lower = -1.0; + calib.dac_ch2_upper = 1.0; return calib; } @@ -1440,14 +1477,37 @@ int calib_validate(rp_calib_params_t * calib_params) { calib_params->dac_ch2_offs = def.dac_ch2_offs; calib_params->set_flags &= ~(1 << 7); } + + // DAC Limits + if (useDefault || !(calib_params->set_flags & (1 << 8))) { + calib_params->dac_ch1_lower = def.dac_ch1_lower; + calib_params->set_flags &= ~(1 << 8); + } + if (useDefault || !(calib_params->set_flags & (1 << 9))) { + calib_params->dac_ch1_upper = def.dac_ch1_upper; + calib_params->set_flags &= ~(1 << 9); + } + if (useDefault || !(calib_params->set_flags & (1 << 10))) { + calib_params->dac_ch2_lower = def.dac_ch2_lower; + calib_params->set_flags &= ~(1 << 10); + } + if (useDefault || !(calib_params->set_flags & (1 << 11))) { + calib_params->dac_ch2_upper = def.dac_ch2_upper; + calib_params->set_flags &= ~(1 << 11); + } + return 0; } int calib_apply() { setCalibDACScale(calib.dac_ch1_fs, 0); setCalibDACOffset(calib.dac_ch1_offs, 0); + setCalibDACLowerLimit(calib.dac_ch1_lower, 0); + setCalibDACUpperLimit(calib.dac_ch1_upper, 0); setCalibDACScale(calib.dac_ch2_fs, 1); setCalibDACOffset(calib.dac_ch2_offs, 1); + setCalibDACLowerLimit(calib.dac_ch2_lower, 1); + setCalibDACUpperLimit(calib.dac_ch2_upper, 1); return 0; } @@ -1511,6 +1571,36 @@ int calib_setDACScale(rp_calib_params_t * calib_params, float value, int channel return 0; } +int calib_setDACLowerLimit(rp_calib_params_t * calib_params, float value, int channel) { + if (channel < 0 || channel > 1) { + return -3; + } + if (channel == 0) { + calib_params->dac_ch1_lower = value; + calib_params->set_flags |= (1 << 8); + } + else if (channel == 1) { + calib_params->dac_ch2_lower = value; + calib_params->set_flags |= (1 << 10); + } + return 0; +} + +int calib_setDACUpperLimit(rp_calib_params_t * calib_params, float value, int channel) { + if (channel < 0 || channel > 1) { + return -3; + } + if (channel == 0) { + calib_params->dac_ch1_upper = value; + calib_params->set_flags |= (1 << 9); + } + else if (channel == 1) { + calib_params->dac_ch2_upper = value; + calib_params->set_flags |= (1 << 11); + } + return 0; +} + void calib_SetToZero() { calib = getDefaultCalib(); diff --git a/src/lib/rp-daq-lib.h b/src/lib/rp-daq-lib.h index 5b4644b1..eb7ec9b2 100644 --- a/src/lib/rp-daq-lib.h +++ b/src/lib/rp-daq-lib.h @@ -56,7 +56,7 @@ #define DIO_IN 1 #define DIO_OUT 0 -#define CALIB_VERSION 1 +#define CALIB_VERSION 2 extern bool verbose; @@ -96,6 +96,8 @@ extern int getSignalType(int, int); extern int setSignalType(int, int, int); extern int setCalibDACScale(float, int); extern int setCalibDACOffset(float, int); +extern int setCalibDACLowerLimit(float, int); +extern int setCalibDACUpperLimit(float, int); extern int setArbitraryWaveform(float*, int); //extern int getRampingPeriod(int); @@ -200,7 +202,7 @@ extern void stopTx(); typedef struct { char id[3+1]; int version; - uint8_t set_flags; + uint16_t set_flags; float adc_ch1_fs; float adc_ch1_offs; float adc_ch2_fs; @@ -209,6 +211,10 @@ typedef struct { float dac_ch1_offs; float dac_ch2_fs; float dac_ch2_offs; + float dac_ch1_lower; + float dac_ch1_upper; + float dac_ch2_lower; + float dac_ch2_upper; } rp_calib_params_t; extern int calib_Init(); @@ -220,6 +226,8 @@ extern int calib_setADCOffset(rp_calib_params_t * calib_params, float value, int extern int calib_setADCScale(rp_calib_params_t * calib_params, float value, int channel); extern int calib_setDACOffset(rp_calib_params_t * calib_params, float value, int channel); extern int calib_setDACScale(rp_calib_params_t * calib_params, float value, int channel); +extern int calib_setDACLowerLimit(rp_calib_params_t * calib_params, float value, int channel); +extern int calib_setDACUpperLimit(rp_calib_params_t * calib_params, float value, int channel); extern rp_calib_params_t calib_GetParams(); extern rp_calib_params_t calib_GetDefaultCalib(); diff --git a/src/server/scpi_commands.c b/src/server/scpi_commands.c index d0402f4f..5518a2b7 100644 --- a/src/server/scpi_commands.c +++ b/src/server/scpi_commands.c @@ -1485,6 +1485,90 @@ static scpi_result_t RP_Calib_DAC_SetScale(scpi_t* context) { return returnSCPIBool(context, true); } +static scpi_result_t RP_Calib_DAC_GetLowerLimit(scpi_t* context) { + int32_t numbers[1]; + SCPI_CommandNumbers(context, numbers, 1, 1); + int channel = numbers[0]; + + rp_calib_params_t calib_params = calib_GetParams(); + if (channel == 0) { + SCPI_ResultFloat(context, calib_params.dac_ch1_lower); + } + else if (channel == 1) { + SCPI_ResultFloat(context, calib_params.dac_ch2_lower); + } + else { + SCPI_ResultFloat(context, NAN); + return SCPI_RES_ERR; + } + return SCPI_RES_OK; +} + +static scpi_result_t RP_Calib_DAC_SetLowerLimit(scpi_t* context) { + if (getServerMode() != CONFIGURATION) { + return returnSCPIBool(context, false); + } + + int32_t numbers[1]; + SCPI_CommandNumbers(context, numbers, 1, 1); + int channel = numbers[0]; + + rp_calib_params_t calib_params = calib_GetParams(); + float limit; + + SCPI_ParamFloat(context, &limit, true); + if (calib_setDACLowerLimit(&calib_params, limit, channel)) { + return returnSCPIBool(context, false); + } + + calib_WriteParams(calib_params, false); + calib_Init(); // Reload from cache from EEPROM + calib_apply(); + return returnSCPIBool(context, true); +} + +static scpi_result_t RP_Calib_DAC_GetUpperLimit(scpi_t* context) { + int32_t numbers[1]; + SCPI_CommandNumbers(context, numbers, 1, 1); + int channel = numbers[0]; + + rp_calib_params_t calib_params = calib_GetParams(); + if (channel == 0) { + SCPI_ResultFloat(context, calib_params.dac_ch1_upper); + } + else if (channel == 1) { + SCPI_ResultFloat(context, calib_params.dac_ch2_upper); + } + else { + SCPI_ResultFloat(context, NAN); + return SCPI_RES_ERR; + } + return SCPI_RES_OK; +} + +static scpi_result_t RP_Calib_DAC_SetUpperLimit(scpi_t* context) { + if (getServerMode() != CONFIGURATION) { + return returnSCPIBool(context, false); + } + + int32_t numbers[1]; + SCPI_CommandNumbers(context, numbers, 1, 1); + int channel = numbers[0]; + + rp_calib_params_t calib_params = calib_GetParams(); + float limit; + + SCPI_ParamFloat(context, &limit, true); + if (calib_setDACUpperLimit(&calib_params, limit, channel)) { + return returnSCPIBool(context, false); + } + + calib_WriteParams(calib_params, false); + calib_Init(); // Reload from cache from EEPROM + calib_apply(); + return returnSCPIBool(context, true); +} + static scpi_result_t RP_Calib_ADC_GetOffset(scpi_t* context) { int32_t numbers[1]; SCPI_CommandNumbers(context, numbers, 1, 1); @@ -1724,6 +1808,10 @@ const scpi_command_t scpi_commands[] = { {.pattern = "RP:CALib:DAC:CHannel#:OFFset", .callback = RP_Calib_DAC_SetOffset,}, {.pattern = "RP:CALib:DAC:CHannel#:SCAle?", .callback = RP_Calib_DAC_GetScale,}, {.pattern = "RP:CALib:DAC:CHannel#:SCAle", .callback = RP_Calib_DAC_SetScale,}, + {.pattern = "RP:CALib:DAC:CHannel#:LIMit:LOWer?", .callback = RP_Calib_DAC_GetLowerLimit,}, + {.pattern = "RP:CALib:DAC:CHannel#:LIMit:LOWer", .callback = RP_Calib_DAC_SetLowerLimit,}, + {.pattern = "RP:CALib:DAC:CHannel#:LIMit:UPper?", .callback = RP_Calib_DAC_GetUpperLimit,}, + {.pattern = "RP:CALib:DAC:CHannel#:LIMit:UPper", .callback = RP_Calib_DAC_SetUpperLimit,}, {.pattern = "RP:CALib:ADC:CHannel#:OFFset?", .callback = RP_Calib_ADC_GetOffset,}, {.pattern = "RP:CALib:ADC:CHannel#:OFFset", .callback = RP_Calib_ADC_SetOffset,}, {.pattern = "RP:CALib:ADC:CHannel#:SCAle?", .callback = RP_Calib_ADC_GetScale,},