("oe", 1)
)
-UART_BANK = 0
-I2C_BANK = 1
+GPIO_BANK = 0
+UART_BANK = 1
+I2C_BANK = 2
"""
Really basic example, uart tx/rx and i2c sda/scl pinmux
"""
class ManPinmux(Elaboratable):
- def __init__(self):
+ def __init__(self, pad_names):
print("Test Manual Pinmux!")
- self.n_banks = 2
+ self.n_banks = 4
self.iomux1 = IOMuxBlockSingle(self.n_banks)
self.iomux2 = IOMuxBlockSingle(self.n_banks)
- self.pad1 = Record(name="Pad1", layout=io_layout)
- self.pad2 = Record(name="Pad2", layout=io_layout)
+ self.pads = {}
+ for pad in pad_names:
+ self.pads[pad] = Record(name=pad, layout=io_layout)
+ self.gpio = {"0": Record(name="gp0", layout=io_layout),
+ "1": Record(name="gp1", layout=io_layout)
+ }
self.uart = Record(name="uart", layout=uart_layout)
self.i2c = {"sda": Record(name="sda", layout=io_layout),
"scl": Record(name="scl", layout=io_layout)
m.submodules.iomux1 = iomux1
m.submodules.iomux2 = iomux2
- pad1 = self.pad1
- pad2 = self.pad2
+ pads = self.pads
+ gpio = self.gpio
uart = self.uart
i2c = self.i2c
bank = self.bank
comb += iomux1.bank.eq(bank)
comb += iomux2.bank.eq(bank)
- # uart connected to bank 0 - Pad 1 tx, Pad 2 rx
+ # ---------------------------
+ # This section is muxing only - doesn'care about pad names
+ # ---------------------------
+ # gpio - gpio0 on Pad1, gpio1 on Pad2
+ comb += iomux1.bank_ports[GPIO_BANK].o.eq(gpio["0"].o)
+ comb += iomux1.bank_ports[GPIO_BANK].oe.eq(gpio["0"].oe)
+ comb += gpio["0"].i.eq(iomux1.bank_ports[GPIO_BANK].i)
+ comb += iomux2.bank_ports[GPIO_BANK].o.eq(gpio["1"].o)
+ comb += iomux2.bank_ports[GPIO_BANK].oe.eq(gpio["1"].oe)
+ comb += gpio["1"].i.eq(iomux2.bank_ports[GPIO_BANK].i)
+ # uart Pad 1 tx, Pad 2 rx
comb += iomux1.bank_ports[UART_BANK].o.eq(uart.tx)
comb += iomux1.bank_ports[UART_BANK].oe.eq(uart.oe)
comb += uart.rx.eq(iomux2.bank_ports[UART_BANK].i)
- # i2c connected to bank 1 - Pad 1 sda, Pad 2 scl
+ # i2c Pad 1 sda, Pad 2 scl
comb += iomux1.bank_ports[I2C_BANK].o.eq(i2c["sda"].o)
comb += iomux1.bank_ports[I2C_BANK].oe.eq(i2c["sda"].oe)
comb += i2c["sda"].i.eq(iomux1.bank_ports[I2C_BANK].i)
comb += iomux2.bank_ports[I2C_BANK].oe.eq(i2c["scl"].oe)
comb += i2c["scl"].i.eq(iomux2.bank_ports[I2C_BANK].i)
- comb += pad1.o.eq(iomux1.out_port.o)
- comb += pad1.oe.eq(iomux1.out_port.oe)
- comb += iomux1.out_port.i.eq(pad1.i)
- comb += pad2.o.eq(iomux2.out_port.o)
- comb += pad2.oe.eq(iomux2.out_port.oe)
- comb += iomux2.out_port.i.eq(pad2.i)
+ # ---------------------------
+ # Here is where the muxes are assigned to the actual pads
+ # ---------------------------
+ # TODO: for-loop to autoconnect muxes to pads (n_pads var?)
+ comb += pads['N1'].o.eq(iomux1.out_port.o)
+ comb += pads['N1'].oe.eq(iomux1.out_port.oe)
+ comb += iomux1.out_port.i.eq(pads['N1'].i)
+ comb += pads['N2'].o.eq(iomux2.out_port.o)
+ comb += pads['N2'].oe.eq(iomux2.out_port.oe)
+ comb += iomux2.out_port.i.eq(pads['N2'].i)
+
+ #temp for testing - connect pad rx-tx
+ #comb += pad2.i.eq(pad1.o)
return m
def __iter__(self):
- for field in self.pad1.fields.values():
- yield field
- for field in self.pad2.fields.values():
- yield field
+ for pad in list(self.pads.keys()):
+ for field in self.pads[pad].fields.values():
+ yield field
for field in self.uart.fields.values():
yield field
for field in self.i2c["sda"].fields.values():
yield dut.bank.eq(bank)
yield Delay(delay)
-def uart_send(uart, byte, delay=1e-6):
+"""
+GPIO test function
+Set the gpio output based on given data sequence, checked at pad.o
+Then sends the same byte via pad.i to gpio input
+"""
+def gpio(gpio, pad, data, delay=1e-6):
+ # Output test - Control GPIO output
+ yield gpio.oe.eq(1)
+ yield Delay(delay)
+ n_bits = len(bin(data)[2:])
+ read = 0
+ for i in range(0, n_bits):
+ bit = (data >> i) & 0x1
+ yield gpio.o.eq(bit)
+ yield Delay(delay)
+ temp = yield pad.o
+ read |= (temp << i)
+ assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
+ # Input test - Control Pad input
+ yield gpio.oe.eq(0)
+ yield Delay(delay)
+ read2 = 0
+ for i in range(0, n_bits):
+ bit = (read >> i) & 0x1
+ yield pad.i.eq(bit)
+ yield Delay(delay)
+ temp = yield gpio.i
+ read2 |= (temp << i)
+ assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
+ # reset input signal
+ yield pad.i.eq(0)
+ yield Delay(delay)
+
+"""
+UART test function
+Sends a byte via uart tx, checked at output pad
+Then sends the same byte via input pad to uart rx
+Input and output pads are different, so must specify both
+"""
+def uart_send(uart, pad_o, pad_i, byte, delay=1e-6):
+ # Drive uart tx - check the word seen at the Pad
yield uart.oe.eq(1)
yield uart.tx.eq(1)
yield Delay(2*delay)
yield uart.tx.eq(0) # start bit
yield Delay(delay)
+ read = 0
# send one byte, lsb first
for i in range(0, 8):
bit = (byte >> i) & 0x1
yield uart.tx.eq(bit)
yield Delay(delay)
+ test_bit = yield pad_o
+ read |= (test_bit << i)
yield uart.tx.eq(1) # stop bit
yield Delay(delay)
+ assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
+ # Drive Pad i - check word at uart rx
+ yield pad_i.eq(1)
+ yield Delay(2*delay)
+ yield pad_i.eq(0) # start bit
+ yield Delay(delay)
+ read2 = 0
+ for i in range(0, 8):
+ bit = (read >> i) & 0x1
+ yield pad_i.eq(bit)
+ yield Delay(delay)
+ test_bit = yield uart.rx
+ read2 |= (test_bit << i)
+ yield pad_i.eq(1) # stop bit
+ yield Delay(delay)
+ assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
+"""
+I2C test function
+Sends a byte via SDA.o (peripheral side), checked at output pad
+Then sends the same byte via input pad to master SDA.i
+This transaction doesn't make the distinction between read/write bit.
+"""
+def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
+ # No checking yet
+ # No pull-up on line implemented, set high instead
+ yield sda.oe.eq(1)
+ yield sda.o.eq(1)
+ yield scl.oe.eq(1)
+ yield scl.o.eq(1)
+ yield sda_pad.i.eq(1)
+ yield Delay(delay)
+ read = 0
+ yield sda.o.eq(0) # start bit
+ yield Delay(delay)
+ for i in range(0, 8):
+ bit = (byte >> i) & 0x1
+ yield sda.o.eq(bit)
+ yield scl.o.eq(0)
+ yield Delay(delay/2)
+ yield scl.o.eq(1)
+ temp = yield sda_pad.o
+ read |= (temp << i)
+ yield Delay(delay/2)
+ yield sda.o.eq(1) # Master releases SDA line
+ yield sda.oe.eq(0)
+ assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
+ # Slave ACK
+ yield sda_pad.i.eq(0)
+ yield scl.o.eq(0)
+ yield Delay(delay/2)
+ yield scl.o.eq(1)
+ yield Delay(delay/2)
+ # Send byte back to master
+ read2 = 0
+ for i in range(0, 8):
+ bit = (read >> i) & 0x1
+ yield sda_pad.i.eq(bit)
+ yield scl.o.eq(0)
+ yield Delay(delay/2)
+ yield scl.o.eq(1)
+ temp = yield sda.i
+ read2 |= (temp << i)
+ yield Delay(delay/2)
+ assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
+ # Master ACK
+ yield sda.oe.eq(1)
+ yield sda.o.eq(0)
+ yield scl.o.eq(0)
+ yield Delay(delay/2)
+ yield scl.o.eq(1)
+ yield Delay(delay/2)
+ # Stop condition - SDA line high after SCL high
+ yield scl.o.eq(0)
+ yield Delay(delay/2)
+ yield scl.o.eq(1)
+ yield Delay(delay/2)
+ yield sda.o.eq(1) # 'release' the SDA line
-def test_man_pinmux(dut):
+# Test the GPIO/UART/I2C connectivity
+def test_man_pinmux(dut, pad_names):
delay = 1e-6
+ # GPIO test
+ yield from set_bank(dut, GPIO_BANK)
+ yield from gpio(dut.gpio['0'], dut.pads['N1'], 0x5a5)
+ yield from gpio(dut.gpio['1'], dut.pads['N2'], 0x5a5)
+ # UART test
yield from set_bank(dut, UART_BANK)
- yield from uart_send(dut.uart, 0x42)
- yield dut.pad1.i.eq(1)
- yield dut.pad2.i.eq(1)
+ yield from uart_send(dut.uart, dut.pads['N1'].o, dut.pads['N2'].i, 0x42)
+ yield dut.pads['N2'].i.eq(0)
+ yield Delay(delay)
+ # I2C test
+ yield from set_bank(dut, I2C_BANK)
+ yield from i2c_send(dut.i2c['sda'], dut.i2c['scl'], dut.pads['N1'], 0x67)
+ yield dut.gpio['0'].oe.eq(1)
+ yield Delay(delay)
+ yield dut.gpio['0'].oe.eq(0)
+ yield Delay(delay)
def sim_man_pinmux():
filename = "test_man_pinmux"
- dut = ManPinmux()
+ pad_names = ["N1", "N2"]
+ dut = ManPinmux(pad_names)
vl = rtlil.convert(dut, ports=dut.ports())
with open(filename+".il", "w") as f:
f.write(vl)
sim = Simulator(m)
- sim.add_process(wrap(test_man_pinmux(dut)))
+ sim.add_process(wrap(test_man_pinmux(dut, pad_names)))
sim_writer = sim.write_vcd(filename+".vcd")
with sim_writer:
sim.run()