Skip to content

Commit 979a53a

Browse files
committed
Merge branch 'rfsocs/intr-thresh' into rfsocs/rfdc
2 parents 86d5d76 + b12fc40 commit 979a53a

File tree

1 file changed

+273
-29
lines changed

1 file changed

+273
-29
lines changed

src/rfdc.py

Lines changed: 273 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import katcp
33
import os
44
import random
5+
from enum import Enum, auto
56

67
LOGGER = logging.getLogger(__name__)
78

@@ -125,6 +126,72 @@ class RFDC(object):
125126
IMR_LOWPASS = 0
126127
IMR_HIGHPASS = 1
127128

129+
# adc threshold settings
130+
UPDATE_THRESHOLD0 = 1
131+
UPDATE_THRESHOLD1 = 2
132+
UPDATE_THRESHOLD_BOTH = 4
133+
134+
THRESHOLD_OFF = 0
135+
THRESHOLD_STICKY_OVER = 1
136+
THRESHOLD_STICKY_UNDER = 2
137+
THRESHOLD_HYSTERISIS = 3
138+
139+
THRESHOLD_CLR_MANUAL = 1
140+
THRESHOLD_CLR_AUTO = 2
141+
142+
# interrupt masks
143+
class InterruptMasks(Enum):
144+
"""
145+
adc and dac datapath interrupt indicating one of the datapath interrupts is active.
146+
To clear, all datapath sub-interrupts must be cleared
147+
"""
148+
IXR_FIFOUSRDAT_MASK = 0x0000000F
149+
IXR_FIFOUSRDAT_OF_MASK = 0x00000001
150+
IXR_FIFOUSRDAT_UF_MASK = 0x00000002
151+
IXR_FIFOMRGNIND_OF_MASK = 0x00000004
152+
IXR_FIFOMRGNIND_UF_MASK = 0x00000008
153+
ADC_IXR_DATAPATH_MASK = 0x00000FF0
154+
ADC_IXR_DMON_STG_MASK = 0x000003F0
155+
DAC_IXR_DATAPATH_MASK = 0x00001FF0
156+
DAC_IXR_INTP_STG_MASK = 0x000003F0
157+
DAC_IXR_INTP_I_STG0_MASK = 0x00000010
158+
DAC_IXR_INTP_I_STG1_MASK = 0x00000020
159+
DAC_IXR_INTP_I_STG2_MASK = 0x00000040
160+
DAC_IXR_INTP_Q_STG0_MASK = 0x00000080
161+
DAC_IXR_INTP_Q_STG1_MASK = 0x00000100
162+
DAC_IXR_INTP_Q_STG2_MASK = 0x00000200
163+
ADC_IXR_DMON_I_STG0_MASK = 0x00000010
164+
ADC_IXR_DMON_I_STG1_MASK = 0x00000020
165+
ADC_IXR_DMON_I_STG2_MASK = 0x00000040
166+
ADC_IXR_DMON_Q_STG0_MASK = 0x00000080
167+
ADC_IXR_DMON_Q_STG1_MASK = 0x00000100
168+
ADC_IXR_DMON_Q_STG2_MASK = 0x00000200
169+
IXR_QMC_GAIN_PHASE_MASK = 0x00000400
170+
IXR_QMC_OFFST_MASK = 0x00000800
171+
DAC_IXR_INVSNC_OF_MASK = 0x00001000
172+
SUBADC_IXR_DCDR_MASK = 0x00FF0000
173+
SUBADC0_IXR_DCDR_OF_MASK = 0x00010000
174+
SUBADC0_IXR_DCDR_UF_MASK = 0x00020000
175+
SUBADC1_IXR_DCDR_OF_MASK = 0x00040000
176+
SUBADC1_IXR_DCDR_UF_MASK = 0x00080000
177+
SUBADC2_IXR_DCDR_OF_MASK = 0x00100000
178+
SUBADC2_IXR_DCDR_UF_MASK = 0x00200000
179+
SUBADC3_IXR_DCDR_OF_MASK = 0x00400000
180+
SUBADC3_IXR_DCDR_UF_MASK = 0x00800000
181+
ADC_OVR_VOLTAGE_MASK = 0x04000000
182+
ADC_OVR_RANGE_MASK = 0x08000000
183+
ADC_DAT_OVR_MASK = 0x40000000
184+
ADC_FIFO_OVR_MASK = 0x80000000
185+
ADC_CMODE_OVR_MASK = 0x10000000 # (Gen 3)
186+
ADC_CMODE_UNDR_MASK = 0x20000000 # (Gen 3)
187+
188+
def parse_interrupt_mask(self, interrupt_mask):
189+
interrupt_status = {}
190+
for interrupt in self.InterruptMasks:
191+
interrupt_status[interrupt.name] = bool(interrupt_mask & interrupt.value)
192+
193+
return interrupt_status
194+
128195
class tile(object):
129196
pass
130197

