|
| 1 | +# |
| 2 | +# This file is part of LiteX-Boards. |
| 3 | +# |
| 4 | +# Copyright (c) 2025 Michael Betz <[email protected]> |
| 5 | +# SPDX-License-Identifier: BSD-2-Clause |
| 6 | +# |
| 7 | +# Obsidian A35 is a low cost FPGA carrier board with several SFP ports, |
| 8 | +# many PMOD IOs and Arduino shield compatibility. |
| 9 | +# It was developed at Berkeley Lab as a kind of smart IO extender. |
| 10 | +# It facilitates interfacing ADCs, DACs, sensors, UI elements or other |
| 11 | +# peripherals to a central larger FPGA board or a PC. |
| 12 | + |
| 13 | + |
| 14 | +from litex.build.generic_platform import Subsignal, Pins, IOStandard, Misc |
| 15 | +from litex.build.xilinx import Xilinx7SeriesPlatform |
| 16 | +from litex.build.openocd import OpenOCD |
| 17 | + |
| 18 | +# IOs ---------------------------------------------------------------------------------------------- |
| 19 | + |
| 20 | +_io = [ |
| 21 | + # WR_CLK0 (125 MHz, DAC-tunable), MGTREFCLK0 |
| 22 | + ( |
| 23 | + "clk125", |
| 24 | + 0, |
| 25 | + Subsignal("p", Pins("D6")), |
| 26 | + Subsignal("n", Pins("D5")), |
| 27 | + ), |
| 28 | + # CLK20_VCXO (20 MHz, DAC-tunable), PAD NOT CLOCK-CAPABLE! |
| 29 | + ("clk20", 0, Pins("D13"), IOStandard("LVCMOS33")), |
| 30 | + # REF_CLK0 (Si5351A, channel 0 and 1, I2C-tunable, 2.5 kHz - 200 MHz), MGTREFCLK1 |
| 31 | + # Note: the Si5351 needs to be configured to get HCSL compatible outputs. |
| 32 | + # See Section 6.7 in the datasheet and register setting CLKx_INV. |
| 33 | + ( |
| 34 | + "clkmgt", |
| 35 | + 0, |
| 36 | + Subsignal("p", Pins("B6")), |
| 37 | + Subsignal("n", Pins("B5")), |
| 38 | + ), |
| 39 | + # CLK2 (Si5351A, channel 2, I2C-tunable, 2.5 kHz - 200 MHz) |
| 40 | + ("clk2", 0, Pins("E15"), IOStandard("LVCMOS33")), |
| 41 | + # Gigabit Ethernet transceiver (RTL8211F-CG) |
| 42 | + ( |
| 43 | + "eth", |
| 44 | + 0, |
| 45 | + Subsignal("rst_n", Pins("A13")), |
| 46 | + Subsignal("mdio", Pins("E18")), |
| 47 | + Subsignal("mdc", Pins("H14")), |
| 48 | + Subsignal("rx_ctl", Pins("D16")), |
| 49 | + Subsignal("rx_data", Pins("B16 C16 D14 C13")), |
| 50 | + Subsignal("tx_ctl", Pins("A17")), |
| 51 | + Subsignal("tx_data", Pins("B17 E16 E17 D18")), |
| 52 | + IOStandard("LVCMOS33"), |
| 53 | + ), |
| 54 | + ( |
| 55 | + "eth_clocks", |
| 56 | + 0, |
| 57 | + Subsignal("tx", Pins("D15")), |
| 58 | + Subsignal("rx", Pins("E13")), |
| 59 | + IOStandard("LVCMOS33"), |
| 60 | + ), |
| 61 | + # USB UART (FT2232HQ) |
| 62 | + ( |
| 63 | + "serial", |
| 64 | + 0, |
| 65 | + # FT2232 --> FPGA |
| 66 | + Subsignal("rx", Pins("H18")), |
| 67 | + # FT2232 <-- FPGA |
| 68 | + Subsignal("tx", Pins("F17")), |
| 69 | + IOStandard("LVCMOS33"), |
| 70 | + ), |
| 71 | + # FT2232 --> FPGA. To use the RTS signal, SW2 must be ON |
| 72 | + ("serial_rts", 0, Pins("B10"), IOStandard("LVCMOS33")), |
| 73 | + # SPI Boot Flash (S25FL128SAGMFI001) |
| 74 | + # use STARTUPE2 primitive to access the clock pin |
| 75 | + ( |
| 76 | + "spiflash", |
| 77 | + 0, |
| 78 | + Subsignal("cs_n", Pins("L15")), |
| 79 | + Subsignal("mosi", Pins("K16")), |
| 80 | + Subsignal("miso", Pins("L17")), |
| 81 | + IOStandard("LVCMOS33"), |
| 82 | + ), |
| 83 | + # I2C system bus, connected to: |
| 84 | + # 0x40: IO-extender for SFP0 and SFP1 status pins (TCA9535RTWR) |
| 85 | + # 0x42: IO-extender for SFP2 and SFP3 status pins (TCA9535RTWR) |
| 86 | + # 0xC0: Clock synthesizer (Si5351A) |
| 87 | + # 0xA0: 256Kb I2C Serial EEPROM with Pre-Programmed Serial Number (24AA256UID) |
| 88 | + # 0xE0: I2C-switch for the 4 SFP ports (PCA9546ARGV) |
| 89 | + ( |
| 90 | + "i2c_fpga", |
| 91 | + 0, |
| 92 | + Subsignal("scl", Pins("H17")), |
| 93 | + Subsignal("sda", Pins("F14")), |
| 94 | + IOStandard("LVCMOS33"), |
| 95 | + ), |
| 96 | + # I2C pins of the Arduino host |
| 97 | + ( |
| 98 | + "i2c_arduino", |
| 99 | + 0, |
| 100 | + Subsignal("scl", Pins("J18")), |
| 101 | + Subsignal("sda", Pins("C12")), |
| 102 | + IOStandard("LVCMOS33"), |
| 103 | + ), |
| 104 | + # 2x DAC for White Rabbit VCXO frequency control (DAC8550IDGK) |
| 105 | + # clk and din is shared between the 2 DACs |
| 106 | + # synca updates the clk125 tuning voltage |
| 107 | + # syncb updates the clk20 tuning voltage |
| 108 | + ( |
| 109 | + "wr_dac", |
| 110 | + 0, |
| 111 | + Subsignal("clk", Pins("C11")), |
| 112 | + Subsignal("din", Pins("B11")), |
| 113 | + Subsignal("synca", Pins("D11")), |
| 114 | + Subsignal("syncb", Pins("D10")), |
| 115 | + IOStandard("LVCMOS33"), |
| 116 | + ), |
| 117 | + # DDR3 DRAM chip (AS4C256M16D3) |
| 118 | + ( |
| 119 | + "ddram", |
| 120 | + 0, |
| 121 | + Subsignal("a", Pins(r"U2 V3 R7 P6 V2 V4 V7 T7 V8 U4 U1 U7 U6 U5 R6 M5"), IOStandard("SSTL15")), |
| 122 | + Subsignal("ba", Pins(r"T3 V6 R2"), IOStandard("SSTL15")), |
| 123 | + Subsignal("ras_n", Pins(r"R3"), IOStandard("SSTL15")), |
| 124 | + Subsignal("cas_n", Pins(r"T2"), IOStandard("SSTL15")), |
| 125 | + Subsignal("we_n", Pins(r"T4"), IOStandard("SSTL15")), |
| 126 | + Subsignal("cs_n", Pins(r"P5"), IOStandard("SSTL15")), |
| 127 | + Subsignal("dm", Pins(r"L5 M6"), IOStandard("SSTL15")), |
| 128 | + Subsignal("dq", Pins(r"K3 L4 K5 K6 J4 L2 J5 L3 N3 M1 N2 M4 N6 M2 P4 N4"), IOStandard("SSTL15")), |
| 129 | + Subsignal("dqs_p", Pins(r"K2 N1"), IOStandard("DIFF_SSTL15")), |
| 130 | + Subsignal("dqs_n", Pins(r"K1 P1"), IOStandard("DIFF_SSTL15")), |
| 131 | + Subsignal("clk_p", Pins(r"R5"), IOStandard("DIFF_SSTL15")), |
| 132 | + Subsignal("clk_n", Pins(r"T5"), IOStandard("DIFF_SSTL15")), |
| 133 | + Subsignal("cke", Pins(r"R1"), IOStandard("SSTL15")), |
| 134 | + Subsignal("odt", Pins(r"P3"), IOStandard("SSTL15")), |
| 135 | + Subsignal("reset_n", Pins(r"J6"), IOStandard("LVCMOS15")), |
| 136 | + Misc("SLEW=FAST"), |
| 137 | + ), |
| 138 | + ( |
| 139 | + "sfp_tx", |
| 140 | + 0, |
| 141 | + Subsignal("p", Pins("H2")), |
| 142 | + Subsignal("n", Pins("H1")), |
| 143 | + ), |
| 144 | + ( |
| 145 | + "sfp_tx", |
| 146 | + 1, |
| 147 | + Subsignal("p", Pins("F2")), |
| 148 | + Subsignal("n", Pins("F1")), |
| 149 | + ), |
| 150 | + ( |
| 151 | + "sfp_tx", |
| 152 | + 2, |
| 153 | + Subsignal("p", Pins("D2")), |
| 154 | + Subsignal("n", Pins("D1")), |
| 155 | + ), |
| 156 | + ( |
| 157 | + "sfp_tx", |
| 158 | + 3, |
| 159 | + Subsignal("p", Pins("B2")), |
| 160 | + Subsignal("n", Pins("B1")), |
| 161 | + ), |
| 162 | + ( |
| 163 | + "sfp_rx", |
| 164 | + 0, |
| 165 | + Subsignal("p", Pins("E4")), |
| 166 | + Subsignal("n", Pins("E3")), |
| 167 | + ), |
| 168 | + ( |
| 169 | + "sfp_rx", |
| 170 | + 1, |
| 171 | + Subsignal("p", Pins("A4")), |
| 172 | + Subsignal("n", Pins("A3")), |
| 173 | + ), |
| 174 | + ( |
| 175 | + "sfp_rx", |
| 176 | + 2, |
| 177 | + Subsignal("p", Pins("C4")), |
| 178 | + Subsignal("n", Pins("C3")), |
| 179 | + ), |
| 180 | + ( |
| 181 | + "sfp_rx", |
| 182 | + 3, |
| 183 | + Subsignal("p", Pins("G4")), |
| 184 | + Subsignal("n", Pins("G3")), |
| 185 | + ), |
| 186 | +] |
| 187 | + |
| 188 | +# Connectors --------------------------------------------------------------------------------------- |
| 189 | + |
| 190 | +_connectors = [ |
| 191 | + ("pmoda", r"M16 N17 R18 U16 M17 N18 P18 V17"), |
| 192 | + ("pmodb", r"T18 U17 U15 V14 R17 T17 V16 U14"), |
| 193 | + ("pmodc", r"M15 N16 P15 K18 N14 P16 K17 L18"), |
| 194 | + ("pmodd", r"J16 K15 F15 J14 J15 M14 G15 L14"), |
| 195 | + ("pmode", r"U10 U9 V9 V11 V12 U12 V13 U11"), |
| 196 | + ("pmodf", r"T13 T12 R13 T14 T15 P14 R16 R15"), |
| 197 | + # digital Arduino host pins |
| 198 | + ("arduino_d", r"G14 H16 A12 B12 C14 G17 G16 A15 C18 F18 C17 B15 B14 A14"), |
| 199 | + # Analog capable Arduino host pins connected to XADC |
| 200 | + # the order is: A0_P, A0_N, A2_P, A2_N, A1_P, A1_N, A3_P, A3_N |
| 201 | + ("arduino_a", r"C8 D8 A9 B9 C9 D9 A10 B10"), |
| 202 | +] |
| 203 | + |
| 204 | + |
| 205 | +def raw_pmod_io(pmod="pmoda", iostd="LVCMOS33"): |
| 206 | + """use with platform.add_extension() to expose a PMOD as GPIO pins""" |
| 207 | + return [ |
| 208 | + ( |
| 209 | + pmod, |
| 210 | + 0, |
| 211 | + Pins(" ".join([f"{pmod}:{i:d}" for i in range(8)])), |
| 212 | + IOStandard(iostd), |
| 213 | + ) |
| 214 | + ] |
| 215 | + |
| 216 | + |
| 217 | +# Platform ----------------------------------------------------------------------------------------- |
| 218 | + |
| 219 | + |
| 220 | +class Platform(Xilinx7SeriesPlatform): |
| 221 | + default_clk_name = "clk125" |
| 222 | + default_clk_period = 1e9 / 125e6 |
| 223 | + |
| 224 | + def __init__(self, toolchain="vivado"): |
| 225 | + # TODO verify part number |
| 226 | + Xilinx7SeriesPlatform.__init__(self, "xc7a35t-csg325", _io, _connectors, toolchain=toolchain) |
| 227 | + self.toolchain.bitstream_commands = ["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"] |
| 228 | + self.toolchain.additional_commands = [ |
| 229 | + ( |
| 230 | + "write_cfgmem -force -format bin -interface spix4 -size 16 -loadbit " |
| 231 | + + '"up 0x0 {build_name}.bit" -file {build_name}.bin' |
| 232 | + ) |
| 233 | + ] |
| 234 | + |
| 235 | + # from pin_map.csv: This is a frequency source, not a phase source, so having it enter on a non-CC pin is OK. |
| 236 | + self.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets clk20_IBUF]") |
| 237 | + self.add_platform_command("set_property CONFIG_VOLTAGE 3.3 [current_design]") |
| 238 | + self.add_platform_command("set_property CFGBVS VCCO [current_design]") |
| 239 | + self.add_platform_command("set_property INTERNAL_VREF 0.75 [get_iobanks 34]") |
| 240 | + |
| 241 | + def create_programmer(self): |
| 242 | + return OpenOCD("openocd_xc7_ft2232.cfg") |
| 243 | + |
| 244 | + def do_finalize(self, fragment): |
| 245 | + Xilinx7SeriesPlatform.do_finalize(self, fragment) |
| 246 | + self.add_period_constraint(self.lookup_request("clk20", loose=True), 1e9 / 20e6) |
| 247 | + self.add_period_constraint(self.lookup_request("clk125", loose=True), 1e9 / 125e6) |
0 commit comments