--- jupyter: description: 'A PADS board in planex2d: px.FromKiCad converts a PADS Layout ASCII file (.asc) with KiCad 10''s kicad-cli and returns its layers as shapes, the copper named by net. The example is a carrier board for a Raspberry Pi Pico W, checked against the Pico''s pin grid.' --- # PADS PADS Layout, from Siemens, formerly Mentor Graphics, exports a board as an ASCII file with the extension `.asc`. `px.FromKiCad` converts it with `kicad-cli`, the command line tool of KiCad 10 or later, and returns the same dict of layers as for a KiCad board. See [KiCad, Altium, Eagle and more](index.md) for how the tool is found. ```python import collections import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Row ``` ## The board The example is the CLAYSIGHT MCU board from The Ohio State University, a two-layer carrier board for a Raspberry Pi Pico W. The file comes from the test data of KiCad's PADS importer and is licensed under the MIT license, Copyright (c) 2024 John Simonis, John LaRocco and Qudsia Tahmina. Download: [ClaySight_MK1.asc](ClaySight_MK1.asc) and its [license](ClaySight_MK1_LICENSE.txt). ```python board = px.FromKiCad("ClaySight_MK1.asc") for name, layer in board.items(): print(f"{name:10} {len(layer.faces):4} faces, {1e6 * layer.mass:9.2f} mm²") ``` The layers are those of a board drawn in KiCad. The two copper layers have their faces named by net and the drill holes cut out, the outline is `Edge.Cuts`, and the silkscreen, solder mask and paste layers hold what KiCad prints there. The text on the board is not read yet, and `FromKiCad` reports how much it left out. ## Copper per net The two copper layers are drawn in copper, with the board outline dashed (Figure 1). Each face carries the name of its net, so the copper can be grouped by net: ```python fcu, bcu, outline = board["F.Cu"], board["B.Cu"], board["Edge.Cuts"] for name, layer in (("F.Cu", fcu), ("B.Cu", bcu)): area = collections.Counter() for f in layer.faces: area[f.name or "(no net)"] += 1e6 * f.mass print(name, len(area), "nets, the largest:", [(net, round(a, 1)) for net, a in area.most_common(3)]) ``` ```python nbsphinx="hide-input" copper = {"face": "#c87533", "ink": "#6b3410", "dashed": [outline], "lw": 0.4} Row((fcu, "F.Cu, the top layer", copper), (bcu, "B.Cu, the bottom layer", copper), caption="The copper layers of a PADS board, read through KiCad") ``` The solder mask openings `F.Mask` and the silkscreen `F.SilkS` laid over the outline show the board as it comes from the manufacturer (Figure 2). ```python nbsphinx="hide-input" top = {"face": "#2f6b45", "ink": "#1d4029", "lw": 0.4, "fills": [(board["F.Mask"], "#d9b46c"), (board["F.SilkS"], "#f4f4ee")]} Row((outline, "F.Mask and F.SilkS over the outline", top), caption="The top of the board") ``` ## A check against the Pico's pin grid The Pico W's datasheet puts its 40 pins on a 2.54 mm grid with 1 mm holes, in two rows along its long edges. On the board, these are the 40 plated holes of 1 mm, which are cut out of the outline. Their centers give the rows and the pitch: ```python pins = [] for hole in outline.faces[0].inner: (x0, y0), (x1, y1) = hole.bounding_box if abs(x1 - x0 - 1e-3) < 1e-7: pins.append(((x0 + x1) / 2, (y0 + y1) / 2)) x = sorted(p[0] for p in pins) y = sorted({round(p[1], 9) for p in pins}) pitch = [1e3 * (b - a) for a, b in zip(y, y[1:])] print(len(pins), "holes of 1 mm, rows", round(1e3 * (x[-1] - x[0]), 6), "mm apart, 7 × 2.54 =", 7 * 2.54) print(len(y), "pins per row, the pitch differs from 2.54 mm by up to", round(1e3 * max(abs(s - 2.54) for s in pitch), 4), "µm") ``` The rows are seven pitches apart, and the pitch is 2.54 mm to within 0.254 µm, a hundredth of a mil. That difference is in the PADS file itself, which stores some of the pins that far off the grid, and the conversion keeps it.