From 39b5dd719353b1a8780892b8233e2dfd9b83a8e1 Mon Sep 17 00:00:00 2001 From: David Lenfesty Date: Sun, 23 Apr 2023 20:45:57 -0600 Subject: [PATCH] gw: finish CDC sampler module Just need to hook this into the FIFO I made before, and write all the peak detection, triggering, and trigger enable logic, + hook everything into a single wishbone address space. --- gateware/litex_main.py | 6 +++++- gateware/sampler.py | 30 ++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/gateware/litex_main.py b/gateware/litex_main.py index 5daf74f..0e3c80f 100755 --- a/gateware/litex_main.py +++ b/gateware/litex_main.py @@ -37,6 +37,7 @@ class _CRG(Module): def __init__(self, platform, sys_clk_freq, use_internal_osc=False, with_usb_pll=False, with_video_pll=False, sdram_rate="1:1"): self.rst = Signal() self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sample_clock = ClockDomain("sample_clock") if sdram_rate == "1:2": self.clock_domains.cd_sys2x = ClockDomain() self.clock_domains.cd_sys2x_ps = ClockDomain() @@ -75,6 +76,9 @@ class _CRG(Module): sdram_clk = ClockSignal("sys2x_ps" if sdram_rate == "1:2" else "sys_ps") self.specials += DDROutput(1, 0, platform.request("sdram_clock"), sdram_clk) + # Sampler clock + pll.create_clkout(self.cd_sample_clock, int(10e6)) + # BaseSoC ------------------------------------------------------------------------------------------ # TODO make my own platform for this based on the colorlight one, so I can export I2C and other pins @@ -138,7 +142,7 @@ class BaseSoC(SoCCore): if with_video_framebuffer: self.add_video_framebuffer(phy=self.videophy, timings="800x600@60Hz", clock_domain="hdmi") - self.submodules.sampler = Sampler(platform.request("adc")) + self.submodules.sampler = Sampler(platform.request("adc"), self.crg.cd_sample_clock.clk) sampler_region = SoCRegion(origin=None, size=0x1000, cached=False) #self.add_wb_slave(0x9000_0000, self.sampler.bus, 0x1000) # TODO better way to do this? diff --git a/gateware/sampler.py b/gateware/sampler.py index eeb7369..4ff93e8 100644 --- a/gateware/sampler.py +++ b/gateware/sampler.py @@ -109,17 +109,35 @@ class CircularBuffer(Module): wr_ptr.eq(0), rd_ptr.eq(0), empty.eq(1)) +from migen.genlib.cdc import PulseSynchronizer + + class Sampler(Module): - def __init__(self, adc_pins): + def __init__(self, adc_pins: Record, sampler_clock: Signal): # TODO correct addr width self.bus = Interface(data_width=32, adr_width=11) # self.clock_domains.foo = ClockDomain() is how to add a new clock domain, accessible at self.foo + # Connect sampler clock domain + self.clock_domains.sample_clock = ClockDomain("sample_clock") + self.comb += self.sample_clock.clk.eq(sampler_clock) - # Provide a slow clock to the ADC, 60MHz / 600 = 100kHz - self._counter = Signal(32) - self.sync += self._counter.eq(self._counter + 1) - self.sync += If(self._counter >= 600, self._counter.eq(0), adc_pins.refclk.eq(~adc_pins.refclk)) + # Hook up ADC REFCLK to sample_clock + self.comb += adc_pins.refclk.eq(sampler_clock) + + # We can synchronize to the sampler clock, whenever it goes high we can + # strobe a single valid signal + synchronizer = PulseSynchronizer("sample_clock", "sys") + self.submodules += synchronizer + + self.valid = Signal() + self.data = Signal(10) + + self.comb += [ + synchronizer.i.eq(self.sample_clock.clk), + self.valid.eq(synchronizer.o), + self.data.eq(adc_pins.data), + ] # Set config pins to constant values self.comb += adc_pins.oen_b.eq(0) # Data pins enable @@ -128,7 +146,7 @@ class Sampler(Module): # The only remaining pin, OTR, is an out of range status indicator # Read directly from the data pins into the wishbone bus for now, just for bringup - self.comb += self.bus.dat_r.eq(adc_pins.data) + self.sync += If(self.valid, self.bus.dat_r.eq(adc_pins.data)) self.sync += self.bus.ack.eq(0) self.sync += If(self.bus.cyc & self.bus.stb, self.bus.ack.eq(1))