mpm: Move tile startup after DB startup

This moves the ADC/DAC tile startup after the daughterboard power-up.
Reason for this is that especially the ADC needs silence when starting
up as it runs its foreground calibration then. If during that time the
daughterboards are not yet powered up we cannot guarantee that which
might impact the noise floor. To move the tile startup, it was factored
out into a (re)start method.
This commit is contained in:
Martin Anderseck 2026-01-30 13:54:39 +01:00 committed by Jörg Hofrichter
parent 3991a85d34
commit 14d215665c
2 changed files with 34 additions and 22 deletions

View File

@ -290,6 +290,10 @@ class x4xx(ZynqComponents, PeriphManagerBase):
try:
self._init_peripherals(args)
self.init_dboards(args)
# We finish initializing the tiles after the daughterboard has powered up
# so the foreground cal can work while the DB is in a defined state and we
# can expect the ADC input level to be as low as possible.
self.clk_mgr.restart_tiles()
# We need to init dio_control separately from peripherals
# since it needs information about available dboards
self._init_dio_control(args)
@ -504,8 +508,11 @@ class x4xx(ZynqComponents, PeriphManagerBase):
# capabilities. This will allow us to figure out a good default MCR,
# and we set that. Remember that earlier, when we turned on the clocks,
# we just picked any valid clock rate so we would be able to communicate
# with all the devices. After this call, all clocks will be set to useful
# and valid values.
# with all the devices. After this call, all clocks except for the RFDC
# will be set to useful and valid values. The RFDC tiles will be started
# afterwards to provide a stable daughterboard state while the ADCs are
# running their foreground calibrations which is part of their
# initialization.
self.clk_mgr.finalize_init(args, self.mboard_regs_control, self.rfdc)
# Init ctrlport endpoint

View File

@ -257,7 +257,8 @@ class X4xxClockManager:
Store a reference to the RFdc object, and update internal state.
This completes initialization of the clocking. After this call, all
clocks are ticking at a useful rate.
clocks are ticking at a useful rate. Only the RFDC tiles still need
to be brought up. x4xx.py takes care of that.
"""
self.clk_ctrl.mboard_regs_control = mboard_regs_control
self.rfdc = rfdc
@ -285,11 +286,7 @@ class X4xxClockManager:
# the clocking policy needs access to the DSP info, meaning this is the
# earliest point during initialization when we can do this reset.
self._reset_clocks(True, ("mmcm", "rfdc"))
self._reset_clocks(False, ("mmcm", "rfdc"))
# Devices that use non-default clocking parameters may require an explicit
# startup after the RFDC reset:
self.rfdc.startup_tiles(quiet=True)
self._reset_clocks(False, ("mmcm",))
# The initial default mcr only works if we have an FPGA with
# a decimation of 2. But we need the overlay applied before we
@ -709,20 +706,6 @@ class X4xxClockManager:
" RF performance. Consider swapping your master clock rate values."
)
self._configure_clock_chain(clk_settings, self.get_time_source(), self.get_ref_clock_freq())
# Bring RFDC out of reset, reset tiles and reconfigure RFDC
self._reset_clocks(False, ("rfdc",))
self.rfdc.reset_tiles()
self.rfdc.configure(clk_settings.spll_config.output_freq, clk_settings.rfdc_configs)
# If non-default clocking parameters are used, reset_tiles() may not be successful in
# the first place, so we have to start the tiles explicitely again after the
# reconfiguration:
self.rfdc.startup_tiles()
# According to PG269, self-cal coefficients get lost when calling startup_tiles().
# Therefore we need to mark self-cal as required again after that. May be skipped
# with 'skip_adc_selfcal' argument (but should be called manually then).
if not self.skip_adc_selfcal:
for db in range(self.num_dboards):
self.tasks[f"db{db}_ADCSelfCal"] = [{"Run": "True"}]
# All settings are applied: Now bring other clocks out of reset. Note
# that cpld and db_clock don't depend on MMCM or RFDC, but we don't need
@ -782,6 +765,27 @@ class X4xxClockManager:
"""
return self.clk_ctrl.get_prc_rate()
@no_rpc
def restart_tiles(self):
"""Configure and (re-)start the tiles."""
clk_settings = self.clk_policy.get_config(
self.get_ref_clock_freq(), self._master_clock_rates
)
# Bring RFDC out of reset, reset tiles and reconfigure RFDC
self._reset_clocks(False, ("rfdc",))
self.rfdc.reset_tiles()
self.rfdc.configure(clk_settings.spll_config.output_freq, clk_settings.rfdc_configs)
# Devices that use non-default clocking parameters may require an explicit
# startup after the RFDC reset:
self.rfdc.startup_tiles()
# According to PG269, self-cal coefficients get lost when calling startup_tiles().
# Therefore we need to mark self-cal as required again after that. May be skipped
# with 'skip_adc_selfcal' argument (but should be called manually then).
if not self.skip_adc_selfcal:
for db in range(self.num_dboards):
self.tasks[f"db{db}_ADCSelfCal"] = [{"Run": "True"}]
###########################################################################
# Clock/Time API (this is a public MPM API)
###########################################################################
@ -987,6 +991,7 @@ class X4xxClockManager:
# clock chain, so if we had an intermediate settting, it will
# be overwritten immediately.
self.set_master_clock_rate(master_clock_rates)
self.restart_tiles()
# Restore the nco frequency to the same values as before the sync source
# was changed, to ensure the device transmission/acquisition continues at
# the requested frequency.