shuttler: init sigma-delta modulator

This commit is contained in:
occheung 2023-09-29 20:39:34 -07:00 committed by Sébastien Bourdeauducq
parent 2eb89cb168
commit 0e8fa8933f
1 changed files with 45 additions and 9 deletions

View File

@ -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: