From 96dabe013a44b78d7c113bb2c30de4c2d950eacb Mon Sep 17 00:00:00 2001 From: David Lenfesty Date: Fri, 24 Mar 2023 17:42:27 -0600 Subject: [PATCH] gateware: add UART to CSR --- gateware/i2c.py | 19 ++++++++++--------- gateware/main.py | 16 ++++++++++++++-- gateware/platforms/__init__.py | 2 +- gateware/platforms/colorlight_i9.py | 14 ++++++++++++-- gateware/uart.py | 16 +++++++++------- 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/gateware/i2c.py b/gateware/i2c.py index 0bd876a..08062da 100644 --- a/gateware/i2c.py +++ b/gateware/i2c.py @@ -41,7 +41,7 @@ class I2C(Elaboratable): # [3]: read - read a byte from the bus # [4]: read_ack - ACK value that gets written out during a read operation # [5]: read_ack_en - Hacky solution to determine if we want to save read_ack - self.CR = Element(6, Element.Access.W, name="CR") + self.CR = Element(6, Element.Access.W, name="I2C_CR") # Status register # @@ -49,27 +49,28 @@ class I2C(Elaboratable): # [0]: busy - bus is busy operating # [1]: ack - an ACK has been received from a bus slave # [2]: read_ack - a convenience read field to see value of CR->read_ack - self.SR = Element(3, Element.Access.R, name="SR") + self.SR = Element(3, Element.Access.R, name="I2C_SR") # Data write register # # Latches in data to be written when write signal is applied. - self.DWR = Element(8, Element.Access.W, name="DWR") + self.DWR = Element(8, Element.Access.W, name="I2C_DWR") # Data read register # # Only presents valid data after 'read' has started, and once 'busy' is no longer asserted. - self.DRR = Element(8, Element.Access.R, name="DRR") + self.DRR = Element(8, Element.Access.R, name="I2C_DRR") # Set up CSR bus addr_width = ceil(log2(64)) # Support up to 64 registers just because data_width = 8 # 32 bit bus self._csr_mux = Multiplexer(addr_width=addr_width, data_width=data_width) - # TODO export the addresses of these somehow - self._csr_mux.add(self.CR) - self._csr_mux.add(self.SR) - self._csr_mux.add(self.DWR) - self._csr_mux.add(self.DRR) + # TODO export these addresses into some config file + cr_start, _stop = self._csr_mux.add(self.CR) + sr_start, _stop = self._csr_mux.add(self.SR) + dwr_start, _stop = self._csr_mux.add(self.DWR) + drr_start, _stop = self._csr_mux.add(self.DRR) + print(f"I2C added. CR 0x{cr_start:x}, SR 0x{sr_start:x}, DWR 0x{dwr_start:x}, DRR 0x{drr_start:x}") self.bus = self._csr_mux.bus # Set up I2C initiator submodule diff --git a/gateware/main.py b/gateware/main.py index c28e312..ea2b277 100644 --- a/gateware/main.py +++ b/gateware/main.py @@ -146,7 +146,6 @@ class Core(Elaboratable): print(f"CSR bus added at 0x{start:08x}") # I2C (connected to DAC for VCO and ADC?) - Signal() if platform is not None: i2c_pads = platform.request("i2c") else: @@ -158,7 +157,20 @@ class Core(Elaboratable): m.d.comb += i2c_pads.scl.i.eq(1) self.i2c = i2c.I2C(50e6, 100e3, i2c_pads) m.submodules.i2c = self.i2c - self.csr.add(self.i2c.bus) + i2c_start, _stop, _step = self.csr.add(self.i2c.bus) + print(f"LED added to CSR at 0x{i2c_start}") + + if platform is not None: + uart_pads = platform.request("uart") + else: + uart_pads = type('UARTPads', (), {}) + uart_pads.tx = Signal() + uart_pads.rx = Signal() + # TODO spread sysclk freq through design + self.uart = uart.UART(50e6, 1152_000) + m.submodules.uart = self.uart + uart_start, _stop, _step = self.csr.add(self.uart.bus) + print(f"UART added to CSR at 0x{uart_start:x}") self.csr_bridge = WishboneCSRBridge(self.csr.bus, data_width=32, name="CSR") m.submodules.csr_bridge = self.csr_bridge diff --git a/gateware/platforms/__init__.py b/gateware/platforms/__init__.py index 28b510f..30c3f9a 100644 --- a/gateware/platforms/__init__.py +++ b/gateware/platforms/__init__.py @@ -1 +1 @@ -from colorlight_i9 import * +from .colorlight_i9 import * diff --git a/gateware/platforms/colorlight_i9.py b/gateware/platforms/colorlight_i9.py index 9ea8d37..c86a727 100644 --- a/gateware/platforms/colorlight_i9.py +++ b/gateware/platforms/colorlight_i9.py @@ -25,8 +25,18 @@ class Colorlight_i9_Platform(LatticeECP5Platform): # attrs=Attrs(IO_TYPE="LVCMOS33", PULLMODE="UP")), UARTResource(0, - tx="J17", - rx="H18", + tx="E17", + rx="D18", + attrs=Attrs(IO_TYPE="LVCMOS33") + ), + UARTResource(1, + tx="P16", + rx="L5", + attrs=Attrs(IO_TYPE="LVCMOS33") + ), + UARTResource(2, + tx="J18", + rx="J16", attrs=Attrs(IO_TYPE="LVCMOS33") ), diff --git a/gateware/uart.py b/gateware/uart.py index 0b52827..3f1aebe 100644 --- a/gateware/uart.py +++ b/gateware/uart.py @@ -38,7 +38,7 @@ class UART(Elaboratable): # # Sets input/output baudrate to system clock / divisor. Resets to value # that provides 115200 baud rate. Writes to this register clear FIFOs. - self.DIVISOR = Element(16, Element.Access.RW, name="DIVISOR") + self.DIVISOR = Element(16, Element.Access.RW, name="UART_DIVISOR") # Status register. # @@ -47,22 +47,23 @@ class UART(Elaboratable): # [1]: txfifo_empty # [2]: rxfifo_full # [3]: rxfifo_empty - self.SR = Element(4, Element.Access.R, name="SR") + self.SR = Element(4, Element.Access.R, name="UART_SR") # Data register. # # Writes push data into TX FIFO, and are discarded if full, reads pull # data from RX FIFO, and are invalid if it is empty. Incoming bytes are discarded # if the RX FIFO is full. - self.DR = Element(8, Element.Access.RW, name="DR") + self.DR = Element(8, Element.Access.RW, name="UART_DR") # Set up CSR bus addr_width = ceil(log2(64)) - data_width = 32 + data_width = 8 self._csr_mux = Multiplexer(addr_width=addr_width, data_width=data_width) - self._csr_mux.add(self.DIVISOR) - self._csr_mux.add(self.SR) - self._csr_mux.add(self.DR) + div_start, _stop = self._csr_mux.add(self.DIVISOR) + sr_start, _stop = self._csr_mux.add(self.SR) + dr_start, _stop = self._csr_mux.add(self.DR) + print(f"UART added. DIVISOR 0x{div_start:x}, SR 0x{sr_start:x}, DR 0x{dr_start:x}") self.bus = self._csr_mux.bus # Actual business logic @@ -94,6 +95,7 @@ class UART(Elaboratable): m.submodules.csr_mux = self._csr_mux # Hook up divisor to register. + # TODO do some validation and write a known good value if a dumb value was provided m.d.comb += self.DIVISOR.r_data.eq(self._serial.divisor) with m.If(self.DIVISOR.w_stb): m.d.sync += self._serial.divisor.eq(self.DIVISOR.w_data)