@@ -157,7 +224,7 @@ def __init__(self, parent, device_name, device_info, initialise=False):
157224
"""
158225
apply the dtbo for the rfdc driver
159226
160-
ideally, this would be incorporated as part of an extended `fpg` implementation that includes the device tree overlwy by including the
227+
ideally, this would be incorporated as part of an extended `fpg` implementation that includes the device tree overlay by including the
161228
dtbo as part of the programming process. The rfdc is the only block that is using the dto at the moment, so instead of completely
162229
implement this extended fpg functionality the rfdc instead manages its own application of the dto.
163230
"""
@@ -1845,32 +1912,6 @@ def update_nco_mts(self, adc_mask, dac_mask, freq):
18451912
print(i)
18461913
return True
18471914

1848-
"""
1849-
Set the inverse sinc filter mode; 0 - disabled, 1 - first nyquist, and for gen 3 devices 2 - second nyquist.
1850-
1851-
:param ntile: Tile index of where target converter block is, in the range (0-3)
1852-
:type ntile: int
1853-
:param nblk: Block index within target converter tile, in the range (0-3)
1854-
:type nblk: int
1855-
:param invsinc_fir_mode: inverse sinc filter mode; 0 - disabled, 1 - first nyquist, and for gen 3 devices 2 - second nyquist.
1856-
1857-
:type invsinc_fir_mode: int
1858-
1859-
:return: 0 if disabled, 1 if first nyquist, and 2 for second nyquist (gen 3 devices only). Returns None if converter is disabled.
1860-
:rtype: int
1861-
1862-
Examples
1863-
----------
1864-
>>>> rfdc.set_invsinc_fir(0,0,rfdc.INVSINC_FIR_DISABLED)
1865-
0 # disabled
1866-
1867-
>>>> rfdc.set_invsinc_fir(0,0,rfdc.INVSINC_FIR_NYQUIST1)
1868-
1 # nyquist zone 1
1869-
1870-
>>>> rfdc.set_invsinc_fir(0,0,rfdc.INVSINC_FIR_NYQUIST2)
1871-
2 # nyquist zone 2
1872-
"""
1873-
18741915

