Compare commits
2 commits
c52d619bb7
...
8179bdb629
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8179bdb629 | ||
|
|
f94145f233 |
2 changed files with 643 additions and 6 deletions
611
src/dorn.py
Normal file
611
src/dorn.py
Normal file
|
|
@ -0,0 +1,611 @@
|
||||||
|
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=turbo_dose
|
#! /usr/bin/ipython3 --profile=thhor
|
||||||
|
|
||||||
import sys, time, getopt, fileinput, struct
|
import sys, time, getopt, fileinput, struct
|
||||||
import uart
|
import uart
|
||||||
|
|
@ -452,9 +452,11 @@ 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):
|
def icmd(self, c, p=None, r=2, flgs=0, mes=None):
|
||||||
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]
|
||||||
|
|
@ -465,10 +467,23 @@ 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)
|
||||||
print(f"icmd → {[f"{ww:04x}" for ww in w]}")
|
if self._verbose:
|
||||||
|
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])
|
||||||
print(f" ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
if self._verbose:
|
||||||
|
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):
|
||||||
|
|
@ -493,9 +508,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=0x037f, fifo=1):
|
def pressure(self, data=None, cmd="BATE", fifo=1):
|
||||||
if data is None:
|
if data is None:
|
||||||
self.icmd(cmd)
|
self.icmd(cmd, mes="bate")
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
data = self.rfifo(fifo)
|
data = self.rfifo(fifo)
|
||||||
import pressure
|
import pressure
|
||||||
|
|
@ -505,6 +520,13 @@ 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):
|
||||||
|
|
@ -529,6 +551,10 @@ 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