Compare commits
No commits in common. "8179bdb629c8709c273a2660edb8e1770eb9cfac" and "c52d619bb74d1dfdbfee9b5bb7c7f5bcbc7a61a5" have entirely different histories.
8179bdb629
...
c52d619bb7
2 changed files with 6 additions and 643 deletions
611
src/dorn.py
611
src/dorn.py
|
|
@ -1,611 +0,0 @@
|
||||||
import math, time, sys
|
|
||||||
|
|
||||||
def _connect(ifc):
|
|
||||||
global _ifc, acmd, rfifo
|
|
||||||
_ifc = ifc
|
|
||||||
acmd = ifc.acmd
|
|
||||||
rfifo = ifc.rfifo
|
|
||||||
|
|
||||||
def degCβ(a, R1=10e3, R25=10e3, B25=3940, res=0x1000):
|
|
||||||
if not a:
|
|
||||||
a = 1
|
|
||||||
R = R1 * a / (res - (a & (res-1)))
|
|
||||||
T = B25/(math.log(R/R25) + B25/298) - 273
|
|
||||||
return T
|
|
||||||
|
|
||||||
def degC(a, idx=0):
|
|
||||||
return degCβ(a, **CONFIG.NTC[idx])
|
|
||||||
|
|
||||||
def HK_fmt(s, i, n, d):
|
|
||||||
return f"{i}. {n}: {repr(d)}\n"
|
|
||||||
|
|
||||||
def HK3_fmt(s, i, n, d):
|
|
||||||
return f"""{i}. {n}
|
|
||||||
T = {d[5]:6.2f} °C, GND = {d[0]:6.3f} V,
|
|
||||||
Vff = {d[1]:6.3f} V, Vnn = {d[2]:6.3f} V, Vpp = {d[3]:6.3f} V, Vdig = {d[4]:6.3f} V,
|
|
||||||
Vcc = {d[6]:6.3f} V, Vss = {d[7]:6.3f} V.
|
|
||||||
"""
|
|
||||||
def HK4_AHBGO_fmt(s, i, n, d):
|
|
||||||
return f"""{i}. {n}
|
|
||||||
Tbgo = {d[0]:6.2f} °C, {d[1]:6.2f} °C, {d[3]:6.2f} °C,
|
|
||||||
Vbias = {d[2]:6.3f} V, Ibias = {d[4]:6.1f} nA, {d[5]:6.1f} nA,
|
|
||||||
Vcc = {d[7]:6.3f} V, Vss = {d[6]:6.3f} V.
|
|
||||||
"""
|
|
||||||
def HK4_SETH_fmt(s, i, n, d):
|
|
||||||
return f"""{i}. {n}
|
|
||||||
Tpa = {d[4]:6.2f} °C, Tbgo = {d[3]:6.2f} °C, {d[5]:6.2f} °C,
|
|
||||||
Vbias = {d[2]:6.3f} V, Ibias = {d[1]:6.1f} nA, {d[0]:6.1f} nA,
|
|
||||||
Vcc = {d[7]:6.3f} V, Vss = {d[6]:6.3f} V.
|
|
||||||
"""
|
|
||||||
def HK7_SETH_fmt(s, i, n, d):
|
|
||||||
if s==0:
|
|
||||||
return f"""{i}. {n}
|
|
||||||
na = {repr(d[:4])}
|
|
||||||
Tpwr = {d[6]:.1f} °C,
|
|
||||||
Vprim = {d[5]:.1f} V, Iprim = {d[4]:.1f} mA,
|
|
||||||
Ibias⁺ = {d[7]:.1f} nA.
|
|
||||||
"""
|
|
||||||
return f"""{i}. {n}
|
|
||||||
na = {repr(d[:4])}
|
|
||||||
Text = {d[6]:.1f} °C,
|
|
||||||
Ibias = {d[4]:.1f} nA,
|
|
||||||
Ibias⁺ = {d[7]:.1f} nA, Vbias⁺ = {d[5]:.1f} V.
|
|
||||||
"""
|
|
||||||
def HK3_LEIA_fmt(s, i, n, d):
|
|
||||||
return f"""{i}. {n}
|
|
||||||
Tadc = {d[0]:6.2f} °C,
|
|
||||||
Vadc = {d[1]:6.3f} V,
|
|
||||||
VbiasD = {d[7]:6.2f} V,
|
|
||||||
Vbias2 = {d[6]:6.1f} V,
|
|
||||||
Vpp = {d[3]:6.3f} V, Vnn = {d[2]:6.3f} V,
|
|
||||||
Vcc = {d[5]:6.3f} V, Vss = {d[4]:6.3f} V.
|
|
||||||
"""
|
|
||||||
def HK4_LEIA_fmt(s, i, n, d):
|
|
||||||
return f"""{i}. {n}
|
|
||||||
Ibias1 = {d[3]:.1f} nA, Ibias2 = {d[2]:.1f} nA, IbiasD = {d[0]:.1f} nA,
|
|
||||||
VbiasG = {d[1]:.1f} V, Vbias1 = {d[4]:.1f} V,
|
|
||||||
Tpa0 = {d[5]:6.2f} °C, Tpa1= {d[6]:6.2f} °C, Tpa2 = {d[7]:6.2f} °C.
|
|
||||||
"""
|
|
||||||
|
|
||||||
class DORN_CONFIG:
|
|
||||||
# stis_ana_core 2×24 ch
|
|
||||||
dorn_addr = 0x2000
|
|
||||||
verbose = True
|
|
||||||
slices = (0,1)
|
|
||||||
n_channels = 24
|
|
||||||
l2 = ( # set6
|
|
||||||
(0, -1203, 0),
|
|
||||||
(1, -1203, 0),
|
|
||||||
(2, -1203, 0),
|
|
||||||
(3, -1186, 0),
|
|
||||||
(4, -39, 2000),
|
|
||||||
(5, 1709, 970),
|
|
||||||
(6, 2000, -1082),
|
|
||||||
(7, 1125, -1888),
|
|
||||||
)
|
|
||||||
|
|
||||||
HK3 = [[
|
|
||||||
("GND",),
|
|
||||||
("Vff", 2.0),
|
|
||||||
("Vnn", 2.5, ("Vpp", -1.5)),
|
|
||||||
("Vpp", 2.0),
|
|
||||||
("Vdig", 2.0),
|
|
||||||
("Tadc", (degC, {})),
|
|
||||||
("Vcc", 2.0),
|
|
||||||
("Vss", 2.5, ("Vcc", -1.5)),
|
|
||||||
]]
|
|
||||||
|
|
||||||
HK = [
|
|
||||||
("INP₀", None, HK_fmt),
|
|
||||||
("INP₁", None, HK_fmt),
|
|
||||||
("INP₂", None, HK_fmt),
|
|
||||||
("HK ADC", HK3, HK3_fmt),
|
|
||||||
("HK PA", None, HK_fmt),
|
|
||||||
("VrefL", None, HK_fmt),
|
|
||||||
("VrefH", None, HK_fmt),
|
|
||||||
("HK_PWR", None, HK_fmt),
|
|
||||||
]
|
|
||||||
|
|
||||||
def n_adc(self):
|
|
||||||
return self.n_channels//3
|
|
||||||
|
|
||||||
def Vref(self, slice=None):
|
|
||||||
try:
|
|
||||||
return self.VREF[slice]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return 3.3
|
|
||||||
|
|
||||||
def n_trigs(self):
|
|
||||||
if self.n_channels > 16:
|
|
||||||
return self.n_adc()
|
|
||||||
return self.n_channels
|
|
||||||
|
|
||||||
def m_trigs(self):
|
|
||||||
return (1 << self.n_trigs()) - 1
|
|
||||||
|
|
||||||
NTC = [dict(R1=10e3, R25=10e3, B25=3940, res=0x1000)]
|
|
||||||
|
|
||||||
HK4_SETH = [
|
|
||||||
[
|
|
||||||
("Ibias₂", 10470/470 * 51/1051 * 100, -97),
|
|
||||||
("Ibias₁", 10470/470 * 51/1051 * 100, -135),
|
|
||||||
("Vbias", -1/0.047),
|
|
||||||
("Tbgo₁", (degC, {})),
|
|
||||||
("Tpa", (degC, {})),
|
|
||||||
("Tbgo₂", (degC, {})),
|
|
||||||
("Vss", 2.5, ("Vcc", -1.5)),
|
|
||||||
("Vcc", 2.0),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
("Ibias₂", 10470/470 * 51/1051 * 100, -98),
|
|
||||||
("Ibias₁", 10470/470 * 51/1051 * 100, -112),
|
|
||||||
("Vbias", -1/0.047, 2.0),
|
|
||||||
("Tbgo₁", (degC, {})),
|
|
||||||
("Tpa", (degC, {})),
|
|
||||||
("Tbgo₂", (degC, {})),
|
|
||||||
("Vss", 2.5, ("Vcc", -1.5)),
|
|
||||||
("Vcc", 2.0),
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
HK7_SETH = [
|
|
||||||
[
|
|
||||||
("na₁",), ("na₂",), ("na₃",), ("na₄",),
|
|
||||||
("Iprim", 2000.0),
|
|
||||||
("Vprim", 16.3),
|
|
||||||
("Tpwr", (degC, {})),
|
|
||||||
("Ibias⁺", 100.0),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
("na₁",), ("na₂",), ("na₃",), ("na₄",),
|
|
||||||
("Ibias", 100.0),
|
|
||||||
("Vbias⁺", 100.0),
|
|
||||||
("Text", (degC, {})),
|
|
||||||
("Ibias⁺", 100.0),
|
|
||||||
],
|
|
||||||
]
|
|
||||||
|
|
||||||
def seth(self):
|
|
||||||
# ! change the class attribute .HK
|
|
||||||
self.HK[4] = ("HK PA", self.HK4_SETH, HK4_SETH_fmt)
|
|
||||||
self.HK[7] = ("HK_PWR", self.HK7_SETH, HK7_SETH_fmt)
|
|
||||||
self.BGO = [(0,3), (0,12), (0,20), (1,3), (1,12), (1,20)]
|
|
||||||
|
|
||||||
HK4_AHBGO = [[
|
|
||||||
("Tbgo₁", (degC, {})),
|
|
||||||
("Tbgo₂", (degC, {})),
|
|
||||||
("Vbias1", -1/0.047),
|
|
||||||
("Tbgo₃", (degC, {})),
|
|
||||||
("Ibias₁", 10470/470 * 51/1051 * 100),
|
|
||||||
("Ibias₂", 10470/470 * 51/1051 * 100),
|
|
||||||
("Vss", 2.5, ("Vcc", -1.5)),
|
|
||||||
("Vcc", 2.0),
|
|
||||||
]]
|
|
||||||
|
|
||||||
def ahbgo(self):
|
|
||||||
# ! change the class attribute .HK
|
|
||||||
self.HK[4] = ("HK PA", self.HK4_AHBGO, HK4_AHBGO_fmt)
|
|
||||||
|
|
||||||
# calib 2025-11-25
|
|
||||||
Fluke_cal = 1/0.862
|
|
||||||
# SN2 dac, 14*HK3H, VbiasD
|
|
||||||
VbiasD_SN2 = [
|
|
||||||
[ 64, 0.51, 0.5 * Fluke_cal ],
|
|
||||||
[ 960, 1.85, 1.6 * Fluke_cal ],
|
|
||||||
[ 1984, 3.36, 2.9 * Fluke_cal ],
|
|
||||||
[ 4992, 7.85, 6.7 * Fluke_cal ],
|
|
||||||
[ 9984, 15.27, 13.1 * Fluke_cal ],
|
|
||||||
[ 14976, 22.56, 19.3 * Fluke_cal ],
|
|
||||||
[ 19968, 29.91, 25.6 * Fluke_cal ],
|
|
||||||
[ 20992, 31.42, 26.9 * Fluke_cal ],
|
|
||||||
[ 21440, 32.06, 27.5 * Fluke_cal ],
|
|
||||||
[ 21952, 32.83, 28.0 * Fluke_cal ],
|
|
||||||
[ 24960, 37.36, 28.6 * Fluke_cal ],
|
|
||||||
]
|
|
||||||
VbiasD_a = 0.033
|
|
||||||
VbiasD_b = 0.9918
|
|
||||||
|
|
||||||
HK3_LEIA = [[
|
|
||||||
("Tadc", (degC, {})),
|
|
||||||
("Vadc", 2.0),
|
|
||||||
("Vnn", 2.5, ("Vpp", -1.5)),
|
|
||||||
("Vpp", 2.0),
|
|
||||||
("Vss", 2.5, ("Vcc", -1.5)),
|
|
||||||
("Vcc", 2.0),
|
|
||||||
("Vbias2", -1/0.022 * 66.6/75.2),
|
|
||||||
("VbiasD", -14 * VbiasD_b - VbiasD_a),
|
|
||||||
]]
|
|
||||||
|
|
||||||
HK4_LEIA = [[
|
|
||||||
("IbiasD", 100., -1.4),
|
|
||||||
("VbiasG", 46.3, ("Vref", -45.3)),
|
|
||||||
("Ibias2", 10470/470 * 51/1051 * 100, -71.0),
|
|
||||||
("Ibias1", 10470/470 * 51/1051 * 100, -52.0),
|
|
||||||
("Vbias1", -1/0.047 * 44.7/48.5),
|
|
||||||
("Tpa0", (degC, {})),
|
|
||||||
("Tpa1", (degC, {})),
|
|
||||||
("Tpa2", (degC, {})),
|
|
||||||
]]
|
|
||||||
|
|
||||||
def leia(self):
|
|
||||||
self.VREF = (3.342,)
|
|
||||||
self.slices=(0,)
|
|
||||||
self.HK[3] = ("HK_AD", self.HK3_LEIA, HK3_LEIA_fmt)
|
|
||||||
self.HK[4] = ("HK_PA", self.HK4_LEIA, HK4_LEIA_fmt)
|
|
||||||
|
|
||||||
def thhor(self):
|
|
||||||
self.slices=(0,)
|
|
||||||
self.n_channels = 12
|
|
||||||
self.NTC = [dict(R1=22e3, R25=10e3, B25=3940, res=0x1000)]
|
|
||||||
|
|
||||||
CONFIG = DORN_CONFIG()
|
|
||||||
|
|
||||||
def hk(sl=0, what="print", data=None):
|
|
||||||
if not data:
|
|
||||||
_ifc.menable()
|
|
||||||
fifo_enable(en=True, sl=sl, hk=True)
|
|
||||||
fifo_reset(sl=sl, hk=True)
|
|
||||||
strobe(sl=sl, hk=True)
|
|
||||||
time.sleep(0.1)
|
|
||||||
fifo_read(sl=sl, hk=True)
|
|
||||||
data=rfifo()
|
|
||||||
if data[0] != 0x5710 + sl:
|
|
||||||
raise ValueError("Read HK packet error", data)
|
|
||||||
if isinstance(data, str):
|
|
||||||
# HDORN … data line
|
|
||||||
if "x" in data:
|
|
||||||
return sl, None
|
|
||||||
data = data.split()
|
|
||||||
if data[0] != "HDORN":
|
|
||||||
return sl, None
|
|
||||||
data = list(map(int, data[1:]))
|
|
||||||
if sl is None:
|
|
||||||
sl = data[0] & 3;
|
|
||||||
if data[0] & 3 != sl:
|
|
||||||
return sl, None
|
|
||||||
if what=="data":
|
|
||||||
return sl, data
|
|
||||||
ND = CONFIG.n_adc()
|
|
||||||
NV = ND
|
|
||||||
data = [d & 0xfff for d in data]
|
|
||||||
data = [data[ND*i+1:ND*i+1+NV] for i in range(8)]
|
|
||||||
if what=="raw":
|
|
||||||
return sl, data
|
|
||||||
Vref = CONFIG.Vref(sl)/4096
|
|
||||||
ddata = []
|
|
||||||
VV = {"Vref": CONFIG.Vref(sl)}
|
|
||||||
for a in range(8):
|
|
||||||
V = {}
|
|
||||||
ddata.append(V)
|
|
||||||
HK = CONFIG.HK[a][1]
|
|
||||||
# cookbook:
|
|
||||||
# None
|
|
||||||
# (name, factor, offset)
|
|
||||||
# (name, factor, (offset_name, factor))
|
|
||||||
# (name, (func, {args}))
|
|
||||||
if not HK:
|
|
||||||
V.update({c:data[a][c] for c in range(8)})
|
|
||||||
continue
|
|
||||||
HK = HK[sl % len(HK)]
|
|
||||||
for c in range(8):
|
|
||||||
H = HK[c]
|
|
||||||
if len(H) > 1:
|
|
||||||
if isinstance(H[1], tuple):
|
|
||||||
data[a][c] = H[1][0](data[a][c], **H[1][1])
|
|
||||||
else:
|
|
||||||
data[a][c] *= Vref*H[1]
|
|
||||||
V[H[0]] = data[a][c]
|
|
||||||
VV.update(V)
|
|
||||||
for c in range(8):
|
|
||||||
H = HK[c]
|
|
||||||
if len(H) > 2:
|
|
||||||
if isinstance(H[2], tuple):
|
|
||||||
data[a][c] += VV[H[2][0]] * H[2][1]
|
|
||||||
else:
|
|
||||||
data[a][c] += H[2]
|
|
||||||
V[H[0]] = data[a][c]
|
|
||||||
|
|
||||||
if what=="cooked":
|
|
||||||
return sl, data
|
|
||||||
if what=="dict":
|
|
||||||
return sl, ddata
|
|
||||||
|
|
||||||
r = []
|
|
||||||
for a in range(8):
|
|
||||||
H=CONFIG.HK[a]
|
|
||||||
# (name, [cookbooks], fmt_function)
|
|
||||||
r.append(H[2](sl, a, H[0], data[a]))
|
|
||||||
|
|
||||||
if what=="print":
|
|
||||||
sys.stderr.write("".join(r))
|
|
||||||
return sl, r
|
|
||||||
|
|
||||||
def dorn_config(a, v=None, mes=None, slice=0):
|
|
||||||
verb = CONFIG.verbose
|
|
||||||
a |= CONFIG.dorn_addr | (slice<<11)
|
|
||||||
if v is None:
|
|
||||||
if not mes:
|
|
||||||
mes = f"dorn[0x{a:03x}]"
|
|
||||||
return acmd(a, task=mes, verb=verb)
|
|
||||||
if not mes:
|
|
||||||
mes = f"dorn[0x{a:03x}] = 0x{v:04x}"
|
|
||||||
if v is False:
|
|
||||||
acmd(a, task=mes, verb=verb)
|
|
||||||
else:
|
|
||||||
acmd(a, v, task=mes, verb=verb)
|
|
||||||
|
|
||||||
def thres(sl, ch, v):
|
|
||||||
dorn_config(0x040 | ch, v, slice=sl)
|
|
||||||
|
|
||||||
def write_l2(sl, ch, i, a, b):
|
|
||||||
dorn_config(0x400 | (ch<<4) | (i<<1) | 0, a & 0xffff, slice=sl)
|
|
||||||
dorn_config(0x400 | (ch<<4) | (i<<1) | 1, b & 0xffff, slice=sl)
|
|
||||||
|
|
||||||
def calib_l2(cal, coeff):
|
|
||||||
if cal is None:
|
|
||||||
return coeff
|
|
||||||
from numpy import array, floor, add, any
|
|
||||||
c = array(coeff)[:,1:] * cal
|
|
||||||
i = floor(c+0.5)
|
|
||||||
e = add.reduce(i)
|
|
||||||
v = e>0
|
|
||||||
w = e<0
|
|
||||||
while any(v) or any(w):
|
|
||||||
d = i - c
|
|
||||||
vv = d.argmax(axis=0)
|
|
||||||
ww = d.argmin(axis=0)
|
|
||||||
for x,f in enumerate(v):
|
|
||||||
if f:
|
|
||||||
i[vv[x],x] -= 1
|
|
||||||
for x,f in enumerate(w):
|
|
||||||
if f:
|
|
||||||
i[ww[x],x] += 1
|
|
||||||
e = add.reduce(i)
|
|
||||||
v = e>0
|
|
||||||
w = e<0
|
|
||||||
return [(x, int(ii[0]), int(ii[1])) for x, ii in enumerate(i)]
|
|
||||||
|
|
||||||
def l2filter(coeff=None, cal=None):
|
|
||||||
if coeff==None:
|
|
||||||
coeff = CONFIG.l2
|
|
||||||
for sl in CONFIG.slices:
|
|
||||||
for ch in range(CONFIG.n_channels):
|
|
||||||
c = coeff
|
|
||||||
if cal and cal[sl] and cal[sl][ch]:
|
|
||||||
c = calib_l2(cal[sl][ch], c)
|
|
||||||
for cc in c:
|
|
||||||
write_l2(sl, ch, *cc)
|
|
||||||
|
|
||||||
def write_l3(sl, ch, *p):
|
|
||||||
scales = (14, 14, 15, 15)
|
|
||||||
for i,pp in enumerate(p):
|
|
||||||
if isinstance(pp, float):
|
|
||||||
pp = int(pp * 2**scales[i])
|
|
||||||
dorn_config(0x100 | (ch<<2) | i, pp & 0xffff, slice=sl)
|
|
||||||
|
|
||||||
def l3banana(
|
|
||||||
# 2025-02-20-seth-pa1-4
|
|
||||||
p0 = -3839,
|
|
||||||
p2 = 13891,
|
|
||||||
p3 = 3579,
|
|
||||||
p4 = 22853 ):
|
|
||||||
for sl in CONFIG.slices:
|
|
||||||
for ch in range(CONFIG.n_channels):
|
|
||||||
write_l3(sl, ch, p0, p2, p3, p4)
|
|
||||||
|
|
||||||
def c16log2(A):
|
|
||||||
return int(math.ceil(16*math.log(1024*A)/math.log(2)))
|
|
||||||
|
|
||||||
def enable_trigger(sl, triggers, det=False, sa=False):
|
|
||||||
i = 2 if sa else 0 if det else 1
|
|
||||||
dorn_config(0x008 | i, triggers, slice=sl)
|
|
||||||
|
|
||||||
def nsamples(sl, n=None, m=None):
|
|
||||||
if n is None:
|
|
||||||
return dorn_config(0x00b, slice=sl)
|
|
||||||
if m is None:
|
|
||||||
m = 0xffff if n else 0
|
|
||||||
enable_trigger(sl, m, sa=True)
|
|
||||||
dorn_config(0x00b, n, slice=sl)
|
|
||||||
|
|
||||||
def triggers(sl, atrig=0xffff, dtrig=0, sam=0, nsa=10):
|
|
||||||
enable_trigger(sl, dtrig, det=True)
|
|
||||||
enable_trigger(sl, atrig)
|
|
||||||
nsamples(sl, nsa, sam)
|
|
||||||
|
|
||||||
def atriggers(sl, atrig=0, gtrig=0, csa=False, gsa=False, nsa=10):
|
|
||||||
dorn_config(0x008, slice=sl, v=atrig & 0xffff, mes="atrig[15:0]")
|
|
||||||
dorn_config(0x009, slice=sl, v=(atrig>>16)|((gtrig&0xff)<<8), mes="gtrig[7:0],atrig[23:8]")
|
|
||||||
dorn_config(0x00a, slice=sl, v=gtrig>>8, mes="gtrig[23:8]")
|
|
||||||
dorn_config(0x00b, slice=sl, v=(gsa<<9)|(csa<<8)|nsa, mes="nsamples")
|
|
||||||
|
|
||||||
def hist_bins(sl, bin0=4.0, res=1, cwin=6, xtalk=6):
|
|
||||||
"""configure dorn_l4 histogramming
|
|
||||||
bin0: float: A-value of bin 0, int: 16LOG2(A)
|
|
||||||
res: bin = 16×log₂(A) >> res
|
|
||||||
cwin: anti-coincidence window [µs]
|
|
||||||
xtalk: x-talk ratio cut: reject if S > (S>>xtalk)
|
|
||||||
"""
|
|
||||||
if isinstance(bin0, float):
|
|
||||||
bin0=c16log2(bin0)
|
|
||||||
dorn_config(0x00c, (xtalk<<8) | cwin, slice=sl)
|
|
||||||
dorn_config(0x00d, (res<<9) | bin0, slice=sl)
|
|
||||||
|
|
||||||
def base_address(hists=None, counters=None, hmask=None, cmask=None):
|
|
||||||
if hists is not None:
|
|
||||||
if counters is None:
|
|
||||||
counters = hists
|
|
||||||
r = dorn_config(0x088, (counters<<3) | hists)
|
|
||||||
else:
|
|
||||||
if hmask is not None:
|
|
||||||
r = dorn_config(0x088, 0x4000 | hmask)
|
|
||||||
if cmask is not None:
|
|
||||||
r = dorn_config(0x088, 0x8000 | cmask)
|
|
||||||
if cmask is None and hmask is None:
|
|
||||||
r = dorn_config(0x088, 0x8000)
|
|
||||||
return r & 7, r >> 3
|
|
||||||
|
|
||||||
def fifo_status(i=None):
|
|
||||||
e = dorn_config(0x084)
|
|
||||||
p = dorn_config(0x085)
|
|
||||||
f = dorn_config(0x086)
|
|
||||||
if i is None:
|
|
||||||
return e,p,f
|
|
||||||
return (e>>i)&1, (p>>i)&1, (f>>i)&1
|
|
||||||
|
|
||||||
def fifo_select(hi=False, sl=None, hk=False, ev=False, sa=False, i=None):
|
|
||||||
if i is not None:
|
|
||||||
f = 1<<i
|
|
||||||
else:
|
|
||||||
f = (sa<<2) | (ev<<1) | hk
|
|
||||||
if sl is not None:
|
|
||||||
f <<= 3*sl+1
|
|
||||||
else:
|
|
||||||
f *= 0b0010010010010
|
|
||||||
f |= hi
|
|
||||||
return f
|
|
||||||
|
|
||||||
def fifo_enable(en=True, rfifo=True, men=True, sl=None, **aa):
|
|
||||||
f = fifo_select(sl=sl, **aa)
|
|
||||||
if sl is None and en is True:
|
|
||||||
en = 0xf
|
|
||||||
elif sl is not None:
|
|
||||||
en <<= sl
|
|
||||||
dorn_config(0x087, (f<<6) | (rfifo<<5) | (men<<4) | en)
|
|
||||||
|
|
||||||
STROBES = {
|
|
||||||
"read_fifos": 0,
|
|
||||||
"incr": 1,
|
|
||||||
"resync": 2,
|
|
||||||
"clock_reset": 3,
|
|
||||||
"hk": 4,
|
|
||||||
"dorn_reset": 8,
|
|
||||||
"mem_reset": 12,
|
|
||||||
"rb_reset": 13,
|
|
||||||
"fifo_reset": 14,
|
|
||||||
}
|
|
||||||
|
|
||||||
def strobe(sl=None, **aa):
|
|
||||||
s = 0
|
|
||||||
for k in aa:
|
|
||||||
if not k in STROBES:
|
|
||||||
raise KeyError(f"No STROBE: {k}")
|
|
||||||
if aa[k]:
|
|
||||||
b = 1
|
|
||||||
if k=="hk":
|
|
||||||
if sl is None:
|
|
||||||
b = 15;
|
|
||||||
else:
|
|
||||||
b <<= sl
|
|
||||||
s |= b << STROBES[k]
|
|
||||||
dorn_config(0x08b, s)
|
|
||||||
|
|
||||||
def fifo_reset(**aa):
|
|
||||||
f = fifo_select(**aa)
|
|
||||||
if not f:
|
|
||||||
strobe(fifo_reset=True)
|
|
||||||
else:
|
|
||||||
dorn_config(0x084, f)
|
|
||||||
|
|
||||||
def fifo_read(**aa):
|
|
||||||
f = fifo_select(**aa)
|
|
||||||
if not f:
|
|
||||||
acmd(0x8800, verb=_verbose)
|
|
||||||
else:
|
|
||||||
dorn_config(0x085, f)
|
|
||||||
|
|
||||||
def default_config(thr=0x7ff):
|
|
||||||
for sl in CONFIG.slices:
|
|
||||||
for ch in range(CONFIG.n_channels):
|
|
||||||
thres(sl, ch, thr)
|
|
||||||
l2filter()
|
|
||||||
l3banana()
|
|
||||||
for sl in CONFIG.slices:
|
|
||||||
atriggers(sl)
|
|
||||||
|
|
||||||
def print_trigger_config():
|
|
||||||
tri = [[dorn_config(0x008 + i, slice=sl)
|
|
||||||
for i in range(4)]
|
|
||||||
for sl in CONFIG.slices]
|
|
||||||
ff = [dorn_config(0x084+i) for i in range(4)]
|
|
||||||
tri.append(ff)
|
|
||||||
e = ff[3]
|
|
||||||
df = [_ifc.Areg(0x11+i) for i in range(3)]
|
|
||||||
df.append(_ifc.Areg(5))
|
|
||||||
tri.append(df)
|
|
||||||
ct0 = tri[0][0] | (tri[0][1]<<16) & 0xff0000
|
|
||||||
ct1 = tri[1][0] | (tri[1][1]<<16) & 0xff0000
|
|
||||||
gt0 = (tri[0][2]<<8) | (tri[0][1]>>8)
|
|
||||||
gt1 = (tri[1][2]<<8) | (tri[1][1]>>8)
|
|
||||||
ns0 = tri[0][3] & 0xff
|
|
||||||
ns1 = tri[1][3] & 0xff
|
|
||||||
se0 = tri[0][3] >> 8
|
|
||||||
se1 = tri[1][3] >> 8
|
|
||||||
print(f"""narena trigger config:
|
|
||||||
trigger detector masks:
|
|
||||||
ctriggers: 0x{ct0:06x} 0x{ct1:06x}
|
|
||||||
gtriggers: 0x{gt0:06x} 0x{gt1:06x}
|
|
||||||
nsamples: {ns0:-6d} {ns1}
|
|
||||||
samples enable: {se0:-6d} {se1}
|
|
||||||
enable: {e&1:-6d} {(e>>1)&1}
|
|
||||||
fifos enable SA/EV/HK HI {(e>>7)&7:03b} {(e>>10)&7:03b} {(e>>6)&1}
|
|
||||||
empty {(ff[0]>>1)&7:03b} {(ff[0]>>4)&7:03b} {ff[0]&1} {(df[3]>>9)&7:03b}
|
|
||||||
packet {(ff[1]>>1)&7:03b} {(ff[1]>>4)&7:03b} {ff[1]&1} {(df[3]>>13)&7:03b}
|
|
||||||
full {(ff[2]>>1)&7:03b} {(ff[2]>>4)&7:03b} {ff[2]&1} {(df[3]>>5)&7:03b}
|
|
||||||
dig fifo status {df[2]&0x3ff} {df[1]&0x3ff} {df[0]&0x3ff}
|
|
||||||
""", file=sys.stderr)
|
|
||||||
return tri
|
|
||||||
|
|
||||||
def read_event(sl=None, ev=None):
|
|
||||||
if ev is None:
|
|
||||||
fifo_read(sl=sl, ev=True)
|
|
||||||
ev = _ifc._read_fifo(2)
|
|
||||||
if (ev[0] & 0xfffc) != 0x5718:
|
|
||||||
raise ValueError(f"EV packet magic mismatch {ev[0]:04x}")
|
|
||||||
Ba = ev[5]
|
|
||||||
Ph = ev[6]
|
|
||||||
A = ev[7]<<8 | ev[9]>>8
|
|
||||||
B = ev[8]<<8 | ev[9]&0xff
|
|
||||||
E = ev[10] | ev[11]<<16
|
|
||||||
if Ba & 0x8000:
|
|
||||||
Ba -= 0x10000
|
|
||||||
if Ph & 0x8000:
|
|
||||||
Ph -= 0x10000
|
|
||||||
if A & 0x800000:
|
|
||||||
A -= 0x1000000
|
|
||||||
if B & 0x800000:
|
|
||||||
B -= 0x1000000
|
|
||||||
if E & 0x80000000:
|
|
||||||
E -= 0x100000000
|
|
||||||
print(f"""PHA Event slice {ev[0]&3} ch {ev[4]&15}
|
|
||||||
time: {ev[1] | ev[2]<<16}
|
|
||||||
Δtime: {ev[3]}
|
|
||||||
lost: {ev[4]>>4}
|
|
||||||
A: {A/1024:.2f}
|
|
||||||
B: {B/1024:.2f}
|
|
||||||
banana: {Ba/0x4000:.4f}
|
|
||||||
φ: {Ph/0x4000:.4f}
|
|
||||||
E: {E/0x20000:.2f}
|
|
||||||
""", file=sys.stderr)
|
|
||||||
return ev
|
|
||||||
|
|
||||||
def read_samples(sl=0, n=None, sa=None):
|
|
||||||
if not sa:
|
|
||||||
if not n:
|
|
||||||
n = nsamples(sl)
|
|
||||||
sa = []
|
|
||||||
while n:
|
|
||||||
ff = dorn_config(0x085)
|
|
||||||
if not (ff & (8 << (3*sl))):
|
|
||||||
break;
|
|
||||||
fifo_read(sl=sl, sa=True)
|
|
||||||
sa.append(rfifo(3))
|
|
||||||
n -= 1
|
|
||||||
for s in sa:
|
|
||||||
if (s[0] & 0xfffc) != 0x5714:
|
|
||||||
raise ValueError(f"SA magic mismatch {s[0]:04x}")
|
|
||||||
t = s[1] | s[2]<<16
|
|
||||||
print(f"{t} ", " ".join([f"{ss&0xfff:5d}" for ss in s[3:]]), file=sys.stderr)
|
|
||||||
return sa
|
|
||||||
|
|
||||||
38
src/dose.py
38
src/dose.py
|
|
@ -1,4 +1,4 @@
|
||||||
#! /usr/bin/ipython3 --profile=thhor
|
#! /usr/bin/ipython3 --profile=turbo_dose
|
||||||
|
|
||||||
import sys, time, getopt, fileinput, struct
|
import sys, time, getopt, fileinput, struct
|
||||||
import uart
|
import uart
|
||||||
|
|
@ -452,11 +452,9 @@ class dose_cmd(uart.uart):
|
||||||
"HKSZ": 0x0018,
|
"HKSZ": 0x0018,
|
||||||
"HKMA": 0x0019,
|
"HKMA": 0x0019,
|
||||||
"HKHV": 0x001a,
|
"HKHV": 0x001a,
|
||||||
|
|
||||||
"BATE": 0x037f,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def icmd(self, c, p=None, r=2, flgs=0, mes=None):
|
def icmd(self, c, p=None, r=2, flgs=0):
|
||||||
if c in self.AADDR:
|
if c in self.AADDR:
|
||||||
c = self.AADDR[c]+flgs
|
c = self.AADDR[c]+flgs
|
||||||
w = [c | 0x8000]
|
w = [c | 0x8000]
|
||||||
|
|
@ -467,23 +465,10 @@ class dose_cmd(uart.uart):
|
||||||
w.extend([0x8001]*(r-1))
|
w.extend([0x8001]*(r-1))
|
||||||
w.append(0)
|
w.append(0)
|
||||||
d = struct.pack(f">{len(w)}H", *w)
|
d = struct.pack(f">{len(w)}H", *w)
|
||||||
if self._verbose:
|
print(f"icmd → {[f"{ww:04x}" for ww in w]}")
|
||||||
if mes:
|
|
||||||
mes = f"[{mes}]"
|
|
||||||
else:
|
|
||||||
mes = ""
|
|
||||||
print(f"icmd{mes} → {[f"{ww:04x}" for ww in w]}")
|
|
||||||
d = self.fpga_cmd(d)
|
d = self.fpga_cmd(d)
|
||||||
r = struct.unpack(f">{len(w)+1}H", d[:2*len(w)+2])
|
r = struct.unpack(f">{len(w)+1}H", d[:2*len(w)+2])
|
||||||
if self._verbose:
|
print(f" ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
||||||
print(f" {mes} ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
|
||||||
return r
|
|
||||||
|
|
||||||
def acmd(self, c, v=None, task=None, verb=True):
|
|
||||||
_v = self._verbose
|
|
||||||
self._verbose = _v
|
|
||||||
r = self.icmd(c, v, mes=task)[-1]
|
|
||||||
self._verbose = _v
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def rfifo(self, fifo=1, n=None):
|
def rfifo(self, fifo=1, n=None):
|
||||||
|
|
@ -508,9 +493,9 @@ class dose_cmd(uart.uart):
|
||||||
print(f"FIFO[{fifo}] ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
print(f"FIFO[{fifo}] ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def pressure(self, data=None, cmd="BATE", fifo=1):
|
def pressure(self, data=None, cmd=0x037f, fifo=1):
|
||||||
if data is None:
|
if data is None:
|
||||||
self.icmd(cmd, mes="bate")
|
self.icmd(cmd)
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
data = self.rfifo(fifo)
|
data = self.rfifo(fifo)
|
||||||
import pressure
|
import pressure
|
||||||
|
|
@ -520,13 +505,6 @@ class dose_cmd(uart.uart):
|
||||||
print(f"bate reading {p=:.2f} mbar, {T=:.2f} °C", file=sys.stderr)
|
print(f"bate reading {p=:.2f} mbar, {T=:.2f} °C", file=sys.stderr)
|
||||||
return p, T, data
|
return p, T, data
|
||||||
|
|
||||||
def menable(self, on=True, what=0x0001):
|
|
||||||
if on:
|
|
||||||
self.icmd("MCONF_SET", what)
|
|
||||||
else:
|
|
||||||
self.icmd("MCONF_CLR", what)
|
|
||||||
|
|
||||||
|
|
||||||
def flags2int(FLAGS, flags):
|
def flags2int(FLAGS, flags):
|
||||||
r = 0
|
r = 0
|
||||||
if isinstance(flags, int):
|
if isinstance(flags, int):
|
||||||
|
|
@ -551,10 +529,6 @@ if tty:
|
||||||
tty = dose_cmd(tty, baud)
|
tty = dose_cmd(tty, baud)
|
||||||
tty._export(globals())
|
tty._export(globals())
|
||||||
tty._verbose = False
|
tty._verbose = False
|
||||||
import dorn
|
|
||||||
from dorn import *
|
|
||||||
dorn._connect(tty)
|
|
||||||
dorn.CONFIG.thhor()
|
|
||||||
|
|
||||||
uart.set_prompt("GRETEL")
|
uart.set_prompt("GRETEL")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue