-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mostly documentation, still not the actual schematics
- Loading branch information
Showing
6 changed files
with
200 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,61 @@ | ||
# Zest | ||
Zest is a FMC mezzanine board with 6 ADC channels and 2 DACs | ||
|
||
This directory will hold the schematics and associated files (but not the layout) | ||
for the the Zest board, an FMC-ish mezzanine board designed for LLRF and related applications. | ||
Before its release as Open Hardware, it was known as the LCLS-II LLRF Digitizer Board, currently Rev. 1.1. | ||
It is in gschem format; to work with it you | ||
need [gschem](http://wiki.geda-project.org/geda:gaf) installed. | ||
Tested on [Debian](https://www.debian.org) Jessie, Stretch, or Buster, where | ||
you simply `apt-get install geda-gschem`. | ||
|
||
 [block diagram](doc/digitizer_block.png) | ||
|
||
The digitizer board features: | ||
|
||
* 8 x transformer-coupled inputs sampled at 95 MS/s (2 x AD9653) | ||
* 2 x transformer-coupled outputs sampled at 190 MS/s (AD9781) | ||
* Input clock source up to 3 GHz (LMK01801, no on-board oscillator) | ||
* Extra clock divider output | ||
* 2 x Pmod digital I/O | ||
* Interface to FPGA via dual-LPC-FMC connectors | ||
* 181.8 x 110 mm, 8-layer, with notch to accommodate Xilinx FMC eval boards | ||
* 4W power dissipation | ||
|
||
## Schematics | ||
|
||
To get PDF versions for reference, | ||
simply `make` in this directory. The result is digitizer_schematics.pdf. | ||
|
||
## Artwork/Gerbers | ||
|
||
Created by Kathy Pham at SLAC using PADS. Latest is 20170519. | ||
The PADS design imports the netlist exported from this gschem design. | ||
These PADS files are _not_ kept in this git repository, but | ||
their SHA256 signatures are kept in the | ||
[layout_20170519.sha256sum](layout_20170519.sha256sum) file in this directory. | ||
|
||
QR-code serial-number overlay Gerbers are generated with `qr_gen.py`. | ||
|
||
## BOM | ||
|
||
Get a copy of the `PC-379-396-15-C02_DIGITIZER BOARD_XY.xlsx` file exported from | ||
the PADS design reference above, and place it in this directory. | ||
|
||
Then `make merged_xy.csv` to merge the actual orderable part numbers (kept here | ||
in the parts.data file) and get a usable xy assembly file for fabrication. | ||
|
||
## Plastic Cover | ||
|
||
One corner of the digitizer (by J3, clock input) has some fragile transformers | ||
very close to where SMA wrenches are used. | ||
It has proved helpful to have a protective cover in place to avoid damage. | ||
This is designed in [OpenSCAD](http://www.openscad.org/) with a process that | ||
matches up its features with the Gerber file; see covergen.py. | ||
The OpenSCAD source file is cover1.scad. | ||
OpenSCAD will export an STL file which is easily 3-D printed. | ||
|
||
## References | ||
|
||
G. Huang, L. R. Doolittle, J. Yang, Y. Xu, | ||
*``Low Noise Digitizer Design for LCLS-II LLRF,''* in NAPAC2016 | ||
[TUPOA40](http://accelconf.web.cern.ch/AccelConf/napac2016/papers/tupoa40.pdf). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* Digitizer cover to protect its transformers near J3 and J20 */ | ||
/* Obsolete, see cover2c.scad */ | ||
/* See also covergen.py */ | ||
|
||
/* 5 mm from board to attached SMA connector, which still fits in */ | ||
/* the 7.9 mm cutout for the board-mount SMA connector. */ | ||
/* 7 mm from board to the beginning of the hex section. */ | ||
/* Part is 5.5 mm thick, to avoid slight interference with SMA connectors found with a 6mm thick version. */ | ||
|
||
module cover() | ||
{ | ||
union() { | ||
difference() { | ||
union () { | ||
translate([0, -39.5, 2]) cube([40.5, 39.5, 3.5]); | ||
/* copper pad on board measures 5.8 mm dia */ | ||
translate([37.55,-36.5, 0]) cylinder(r=2.9, h=4, $fn=30); | ||
} | ||
union () { | ||
/* 106.3 mil = 2.7 mm dia hole, tight clearance for 4-40 */ | ||
translate([37.55, -36.5, -1]) cylinder(r=1.5, h=8, $fn=30); | ||
translate([ -1, -11.50, 0]) cube([10.6, 7.7, 8]); /* J3 */ | ||
translate([ -1, -26.75, 0]) cube([10.6, 7.7, 8]); /* J20 */ | ||
translate([ -1, -42.00, 0]) cube([10.6, 7.7, 8]); /* J11 */ | ||
/* TCM4-19 datasheet claims max height 4.06 mm, I measure 3.1 mm */ | ||
translate([11.3, -15.2, 0]) cube([4.2, 4, 4.0]); /* U34 */ | ||
translate([17.3, -15.2, 0]) cube([4.2, 4, 4.0]); /* T1 */ | ||
translate([11.3, -26.0, 0]) cube([4.2, 4, 4.0]); /* T1 */ | ||
translate([39, -24, 1]) mirror(v=[1, 0, 0]) linear_extrude(height = 1.5) { | ||
text("LBNL", size = 6.2, font = "Liberation Sans"); | ||
} | ||
translate([28, -34, 1]) mirror(v=[1, 0, 0]) linear_extrude(height = 1.5) { | ||
text("R3", size = 6.2, font = "Liberation Sans"); | ||
} | ||
} | ||
} | ||
/* these are the stubs supposed to rest on the bare board */ | ||
translate([0, -3.6, 0]) cube([ 9.5, 3.6, 2]); | ||
translate([0, -18.2, 0]) cube([ 9.5, 3.6, 2]); | ||
translate([0, -33.1, 0]) cube([16.0, 5.2, 2]); | ||
translate([25.3, -6.1, 0]) cube([ 9.5, 6.1, 2]); | ||
} | ||
} | ||
|
||
cover(); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
6cbed80c2a59994bd1079787402c8bbd41b0e4aac596df6ae13ff0d52cd22452 PC-379-396-15-C02_DIGITIZER BOARD_GERBER.zip | ||
41695319dbba6b2a0f070e53f15aa4e91d6cd02aab0c0f8df19309e846284ad0 PC-379-396-15-C02_DIGITIZER BOARD.pcb | ||
755974be8790143d8e31a287eb366f4e4facb41aa9633fdf04591ec5c7711a8d PC-379-396-15-C02_DIGITIZER BOARD_XY.xlsx | ||
e4acd72a8bf70de439603d0e74e5d18f4af4e1b64bf01f2c5adaf508655656ea PC-379-396-15-C02_DIGITIZER SA TOP.pdf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import numpy | ||
import qrtools | ||
import scipy.ndimage | ||
import os | ||
|
||
def qrpng2pcbpoly(qrpngfilename, x0=9600, y0=3200): | ||
im = scipy.ndimage.imread(qrpngfilename, flatten=True) | ||
ymax, xmax = im.shape | ||
y, x = numpy.where(im == 255) | ||
x0 = x0 - 450 | ||
y0 = y0 + 430 | ||
step = 14 | ||
polygons = [] | ||
for ix, xvalue in enumerate(x): | ||
x1 = x0+xvalue*step | ||
x2 = x0+xvalue*step+step | ||
y1 = y0-(ymax-y[ix])*step | ||
y2 = y0-(ymax-y[ix])*step+step | ||
polygons.append(''' Polygon("clearpoly") | ||
( | ||
[%.2fmil %.2fmil] [%.2fmil %.2fmil] [%.2fmil %.2fmil] [%.2fmil %.2fmil] | ||
)''' % (x1, y1, x2, y1, x2, y2, x1, y2)) | ||
return '\n'.join(polygons) | ||
|
||
# String length limits for Version 2 (25x25), assuming "Alphanumeric" encoding: | ||
# level='S' 40 | ||
# level='M' 28 | ||
# level='Q' 22 | ||
def qrgen(string, level='M'): | ||
print("qrgen: " + string) | ||
qr = qrtools.QR(string, pixel_size=1, margin_size=2, level=level) | ||
qr.encode(string) | ||
return string+'.png' | ||
|
||
def pcbstring(x, y, size, s): | ||
return ''' | ||
Text[%3.2fmil %3.2fmil 0 %d "%s" "clearline"]''' % (x, y, size, s) | ||
|
||
def pcbstrings(l): | ||
return "".join([pcbstring(*ll) for ll in l]) | ||
|
||
def munge_size(l, xmax, ymax): | ||
if l[0:7] == 'PCB["" ': | ||
return 'PCB["" %.2fmil %.2fmil]' % (xmax, ymax) | ||
else: | ||
return l | ||
|
||
def get_template(xmax=12000, ymax=10000): | ||
with open("template.pcb", "r") as f: | ||
template = f.read() | ||
lines = template.split('\n') | ||
return "\n".join([munge_size(l, xmax=xmax, ymax=ymax) for l in lines]) | ||
|
||
|
||
def pcbfile(silk, template): | ||
return template + '''Layer(10 "top silk" "silk") | ||
( | ||
'''+silk+''' | ||
)''' | ||
|
||
def infopcb(lines, sn, x0=9600, y0=3200): | ||
line_break = lines.split('\n') | ||
return pcbstrings([ | ||
(x0, y0+0, 110, line_break[0]), | ||
(x0, y0+70, 110, line_break[1]), | ||
(x0, y0+140, 110, line_break[2]), | ||
(x0, y0+210, 200, 'S'), | ||
(x0, y0+320, 200, 'N'), | ||
(x0+100, y0+180, 500, '%03d' % sn)]) | ||
|
||
def oneboard(gerber_name="a.gbr", sn=1, qr_string="TEST 1", desc_string="", x0=3900, y0=1200, level="M", template="", lines=""): | ||
polys = qrpng2pcbpoly(qrgen(qr_string, level=level), x0=x0, y0=y0) | ||
pcbstr = pcbfile(silk=infopcb(lines, sn, x0=x0, y0=y0)+polys, template=template) | ||
pcb_name = 'test' | ||
with open(pcb_name+'.pcb', 'w') as f: | ||
f.write(pcbstr) | ||
f.close() | ||
os.system('pcb -x gerber %s.pcb && mv %s.%s.gbr %s' % (pcb_name, pcb_name, 'topsilk', gerber_name)) | ||
|
||
|
||
if __name__ == "__main__": | ||
setup = [3900, 7450, 'qr_sn_%03d.gbr', 'LBNL DIGITIZER V1.1 SN %03d', 'M', 'LBNL Digitizer\nLCLS-II LLRF\nRevision 1.1'] | ||
# setup = [10000, 5360, 'qr_dn_sn_%03d.gbr', 'FNAL DOWNCVT REV C SN %03d', 'M', 'FNAL DOWNCVT\nLCLS-II LLRF\nRev C'] | ||
# setup = [6900, 2300, 'qr_up_sn_%03d.gbr', 'FNAL UPCVT REV C SN %03d', 'M', 'FNAL UPCVT\nLCLS-II LLRF\nRev C'] | ||
x0, y0, gerber_base, qr_base, level, lines = setup | ||
template = get_template(xmax=x0+1000, ymax=y0+1000) | ||
for sn in range(32, 57): | ||
gerber_name = gerber_base % sn | ||
qr_string = qr_base % sn | ||
desc_string = '' | ||
oneboard(gerber_name=gerber_name, sn=sn, qr_string=qr_string, desc_string=desc_string, x0=x0, y0=0, level=level, template=template, lines=lines) |