def __init__(self, *, rx_depth=16, tx_depth=16, **kwargs): super().__init__() self._phy = AsyncSerial(**kwargs) self._rx_fifo = SyncFIFO(width=self._phy.rx.data.width, depth=rx_depth) self._tx_fifo = SyncFIFO(width=self._phy.tx.data.width, depth=tx_depth) bank = self.csr_bank() self._enabled = bank.csr(1, "w") self._divisor = bank.csr(self._phy.divisor.width, "rw") self._rx_data = bank.csr(self._phy.rx.data.width, "r") self._rx_rdy = bank.csr(1, "r") self._rx_err = bank.csr(len(self._phy.rx.err), "r") self._tx_data = bank.csr(self._phy.tx.data.width, "w") self._tx_rdy = bank.csr(1, "r") self._rx_rdy_ev = self.event(mode="level") self._rx_err_ev = self.event(mode="rise") self._tx_mty_ev = self.event(mode="rise") self._bridge = self.bridge(data_width=32, granularity=8, alignment=2) self.bus = self._bridge.bus self.irq = self._bridge.irq self.tx = Signal() self.rx = Signal() self.enabled = Signal() self.driving = Signal()
def elaborate(self, platform): m = Module() # Received symbols are aligned and processed by the PCIePhyRX # The PCIePhyTX sends symbols to the SERDES #m.submodules.serdes = serdes = LatticeECP5PCIeSERDESx2() # Declare SERDES module with 1:2 gearing m.submodules.serdes = serdes = LatticeECP5PCIeSERDES( 2) # Declare SERDES module with 1:2 gearing m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), serdes.lane.rx_align.eq(1), ] uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart m.submodules.debug = UARTDebugger(uart, 9, CAPTURE_DEPTH, Cat(serdes.lane.rx_symbol, serdes.lane.tx_symbol, Signal(9 * 8 - 18 * 2)), "rx", timeout=100 * 1000 * 1000) return m
def elaborate(self, platform): stereo = platform.request("stereo") uart = platform.request("uart") divisor = int(platform.default_clk_frequency // 115200) m = Module() # Create the uart m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart) pwm_acc = Signal(9) dat_r = Signal(8) m.d.comb += [ serial.rx.ack.eq(1), stereo.l.o.eq(Mux(pwm_acc[-1], 0x7, 0x0)), # Not too loud stereo.r.o.eq(stereo.l.o) ] with m.If(serial.rx.rdy): m.d.sync += dat_r.eq(serial.rx.data) m.d.sync += pwm_acc.eq(pwm_acc[:8] + dat_r) return m
def elaborate(self, platform): m = Module() m.submodules.phy = ecp5_phy = LatticeECP5PCIePhy() phy = ecp5_phy.phy ltssm = phy.ltssm lane = phy.descrambled_lane # Temperature sensor, the chip gets kinda hot refclkcounter = Signal(32) m.d.sync += refclkcounter.eq(refclkcounter + 1) sample = Signal() m.d.sync += sample.eq(refclkcounter[25]) m.submodules.dtr = dtr = DTR(start=refclkcounter[25] & ~sample) leds_alnum = Cat(platform.request("alnum_led", 0)) m.d.comb += leds_alnum.eq(ltssm.debug_state) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor = int(100), pins = uart_pins) m.submodules += uart if NO_DEBUG: pass else: # 64t 9R 9R 9T 9T 2v 4- 6D # t = Ticks since state was entered # R = RX symbol # T = TX symbol # v = RX valid # D = DTR Temperature, does not correspond to real temperature besides the range of 21-29 °C. After that in 10 °C steps (30 = 40 °C, 31 = 50 °C etc...), see TN1266 time_since_state = Signal(64) with m.If(ltssm.debug_state != State.L0): m.d.rx += time_since_state.eq(0) with m.Else(): m.d.rx += time_since_state.eq(time_since_state + 1) m.submodules += UARTDebugger(uart, 14, CAPTURE_DEPTH, Cat( time_since_state, lane.rx_symbol, lane.tx_symbol, lane.rx_locked & lane.rx_present & lane.rx_aligned, lane.rx_locked & lane.rx_present & lane.rx_aligned, Signal(4), Signal(4), phy.dll.tx.started_sending, phy.dll.tx.started_sending#dtr.temperature ), "rx") return m
def __init__(self, *, rx_depth=16, tx_depth=16, **kwargs): super().__init__() self._phy = AsyncSerial(**kwargs) self._rx_fifo = SyncFIFO(width=self._phy.rx.data.width, depth=rx_depth) self._tx_fifo = SyncFIFO(width=self._phy.tx.data.width, depth=tx_depth) bank = self.csr_bank() self._divisor = bank.csr(self._phy.divisor.width, "rw") self._rx_data = bank.csr(self._phy.rx.data.width, "r") self._rx_rdy = bank.csr(1, "r") self._rx_err = bank.csr(len(self._phy.rx.err), "r") self._tx_data = bank.csr(self._phy.tx.data.width, "w") self._tx_rdy = bank.csr(1, "r") self._rx_rdy_ev = self.event(mode="level") self._rx_err_ev = self.event(mode="rise") self._tx_mty_ev = self.event(mode="rise")
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(1) m.submodules.lane = lane = serdes.lane #lane = serdes.lane m.d.comb += [ # serdes.txd.eq(K(28,5)), #lane.rx.eq(1), Crucial? lane.rx_invert.eq(0), lane.rx_align.eq(1), ] #m.domains.sync = ClockDomain() m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ #ClockSignal("sync").eq(serdes.refclk), ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] cntr = Signal(5) with m.If(cntr == 0): m.d.tx += lane.tx_symbol.eq(Ctrl.COM) with m.Elif(cntr == 1): m.d.tx += lane.tx_symbol.eq(Ctrl.SKP) with m.Elif(cntr == 2): m.d.tx += lane.tx_symbol.eq(Ctrl.SKP) with m.Elif(cntr == 3): m.d.tx += lane.tx_symbol.eq(Ctrl.SKP) with m.Elif(cntr == 4): m.d.tx += lane.tx_symbol.eq(Ctrl.STP) with m.Elif(cntr[2:] == 2): m.d.tx += lane.tx_symbol.eq(Ctrl.EDB) with m.Elif(cntr[2:] == 3): m.d.tx += lane.tx_symbol.eq(Ctrl.EIE) with m.Elif(cntr[2:] == 4): m.d.tx += lane.tx_symbol.eq(Ctrl.END) with m.Elif(cntr[2:] == 5): m.d.tx += lane.tx_symbol.eq(Ctrl.IDL) with m.Else(): m.d.tx += lane.tx_symbol.eq(cntr) m.d.tx += cntr.eq(cntr + 1) #with m.FSM(domain="tx"): # with m.State("1"): # m.d.tx += lane.tx_symbol.eq(Ctrl.COM) # m.next = "2" # with m.State("2"): # m.d.tx += lane.tx_symbol.eq(Ctrl.SKP) # m.d.tx += cntr.eq(cntr + 1) # with m.If(cntr == 3): # m.d.tx += cntr.eq(0) # m.next = "1" platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) #refclkcounter = Signal(32) #m.d.sync += refclkcounter.eq(refclkcounter + 1) #rxclkcounter = Signal(32) #m.d.rx += rxclkcounter.eq(rxclkcounter + 1) #txclkcounter = Signal(32) #m.d.tx += txclkcounter.eq(txclkcounter + 1) led_att1 = platform.request("led", 0) led_att2 = platform.request("led", 1) led_sta1 = platform.request("led", 2) led_sta2 = platform.request("led", 3) led_err1 = platform.request("led", 4) led_err2 = platform.request("led", 5) led_err3 = platform.request("led", 6) led_err4 = platform.request("led", 7) m.d.rx += lane.det_enable.eq(1) m.d.comb += [ led_att2.eq(~(serdes.lane.rx_aligned)), led_err1.eq(~(serdes.lane.rx_present)), led_err2.eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)), led_err3.eq(~(lane.det_valid)), #serdes.rxde0)), led_err4.eq(~(lane.det_status)), #serdes.rxce0)), ] triggered = Signal(reset=1) #m.d.tx += triggered.eq((triggered ^ ((lane.rx_symbol[0:9] == Ctrl.EIE) | (lane.rx_symbol[9:18] == Ctrl.EIE)))) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart #m.d.rx += lane.tx_e_idle.eq(1) debug = UARTDebugger(uart, 2, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6)), "rx", triggered) # lane.rx_present & lane.rx_locked) m.submodules += debug return m
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = LatticeECP5PCIeSERDESx4( speed_5GTps=False, CH=0) m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner( serdes.lane)) m.d.comb += [ lane.rx_invert.eq(0), lane.rx_align.eq(1), ] #m.domains.sync = ClockDomain() m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ #ClockSignal("sync").eq(serdes.refclk), ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] cntr = Signal(1) with m.If(cntr[0]): m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM) m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) m.d.tx += lane.tx_symbol[18:27].eq(Ctrl.SKP) m.d.tx += lane.tx_symbol[27:36].eq(Ctrl.SKP) with m.Else(): m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL) m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL) m.d.tx += lane.tx_symbol[18:27].eq(Ctrl.IDL) m.d.tx += lane.tx_symbol[27:36].eq(Ctrl.IDL) m.d.tx += cntr.eq(cntr + 1) platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) leds = [] for i in range(8): leds.append(platform.request("led", i)) m.d.rx += Cat(leds).eq(lane.rx_symbol[0:8] ^ lane.rx_symbol[8:16] ^ lane.rx_symbol[16:24] ^ lane.rx_symbol[24:32] ^ Cat(lane.rx_symbol[32:36], Signal(4))) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart #m.d.rx += lane.tx_e_idle.eq(1) debug = UARTDebugger( uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_valid[0], Signal(6), lane.rx_symbol[9:18], lane.rx_valid[1], Signal(6), lane.rx_symbol[18:27], lane.rx_valid[2], Signal(6), lane.rx_symbol[27:36], lane.rx_valid[3], Signal(6)), "rx") m.submodules += debug return m
def elaborate(self, platform): platform.add_resources([ Resource( "pcie_x1", 0, Subsignal("perst", Pins("A6"), Attrs(IO_TYPE="LVCMOS33")), ) ]) m = Module() uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) cd_serdes = ClockDomain() m.domains += cd_serdes m.domains.gearout = ClockDomain() serdes = LatticeECP5PCIeSERDES() #aligner = DomainRenamer("rx")(PCIeSERDESAligner(serdes.lane)) # The lane dout = Signal(4 * 4 * 12) m.submodules += DomainRenamer("rx")( Resizer( Cat( #Signal(9, reset=0xFE), Signal(6, reset=0), Signal(1, reset=1), Signal(8,reset=0), #Signal(9, reset=0xDC), Signal(6, reset=0), Signal(1, reset=1), Signal(8,reset=2), serdes.lane.rx_symbol.word_select(0, 9), Signal(6, reset=0), serdes.lane.rx_valid[0], serdes.lane.det_valid, serdes.lane.det_status, serdes.lane.rx_present, serdes.lane.rx_locked, serdes.lane.rx_aligned, Signal(3), serdes.lane.rx_symbol.word_select(1, 9), Signal(6, reset=0), serdes.lane.rx_valid[1], Signal(8, reset=0x11), ), dout, ClockSignal("gearout"))) platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) # Arduino tx m.d.comb += platform.request("test").o.eq(ClockSignal("gearout")) debug = UARTDebugger( uart, 24, 1000, dout, "gearout") # serdes.lane.rx_present & serdes.lane.rx_locked) m.submodules += [ uart, serdes, # aligner, debug, ] m.d.comb += [ cd_serdes.clk.eq(serdes.rx_clk_o), serdes.rx_clk_i.eq(cd_serdes.clk), serdes.tx_clk_i.eq(cd_serdes.clk), serdes.lane.rx_align.eq(1), serdes.lane.tx_symbol.eq(K(28, 3)), serdes.lane.rx_invert.eq(0), #aligner.rx_align.eq(1), serdes.lane.det_enable.eq(0), ] m.d.sync += platform.request("led", 0).o.eq(~serdes.lane.det_valid) m.d.sync += platform.request("led", 1).o.eq(~serdes.lane.det_status) m.d.sync += platform.request("led", 2).o.eq(~serdes.lane.rx_present) m.d.sync += platform.request("led", 3).o.eq(~serdes.lane.rx_locked) m.d.sync += platform.request("led", 4).o.eq(~serdes.lane.rx_aligned) m.d.sync += platform.request("led", 5).o.eq(~(serdes.lane.rx_locked)) m.d.sync += platform.request("led", 6).o.eq(~(serdes.lane.tx_locked)) m.d.sync += platform.request("led", 7).o.eq(~1) #with m.FSM(): # with m.State("start"): # m.next = "a" # with m.State("a"): # m.d.sync += serdes.lane.det_enable.eq(0) return m
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(2) m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner( serdes.lane)) m.d.comb += [ lane.rx_invert.eq(0), lane.rx_align.eq(1), ] m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) led_att1 = platform.request("led", 0) led_att2 = platform.request("led", 1) led_sta1 = platform.request("led", 2) led_sta2 = platform.request("led", 3) led_err1 = platform.request("led", 4) led_err2 = platform.request("led", 5) led_err3 = platform.request("led", 6) led_err4 = platform.request("led", 7) #m.d.comb += [ # led_att1.eq(~(ClockSignal("rx") ^ ClockSignal("tx"))), #] count = Signal() refclkcounter = Signal(64) txclkcounter = Signal(64) rxclkcounter = Signal(64) with m.If(count): m.d.sync += refclkcounter.eq(refclkcounter + 1) m.d.tx += txclkcounter.eq(txclkcounter + 1) m.d.rx += rxclkcounter.eq(rxclkcounter + 1) counter = Signal(16) sample = Signal() with m.FSM(): with m.State("Wait"): m.d.sync += count.eq(1) m.d.sync += counter.eq(counter + 1) with m.If(counter == 0xFFFF): m.d.sync += count.eq(0) m.d.sync += counter.eq(0) m.next = "Sample Delay" with m.State("Sample Delay"): m.d.sync += counter.eq(counter + 1) with m.If(counter == 0xF): m.d.sync += counter.eq(0) m.next = "Sample" with m.State("Sample"): m.d.sync += sample.eq(1) m.next = "Sample After Delay" with m.State("Sample After Delay"): m.d.sync += sample.eq(0) m.d.sync += counter.eq(counter + 1) with m.If(counter == 0xF): m.d.sync += counter.eq(0) m.next = "Wait" uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart debug = UARTDebugger(uart, 8 * 3, CAPTURE_DEPTH, Cat(refclkcounter, txclkcounter, rxclkcounter), "sync", sample) # lane.rx_present & lane.rx_locked) m.submodules += debug return m
def test_write(self): pins = Record([("rx", pin_layout(1, dir="i")), ("tx", pin_layout(1, dir="o"))]) dut = UARTBridge(divisor=self.divisor, pins=pins) serial = AsyncSerial(divisor=self.divisor) m = Module() m.submodules.bridge = dut m.submodules.serial = serial m.d.comb += [ pins.rx.i.eq(serial.tx.o), serial.rx.i.eq(pins.tx.o), ] def process(): # Send write command yield from serial_write(serial, 0x01) yield # Length = 1 yield from serial_write(serial, 0x01) yield # Send 0x4000 as address yield from serial_write(serial, 0x00) yield yield from serial_write(serial, 0x00) yield yield from serial_write(serial, 0x40) yield yield from serial_write(serial, 0x00) yield # Send 0xFEEDFACE as value yield from serial_write(serial, 0xFE) yield yield from serial_write(serial, 0xED) yield yield from serial_write(serial, 0xFA) yield yield from serial_write(serial, 0xCE) # Handle wishbone request timeout = 0 while not (yield dut.bus.cyc): yield timeout += 1 if timeout > self.timeout: raise RuntimeError("Simulation timed out") # Ensure Wishbone address is the one we asked for self.assertEqual((yield dut.bus.adr), 0x00004000) self.assertEqual((yield dut.bus.dat_w), 0xFEEDFACE) self.assertTrue((yield dut.bus.we)) # Answer yield dut.bus.ack.eq(1) yield sim = Simulator(m) with sim.write_vcd("test_uartbridge.vcd"): sim.add_clock(1e-6) sim.add_sync_process(process) sim.run()
def elaborate(self, platform): m = Module() m.submodules.serial = serial = AsyncSerial(divisor=self._divisor, pins=self._pins) address_width = 32 data_width = 32 cmd = Signal(8) length = Signal(8) address = Signal(address_width) data = Signal(data_width) bytes_count = Signal(range(data_width // 8)) words_count = Signal(8) m.d.comb += [ self.bus.dat_w.eq(data), self.bus.adr.eq(address), ] with m.FSM(): with m.State("Receive-Cmd"): m.d.comb += serial.rx.ack.eq(1) # Reset registers m.d.sync += [ bytes_count.eq(data_width // 8 - 1), words_count.eq(0), ] with m.If(serial.rx.rdy): m.d.sync += cmd.eq(serial.rx.data) m.next = "Receive-Length" with m.State("Receive-Length"): m.d.comb += serial.rx.ack.eq(1) with m.If(serial.rx.rdy): m.d.sync += length.eq(serial.rx.data) m.next = "Receive-Address" with m.State("Receive-Address"): m.d.comb += serial.rx.ack.eq(1) with m.If(serial.rx.rdy): m.d.sync += [ address.eq(Cat(serial.rx.data, address)), bytes_count.eq(bytes_count - 1), ] with m.If(bytes_count == 0): with m.Switch(cmd): with m.Case(0x01): m.next = "Handle-Write" with m.Case(0x02): m.next = "Handle-Read" with m.Case(): m.next = "Receive-Cmd" with m.State("Handle-Write"): m.d.comb += serial.rx.ack.eq(1) with m.If(serial.rx.rdy): m.d.sync += [ data.eq(Cat(serial.rx.data, data)), bytes_count.eq(bytes_count - 1), ] with m.If(bytes_count == 0): m.next = "Write-Data" with m.State("Write-Data"): m.d.comb += [ self.bus.stb.eq(1), self.bus.we.eq(1), self.bus.cyc.eq(1), self.bus.sel.eq(0xF), ] with m.If(self.bus.ack): m.next = "Receive-Cmd" with m.State("Handle-Read"): m.d.comb += [ self.bus.stb.eq(1), self.bus.we.eq(0), self.bus.cyc.eq(1), self.bus.sel.eq(0xF), ] with m.If(self.bus.ack): m.d.sync += [ bytes_count.eq(data_width // 8 - 1), data.eq(self.bus.dat_r), ] m.next = "Send-Data" with m.State("Send-Data"): m.d.comb += serial.tx.ack.eq(1) with m.Switch(bytes_count): for i in range(data_width // 8): with m.Case(i): m.d.comb += serial.tx.data.eq(data[i * 8:(i + 1) * 8]) with m.If(serial.tx.rdy): m.next = "Send-Data-Wait" with m.State("Send-Data-Wait"): with m.If(serial.tx.rdy): m.d.sync += [ bytes_count.eq(bytes_count - 1), ] with m.If(bytes_count == 0): m.next = "Receive-Cmd" with m.Else(): m.next = "Send-Data" return m
def elaborate(self, platform): m = Module() gearing = 1 m.submodules.serdes = serdes = LatticeECP5PCIeSERDES( gearing) # Declare SERDES module with 1:2 gearing lane = serdes.lane m.d.comb += lane.tx_e_idle.eq(0) m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] # Clock outputs for the RX and TX clock domain platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) # Counters for the LEDs refclkcounter = Signal(32) m.d.sync += refclkcounter.eq(refclkcounter + 1) rxclkcounter = Signal(32) m.d.rx += rxclkcounter.eq(rxclkcounter + 1) txclkcounter = Signal(32) m.d.tx += txclkcounter.eq(txclkcounter + 1) old_rx = Signal(8) m.d.sync += old_rx.eq(Cat(lane.rx_symbol[0:8])) tx_symbol = Signal(9, reset=56) timer = Signal(32) fftest_a = Signal(32) fftest_b = Signal(32) fftest_a_last = Signal(32) slipcnt = Signal(5) lastslip = Signal() m.d.rx += serdes.slip.eq(rxclkcounter[2]) m.d.sync += lastslip.eq(serdes.slip) with m.If(serdes.slip & ~lastslip): with m.If(slipcnt < (10 * gearing - 1)): m.d.sync += slipcnt.eq(slipcnt + 1) with m.Else(): m.d.sync += slipcnt.eq(0) leds = Cat(platform.request("led", i) for i in range(8)) m.d.comb += leds[0].eq(~serdes.lane.rx_locked) m.d.comb += leds[1].eq(~serdes.lane.rx_present) #m.submodules += FFSynchronizer(fftest_a, fftest_b, o_domain="tx") with m.FSM(): #with m.State("Align"): # m.d.rx += fftest_a.eq(~fftest_a) # m.d.rx += timer.eq(timer + 1) # m.d.rx += fftest_a_last.eq(fftest_a) # m.d.tx += fftest_b.eq(fftest_a) # # with m.If(fftest_b != fftest_a_last): # m.d.rx += timer.eq(0) # # m.d.rx += serdes.slip.eq(rxclkcounter[10]) # # with m.If(timer == 128): # m.next = "BERTest" # # # m.next = "BERTest" with m.State("Align2"): last_rxclkcounter = Signal(32) m.d.rx += last_rxclkcounter.eq(rxclkcounter) m.d.rx += timer.eq(timer + 1) m.d.rx += tx_symbol.eq(Ctrl.STP) cond = (Cat(lane.rx_symbol[0:9]) == Ctrl.STP) & (Cat( lane.rx_symbol[9:18]) == Ctrl.COM) with m.If( rxclkcounter[8] & ~last_rxclkcounter[8] ): #~((Cat(lane.rx_symbol[0:9]) - old_rx == 0) | (Cat(lane.rx_symbol[0:9]) - old_rx == -2))) with m.If(cond): m.d.rx += timer.eq(0) m.next = "BERTest" with m.Else(): pass #m.d.rx += serdes.slip.eq(~serdes.slip) # Invert Lane if too long errored m.d.rx += lane.rx_invert.eq(timer[16]) with m.State("BERTest"): m.d.rx += lane.tx_disp.eq(0) #m.d.rx += lane.tx_set_disp.eq(1) m.d.rx += timer.eq(timer + 1) m.d.rx += tx_symbol.eq(Cat(timer[0:8], 0)) m.d.rx += lane.rx_invert.eq(1) #m.d.rx += tx_symbol.eq(tx_symbol + 1) commacnt = Signal(3) #m.d.sync += commacnt.eq(commacnt + 1) with m.If(commacnt == 6): m.d.sync += commacnt.eq(0) #m.d.comb += Cat(serdes.lane.tx_symbol[0:9]).eq(Mux(commacnt == 2, Ctrl.COM, Ctrl.STP))#(tx_symbol) m.d.comb += Cat(serdes.lane.tx_symbol[0:9]).eq(0b101010101) m.d.comb += Cat(serdes.lane.tx_symbol[9:18]).eq(Ctrl.COM) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart m.d.sync += lane.rx_align.eq(1) #debug = UARTDebugger(uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6), lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1], Signal(6), # lane.tx_symbol[0:9], Signal(7), lane.tx_symbol[9:18], Signal(7)), "rx") #debug = UARTDebugger(uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6), lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1], Signal(6), # serdes.tx_bus_s_2[0:9], Signal(7), serdes.tx_bus_s_2[12:21], Signal(7)), "rx") #debug = UARTDebugger(uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6+9), lane.rx_valid[0], Signal(6), # serdes.tx_bus_s_2[0:9], Signal(7+9), Signal(7)), "rx") #debug = UARTDebugger(uart, 9, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6+9), lane.rx_valid[0], Signal(6), # serdes.tx_bus[0:9], Signal(7+9), Signal(7), Cat(slipcnt, lane.rx_present, lane.rx_locked, lane.rx_valid)), "rx") debug = UARTDebugger( uart, 9, CAPTURE_DEPTH, Cat(serdes.rx_bus[0:10], lane.rx_aligned, Signal(5 + 9), lane.rx_valid[0], Signal(6), serdes.tx_bus[0:10], Signal(6 + 9), Signal(7), Cat(slipcnt, lane.rx_present, lane.rx_locked, lane.rx_valid)), "rx") m.submodules += debug return m
def elaborate(self, platform: Platform) -> Module: m = Module() # UART pins for the AsyncSerial, is needed for doing output enable uart_pins = Record([("rx", [("i", 1)]), ("tx", [("o", 1)])]) # Add the UART resources of the ROCKPro64 platform.add_resources( [Resource("rx_rp64", 0, Pins(self.rx, dir="i"))]) platform.add_resources( [Resource("tx_rp64", 0, Pins(self.tx, dir="oe"))]) rx_pin = platform.request("rx_rp64", 0) tx_pin = platform.request("tx_rp64", 0) m.d.comb += uart_pins.rx.i.eq(rx_pin.i) m.d.comb += tx_pin.o.eq(uart_pins.tx.o) # ROCKPro64 refuses to boot if this is high enable_tx = Signal() m.d.comb += tx_pin.oe.eq(enable_tx) # 1.5 Megabaud UART to the ROCKPro64 uart = AsyncSerial(divisor=int(self.clk / 1.5E6), pins=uart_pins) m.submodules += uart # Send 0x03 (Ctrl C) until the u-boot prompt appears (might take quite a while because apparently it seems to try to connect to the network interface for a long time) # Send 'pci enum' once '=>' is received and init is asserted # Set init_sent to high for 1 cycle after '\n' has been sent # Turn a string into a list of bytes def generate_memory(data_string): result = [] for char in data_string: result.append(ord(char)) return result # Command to send. Don't forget to change depth when changing this command. depth = 10 pci_mem = Memory(width=8, depth=depth, init=generate_memory(' pci enum\n')) pci_rport = m.submodules.pci_rport = pci_mem.read_port() # Hardwired to 1, since boot is not yet controlled m.d.comb += enable_tx.eq(1) # We can always accept data m.d.comb += uart.rx.ack.eq(1) with m.FSM(): with m.State("Wait"): m.d.sync += [ uart.tx.data.eq(0x03), # Spam Ctrl C uart.tx.ack.eq(1), ] # Wait for '=>' with m.If(uart.rx.data == ord('=')): m.next = "uboot-1" with m.State("uboot-1"): m.d.sync += self.init_sent.eq(0) with m.If(uart.rx.data == ord('>')): m.next = "uboot-2" # Arrived at u-boot prompt, ready to sent, waiting for init signal with m.State("uboot-2"): m.d.sync += self.rdy.eq(1) with m.If(self.init): m.next = "send-pci-start" # Go! Set the UART data to what the memory outputs. with m.State("send-pci-start"): m.d.sync += [ self.rdy.eq(0), uart.tx.data.eq(pci_rport.data), pci_rport.addr.eq(0), ] # Once the TX is ready, send data with m.If(uart.tx.rdy): m.next = "send-pci-data" with m.State("send-pci-data"): m.d.sync += uart.tx.data.eq(pci_rport.data) m.d.sync += uart.tx.ack.eq(uart.tx.rdy) # When the TX stops being ready, set the next byte. Doesn't work with 'Rose'. with m.If(Fell(uart.tx.rdy)): m.d.sync += pci_rport.addr.eq(pci_rport.addr + 1) # Once all data has been sent, go back to waiting for '>' and strobe init_sent. with m.If((pci_rport.addr == depth - 1)): m.next = "uboot-1" m.d.sync += self.init_sent.eq(1) uart_pins = platform.request("uart", 0) #m.d.comb += uart_pins.tx.o.eq(tx_pin.o) m.d.comb += uart_pins.tx.o.eq(rx_pin.i) return m
def elaborate(self, platform): m = Module() # Received symbols are aligned and processed by the PCIePhyRX # The PCIePhyTX sends symbols to the SERDES m.submodules.serdes = serdes = LatticeECP5PCIeSERDESx2( ) # Declare SERDES module with 1:2 gearing m.submodules.aligner = aligner = DomainRenamer("rx")(PCIeSERDESAligner( serdes.lane)) # Aligner for aligning COM symbols m.submodules.scrambler = lane = PCIeScrambler( aligner) # Aligner for aligning COM symbols #lane = serdes.lane # Aligner for aligning COM symbols m.submodules.phy_rx = phy_rx = PCIePhyRX(aligner, lane) m.submodules.phy_tx = phy_tx = PCIePhyTX(lane) #m.submodules.lfsr = lfsr = PCIeLFSR(0, 1) #m.submodules.phy_txfake = phy_txfake = PCIePhyTX(PCIeSERDESInterface(ratio = 2)) # Link Status Machine to test #m.submodules.ltssm = ltssm = PCIeLTSSM(lane, phy_tx, phy_rx) m.submodules.ltssm = ltssm = PCIeLTSSM(lane, phy_tx, phy_rx) #m.d.comb += [ # phy_tx.ts.eq(0), # phy_tx.ts.valid.eq(1), # phy_tx.ts.rate.eq(1), # phy_tx.ts.ctrl.eq(0) #] m.d.rx += lane.enable.eq(ltssm.status.link.scrambling & ~phy_tx.sending_ts) m.d.comb += [ #lane.rx_invert.eq(0), serdes.lane.rx_align.eq(1), ] m.d.comb += [ #lane.rx_invert.eq(0), lane.rx_align.eq(1), ] # Declare the RX and TX clock domain, most of the logic happens in the RX domain m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] # Clock outputs for the RX and TX clock domain #platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) #m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) #platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) #m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) # Counters for the LEDs refclkcounter = Signal(32) m.d.sync += refclkcounter.eq(refclkcounter + 1) rxclkcounter = Signal(32) m.d.rx += rxclkcounter.eq(rxclkcounter + 1) txclkcounter = Signal(32) m.d.tx += txclkcounter.eq(txclkcounter + 1) #m.d.rx += serdes.slip.eq(rxclkcounter[25]) ## Sample temperature once a second #m.d.sync += dtr.start.eq(refclkcounter[25]) # Temperature sensor, the chip gets kinda hot sample = Signal() m.d.sync += sample.eq(refclkcounter[25]) m.submodules.dtr = dtr = DTR(start=refclkcounter[25] & ~sample) # Can be used to count how many cycles det_status is on, currently unused detstatuscounter = Signal(7) with m.If(lane.det_valid & lane.det_status): m.d.tx += detstatuscounter.eq(detstatuscounter + 1) leds = Cat(platform.request("led", i) for i in range(8)) leds_alnum = Cat(platform.request("alnum_led", 0)) # Information LEDs, first three output the clock frequency of the clock domains divided by 2^26 #m.d.comb += [ # leds[0].eq(~(refclkcounter[25])), # leds[2].eq(~(rxclkcounter[25])), # leds[3].eq(~(txclkcounter[25])), # leds[1].eq(~(serdes.lane.rx_aligned)), # leds[4].eq(~(serdes.lane.rx_present)), # leds[5].eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)), # leds[6].eq(~(0)),#serdes.rxde0)), # leds[7].eq(~(ltssm.status.link.up)),#serdes.rxce0)), #] m.d.comb += leds_alnum.eq(ltssm.debug_state) m.d.comb += leds.eq(~ltssm.debug_state) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart # In the default mode, there are some extra words for debugging data debug1 = Signal(16) debug2 = Signal(16) debug3 = Signal(16) debug4 = Signal(16) # For example data from the LTSSM m.d.comb += debug1.eq(ltssm.tx_ts_count) m.d.comb += debug2.eq(ltssm.rx_ts_count) # Or data about TSs m.d.comb += debug3.eq( Cat(phy_rx.ts.valid, phy_rx.ts.lane.valid, phy_rx.ts.link.valid, phy_rx.ts.ts_id)) m.d.comb += debug4.eq(1234) if NO_DEBUG: pass if self.tstest: # l = Link Number, L = Lane Number, v = Link Valid, V = Lane Valid, t = TS Valid, T = TS ID, n = FTS count, r = TS.rate, c = TS.ctrl, d = lane.det_status, D = lane.det_valid # DdTcccccrrrrrrrrnnnnnnnnLLLLLtVvllllllll debug = UARTDebugger( uart, 5, CAPTURE_DEPTH, Cat(phy_rx.ts.link.number, phy_rx.ts.link.valid, phy_rx.ts.lane.valid, phy_rx.ts.valid, phy_rx.ts.lane.number, phy_rx.ts.n_fts, phy_rx.ts.rate, phy_rx.ts.ctrl, phy_rx.ts.ts_id, lane.det_status, lane.det_valid), "rx") # lane.rx_present & lane.rx_locked) #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(ts.link.number, ts.link.valid, ts.lane.valid, ts.valid, ts.lane.number, ts.n_fts, ts.rate, ts.ctrl, ts.ts_id, Signal(2)), "rx") # lane.rx_present & lane.rx_locked) #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(Signal(8, reset=123), Signal(4 * 8)), "rx") # lane.rx_present & lane.rx_locked) elif STATE_TEST: # 32t 9R 9R 9T 9T 2v 2- # t = Ticks since state was entered # R = RX symbol # T = TX symbol # v = RX valid time_since_state = Signal(32) with m.If(ltssm.debug_state != TESTING_STATE): m.d.rx += time_since_state.eq(0) with m.Else(): m.d.rx += time_since_state.eq(time_since_state + 1) #m.d.rx += time_since_state.eq(ltssm.status.link.scrambling) #m.d.rx += time_since_state.eq(ltssm.rx_idl_count_total) #m.d.rx += time_since_state.eq(Cat(phy_rx.inverted, lane.rx_invert)) debug = UARTDebugger( uart, 9, CAPTURE_DEPTH, Cat(time_since_state, lane.rx_symbol, lane.tx_symbol, lane.rx_locked & lane.rx_present & lane.rx_aligned, lane.rx_locked & lane.rx_present & lane.rx_aligned, Signal(2)), "rx" ) #, (ltssm.debug_state == TESTING_STATE) & (time_since_state < CAPTURE_DEPTH), timeout=100 * 1000 * 1000) elif FSM_LOG: # Keep track of time in 8 nanosecond increments time = Signal(64) m.d.rx += time.eq(time + 1) # Real time in 10 ns ticks, doesnt drift or change in frequency as compared to the RX clock domain. realtime = Signal(64) m.d.sync += realtime.eq(realtime + 1) # Real time FF sync realtime_rx = Signal(64) m.submodules += FFSynchronizer(realtime, realtime_rx, o_domain="rx") last_state = Signal(8) m.d.rx += last_state.eq(ltssm.debug_state) # 8o 8c 64t 64r 32i 6T 1v 1- 8l 5L o O 1- # o = old state, c = current state, t = time, r = realtime, i = idle count, T = temperature, v = temperature valid, - = empty, l = link, L = lane, o = link valid, O = lane valid # preceding number is number of bits debug = UARTDebugger(uart, 25, CAPTURE_DEPTH, Cat(last_state, ltssm.debug_state, time, realtime_rx, Signal(32), dtr.temperature, Signal(1), dtr.valid, phy_rx.ts.link.number, phy_rx.ts.lane.number, phy_rx.ts.link.valid, phy_rx.ts.lane.valid, Signal(1)), "rx", ltssm.debug_state != last_state, timeout=100 * 1000 * 1000) else: # ssssssss sa000000 ssssssss sb000000 llllllll SSSSSSSS S0000000 SSSSSSSS S0000000 dddddddd dddddddd dddddddd dddddddd dddddddd dddddddd dddddddd dddddddd s = rx_symbol, S = tx_symbol, a = aligned, b = valid, l = ltssm state, d = debug debug = UARTDebugger(uart, 17, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6), lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1], Signal(6), ltssm.debug_state, lane.tx_symbol[0:9], Signal(7), lane.tx_symbol[9:18], Signal(7), debug1, debug2, debug3, debug4), "rx") # lane.rx_present & lane.rx_locked) m.submodules += debug return m
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(2) m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner( serdes.lane)) m.submodules.phy_rx = phy_rx = PCIePhyRX(lane) #lane = serdes.lane m.d.comb += [ # serdes.txd.eq(K(28,5)), #lane.rx.eq(1), Crucial? lane.rx_invert.eq(0), lane.rx_align.eq(1), ] #m.domains.sync = ClockDomain() m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ #ClockSignal("sync").eq(serdes.refclk), ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] cntr = Signal(8) #m.d.tx += lane.tx_symbol.eq(Ctrl.IDL) with m.FSM(domain="tx"): with m.State("1"): m.d.tx += lane.tx_symbol.eq(Ctrl.COM) m.next = "2" with m.State("2"): m.d.tx += lane.tx_symbol.eq(Ctrl.SKP) m.d.tx += cntr.eq(cntr + 1) with m.If(cntr == 3): m.d.tx += cntr.eq(0) m.next = "1" platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) refclkcounter = Signal(32) m.d.sync += refclkcounter.eq(refclkcounter + 1) rxclkcounter = Signal(32) m.d.rx += rxclkcounter.eq(rxclkcounter + 1) txclkcounter = Signal(32) m.d.tx += txclkcounter.eq(txclkcounter + 1) led_att1 = platform.request("led", 0) led_att2 = platform.request("led", 1) led_sta1 = platform.request("led", 2) led_sta2 = platform.request("led", 3) led_err1 = platform.request("led", 4) led_err2 = platform.request("led", 5) led_err3 = platform.request("led", 6) led_err4 = platform.request("led", 7) m.d.rx += lane.det_enable.eq(1) m.d.comb += [ led_att1.eq(~(refclkcounter[25])), led_att2.eq(~(serdes.lane.rx_aligned)), led_sta1.eq(~(rxclkcounter[25])), led_sta2.eq(~(txclkcounter[25])), led_err1.eq(~(serdes.lane.rx_present)), led_err2.eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)), led_err3.eq(~(lane.det_valid)), #serdes.rxde0)), led_err4.eq(~(lane.det_status)), #serdes.rxce0)), ] triggered = Signal(reset=1) #m.d.tx += triggered.eq((triggered ^ ((lane.rx_symbol[0:9] == Ctrl.EIE) | (lane.rx_symbol[9:18] == Ctrl.EIE)))) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart m.d.rx += lane.tx_e_idle.eq(1) if self.tstest: # l = Link Number, L = Lane Number, v = Link Valid, V = Lane Valid, t = TS Valid, T = TS ID, n = FTS count, r = TS.rate, c = TS.ctrl, d = lane.det_status, D = lane.det_valid # DdTcccccrrrrrrrrnnnnnnnnLLLLLtVvllllllll debug = UARTDebugger( uart, 5, CAPTURE_DEPTH, Cat(phy_rx.ts.link.number, phy_rx.ts.link.valid, phy_rx.ts.lane.valid, phy_rx.ts.valid, phy_rx.ts.lane.number, phy_rx.ts.n_fts, phy_rx.ts.rate, phy_rx.ts.ctrl, phy_rx.ts.ts_id, lane.det_status, lane.det_valid), "rx") # lane.rx_present & lane.rx_locked) #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(ts.link.number, ts.link.valid, ts.lane.valid, ts.valid, ts.lane.number, ts.n_fts, ts.rate, ts.ctrl, ts.ts_id, Signal(2)), "rx") # lane.rx_present & lane.rx_locked) #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(Signal(8, reset=123), Signal(4 * 8)), "rx") # lane.rx_present & lane.rx_locked) else: debug = UARTDebugger( uart, 4, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6), lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1], Signal(6)), "rx", triggered) # lane.rx_present & lane.rx_locked) m.submodules += debug return m
def elaborate(self, platform): # VGA constants pixel_f = self.timing.pixel_freq hsync_front_porch = self.timing.h_front_porch hsync_pulse_width = self.timing.h_sync_pulse hsync_back_porch = self.timing.h_back_porch vsync_front_porch = self.timing.v_front_porch vsync_pulse_width = self.timing.v_sync_pulse vsync_back_porch = self.timing.v_back_porch # Pins clk25 = platform.request("clk25") ov7670 = platform.request("ov7670") led = [platform.request("led", i) for i in range(8)] leds = Cat([i.o for i in led]) led8_2 = platform.request("led8_2") leds8_2 = Cat([led8_2.leds[i] for i in range(8)]) led8_3 = platform.request("led8_3") leds8_3 = Cat([led8_3.leds[i] for i in range(8)]) leds16 = Cat(leds8_3, leds8_2) btn1 = platform.request("button_fire", 0) btn2 = platform.request("button_fire", 1) up = platform.request("button_up", 0) down = platform.request("button_down", 0) pwr = platform.request("button_pwr", 0) left = platform.request("button_left", 0) right = platform.request("button_right", 0) sw = Cat([platform.request("switch",i) for i in range(4)]) uart = platform.request("uart") divisor = int(platform.default_clk_frequency // 460800) esp32 = platform.request("esp32_spi") csn = esp32.csn sclk = esp32.sclk copi = esp32.copi cipo = esp32.cipo m = Module() # Clock generator. m.domains.sync = cd_sync = ClockDomain("sync") m.domains.pixel = cd_pixel = ClockDomain("pixel") m.domains.shift = cd_shift = ClockDomain("shift") m.submodules.ecp5pll = pll = ECP5PLL() pll.register_clkin(clk25, platform.default_clk_frequency) pll.create_clkout(cd_sync, platform.default_clk_frequency) pll.create_clkout(cd_pixel, pixel_f) pll.create_clkout(cd_shift, pixel_f * 5.0 * (1.0 if self.ddr else 2.0)) # Add CamRead submodule camread = CamRead() m.submodules.camread = camread # Camera config cam_x_res = 640 cam_y_res = 480 camconfig = CamConfig() m.submodules.camconfig = camconfig # OV7670 options: bit 0 = color bar ov_opts = Signal(8, reset=0) ov_brightness = Signal(8, reset=0) ov_contrast = Signal(8, reset=0x40) # Connect the camera pins and config and read modules m.d.comb += [ ov7670.cam_RESET.eq(1), ov7670.cam_PWON.eq(0), ov7670.cam_XCLK.eq(clk25.i), ov7670.cam_SIOC.eq(camconfig.sioc), ov7670.cam_SIOD.eq(camconfig.siod), camconfig.start.eq(btn1), camconfig.options.eq(ov_opts), camconfig.brightness.eq(ov_brightness), camconfig.contrast.eq(ov_contrast), camread.p_data.eq(Cat([ov7670.cam_data[i] for i in range(8)])), camread.href.eq(ov7670.cam_HREF), camread.vsync.eq(ov7670.cam_VSYNC), camread.p_clock.eq(ov7670.cam_PCLK) ] # Create the uart m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart) # Frame buffer x_res= cam_x_res // 2 y_res= cam_y_res // 2 buffer = Memory(width=16, depth=x_res * y_res) m.submodules.r = r = buffer.read_port() m.submodules.w = w = buffer.write_port() # Button debouncers m.submodules.debup = debup = Debouncer() m.submodules.debdown = debdown = Debouncer() m.submodules.debosd = debosd = Debouncer() m.submodules.debsel = debsel = Debouncer() m.submodules.debsnap = debsnap = Debouncer() m.submodules.debhist = debhist = Debouncer() # Connect the buttons to debouncers m.d.comb += [ debup.btn.eq(up), debdown.btn.eq(down), debosd.btn.eq(pwr), debsel.btn.eq(right), debsnap.btn.eq(left), debhist.btn.eq(btn2) ] # Image processing configuration registers flip = Signal(2, reset=1) # Flip the image horizontally or vertically mono_en = Signal(reset=0) # Convert to monochrome invert = Signal(reset=0) # Invert monochrome image thresh_en = Signal(reset=0) # Apply threshold to monochrome image threshold = Signal(8, reset=0) # Threshold value border = Signal(reset=0) # Use OSD to show a border filt_en = Signal(reset=0) # Apply a color filter l = Rgb565(reset=(18,12,6)) # Image filter low values h = Rgb565(reset=(21,22,14)) # Image filter high values grid = Signal(reset=0) # Use OSD to show a grid hist_view = Signal(reset=1) # Switch to histogram view hist_chan = Signal(2, reset=0) # The histogram channel to calculate ccr = CC(reset=(0,0,18,12,16)) # Color control record sharpness = Signal(unsigned(4), reset=0) # Used to select image convolution kernel for blur/sharpness roi = Roi() # Region on interest frozen = Signal(reset=1) # Freeze/unfreeze video display sat_en = Signal() saturation = Signal(5, reset=16) border_color = Rgb565(reset=(31,0,0)) double = Signal(reset=0) square = Signal(reset=0) # Control synchronization of camera with fifo sync_fifo = Signal(reset=0) # OSD control signals osd_val = Signal(4, reset=0) # Account for spurious start-up button pushes osd_on = Signal(reset=1) osd_sel = Signal(reset=1) # Snapshot signals snap = Signal(reset=0) writing = Signal(reset=0) written = Signal(reset=0) byte = Signal(reset=0) w_addr = Signal(18) # Signals for calculating histogram hist_val = Signal(6) # Signals for displaying histogram hist_color = Signal(8) hbin = Signal(6, reset=0) bin_cnt = Signal(5, reset=0) old_x = Signal(10) # Frame buffer coordinates frame_x = Signal(9) frame_y = Signal(9) # VGA signals vga_r = Signal(8) vga_g = Signal(8) vga_b = Signal(8) vga_hsync = Signal() vga_vsync = Signal() vga_blank = Signal() # Fifo stream m.submodules.fifo_stream = fs = FifoStream(x_res = x_res, y_res = y_res, fifo_depth=1024) # SPI memory for remote configuration m.submodules.spimem = spimem = SpiMem(addr_bits=32) # Color Control m.submodules.cc = cc = ColorControl() # Image convolution m.submodules.imc = imc = ImageConv(res_x=x_res, res_y=y_res) # Statistics m.submodules.stats = stats = Stats() # Histogram m.submodules.hist = hist = Hist() # Filter m.submodules.fil = fil = Filt() # Monochrome m.submodules.mon = mon = Mono() # Saturation m.submodules.sat = sat = Saturation() # Buffer m.submodules.buf = buf = Buffer() # Double m.submodules.doub = doub = Double() # Square m.submodules.sq = sq = Square() # Border m.submodules.bord = bord = Border() # Color correction matrix m.submodules.ccm = ccm = Ccm() # Half resolution m.submodules.half = half = Half() # Sync the fifo with the camera with m.If(~sync_fifo & (camread.o_x == cam_x_res - 1) & (camread.o_y == cam_y_res -1)): m.d.sync += sync_fifo.eq(1) with m.If(btn1): m.d.sync += sync_fifo.eq(0) m.d.comb += leds16.eq(fs.o_level) # Histogram channels hist_chans = Array([cc.o.r, cc.o.g, cc.o.b, mon.o_m]) # Input image processing pipeline pipeline = [ [camread, {}, True], # Read from OV7670 Sensor [half, {"i_reset" : ~sync_fifo}, True], # Reduce resolution to 320x240 [fs, {"i_reset" : ~sync_fifo}, True], # Write data to FIFO [sq, {"i_reset" : ~sync_fifo, # Optional reduce to square "i_en" : square}, True], [doub, {"i_reset" : ~sync_fifo, # Optional zoom in horizontally "i_en" : double}, True], [cc, {"i_cc" : ccr}, True], # Apply color control [ccm, {}, True], # Apply color control matrix [sat, {"i_en" : sat_en, # Adjust color saturation "i_saturation" : saturation}, True], [fil, {"i_en" : filt_en, # Apply optional color filter "i_eof" : fs.o_eof, "i_l" : l, "i_h" : h}, True], [mon, {"i_en" : mono_en | invert | thresh_en, # Optional, monochrome, invert and threshold "i_invert" : invert, "i_thresh" : thresh_en, "i_threshold" : threshold}, True], [bord, {"i_reset" : ~sync_fifo, "i_en" : border, "i_width" : 5, "i_color" : border_color}, True], [imc, {"i_ready" : 1, # Image convolution for blur and sharpness "i_reset" : ~sync_fifo, "i_sel" : sharpness}, True], [stats, {"i" : cc.o, # Produce statistics "i_valid" : cc.o_valid, "i_avg_valid" : (fs.o_x >= 32) & (fs.o_x < 288) & (fs.o_y >= 56) & (fs.o_y < 184), "i_eof" : fs.o_eof, "i_x" : fs.o_x, "i_y" : fs.o_y, "i_roi" : roi}, False], [hist, {"i_p" : hist_chans[hist_chan], # Produce histogram "i_valid" : mon.o_valid, "i_eof" : fs.o_eof, "i_x" : fs.o_x, "i_y" : fs.o_y, "i_roi" : roi, "i_bin" : hbin}, False] ] output = imc # Connect pipeline inputs and outputs and ready and valid signals def execute(pl): us = None # Upstream for p in pl: mod = p[0] d = p[1] st = p[2] # Stream or Sink if st and us is not None: m.d.comb += mod.i.eq(us.o) m.d.comb += mod.i_valid.eq(us.o_valid) m.d.comb += us.i_ready.eq(mod.o_ready) if st: us = mod for k in d: m.d.comb += mod.__dict__[k].eq(d[k]) execute(pipeline) # Take a snapshot, freeze the camera, and write the framebuffer to the uart # Note that this suspends video output with m.If(debsnap.btn_down | (spimem.wr & (spimem.addr == 22))): with m.If(frozen): m.d.sync += frozen.eq(0) with m.Else(): m.d.sync += [ snap.eq(1), frozen.eq(0), w_addr.eq(0), written.eq(0), byte.eq(0) ] # Wait to end of frame after requesting snapshot, before start of writing to uart with m.If(output.o_eof & snap): m.d.sync += [ frozen.eq(1), snap.eq(0) ] with m.If(~written): m.d.sync += writing.eq(1) # Connect the uart m.d.comb += [ serial.tx.data.eq(Mux(byte, r.data[8:], r.data[:8])), serial.tx.ack.eq(writing) ] # Write to the uart from frame buffer (affects video output) with m.If(writing): with m.If(w_addr == x_res * y_res): m.d.sync += [ writing.eq(0), written.eq(1) ] with m.Elif(serial.tx.ack & serial.tx.rdy): m.d.sync += byte.eq(~byte) with m.If(byte): m.d.sync += w_addr.eq(w_addr+1) # Connect spimem pins m.d.comb += [ spimem.csn.eq(~csn), spimem.sclk.eq(sclk), spimem.copi.eq(copi), cipo.eq(spimem.cipo), ] # Configuration registers (list implies read-only, i.e a status register) # Index in list is the address spi_vals = Array([ccr.brightness, ccr.redness, ccr.greenness, ccr.blueness, l.r, h.r, l.g, h.g, l.b, h.b, sharpness, filt_en, border, mono_en, invert, grid, hist_view, roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, [fil.o_nz[16:]], [fil.o_nz[8:16]], [fil.o_nz[:8]], threshold, thresh_en, hist_chan, flip, [stats.o_min.r], [stats.o_min.g], [stats.o_min.b], [stats.o_max.r], [stats.o_max.g], [stats.o_max.b], [stats.o_avg.r], [stats.o_avg.g], [stats.o_avg.b], frozen, writing, written, sat_en, saturation, ccr.offset, ccm.i_ccm[0], ccm.i_ccm[1], ccm.i_ccm[2], ccm.i_ccm[3], ccm.i_ccm[4], ccm.i_ccm[5], ccm.i_ccm[6], ccm.i_ccm[7], ccm.i_ccm[8], ov_opts, ov_brightness, ov_contrast, double, square]) with m.If(spimem.wr): with m.Switch(spimem.addr): for i in range(len(spi_vals)): if not isinstance(spi_vals[i], list): with m.Case(i): m.d.sync += spi_vals[i].eq(spimem.dout) with m.If(spimem.rd): with m.Switch(spimem.addr): for i in range(len(spi_vals)): val = spi_vals[i][0] if isinstance(spi_vals[i], list) else spi_vals[i] with m.Case(i): m.d.sync += spimem.din.eq(val) # Add VGA generator m.submodules.vga = vga = VGA( resolution_x = self.timing.x, hsync_front_porch = hsync_front_porch, hsync_pulse = hsync_pulse_width, hsync_back_porch = hsync_back_porch, resolution_y = self.timing.y, vsync_front_porch = vsync_front_porch, vsync_pulse = vsync_pulse_width, vsync_back_porch = vsync_back_porch, bits_x = 16, # Play around with the sizes because sometimes bits_y = 16 # a smaller/larger value will make it pass timing. ) # Fetch histogram for display num_bins = cam_x_res // 32 m.d.sync += old_x.eq(vga.o_beam_x) with m.If(vga.o_beam_x == 0): m.d.sync += [ hbin.eq(0), bin_cnt.eq(0) ] with m.Elif(vga.o_beam_x != old_x): m.d.sync += bin_cnt.eq(bin_cnt+1) with m.If(bin_cnt == num_bins - 1): m.d.sync += [ bin_cnt.eq(0), hbin.eq(hbin+1) ] # Switch between camera and histogram view with m.If(debhist.btn_down): m.d.sync += hist_view.eq(~hist_view) # Connect frame buffer, with optional x and y flip vga_x = vga.o_beam_x[1:] vga_y = vga.o_beam_y[1:] m.d.comb += [ frame_x.eq(Mux(flip[0], x_res - 1 - vga_x, vga_x)), frame_y.eq(Mux(flip[1], y_res - 1 - vga_y, vga_y)), w.en.eq(output.o_valid & ~frozen), w.addr.eq(output.o_y * x_res + output.o_x), w.data.eq(output.o.as_data()), r.addr.eq(Mux(writing, w_addr, frame_y * x_res + frame_x)) ] # Apply the On-Screen Display (OSD) m.submodules.osd = osd = OSD() m.d.comb += [ osd.x.eq(vga.o_beam_x), osd.y.eq(vga.o_beam_y), hist_color.eq(Mux((479 - osd.y) < hist.o_val[8:], 0xff, 0x00)), osd.i_r.eq(Mux(hist_view, Mux((hist_chan == 0) | (hist_chan == 3), hist_color, 0), Cat(C(0, 3), r.data[11:16]))), osd.i_g.eq(Mux(hist_view, Mux((hist_chan == 1) | (hist_chan == 3), hist_color, 0), Cat(C(0, 2), r.data[5:11]))), osd.i_b.eq(Mux(hist_view, Mux((hist_chan == 2) | (hist_chan == 3), hist_color, 0), Cat(C(0, 3), r.data[0:5]))), osd.on.eq(osd_on), osd.osd_val.eq(osd_val), osd.sel.eq(osd_sel), osd.grid.eq(grid), osd.border.eq(border), osd.roi.eq(roi.en & ~hist_view), osd.roi_x.eq(roi.x), osd.roi_y.eq(roi.y), osd.roi_w.eq(roi.w), osd.roi_h.eq(roi.h) ] # OSD control dummy = Signal() osd_vals = Array([ccr.offset, ccr.brightness, ccr.redness, ccr.greenness, ccr.blueness, sharpness, sat_en, saturation, mono_en, invert, thresh_en, threshold, hist_chan, Cat(border, grid), flip, filt_en]) def do_btn(m, btn, val, inc): with m.If(btn.btn_down): with m.If(~osd_sel): m.d.sync += osd_val.eq(osd_val - inc) with m.Else(): with m.Switch(osd_val): for i in range(len(osd_vals)): with m.Case(i): if (len(osd_vals[i]) == 1): m.d.sync += osd_vals[i].eq(val) else: m.d.sync += osd_vals[i].eq(osd_vals[i] + inc) with m.If(debosd.btn_down): m.d.sync += osd_on.eq(~osd_on) with m.If(osd_on): with m.If(debsel.btn_down): m.d.sync += osd_sel.eq(~osd_sel) do_btn(m, debup, 1, 1) do_btn(m, debdown, 0, -1) # Show configuration values on leds with m.Switch(osd_val): for i in range(len(osd_vals)): with m.Case(i): m.d.comb += leds.eq(osd_vals[i]) # Generate VGA signals m.d.comb += [ vga.i_clk_en.eq(1), vga.i_test_picture.eq(0), vga.i_r.eq(osd.o_r), vga.i_g.eq(osd.o_g), vga.i_b.eq(osd.o_b), vga_r.eq(vga.o_vga_r), vga_g.eq(vga.o_vga_g), vga_b.eq(vga.o_vga_b), vga_hsync.eq(vga.o_vga_hsync), vga_vsync.eq(vga.o_vga_vsync), vga_blank.eq(vga.o_vga_blank), ] # VGA to digital video converter. tmds = [Signal(2) for i in range(4)] m.submodules.vga2dvid = vga2dvid = VGA2DVID(ddr=self.ddr, shift_clock_synchronizer=False) m.d.comb += [ vga2dvid.i_red.eq(vga_r), vga2dvid.i_green.eq(vga_g), vga2dvid.i_blue.eq(vga_b), vga2dvid.i_hsync.eq(vga_hsync), vga2dvid.i_vsync.eq(vga_vsync), vga2dvid.i_blank.eq(vga_blank), tmds[3].eq(vga2dvid.o_clk), tmds[2].eq(vga2dvid.o_red), tmds[1].eq(vga2dvid.o_green), tmds[0].eq(vga2dvid.o_blue), ] # GPDI pins if (self.ddr): # Vendor specific DDR modules. # Convert SDR 2-bit input to DDR clocked 1-bit output (single-ended) # onboard GPDI. m.submodules.ddr0_clock = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[3][0], i_D1 = tmds[3][1], o_Q = self.o_gpdi_dp[3]) m.submodules.ddr0_red = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[2][0], i_D1 = tmds[2][1], o_Q = self.o_gpdi_dp[2]) m.submodules.ddr0_green = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[1][0], i_D1 = tmds[1][1], o_Q = self.o_gpdi_dp[1]) m.submodules.ddr0_blue = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[0][0], i_D1 = tmds[0][1], o_Q = self.o_gpdi_dp[0]) else: m.d.comb += [ self.o_gpdi_dp[3].eq(tmds[3][0]), self.o_gpdi_dp[2].eq(tmds[2][0]), self.o_gpdi_dp[1].eq(tmds[1][0]), self.o_gpdi_dp[0].eq(tmds[0][0]), ] return m
def elaborate(self, platform): m = Module() m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(2) m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner( serdes.lane)) #m.submodules.phy_rx = phy_rx = PCIePhyRX(lane) #lane = serdes.lane m.d.comb += [ # serdes.txd.eq(K(28,5)), #lane.rx.eq(1), Crucial? lane.rx_invert.eq(0), lane.rx_align.eq(1), ] #m.domains.sync = ClockDomain() m.domains.rx = ClockDomain() m.domains.tx = ClockDomain() m.d.comb += [ #ClockSignal("sync").eq(serdes.refclk), ClockSignal("rx").eq(serdes.rx_clk), ClockSignal("tx").eq(serdes.tx_clk), ] cntr = Signal(5) #with m.If(cntr == 0): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) #with m.Elif(cntr == 1): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) #with m.Elif(cntr == 2): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.EIE) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EDB) #with m.Elif(cntr == 3): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.STP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SDP) #with m.Elif(cntr == 4): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EIE) #with m.Elif(cntr == 5): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.EDB) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EDB) #with m.Elif(cntr == 6): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.EIE) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EIE) #with m.Elif(cntr == 7): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.END) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.END) #with m.Elif(cntr == 8): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL) #with m.Else(): # m.d.tx += lane.tx_symbol.eq(cntr) with m.If(cntr == 0): m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM) m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) with m.Elif(cntr == 1): m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) #with m.Elif(cntr == 6): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) #with m.Elif(cntr == 7): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) # #with m.Elif(cntr == 12): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.COM) #with m.Elif(cntr == 13): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) #with m.Elif(cntr == 14): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL) # #with m.Elif(cntr == 20): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.COM) #with m.Elif(cntr == 21): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP) #with m.Elif(cntr == 22): # m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP) # m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL) with m.Else(): m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL) m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL) #m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM) #m.d.tx += lane.tx_symbol[9:18].eq(cntr) m.d.tx += cntr.eq(cntr + 1) #with m.FSM(domain="tx"): # with m.State("1"): # m.d.tx += lane.tx_symbol.eq(Ctrl.COM) # m.next = "2" # with m.State("2"): # m.d.tx += lane.tx_symbol.eq(Ctrl.SKP) # m.d.tx += cntr.eq(cntr + 1) # with m.If(cntr == 3): # m.d.tx += cntr.eq(0) # m.next = "1" platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))]) #m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx")) platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))]) #m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx")) refclkcounter = Signal(32) m.d.sync += refclkcounter.eq(refclkcounter + 1) rxclkcounter = Signal(32) m.d.rx += rxclkcounter.eq(rxclkcounter + 1) txclkcounter = Signal(32) m.d.tx += txclkcounter.eq(txclkcounter + 1) led_att1 = platform.request("led", 0) led_att2 = platform.request("led", 1) led_sta1 = platform.request("led", 2) led_sta2 = platform.request("led", 3) led_err1 = platform.request("led", 4) led_err2 = platform.request("led", 5) led_err3 = platform.request("led", 6) led_err4 = platform.request("led", 7) m.d.rx += lane.det_enable.eq(1) m.d.comb += [ led_att1.eq(~(refclkcounter[25])), led_att2.eq(~(serdes.lane.rx_aligned)), led_sta1.eq(~(rxclkcounter[25])), led_sta2.eq(~(txclkcounter[25])), led_err1.eq(~(serdes.lane.rx_present)), led_err2.eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)), led_err3.eq(~(lane.det_valid)), #serdes.rxde0)), led_err4.eq(~(lane.det_status)), #serdes.rxce0)), ] triggered = Const(1) #m.d.tx += triggered.eq((triggered ^ ((lane.rx_symbol[0:9] == Ctrl.EIE) | (lane.rx_symbol[9:18] == Ctrl.EIE)))) uart_pins = platform.request("uart", 0) uart = AsyncSerial(divisor=int(100), pins=uart_pins) m.submodules += uart #m.d.rx += lane.tx_e_idle.eq(1) debug = UARTDebugger(uart, 4, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_valid[0], Signal(6), lane.rx_symbol[9:18], lane.rx_valid[1], Signal(6)), "rx", triggered) # lane.rx_present & lane.rx_locked) # You need to add the SERDES within the SERDES as a self. attribute for this to work #debug = UARTDebugger(uart, 4, CAPTURE_DEPTH, Cat(serdes.serdes.lane.rx_symbol[0:9], cntr == 0, Signal(6), Signal(9), lane.rx_valid[0] | lane.rx_valid[1], Signal(6)), "rxf", triggered) # lane.rx_present & lane.rx_locked) m.submodules += debug return m
def elaborate(self, platform): # VGA constants pixel_f = self.timing.pixel_freq hsync_front_porch = self.timing.h_front_porch hsync_pulse_width = self.timing.h_sync_pulse hsync_back_porch = self.timing.h_back_porch vsync_front_porch = self.timing.v_front_porch vsync_pulse_width = self.timing.v_sync_pulse vsync_back_porch = self.timing.v_back_porch # Pins clk25 = platform.request("clk25") ov7670 = platform.request("ov7670") led = [platform.request("led", i) for i in range(8)] leds = Cat([i.o for i in led]) led8_2 = platform.request("led8_2") leds8_2 = Cat([led8_2.leds[i] for i in range(8)]) led8_3 = platform.request("led8_3") leds8_3 = Cat([led8_3.leds[i] for i in range(8)]) leds16 = Cat(leds8_3, leds8_2) btn1 = platform.request("button_fire", 0) btn2 = platform.request("button_fire", 1) up = platform.request("button_up", 0) down = platform.request("button_down", 0) pwr = platform.request("button_pwr", 0) left = platform.request("button_left", 0) right = platform.request("button_right", 0) sw = Cat([platform.request("switch",i) for i in range(4)]) uart = platform.request("uart") divisor = int(platform.default_clk_frequency // 460800) esp32 = platform.request("esp32_spi") csn = esp32.csn sclk = esp32.sclk copi = esp32.copi cipo = esp32.cipo m = Module() # Clock generator. m.domains.sync = cd_sync = ClockDomain("sync") m.domains.pixel = cd_pixel = ClockDomain("pixel") m.domains.shift = cd_shift = ClockDomain("shift") m.submodules.ecp5pll = pll = ECP5PLL() pll.register_clkin(clk25, platform.default_clk_frequency) pll.create_clkout(cd_sync, platform.default_clk_frequency) pll.create_clkout(cd_pixel, pixel_f) pll.create_clkout(cd_shift, pixel_f * 5.0 * (1.0 if self.ddr else 2.0)) # Add CamRead submodule camread = CamRead() m.submodules.camread = camread # Camera config cam_x_res = 640 cam_y_res = 480 camconfig = CamConfig() m.submodules.camconfig = camconfig # Connect the camera pins and config and read modules m.d.comb += [ ov7670.cam_RESET.eq(1), ov7670.cam_PWON.eq(0), ov7670.cam_XCLK.eq(clk25.i), ov7670.cam_SIOC.eq(camconfig.sioc), ov7670.cam_SIOD.eq(camconfig.siod), camconfig.start.eq(btn1), camread.p_data.eq(Cat([ov7670.cam_data[i] for i in range(8)])), camread.href.eq(ov7670.cam_HREF), camread.vsync.eq(ov7670.cam_VSYNC), camread.p_clock.eq(ov7670.cam_PCLK) ] # Create the uart m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart) # Input fifo fifo_depth=1024 m.submodules.fifo = fifo = SyncFIFOBuffered(width=16,depth=fifo_depth) # Frame buffer x_res= cam_x_res // 2 y_res= cam_y_res buffer = Memory(width=16, depth=x_res * y_res) m.submodules.r = r = buffer.read_port() m.submodules.w = w = buffer.write_port() # Button debouncers m.submodules.debup = debup = Debouncer() m.submodules.debdown = debdown = Debouncer() m.submodules.debosd = debosd = Debouncer() m.submodules.debsel = debsel = Debouncer() m.submodules.debsnap = debsnap = Debouncer() m.submodules.debhist = debhist = Debouncer() # Connect the buttons to debouncers m.d.comb += [ debup.btn.eq(up), debdown.btn.eq(down), debosd.btn.eq(pwr), debsel.btn.eq(right), debsnap.btn.eq(left), debhist.btn.eq(btn2) ] # Image processing options flip = Signal(2, reset=1) mono = Signal(reset=0) invert = Signal(reset=0) gamma = Signal(reset=0) border = Signal(reset=0) filt = Signal(reset=0) grid = Signal(reset=0) histo = Signal(reset=1) hbin = Signal(6, reset=0) bin_cnt = Signal(5, reset=0) thresh = Signal(reset=0) threshold = Signal(8, reset=0) hist_chan = Signal(2, reset=0) ccc = CC(reset=(0,18,12,16)) sharpness = Signal(unsigned(4), reset=0) osd_val = Signal(4, reset=0) # Account for spurious start-up button pushes osd_on = Signal(reset=1) osd_sel = Signal(reset=1) snap = Signal(reset=0) frozen = Signal(reset=1) writing = Signal(reset=0) written = Signal(reset=0) byte = Signal(reset=0) w_addr = Signal(18) # Color filter l = Rgb565(reset=(18,12,6)) # Initialised to red LEGO filter h = Rgb565(reset=(21,22,14)) # Region of interest roi = Roi() # VGA signals vga_r = Signal(8) vga_g = Signal(8) vga_b = Signal(8) vga_hsync = Signal() vga_vsync = Signal() vga_blank = Signal() # Fifo co-ordinates f_x = Signal(9) f_y = Signal(9) f_frame_done = Signal() # Pixel from fifo pix = Rgb565() # SPI memory for remote configuration m.submodules.spimem = spimem = SpiMem(addr_bits=32) # Color Control m.submodules.cc = cc = ColorControl() # Image convolution m.submodules.imc = imc = ImageConv() # Statistics m.submodules.stats = stats = Stats() # Histogram m.submodules.hist = hist = Hist() # Filter m.submodules.fil = fil = Filt() # Monochrome m.submodules.mon = mon = Mono() # Sync the fifo with the camera sync_fifo = Signal(reset=0) with m.If(~sync_fifo & ~fifo.r_rdy & (camread.col == cam_x_res - 1) & (camread.row == cam_y_res -1)): m.d.sync += [ sync_fifo.eq(1), f_x.eq(0), f_y.eq(0) ] with m.If(btn1): m.d.sync += sync_fifo.eq(0) # Connect the fifo m.d.comb += [ fifo.w_en.eq(camread.pixel_valid & camread.col[0] & sync_fifo), # Only write every other pixel fifo.w_data.eq(camread.pixel_data), fifo.r_en.eq(fifo.r_rdy & ~imc.o_stall) ] # Calculate fifo co-ordinates m.d.sync += f_frame_done.eq(0) with m.If(fifo.r_en & sync_fifo): m.d.sync += f_x.eq(f_x + 1) with m.If(f_x == x_res - 1): m.d.sync += [ f_x.eq(0), f_y.eq(f_y + 1) ] with m.If(f_y == y_res - 1): m.d.sync += [ f_y.eq(0), f_frame_done.eq(1) ] # Extract pixel from fifo data m.d.comb += [ pix.r.eq(fifo.r_data[11:]), pix.g.eq(fifo.r_data[5:11]), pix.b.eq(fifo.r_data[:5]) ] # Connect color control m.d.comb += [ cc.i.eq(pix), cc.i_cc.eq(ccc) ] # Calculate per-frame statistics, after applying color correction m.d.comb += [ stats.i.eq(cc.o), stats.i_valid.eq(fifo.r_rdy), # This is not valid when a region of interest is active stats.i_avg_valid.eq((f_x >= 32) & (f_x < 288) & (f_y >= 112) & (f_y < 368)), stats.i_frame_done.eq(f_frame_done), stats.i_x.eq(f_x), stats.i_y.eq(f_y), stats.i_roi.eq(roi) ] # Produce histogram, after applying color correction, and after monochrome, for monochrome histogram with m.Switch(hist_chan): with m.Case(0): m.d.comb += hist.i_p.eq(cc.o.r) with m.Case(1): m.d.comb += hist.i_p.eq(cc.o.g) with m.Case(2): m.d.comb += hist.i_p.eq(cc.o.b) with m.Case(3): m.d.comb += hist.i_p.eq(mon.o_m) m.d.comb += [ hist.i_valid.eq(fifo.r_rdy), hist.i_clear.eq(f_frame_done), hist.i_x.eq(f_x), hist.i_y.eq(f_y), hist.i_roi.eq(roi), hist.i_bin.eq(hbin) # Used when displaying histogram ] # Apply filter, after color correction m.d.comb += [ fil.i.eq(cc.o), fil.i_valid.eq(fifo.r_en), fil.i_en.eq(filt), fil.i_frame_done.eq(f_frame_done), fil.i_l.eq(l), fil.i_h.eq(h) ] # Apply mono, after color correction and filter m.d.comb += [ mon.i.eq(fil.o), mon.i_en.eq(mono), mon.i_invert.eq(invert), mon.i_thresh.eq(thresh), mon.i_threshold.eq(threshold) ] # Apply image convolution, after other transformations m.d.comb += [ imc.i.eq(mon.o), imc.i_valid.eq(fifo.r_rdy), imc.i_reset.eq(~sync_fifo), # Select image convolution imc.i_sel.eq(sharpness) ] # Take a snapshot, freeze the camera, and write the framebuffer to the uart # Note that this suspends video output with m.If(debsnap.btn_down | (spimem.wr & (spimem.addr == 22))): with m.If(frozen): m.d.sync += frozen.eq(0) with m.Else(): m.d.sync += [ snap.eq(1), frozen.eq(0), w_addr.eq(0), written.eq(0), byte.eq(0) ] # Wait to end of frame after requesting snapshot, before start of writing to uart with m.If(imc.o_frame_done & snap): m.d.sync += [ frozen.eq(1), snap.eq(0) ] with m.If(~written): m.d.sync += writing.eq(1) # Connect the uart m.d.comb += [ serial.tx.data.eq(Mux(byte, r.data[8:], r.data[:8])), serial.tx.ack.eq(writing) ] # Write to the uart from frame buffer (affects video output) with m.If(writing): with m.If(w_addr == x_res * y_res): m.d.sync += [ writing.eq(0), written.eq(1) ] with m.Elif(serial.tx.ack & serial.tx.rdy): m.d.sync += byte.eq(~byte) with m.If(byte): m.d.sync += w_addr.eq(w_addr+1) # Connect spimem m.d.comb += [ spimem.csn.eq(~csn), spimem.sclk.eq(sclk), spimem.copi.eq(copi), cipo.eq(spimem.cipo), ] # Writable configuration registers spi_wr_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, l.r, h.r, l.g, h.g, l.b, h.b, sharpness, filt, border, mono, invert, grid, histo, roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, None, None, None, threshold, thresh, hist_chan, flip, None, None, None, None, None, None, None, None, None, frozen]) with m.If(spimem.wr): with m.Switch(spimem.addr): for i in range(len(spi_wr_vals)): if spi_wr_vals[i] is not None: with m.Case(i): m.d.sync += spi_wr_vals[i].eq(spimem.dout) # Readable configuration registers spi_rd_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, l.r, h.r, l.g, h.g, l.b, h.b, sharpness, filt, border, mono, invert, grid, histo, roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, fil.o_nz[16:], fil.o_nz[8:16], fil.o_nz[:8], threshold, thresh, hist_chan, flip, stats.o_min.r, stats.o_min.g, stats.o_min.b, stats.o_max.r, stats.o_max.g, stats.o_max.b, stats.o_avg.r, stats.o_avg.g, stats.o_avg.b, frozen, writing, written]) with m.If(spimem.rd): with m.Switch(spimem.addr): for i in range(len(spi_rd_vals)): with m.Case(i): m.d.sync += spimem.din.eq(spi_rd_vals[i]) # Add VGA generator m.submodules.vga = vga = VGA( resolution_x = self.timing.x, hsync_front_porch = hsync_front_porch, hsync_pulse = hsync_pulse_width, hsync_back_porch = hsync_back_porch, resolution_y = self.timing.y, vsync_front_porch = vsync_front_porch, vsync_pulse = vsync_pulse_width, vsync_back_porch = vsync_back_porch, bits_x = 16, # Play around with the sizes because sometimes bits_y = 16 # a smaller/larger value will make it pass timing. ) # Fetch histogram for display old_x = Signal(10) m.d.sync += old_x.eq(vga.o_beam_x) with m.If(vga.o_beam_x == 0): m.d.sync += [ hbin.eq(0), bin_cnt.eq(0) ] with m.Elif(vga.o_beam_x != old_x): m.d.sync += bin_cnt.eq(bin_cnt+1) with m.If(bin_cnt == 19): m.d.sync += [ bin_cnt.eq(0), hbin.eq(hbin+1) ] # Switch between camera and histogram view with m.If(debhist.btn_down): m.d.sync += histo.eq(~histo) # Connect frame buffer, with optional x and y flip x = Signal(10) y = Signal(9) m.d.comb += [ w.en.eq(imc.o_valid & ~frozen), w.addr.eq(imc.o_y * x_res + imc.o_x), w.data.eq(Cat(imc.o.b, imc.o.g, imc.o.r)), y.eq(Mux(flip[1], y_res - 1 - vga.o_beam_y, vga.o_beam_y)), x.eq(Mux(flip[0], x_res - 1 - vga.o_beam_x[1:], vga.o_beam_x[1:])), r.addr.eq(Mux(writing, w_addr, y * x_res + x)) ] # Apply the On-Screen Display (OSD) m.submodules.osd = osd = OSD() hist_col = Signal(8) m.d.comb += [ osd.x.eq(vga.o_beam_x), osd.y.eq(vga.o_beam_y), hist_col.eq(Mux((479 - osd.y) < hist.o_val[8:], 0xff, 0x00)), osd.i_r.eq(Mux(histo, Mux((hist_chan == 0) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(3)), r.data[11:16]))), osd.i_g.eq(Mux(histo, Mux((hist_chan == 1) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(2)), r.data[5:11]))), osd.i_b.eq(Mux(histo, Mux((hist_chan == 2) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(3)), r.data[0:5]))), osd.on.eq(osd_on), osd.osd_val.eq(osd_val), osd.sel.eq(osd_sel), osd.grid.eq(grid), osd.border.eq(border), osd.roi.eq(roi.en & ~histo), osd.roi_x.eq(roi.x), osd.roi_y.eq(roi.y), osd.roi_w.eq(roi.w), osd.roi_h.eq(roi.h) ] # OSD control osd_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, mono, flip[0], flip[1], border, sharpness, invert, grid, filt]) with m.If(debosd.btn_down): m.d.sync += osd_on.eq(~osd_on) with m.If(osd_on): with m.If(debsel.btn_down): m.d.sync += osd_sel.eq(~osd_sel) with m.If(debup.btn_down): with m.If(~osd_sel): m.d.sync += osd_val.eq(Mux(osd_val == 0, 11, osd_val-1)) with m.Else(): with m.Switch(osd_val): for i in range(len(osd_vals)): with m.Case(i): if (len(osd_vals[i]) == 1): m.d.sync += osd_vals[i].eq(1) else: m.d.sync += osd_vals[i].eq(osd_vals[i]+1) with m.If(debdown.btn_down): with m.If(~osd_sel): m.d.sync += osd_val.eq(Mux(osd_val == 11, 0, osd_val+1)) with m.Else(): with m.Switch(osd_val): for i in range(len(osd_vals)): with m.Case(i): if (len(osd_vals[i]) == 1): m.d.sync += osd_vals[i].eq(0) else: m.d.sync += osd_vals[i].eq(osd_vals[i]-1) # Show configuration values on leds with m.Switch(osd_val): for i in range(len(osd_vals)): with m.Case(i): m.d.comb += leds.eq(osd_vals[i]) # Generate VGA signals m.d.comb += [ vga.i_clk_en.eq(1), vga.i_test_picture.eq(0), vga.i_r.eq(osd.o_r), vga.i_g.eq(osd.o_g), vga.i_b.eq(osd.o_b), vga_r.eq(vga.o_vga_r), vga_g.eq(vga.o_vga_g), vga_b.eq(vga.o_vga_b), vga_hsync.eq(vga.o_vga_hsync), vga_vsync.eq(vga.o_vga_vsync), vga_blank.eq(vga.o_vga_blank), ] # VGA to digital video converter. tmds = [Signal(2) for i in range(4)] m.submodules.vga2dvid = vga2dvid = VGA2DVID(ddr=self.ddr, shift_clock_synchronizer=False) m.d.comb += [ vga2dvid.i_red.eq(vga_r), vga2dvid.i_green.eq(vga_g), vga2dvid.i_blue.eq(vga_b), vga2dvid.i_hsync.eq(vga_hsync), vga2dvid.i_vsync.eq(vga_vsync), vga2dvid.i_blank.eq(vga_blank), tmds[3].eq(vga2dvid.o_clk), tmds[2].eq(vga2dvid.o_red), tmds[1].eq(vga2dvid.o_green), tmds[0].eq(vga2dvid.o_blue), ] # GPDI pins if (self.ddr): # Vendor specific DDR modules. # Convert SDR 2-bit input to DDR clocked 1-bit output (single-ended) # onboard GPDI. m.submodules.ddr0_clock = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[3][0], i_D1 = tmds[3][1], o_Q = self.o_gpdi_dp[3]) m.submodules.ddr0_red = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[2][0], i_D1 = tmds[2][1], o_Q = self.o_gpdi_dp[2]) m.submodules.ddr0_green = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[1][0], i_D1 = tmds[1][1], o_Q = self.o_gpdi_dp[1]) m.submodules.ddr0_blue = Instance("ODDRX1F", i_SCLK = ClockSignal("shift"), i_RST = 0b0, i_D0 = tmds[0][0], i_D1 = tmds[0][1], o_Q = self.o_gpdi_dp[0]) else: m.d.comb += [ self.o_gpdi_dp[3].eq(tmds[3][0]), self.o_gpdi_dp[2].eq(tmds[2][0]), self.o_gpdi_dp[1].eq(tmds[1][0]), self.o_gpdi_dp[0].eq(tmds[0][0]), ] return m