forked from M-Labs/artiq
shuttler: init sigma-delta modulator
This commit is contained in:
parent
2eb89cb168
commit
0e8fa8933f
|
@ -93,13 +93,36 @@ class DacInterface(Module, AutoCSR):
|
||||||
p_DDR_CLK_EDGE="SAME_EDGE")
|
p_DDR_CLK_EDGE="SAME_EDGE")
|
||||||
for bit in range(bit_width)]
|
for bit in range(bit_width)]
|
||||||
|
|
||||||
|
|
||||||
|
class SigmaDeltaModulator(Module):
|
||||||
|
"""First order Sigma-Delta modulator."""
|
||||||
|
def __init__(self, x_width, y_width):
|
||||||
|
self.x = Signal(x_width)
|
||||||
|
self.y = Signal(y_width)
|
||||||
|
|
||||||
|
# The SDM cannot represent any sample >0x7ffc with pulse modulation
|
||||||
|
# Allowing pulse modulation on values >0x7ffc may overflow the
|
||||||
|
# accumulator, so the DAC code becomes 0x2000 -> -10.V.
|
||||||
|
x_capped = Signal(x_width)
|
||||||
|
self.comb += If((self.x & 0xfffc) == 0x7ffc,
|
||||||
|
x_capped.eq(0x7ffc),
|
||||||
|
).Else(
|
||||||
|
x_capped.eq(self.x),
|
||||||
|
)
|
||||||
|
|
||||||
|
acc = Signal(x_width)
|
||||||
|
|
||||||
|
self.comb += self.y.eq(acc[x_width-y_width:])
|
||||||
|
self.sync.rio += acc.eq(x_capped - Cat(Replicate(0, x_width-y_width), self.y) + acc)
|
||||||
|
|
||||||
|
|
||||||
class Dac(Module):
|
class Dac(Module):
|
||||||
"""Output module.
|
"""Output module.
|
||||||
|
|
||||||
Holds the two output line executors.
|
Holds the two output line executors.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
data (Signal[16]): Output value to be send to the DAC.
|
data (Signal[14]): Output value to be send to the DAC.
|
||||||
clear (Signal): Clear accumulated phase offset when loading a new
|
clear (Signal): Clear accumulated phase offset when loading a new
|
||||||
waveform. Input.
|
waveform. Input.
|
||||||
gain (Signal[16]): Output value gain. The gain signal represents the
|
gain (Signal[16]): Output value gain. The gain signal represents the
|
||||||
|
@ -107,9 +130,9 @@ class Dac(Module):
|
||||||
offset (Signal[16]): Output value offset.
|
offset (Signal[16]): Output value offset.
|
||||||
i (Endpoint[]): Coefficients of the output lines.
|
i (Endpoint[]): Coefficients of the output lines.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self, sdm=False):
|
||||||
self.clear = Signal()
|
self.clear = Signal()
|
||||||
self.data = Signal(16)
|
self.data = Signal(14)
|
||||||
self.gain = Signal(16)
|
self.gain = Signal(16)
|
||||||
self.offset = Signal(16)
|
self.offset = Signal(16)
|
||||||
|
|
||||||
|
@ -128,16 +151,21 @@ class Dac(Module):
|
||||||
# Buffer data should have 2 more bits than the desired output width
|
# Buffer data should have 2 more bits than the desired output width
|
||||||
# It is to perform overflow/underflow detection
|
# It is to perform overflow/underflow detection
|
||||||
data_buf = Signal(18)
|
data_buf = Signal(18)
|
||||||
|
data_sink = Signal(16)
|
||||||
|
|
||||||
|
if sdm:
|
||||||
|
self.submodules.sdm = SigmaDeltaModulator(16, 14)
|
||||||
|
|
||||||
self.sync.rio += [
|
self.sync.rio += [
|
||||||
data_raw.eq(reduce(add, [sub.data for sub in subs])),
|
data_raw.eq(reduce(add, [sub.data for sub in subs])),
|
||||||
# Extra buffer for timing for the DSP
|
# Extra buffer for timing for the DSP
|
||||||
data_buf.eq(((data_raw * Cat(self.gain, ~self.gain[-1])) + (self.offset << 16))[16:]),
|
data_buf.eq(((data_raw * Cat(self.gain, ~self.gain[-1])) + (self.offset << 16))[16:]),
|
||||||
If(overflow,
|
If(overflow,
|
||||||
self.data.eq(0x7fff),
|
data_sink.eq(0x7fff),
|
||||||
).Elif(underflow,
|
).Elif(underflow,
|
||||||
self.data.eq(0x8000),
|
data_sink.eq(0x8000),
|
||||||
).Else(
|
).Else(
|
||||||
self.data.eq(data_buf),
|
data_sink.eq(data_buf),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -148,6 +176,14 @@ class Dac(Module):
|
||||||
underflow.eq(data_buf[-1] & (~data_buf[-2] | ~data_buf[-3])),
|
underflow.eq(data_buf[-1] & (~data_buf[-2] | ~data_buf[-3])),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if sdm:
|
||||||
|
self.comb += [
|
||||||
|
self.sdm.x.eq(data_sink),
|
||||||
|
self.data.eq(self.sdm.y),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.comb += self.data.eq(data_sink[2:])
|
||||||
|
|
||||||
self.i = [ sub.i for sub in subs ]
|
self.i = [ sub.i for sub in subs ]
|
||||||
self.submodules += subs
|
self.submodules += subs
|
||||||
|
|
||||||
|
@ -313,7 +349,7 @@ class Shuttler(Module, AutoCSR):
|
||||||
Attributes:
|
Attributes:
|
||||||
phys (list): List of Endpoints.
|
phys (list): List of Endpoints.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pads):
|
def __init__(self, pads, sdm=False):
|
||||||
NUM_OF_DACS = 16
|
NUM_OF_DACS = 16
|
||||||
|
|
||||||
self.submodules.dac_interface = DacInterface(pads)
|
self.submodules.dac_interface = DacInterface(pads)
|
||||||
|
@ -347,12 +383,12 @@ class Shuttler(Module, AutoCSR):
|
||||||
self.phys.append(Phy(trigger_iface, [], []))
|
self.phys.append(Phy(trigger_iface, [], []))
|
||||||
|
|
||||||
for idx in range(NUM_OF_DACS):
|
for idx in range(NUM_OF_DACS):
|
||||||
dac = Dac()
|
dac = Dac(sdm=sdm)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
dac.clear.eq(self.cfg.clr[idx]),
|
dac.clear.eq(self.cfg.clr[idx]),
|
||||||
dac.gain.eq(self.cfg.gain[idx]),
|
dac.gain.eq(self.cfg.gain[idx]),
|
||||||
dac.offset.eq(self.cfg.offset[idx]),
|
dac.offset.eq(self.cfg.offset[idx]),
|
||||||
self.dac_interface.data[idx // 2][idx % 2].eq(dac.data[2:])
|
self.dac_interface.data[idx // 2][idx % 2].eq(dac.data)
|
||||||
]
|
]
|
||||||
|
|
||||||
for i in dac.i:
|
for i in dac.i:
|
||||||
|
|
Loading…
Reference in New Issue