SelfCal: Add startup_tile() for cal_mode selection

To follow Xilinx' recommendations for self-cal usage this adds
startup_tile() to the cal_mode selection and we query if the cal_mode
was set properly. Since we do this, on the host side we allow the full
first Nyquist zone to be used for self-cal.
This commit is contained in:
Martin Anderseck 2023-07-06 17:39:05 +02:00 committed by michael-west
parent b4c24091ed
commit 55fd43cc27
4 changed files with 47 additions and 7 deletions

View File

@ -50,21 +50,20 @@ void adc_self_calibration::run(size_t chan, uhd::device_addr_t params)
if (params.has_key("cal_freq")) {
const double cal_freq = params.cast<double>("cal_freq", cal_params.rx_freq);
if (cal_freq < 0 or cal_freq > 0.4 * _daughterboard->get_converter_rate()) {
// According to PG269 calibration modes are available for up to Fs / 2
if (cal_freq < 0 or cal_freq > _daughterboard->get_converter_rate() / 2) {
RFNOC_LOG_WARNING("Invalid value for `cal_freq`: "
<< cal_freq
<< ". Valid values are "
"between 0 Hz and 0.4 x converter_rate. Using default "
"between 0 Hz and converter_rate / 2. Using default "
<< cal_params.rx_freq / 1e6 << " MHz.");
} else {
cal_params.rx_freq = cal_freq;
cal_params.tx_freq = cal_freq;
// 0.4 * Fs/2 as limit between cal mode and 2 according to PG269
// 0.4 * Fs is the limit between cal mode 2 and 1 according to PG269
if (cal_freq <= (0.4 * _daughterboard->get_converter_rate())) {
cal_params.calibration_mode = "calib_mode2";
} else {
// This will never be reached as long as we want to limit ourselves to
// calib_mode2
cal_params.calibration_mode = "calib_mode1";
}
RFNOC_LOG_DEBUG("Custom cal_freq: " << cal_freq << " => Calibration Mode: "

View File

@ -413,6 +413,15 @@ public:
bool set_calibration_mode(
uint32_t tile_id, uint32_t block_id, calibration_mode_options calibration_mode);
/**
* Gets the calibration mode of a given ADC
*
* @param tile_id the tile ID of the block to set
* @param block_id the block ID of the block to set
* @return the calibration mode
*/
calibration_mode_options get_calibration_mode(uint32_t tile_id, uint32_t block_id);
/**
* Enables/Disables the Inverse-Sinc filter on a DAC block.
*
@ -760,6 +769,7 @@ void export_rfdc(py::module& top_module)
.def("set_mixer_mode", &rfdc_ctrl::set_mixer_mode)
.def("set_nyquist_zone", &rfdc_ctrl::set_nyquist_zone)
.def("set_calibration_mode", &rfdc_ctrl::set_calibration_mode)
.def("get_calibration_mode", &rfdc_ctrl::get_calibration_mode)
.def("enable_inverse_sinc_filter", &rfdc_ctrl::enable_inverse_sinc_filter)
.def("get_sample_rate", &rfdc_ctrl::get_sample_rate)
.def("configure_pll", &rfdc_ctrl::configure_pll)

View File

@ -460,6 +460,18 @@ bool rfdc_ctrl::set_calibration_mode(
== XRFDC_SUCCESS;
}
rfdc_ctrl::calibration_mode_options rfdc_ctrl::get_calibration_mode(
uint32_t tile_id, uint32_t block_id)
{
uint8_t cal_mode;
if (XRFdc_GetCalibrationMode(rfdc_inst_ptr, tile_id, block_id, &cal_mode)
!= XRFDC_SUCCESS) {
throw mpm::runtime_error("Error in RFDC code: Failed to get calibration mode.");
}
return cal_mode == 1 ? calibration_mode_options::CALIB_MODE1
: calibration_mode_options::CALIB_MODE2;
}
bool rfdc_ctrl::enable_inverse_sinc_filter(
uint32_t tile_id, uint32_t block_id, bool enable)
{

View File

@ -651,9 +651,28 @@ class X4xxRfdcCtrl:
}
if mode not in MODES:
raise RuntimeError(
f"Mode {mode} is not one of the allowable modes {list(MODES.keys())}")
f"Mode {mode} is not one of the allowable modes {list(MODES.keys())}.")
for tile_id, block_id, _ in self._find_converters(slot_id, channel, "rx"):
self._rfdc_ctrl.set_calibration_mode(tile_id, block_id, MODES[mode])
# Only set the cal-mode if it is not yet what we want.
if self._rfdc_ctrl.get_calibration_mode(tile_id, block_id) != MODES[mode]:
self.log.debug(f"Setting calibration mode {mode} "
f"for tile_id {tile_id}, block {block_id}.")
self._rfdc_ctrl.set_calibration_mode(tile_id, block_id, MODES[mode])
# As per PG269:
self._rfdc_ctrl.startup_tile(tile_id, False)
# Ensure the cal-mode was set properly, otherwise throw
if self._rfdc_ctrl.get_calibration_mode(tile_id, block_id) != MODES[mode]:
self.log.error(
"RFDC error: Desired calibration mode could not be set properly "
f"for tile_id {tile_id}, block {block_id}.")
raise RuntimeError(
"RFDC error: Desired calibration mode could not be set properly "
f"for tile_id {tile_id}, block {block_id}.")
self.log.debug(f"Successfully set calibration mode to {mode} "
f"for tile_id {tile_id}, block {block_id}.")
else:
self.log.debug(f"Calibration mode {mode} for tile_id {tile_id}, "
f"block {block_id} already set, not changing it.")
def set_cal_frozen(self, frozen, slot_id, channel):
"""