Skip to content

Commit 521e25c

Browse files
Merge pull request #686 from michael-betz/obsidian
add board support for Berkeley lab Obsidian A35 board
2 parents e71f8bd + 9c09122 commit 521e25c

File tree

2 files changed

+502
-0
lines changed

2 files changed

+502
-0
lines changed
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
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

Comments
 (0)