Hi Ken,
Right now, the documentation for tbs3’s methods are tied to casperfpga
<https://github.com/casper-astro/casperfpga/blob/py38/src/rfdc.py> as
docstrings. For example, the method that calls tbs3’s `rfdc-update-nco` has a
docstring here:
https://github.com/casper-astro/casperfpga/blob/py38/src/rfdc.py#L2034. Do you
use casperfpga for control? Or do you use another katcp client?
A SYSREF NCO update for MTS is accomplished by replicating these steps outlined
in PG269 using casperfpga’s methods, which wrap tbs3’s implementation of the
relevant driver methods. The docstrings are deficient in that there is not
examples that piece together the relevant methods to achieve control sequences
like this one and their other use cases. Here are annotated excerpts taken from
a casperfpga control code for an arbitrary waveform generator. If using another
katcp client, you would need to investigate each of these casperfpga methods
and map out the equivalent sequence of tbs3 calls when using another other
katcp client.
```
"""
Step 0 - Casperfpga specific initialization of RFDC tiles and then
start with MTS alignment
"""
rfdc = self.adcs.rfdc
rfdc.init()
# all other settings were programmed into the rfdc's mask in the casper
design and are default
rfdc.run_mts(rfdc.ADC_TILE, tile_mask=15)
rfdc.run_mts(rfdc.DAC_TILE, tile_mask=15)
“””
Step 1 - Disable the analog SYSREF receiver
“””
# disable sysref; to be enabled for sysref synchronization of nco frequency
and phase changes
rfdc.sysref_en(0)
“””
Steps 2 and 3 - Set the update event source to SYSREF and desired user
NCO frequency and
phase. Waiting for successful return of API calls is inherent.
“””
# set the dac/adc mixer's update source to be SYSREF pulses
# for the dac, choose to target only those that will be active as
designated by `waveform_ctrl_regs`
for waveform_reg in self.waveform_ctrl_regs:
tile_idx, blk_idx = (int(waveform_reg[1]), int(waveform_reg[2]))
rfdc.set_mixer_event_source(tile_idx, blk_idx, rfdc.DAC_TILE,
rfdc.EVNT_SRC_SYSREF)
# for the adc, choose to just update all converters within tiles 2 and 3
adc_tiles = [2,3]
for tile_idx in adc_tiles:
for blk_idx in range(0,4):
rfdc.set_mixer_event_source(tile_idx, blk_idx, rfdc.ADC_TILE,
rfdc.EVNT_SRC_SYSREF)
# set the desired user nco freq and phase.
for (waveform_reg, freq, phase) in zip(self.waveform_ctrl_regs, nco_freq,
nco_phase):
tile_idx, blk_idx = (int(waveform_reg[1]), int(waveform_reg[2]))
rfdc.set_fine_mixer_freq(tile_idx, blk_idx, rfdc.DAC_TILE, freq, phase,
force=0)
“””
Step 4 and 5 - The SYSREF clock was optionally left in continuous mode
and already assumed
stable. The SYSREF receiver is enabled allowing synchronous update on
the next sensed pulse
edge. This only works for Gen 3 RFSoCs. Gen1 RFSoCs need external
control code to disable
SYSREF, as they cannot gate SYSREF in the same way.
“””
# synchronize the update
rfdc.sysref_en(1)
“””
Step 7 - Disable the analog SYSREF receiver (gate SYSREF)
“””
rfdc.sysref_en(0)
```
Note that there is no step (8), as it is indicated optional in PG269. Because
(8) is optional, this lends to step (4) also being optional, and why it is
grouped with (5) above.
The critical semantic here is that for MTS updates the `force` argument to
`set_fine_mixer_freq()` be `0`. If not specified as zero, it defaults to
automatically issue the update, undermining the process.
Hope this helps,
Mitch
> On Feb 6, 2026, at 1:54 PM, Ken Semanov <[email protected]> wrote:
>
> Hello Mitch,
>
> Thanks for the help and the speedy reply. If it's not too much trouble,
> could you describe any new calling semantics that have changed in the
> function rfdc_update_nco_cmd() ??
>
> int rfdc_update_nco_cmd(struct katcp_dispatch *d, int argc)
>
> There is a variable number of arguments present and so we are somewhat lost.
> Originally, our requirement for calling XRFdc_ResetNCOPhase( ) was
> motivated by page 195 of PG269. To avoid any bot censors that may be in
> Google Groups, I will not post an image, but instead reproduce page 195
> below. It is possible we are missing a step. Thanks!
>
>
>
>
> .
> AMD _>^| Chapter 4: Designing with the core
>
> 1. Disable the analog SYSREF receiver with the API command.
>
> SysRefEnable = 0
> status_dac|=XRFdc_MTS_Sysref_Config(&InstancePtr,
> &DACSyncConfigPtr,&ADCSyncConfigPtr, SysRefEnable)
>
> 2. Set the mixer settings, NCO phase reset, QMC, and/or coarse delay.
>
> XRFdc_Mixer_Settings Mixer_Settings; // Declare mixer settings struct
> u32 Type = XRFDC_DAC_TILE;
> u32 Tile_Id ;
> u32 Block_Id ;
> u32 Mixer_Settings.EventSource = XRFDC_EVNT_SRC_SYSREF;
> // it is assumed other Mixer settings have been previously assigned in the
> user code
> for (Tile_Id = 0; Tile_Id < 4; Tile_Id++ ) {
> for (Block_Id = 0; Block_Id < 4; Block_Id++ ) {
> XRFdc_SetMixerSettings(&RFdcInst, Type, Tile_Id,
> Block_Id,&Mixer_Settings);
> status_dac |= XRFdc_ResetNCOPhase(&RFdcInst,Type,Tile_Id,Block_Id);
> // Note that Coarse mixer and QMC could also be part of this for loop.
> }
> }
>
> 3. Wait for successful return of API calls to ensure all register writes have
> been completed.
>
> if (status_dac!=XST_SUCCESS) // Execute error code;
>
> 4. Enable the analog SYSREF clock in continuous mode and ensure this clock is
> stable.
>
> 5. Enable the analog SYSREF receiver with the API command.
>
> SysRefEnable = 1;
> status_dac|=XRFdc_MTS_Sysref_Config(&InstancePtr,
> &DACSyncConfigPtr,&ADCSyncConfigPtr, SysRefEnable);
>
> 6. Wait long enough to ensure a rising edge has been detected, at this point
> the update would commence.
>
> 7. Disable the analog SYSREF receiver with the API command.
>
> SysRefEnable = 0;
> status_dac|=XRFdc_MTS_Sysref_Config(&InstancePtr,
> &DACSyncConfigPtr,&ADCSyncConfigPtr, SysRefEnable);
>
> 8. Disable the external analog SYSREF clock (optional).
>
> Figure 148: Dynamic Update Event Trigger Using SYSREF for Single Device with
> AC- or
> DC-Coupling
>
> .
> On Thursday, February 5, 2026 at 11:23:03 AM UTC-5 Mitchell Burnett wrote:
>> Hi Ken,
>>
>> Just closing the loop here. I did take a look and can confirm that the py38
>> branch for casperfpga at https://github.com/casper-astro/casperfpga had
>> already received all the updates necessary for tbs3’s changes.
>>
>> Mitch
>>
>>
>>> On Feb 4, 2026, at 2:52 PM, Mitchell Burnett <[email protected] <>>
>>> wrote:
>>>
>>> Ignore the previously suggested branch for caspefpga, the best one to try
>>> would already be https://github.com/casper-astro/casperfpga py38 branch. It
>>> had previously been changed to immediately trigger an update or wait for
>>> some other external event.
>>>
>>> Mitch
>>>
>>>> On Feb 4, 2026, at 2:44 PM, Mitchell Burnett <[email protected] <>>
>>>> wrote:
>>>>
>>>> Hi Ken,
>>>>
>>>> A version with your requested change was made last night and can be found
>>>> here: https://casper.groups.et.byu.net/zcu216/zcu216update/. It’s the
>>>> tcpborphserver3_v8.1 file with md5 checksum
>>>> 6b9f2c25a7d1c0f34883574a5e0fcb04.
>>>>
>>>> I’m still working on the changes to casperfpga’s rfdc.py to push back.
>>>> But, you may be able to try this branch until I can get some time tonight
>>>> to push it back:
>>>> https://github.com/mitchburnett/casperfpga/tree/rfsocs/rfdc-mts-nco
>>>>
>>>> Hope this helps,
>>>> Mitch
>>>>
>>>>> On Jan 29, 2026, at 3:59 PM, Ken Semanov <[email protected] <>> wrote:
>>>>>
>>>>> Hello,
>>>>>
>>>>> We are attempting to perform MTS on a quadtile ZCU216. Our use-case
>>>>> requires a call to API function, XRFdc_ResetNCOPhase( ) At present,
>>>>> it does not appear that tcpborphserver3 has functionality for this,
>>>>> neither in master branch nor rfsoc/rfdc branch.
>>>>>
>>>>> Below is a section of rfsoc.c located at
>>>>> /alpaca/casper/katcp/-/blob/rfsoc/rfdc/tcpborphserver3/rfsoc.c starting
>>>>> line 1413,
>>>>>
>>>>> int rfdc_update_nco_cmd(struct katcp_dispatch *d, int argc) {
>>>>> struct tbs_raw *tr;
>>>>> struct tbs_rfdc *rfdc;
>>>>> // cmd variables
>>>>> int result;
>>>>> unsigned int tile, blk;
>>>>> XRFdc_Mixer_Settings mixer;
>>>>> char* type;
>>>>> int converter_type;
>>>>> double nco_freq;
>>>>> double nco_phase;
>>>>> unsigned int trigger_update = 1; // defaulat to force update event
>>>>>
>>>>> To match our use-case we would make the following modifications.
>>>>>
>>>>> (1) trigger_update would be moved to a function argument , so that we
>>>>> can toggle it. (we believe a call to XRFdc_UpdateEvent() at line 1506
>>>>> invokes an error by design)
>>>>>
>>>>> (2) XRFdc_ResetNCOPhase( ) would be called somewhere after the call to
>>>>> XRFdc_SetMixerSettings() (line 1498 in rfsoc.c )
>>>>>
>>>>> Are these modifications possible?
>>>>> Thanks for reading!
>>>>>
>>>>> --
>>>>> You received this message because you are subscribed to the Google Groups
>>>>> "[email protected] <>" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send an
>>>>> email to [email protected] <>.
>>>>> To view this discussion visit
>>>>> https://groups.google.com/a/lists.berkeley.edu/d/msgid/casper/551bd52d-4c0d-43f5-93a9-3c06dd5eda9fn%40lists.berkeley.edu
>>>>>
>>>>> <https://groups.google.com/a/lists.berkeley.edu/d/msgid/casper/551bd52d-4c0d-43f5-93a9-3c06dd5eda9fn%40lists.berkeley.edu?utm_medium=email&utm_source=footer>.
>>>>
>>>
>>
--
You received this message because you are subscribed to the Google Groups
"[email protected]" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/a/lists.berkeley.edu/d/msgid/casper/8404065E-F5CA-488F-9D66-99E61A846C66%40gmail.com.