From a874c6142b704df9166f77796887a59ad248dcf5 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 24 Mar 2022 13:28:12 +0000 Subject: [PATCH] establish power-on reset stabilisation for Arty A7 and ECP5 --- src/arty_crg.py | 106 +++++++++++++++++++++++------------------------- src/ls2.py | 7 ++-- 2 files changed, 53 insertions(+), 60 deletions(-) diff --git a/src/arty_crg.py b/src/arty_crg.py index ef57b0b..04b22b4 100644 --- a/src/arty_crg.py +++ b/src/arty_crg.py @@ -38,8 +38,9 @@ class XilinxClocking(Elaboratable): def __init__(self, clkin, vco_margin=0): self.clkin = clkin self.vco_margin = vco_margin - self.reset = Signal() - self.locked = Signal() + self.reset = Signal(reset_less=True) + self.locked = Signal(reset_less=True) + self.pod_done = Signal(reset_less=True) # provide this @ rawclk self.clkin_freq = None self.vcxo_freq = None self.nclkouts = 0 @@ -66,7 +67,7 @@ class XilinxClocking(Elaboratable): if with_reset: arst = Signal() m.submodules += ResetSynchronizer(arst, domain=cd.name) - comb += arst.eq(~self.locked | self.reset) + comb += arst.eq(~self.locked | self.reset | ~self.pod_done) if buf is None: comb += cd.clk.eq(clkout) else: @@ -193,11 +194,12 @@ class ECP5PLL(Elaboratable): def __init__(self, clkin, clksel=Signal(shape=2, reset=2), reset=Signal(reset_less=True), - locked=Signal()): + locked=Signal(reset_less=True)): self.clkin = clkin self.clkin_freq = None self.clksel = clksel self.locked = locked + self.pod_done = Signal(reset_less=True) # must be set in rawclk self.reset = reset self.nclkouts = 0 self.clkouts = {} @@ -217,14 +219,14 @@ class ECP5PLL(Elaboratable): assert freq <= clki_freq_max self.clkin_freq = freq - def create_clkout(self, cd, freq, phase=0, margin=1e-2): + def create_clkout(self, cd, freq, phase=0, margin=1e-2, reset=True): (clko_freq_min, clko_freq_max) = self.clko_freq_range assert freq >= clko_freq_min assert freq <= clko_freq_max assert self.nclkouts < self.nclkouts_max - self.clkouts[self.nclkouts] = (cd, freq, phase, margin) + self.clkouts[self.nclkouts] = (cd, freq, phase, margin, reset) #create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts) - print("clock domain", cd.domain, freq, margin, self.nclkouts) + print("clock domain", cd.domain, freq, margin, self.nclkouts, reset) self.nclkouts += 1 def compute_config(self): @@ -236,7 +238,7 @@ class ECP5PLL(Elaboratable): vco_freq = self.clkin_freq/clki_div*clkfb_div*1 # clkos3_div=1 (vco_freq_min, vco_freq_max) = self.vco_freq_range if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max: - for n, (clk, f, p, m) in sorted(self.clkouts.items()): + for n, (clk, f, p, m, rst) in sorted(self.clkouts.items()): valid = False for d in range(*self.clko_div_range): clk_freq = vco_freq/d @@ -259,6 +261,8 @@ class ECP5PLL(Elaboratable): raise ValueError("No PLL config found") def elaborate(self, platform): + m = Module() + config = self.compute_config() clkfb = Signal() self.params.update( @@ -280,7 +284,7 @@ class ECP5PLL(Elaboratable): o_LOCK = self.locked, ) # for each clock-out, set additional parameters - for n, (clk, f, p, m) in sorted(self.clkouts.items()): + for n, (clk, f, p, m, rst) in sorted(self.clkouts.items()): n_to_l = {0: "P", 1: "S", 2: "S2"} div = config["clko{}_div".format(n)] cphase = int(p*(div + 1)/360 + div) @@ -290,57 +294,34 @@ class ECP5PLL(Elaboratable): self.params["p_CLKO{}_CPHASE".format(n_to_l[n])] = cphase self.params["o_CLKO{}".format(n_to_l[n])] = clk - m = Module() + # for each clock-out, do a reset sync if required + arst = Signal() + comb += arst.eq(~self.locked | self.reset | ~self.pod_done) + for n, (clk, f, p, m, rst) in sorted(self.clkouts.items()): + rsts = ResetSynchroniser(arst, domain=clk) + m.submodules['%s_rst' % clk] = rsts + + # actual PLL, finally print ("params", self.params) pll = Instance("EHXPLLL", **self.params) m.submodules.pll = pll return m - pll = Instance("EHXPLLL", - p_OUTDIVIDER_MUXA='DIVA', - p_OUTDIVIDER_MUXB='DIVB', - p_CLKOP_ENABLE='ENABLED', - p_CLKOS_ENABLE='ENABLED', - p_CLKOS2_ENABLE='DISABLED', - p_CLKOS3_ENABLE='DISABLED', - p_CLKOP_DIV=self.CLKOP_DIV, - p_CLKOS_DIV=self.CLKOS_DIV, - p_CLKFB_DIV=self.CLKFB_DIV, - p_CLKI_DIV=self.CLKI_DIV, - p_FEEDBK_PATH='INT_OP', - p_CLKOP_TRIM_POL="FALLING", - p_CLKOP_TRIM_DELAY=0, - p_CLKOS_TRIM_POL="FALLING", - p_CLKOS_TRIM_DELAY=0, - i_CLKI=self.clkin, - i_RST=0, - i_STDBY=0, - i_PHASESEL0=0, - i_PHASESEL1=0, - i_PHASEDIR=0, - i_PHASESTEP=0, - i_PHASELOADREG=0, - i_PLLWAKESYNC=0, - i_ENCLKOP=1, - i_ENCLKOS=1, - i_ENCLKOS2=0, - i_ENCLKOS3=0, - o_CLKOP=self.clkout1, - o_CLKOS=self.clkout2, - o_CLKOS2=self.clkout3, - o_CLKOS3=self.clkout4, - o_LOCK=self.lock, - ) # CRG ---------------------------------------------------------------- class ArtyA7CRG(Elaboratable): def __init__(self, sys_clk_freq): self.sys_clk_freq = sys_clk_freq + self.reset = Signal(reset_less=True) def elaborate(self, platform): m = Module() + # reset + reset = platform.request(platform.default_rst).i + m.d.comb += self.reset.eq(reset) + # Get 100Mhz from oscillator clk100 = platform.request("clk100") cd_rawclk = ClockDomain("rawclk", local=True, reset_less=True) @@ -363,11 +344,20 @@ class ArtyA7CRG(Elaboratable): #m.domains += cd_eth m.domains += dramsync + # PLL module m.submodules.pll = pll = S7PLL(clk100, speedgrade=-1) - reset = platform.request(platform.default_rst).i + + # Power-on delay (a LOT) + podcnt = Signal(18, reset=-1) + pod_done = Signal(reset_less=True) + with m.If((podcnt != 0) & pll.locked): + m.d.rawclk += podcnt.eq(podcnt-1) + m.d.rawclk += pod_done.eq(podcnt == 0) + + # PLL setup m.d.comb += pll.reset.eq(reset) + m.d.comb += pll.pod_done.eq(pod_done) pll.set_clkin_freq(100e6) - pll.create_clkout(sync, self.sys_clk_freq) #platform.add_period_constraint(clk100_buf, 1e9/100e6) @@ -376,12 +366,14 @@ class ArtyA7CRG(Elaboratable): # temporarily set dram sync clock exactly equal to main sync m.d.comb += ClockSignal("dramsync").eq(ClockSignal("sync")) + return m class ECPIX5CRG(Elaboratable): def __init__(self, sys_clk_freq=100e6): self.sys_clk_freq = sys_clk_freq + self.reset = Signal(reset_less=True) def elaborate(self, platform): m = Module() @@ -394,6 +386,8 @@ class ECPIX5CRG(Elaboratable): # Reset reset = platform.request(platform.default_rst).i + m.d.comb += self.reset.eq(reset) + gsr0 = Signal() gsr1 = Signal() @@ -410,10 +404,13 @@ class ECPIX5CRG(Elaboratable): i_GSR=gsr1), ] - # Power-on delay (655us) - podcnt = Signal(3, reset=-1) + # create PLL module + m.submodules.pll = pll = ECP5PLL(ClockSignal("rawclk"), reset=~reset) + + # Power-on delay (lots) + podcnt = Signal(8, reset=-1) pod_done = Signal() - with m.If(podcnt != 0): + with m.If((podcnt != 0) & pll.locked): m.d.rawclk += podcnt.eq(podcnt-1) m.d.rawclk += pod_done.eq(podcnt == 0) @@ -424,7 +421,9 @@ class ECPIX5CRG(Elaboratable): cd_init = ClockDomain("init", local=False) cd_sync = ClockDomain("sync", local=False) cd_dramsync = ClockDomain("dramsync", local=False) - m.submodules.pll = pll = ECP5PLL(ClockSignal("rawclk"), reset=~reset) + + # create clocks for the PLL + m.d.comb += pll.pod_done.eq(pod_done) pll.set_clkin_freq(100e6) pll.create_clkout(ClockSignal("sync2x_unbuf"), 2*self.sys_clk_freq) pll.create_clkout(ClockSignal("init"), 25e6) @@ -437,11 +436,6 @@ class ECPIX5CRG(Elaboratable): m.domains += cd_init m.domains += cd_sync m.domains += cd_dramsync - reset_ok = Signal(reset_less=True) - m.d.comb += reset_ok.eq(~pll.locked|~pod_done) - m.d.comb += ResetSignal("init").eq(reset_ok) - m.d.comb += ResetSignal("sync").eq(reset_ok) - m.d.comb += ResetSignal("dramsync").eq(reset_ok) # # Generating sync (100Mhz) from sync2x diff --git a/src/ls2.py b/src/ls2.py index 60aafd2..0ecc9ce 100644 --- a/src/ls2.py +++ b/src/ls2.py @@ -587,7 +587,7 @@ def build_platform(fpga, firmware): if fpga == 'versa_ecp5_85': clk_freq = 55e6 if fpga == 'arty_a7': - clk_freq = 12e6 + clk_freq = 25e6 # select a firmware address fw_addr = None @@ -635,10 +635,9 @@ def build_platform(fpga, firmware): elif platform is not None and fpga in ['arty_a7']: hyperram_ios = HyperRAMResource(0, cs_n="B11", dq="D4 D3 F4 F3 G2 H2 D2 E2", - rwds="U13", rst_n="T13", ck_p="V10" + rwds="U13", rst_n="T13", ck_p="V10", # ck_n="D12" - for later (DDR) - ) - #attrs=Attrs(IO_TYPE="LVCMOS33")) + attrs=Attrs(IOSTANDARD="LVCMOS33")) platform.add_resources(hyperram_ios) hyperram_pins = platform.request("hyperram") print ("arty a7 hyperram", hyperram_ios) -- 2.30.2