18751916
def set_mixer_mode(self, ntile, nblk, converter_type, mixer_mode, force=1):
18761917
"""
@@ -2109,9 +2150,212 @@ def get_mixer_settings(self, ntile, nblk, converter_type):
21092150

21102151
return mixer_config
21112152

2112-
def get_adc_snapshot(self, ntile, nblk):
2153+
def get_adc_threshold(self, ntile, nblk):
2154+
"""
2155+
Get the threshold settings for target ADC
2156+
2157+
:param ntile: Tile index of where target converter block is, in the range (0-3)
2158+
:type ntile: int
2159+
:param nblk: Block index within target converter tile, in the range (0-3)
2160+
:type nlblk: int
2161+
2162+
:return: dict[str, int] of threshold settings, otherwise None if target converter is disabled
2163+
2164+
Examples
2165+
---------
2166+
>>>> rfdc.set_adc_thresh(0, 0, rfdc.UPDATE_THRESHOLD_BOTH, rfdc.THRESHOLD_STICKY_UNDER, rfdc.THRESHOLD_STICKY_OVER, 8, 8, 1000, 1000, 12000, 12000)
2167+
>>>> {'UpdateThreshold': 4,
2168+
'ThresholdMode0': 2,
2169+
'ThresholdMode1': 1,
2170+
'ThresholdAvgVal0': 8,
2171+
'ThresholdAvgVal1': 8,
2172+
'ThresholdUnderVal0': 1000,
2173+
'ThresholdUnderVal1': 1000,
2174+
'ThresholdOverVal0': 12000,
2175+
'ThresholdOverVal1': 12000}
2176+
"""
2177+
t = self.parent.transport
2178+
2179+
args = (ntile, nblk)
2180+
reply, informs = t.katcprequest(name='rfdc-get-adc-thresh', request_timeout=t._timeout, request_args=args)
2181+
2182+
thresh_config = {}
2183+
info = informs[0].arguments[0].decode().split(', ')
2184+
if len(info) == 1: # (disabled) response
2185+
return thresh_config
2186+
2187+
for stat in info:
2188+
k,v = stat.split(' ')
2189+
thresh_config[k] = int(v)
2190+
2191+
return thresh_config
2192+
2193+
2194+
def set_adc_threshold(self, ntile, nblk, threshold_to_update, threshold0_mode, threshold1_mode, threshold0_avg_val, threshold1_avg_val,
2195+
threshold0_under_val, threshold1_under_val, threshold0_over_val, threshold1_over_val):
2196+
"""
2197+
Configure threshold settings for target ADC
2198+
2199+
Threshold update constants are: UPDATE_THRESHOLD0 (1), UPDATE_THRESHOLD1 (2), UPDATE_THRESHOLD_BOTH (4)
2200+
Threshold mode constants are: THRESHOLD_OFF (0), THRESHOLD_STICKY_UNDER (1), THRESHOLD_STICKY_OVER (2), THRESHOLD_HYSTERISIS (3)
2201+
2202+
:param ntile: Tile index of where target converter block is, in the range (0-3)
2203+
:type ntile: int
2204+
:param nblk: Block index within target converter tile, in the range (0-3)
2205+
:type nlblk: int
2206+
:param threshold_to_update: Update settings for Threshold0, Threshold1, or both simultaneously
2207+
:type threshold_to_update: int
2208+
:param threshold0_mode: The operating mode for Threshold0, {0 Off, sticky-over, sicky-under, hysteresis}
2209+
:type threshold0_mode: int
2210+
:param threshold1_mode: The operating mode for Threshold0, {Off, sticky-over, sicky-under, hysteresis}
2211+
:type threshold1_mode: int
2212+
:param threshold0_avg_val: Delay value before asserting Threshold0
2213+
:type threshold0_avg_val: int
2214+
:param thresdhol1_avg_val: Delay value before asserting Threshold1
2215+
:type threshold1_avg_val: int
2216+
:param threshold0_under_val: The under "lower" value to use on Threshold0
2217+
:type threshold0_under_val: int
2218+
:param threshold1_under_val: The under "lower" value to use on Threshold1
2219+
:type threshold1_under_val: int
2220+
:param threshold0_over_val: The over "upper" value to use on Threshold0
2221+
:type threshold0_over_val: int
2222+
:param threshold1_over_val: The over "upper" value to use on Threshold1
2223+
:type threshold1_over_val: int
2224+
2225+
:return: dict[str, int] of threshold settings, otherwise None if target converter is disabled
2226+
2227+
Examples
2228+
---------
2229+
>>>> rfdc.set_adc_thresh(0, 0, rfdc.UPDATE_THRESHOLD_BOTH, rfdc.THRESHOLD_STICKY_UNDER, rfdc.THRESHOLD_STICKY_OVER, 8, 8, 1000, 1000, 12000, 12000)
2230+
>>>> {'UpdateThreshold': 4,
2231+
'ThresholdMode0': 2,
2232+
'ThresholdMode1': 1,
2233+
'ThresholdAvgVal0': 8,
2234+
'ThresholdAvgVal1': 8,
2235+
'ThresholdUnderVal0': 1000,
2236+
'ThresholdUnderVal1': 1000,
2237+
'ThresholdOverVal0': 12000,
2238+
'ThresholdOverVal1': 12000}
2239+
"""
2240+
t = self.parent.transport
2241+
args = (ntile, nblk, threshold_to_update, threshold0_mode, threshold1_mode,
2242+
threshold0_avg_val, threshold1_avg_val,
2243+
threshold0_under_val, threshold1_under_val,
2244+
threshold0_over_val, threshold1_over_val)
2245+
reply, informs = t.katcprequest(name='rfdc-set-adc-thresh', request_timeout=t._timeout, request_args=args)
2246+
2247+
thresh_config = {}
2248+
info = informs[0].arguments[0].decode().split(', ')
2249+
if len(info) == 1: # (disabled) response
2250+
return thresh_config
2251+
2252+
for stat in info:
2253+
k,v = stat.split(' ')
2254+
thresh_config[k] = int(v)
2255+
2256+
return thresh_config
2257+
2258+
2259+
def set_thresh_clr_mode(self, ntile, nblk, threshold_to_update, clr_mode):
2260+
"""
2261+
Configure threshold flag to be cleared manually with `thresh_sticky_clr` or with a QMC gain update for target ADC.
2262+
The default mode for an enabled threshold is to be cleared manually. Thereshold clear modes are integer values:
2263+
rfdc.THRESHOLD_CLR_MANUAL=1, rfdc.THRESHOLD_CLR_AUTO=2.
2264+
2265+
:param ntile: Tile index of where target converter block is, in the range (0-3)
2266+
:type ntile: int
2267+
:param nblk: Block index within target converter tile, in the range (0-3)
2268+
:type nblk: int
2269+
:param threshold_to_update: Update settings for Threshold0, Threshold1, or both simultaneously
2270+
:type threshold_to_update: int
2271+
:param clr_mode: The clear mode to be used
2272+
:type clr_mode: int
2273+
2274+
:return: None
2275+
2276+
Examples
2277+
_________
2278+
>>>> rfdc.set_thresh_clr_mode(0, 0, rfdc.UPDATE_THRESHOLD_BOTH, rfdc.THRESHOLD_CLR_MANUAL)
2279+
"""
2280+
t = self.parent.transport
2281+
args = (ntile, nblk, threshold_to_update, clr_mode)
2282+
reply, informs = t.katcprequest(name='rfdc-set-thresh-clrmode', request_timeout=t._timeout, request_args=args)
2283+
2284+
2285+
def thresh_sticky_clr(self, ntile, nblk, threshold_to_update):
21132286
"""
2287+
Clears sticky threshold flags for target ADC with threshold flag clear mode `THRESHOLD_CLR_MANUAL`.
2288+
2289+
:param ntile: Tile index of where target converter block is, in the range (0-3)
2290+
:type ntile: int
2291+
:param nblk: Block index within target converter tile, in the range (0-3)
2292+
:type nblk: int
2293+
:param threshold_to_update: Update settings for Threshold0, Threshold1, or both simultaneously
2294+
:type threshold_to_update: int
2295+
:param clr_mode: The clear mode to be used
2296+
:type clr_mode: int
2297+
2298+
:return: None
2299+
2300+
Examples
2301+
_________
2302+
>>>> rfdc.thresh_sticky_clr(0, 0, rfdc.UPDATE_THRESHOLD_BOTH)
21142303
"""
2115-
raise NotImplemented()
2304+
t = self.parent.transport
2305+
args = (ntile, nblk, threshold_to_update)
2306+
reply, informs = t.katcprequest(name='rfdc-thresh-stickyclr', request_timeout=t._timeout, request_args=args)
2307+
2308+
def get_en_intr(self, ntile, nblk, converter_type):
2309+
"""
2310+
"""
2311+
t = self.parent.transport
2312+
2313+
args = (ntile, nblk, "adc" if converter_type == self.ADC_TILE else "dac")
2314+
reply, informs = t.katcprequest(name='rfdc-get-en-intr', request_timeout=t._timeout, request_args=args)
2315+
2316+
enabled_intr = {}
2317+
info = informs[0].arguments[0].decode().split(' ')
2318+
print(info)
2319+
if len(info) == 1: # (disabled) response
2320+
return intr_status
2321+
else:
2322+
mask = int(info[1])
2323+
2324+
return self.parse_interrupt_mask(mask)
2325+
2326+
def set_en_intr(self, ntile, nblk, converter_type, interrupt_mask):
2327+
"""
2328+
"""
2329+
t = self.parent.transport
2330+
2331+
args = (ntile, nblk, "adc" if converter_type == self.ADC_TILE else "dac", interrupt_mask)
2332+
reply, informs = t.katcprequest(name='rfdc-set-en-intr', request_timeout=t._timeout, request_args=args)
2333+
2334+
enabled_intr = {}
2335+
info = informs[0].arguments[0].decode().split(' ')
2336+
print(info)
2337+
if len(info) == 1: # (disabled) response
2338+
return intr_status
2339+
else:
2340+
mask = int(info[1])
2341+
2342+
return self.parse_interrupt_mask(mask)
2343+
2344+
def get_intr_status(self, ntile, nblk, converter_type):
2345+
"""
2346+
"""
2347+
t = self.parent.transport
2348+
2349+
args = (ntile, nblk, "adc" if converter_type == self.ADC_TILE else "dac")
2350+
reply, informs = t.katcprequest(name='rfdc-get-intr-status', request_timeout=t._timeout, request_args=args)
2351+
2352+
intr_status = {}
2353+
info = informs[0].arguments[0].decode().split(' ')
2354+
print(info)
2355+
if len(info) == 1: # (disabled) response
2356+
return intr_status
2357+
else:
2358+
mask = int(info[1])
21162359

2360+
return self.parse_interrupt_mask(mask)
21172361

0 commit comments

Comments
 (0)