def place_parts(json_dict, pcb): # compute upper left corner of board board_ul = Point(*BoardTools.get_board_ul(json_dict['board_edge'])) # place all components for name, module in json_dict['module_dict'].items(): if module['type'] == 'comp': # set rotation rot = module['rotation'] pcb.modules[name].rotation = rot # make the buffer vector if round(degrees(rot)) in [0, 180]: buf_space = Point(module['bufx'], module['bufy']) elif round(degrees(rot)) in [90, 270]: buf_space = Point(module['bufy'], module['bufx']) else: raise Exception("Can't determine rotation.") # set position pcb.modules[name].position = \ pcb.modules[name].position \ + Point(module['x'], module['y']) \ + buf_space \ + board_ul \ - pcb.modules[name].boundingBox.ul elif module['type'] == 'keepout': pass else: raise Exception('Unimplemented component type: ' + str(module['type']))
def draw_board_edge(json_dict, pcb): # compute upper left corner of board board_ul = Point(*BoardTools.get_board_ul(json_dict['board_edge'])) # draw edge edge = [Point(x, y) + board_ul for x, y in json_dict['board_edge']] pcb.add_polyline(edge, layer='Edge.Cuts')
def __init__(self, start, end, layer='F.SilkS', width=0.15, board=None): line = pcbnew.DRAWSEGMENT(board and board.native_obj) line.SetShape(pcbnew.S_SEGMENT) line.SetStart(Point.native_from(start)) line.SetEnd(Point.native_from(end)) line.SetLayer(pcbnew_layer.get_board_layer(board, layer)) line.SetWidth(int(width * units.DEFAULT_UNIT_IUS)) self._obj = line
def __init__(self, width, start, end, layer="F.Cu", board=None): self._track = pcbnew.TRACK(board and board.native_obj) self._track.SetWidth(int(width * units.DEFAULT_UNIT_IUS)) if board: self._track.SetLayer(board.get_layer(layer)) else: self._track.SetLayer(pcbnew_layer.get_std_layer(layer)) self._track.SetStart(Point.native_from(start)) self._track.SetEnd(Point.native_from(end))
def __init__(self, width, start, end, layer='F.Cu', board=None): self._track = pcbnew.TRACK(board and board.native_obj) self._track.SetWidth(int(width * units.DEFAULT_UNIT_IUS)) if board: self._track.SetLayer(board.get_layer(layer)) else: self._track.SetLayer(pcbnew_layer.get_std_layer(layer)) self._track.SetStart(Point.native_from(start)) self._track.SetEnd(Point.native_from(end))
def __init__(self, center, radius, layer='F.SilkS', width=0.15, board=None): circle = pcbnew.DRAWSEGMENT(board and board.native_obj) circle.SetShape(pcbnew.S_CIRCLE) circle.SetCenter(Point.native_from(center)) start_coord = Point.native_from( (center[0], center[1] + radius)) circle.SetArcStart(start_coord) circle.SetLayer(pcbnew_layer.get_board_layer(board, layer)) circle.SetWidth(int(width * units.DEFAULT_UNIT_IUS)) self._obj = circle
def get_fixed_pos(self): if self.mode.lower() == 'ul': ul_relative = Point(0, 0) elif self.mode.lower() == 'pin1': ul_relative = self.boundingBox.ul - self['1'].pad.center elif self.mode.lower() == 'center': comp_center = Point.wrap(self.module._obj.GetCenter()) ul_relative = self.boundingBox.ul - comp_center else: raise Exception('Unimplemented positioning mode.') return self.position + ul_relative
def __init__(self, center, radius, start_angle, stop_angle, layer='F.SilkS', width=0.15, board=None): start_coord = radius * cmath.exp(math.radians(start_angle - 90) * 1j) start_coord = Point.native_from((start_coord.real, start_coord.imag)) angle = stop_angle - start_angle arc = pcbnew.DRAWSEGMENT(board and board.native_obj) arc.SetShape(pcbnew.S_ARC) arc.SetCenter(Point.native_from(center)) arc.SetArcStart(start_coord) arc.SetAngle(angle * 10) arc.SetLayer(pcbnew_layer.get_board_layer(board, layer)) arc.SetWidth(int(width * units.DEFAULT_UNIT_IUS)) self._obj = arc
def add_keepouts(self, min_kw=1e-3, min_kh=1e-3): # TODO: handle more general cases # determine the board height from the edge ylist = [p.y for p in self.edge] height = max(ylist) - min(ylist) for p0, p1 in zip(self.edge[:-1], self.edge[1:]): x0, y0 = p0 x1, y1 = p1 if x1 > x0: # quadrants I and IV kw = x1 - x0 kh = max(y0, y1) kx = x0 ky = 0 elif x0 > x1: # quadrants II and III kw = x0 - x1 kh = height - min(y0, y1) kx = x1 ky = min(y0, y1) else: continue if kw > min_kw and kh > min_kw: kpos = Point(kx, ky) self.add(PcbKeepout(width=kw, height=kh, position=kpos))
def boundary(edge): ul = Point(*BoardTools.get_board_ul(edge)) edge = [ul + Point(x, y) for x, y in edge] # repeat the last point edge = edge + [edge[-1]] # add points to the edge path = ['path', 'pcb', '0'] for point in edge: # convert points from mm to um # and negate y coordinate x = '%d' % dsnx(point.x) y = '%d' % dsny(point.y) path = path[:] + [x, y] return ['boundary', path]
def inst_atmega328p(self): # Main microcontroller atmega328 = ATMEGA328P() self.pcb.add(atmega328) # Power connections atmega328.wire_power(vdd='+5V', gnd='GND') self.add_dcap(atmega328.get_pin('VCC')) self.add_dcap(atmega328.get_pin('AVCC')) # Analog reference atmega328.get_pin('AREF').wire('AREF') self.add_dcap(atmega328.get_pin('AREF')) # Crystal circuit atmega328.wire_xtal('XTAL1', 'XTAL2') self.pcb.add(Crystal('XTAL1', 'XTAL2')) self.pcb.add(Capacitor('XTAL1', 'GND', value=22e-12)) self.pcb.add(Capacitor('XTAL2', 'GND', value=22e-12)) # Crystal routing constraints self.pcb.add_net_constr('XTAL1', length=4) self.pcb.add_net_constr('XTAL2', length=4) # Reset circuit atmega328.get_pin('~RESET~').wire('RESET') self.pcb.add(Resistor('RESET', '+5V', value=10e3)) # Reset button self.pcb.add(SPST('RESET', 'GND')) # ICSP connector icsp_pos = Point(2505.512, self.top - 1198.031, 'mils') self.pcb.add( ICSP( sck='IO13', miso='IO12', mosi='IO11', reset='RESET', vdd='+5V', gnd='GND', position=icsp_pos, mode='PIN1')) # Wire Port B pb = atmega328.PB for idx in range(6): pb[idx].wire('IO' + str(idx + 8)) # Wire Port C pc = atmega328.PC for idx in range(6): pc[idx].wire('AD' + str(idx)) # Wire Port D pd = atmega328.PD for idx in range(8): pd[idx].wire('IO' + str(idx))
def make_nets(pcb, out): out = [x for x in out[1:] if x[0] == 'net'] for entry in out: net = entry[1].replace('"', '') for routing in entry[2:]: if routing[0] == 'wire': paths = [x for x in routing[1:] if x[0] == 'path'] for path in paths: layer = path[1] width = float(path[2]) / 1e4 coords = [ Point(sesx(x), sesy(y)) for x, y in chunks(path[3:], 2) ] pcb.add_track(coords, layer, width, net) elif routing[0] == 'via': via_name = routing[1] size, drill = get_via_params(via_name) coord = Point(sesx(routing[2]), sesy(routing[3])) pcb.add_via(coord=coord, size=size, drill=drill, net=net)
def __init__(self, coord, layer_pair, size, drill, board=None): self._via = pcbnew.VIA(board and board.native_obj) self._via.SetViaType(via_type) self._via.SetWidth(int(size * units.DEFAULT_UNIT_IUS)) coord_point = Point.build_from(coord) self._via.SetEnd(coord_point.native_obj) self._via.SetStart(coord_point.native_obj) if board: self._via.SetLayerPair(board.get_layer(layer_pair[0]), board.get_layer(layer_pair[1])) else: self._via.SetLayerPair(layer.get_std_layer(layer_pair[0]), layer.get_std_layer(layer_pair[1])) self._via.SetDrill(int(drill * units.DEFAULT_UNIT_IUS))
def compile(self): print 'Adding components' r1 = Resistor('VDD', 'V1') r2 = Resistor('V1', 'V2') r3 = Resistor('V2', 'V3') r4 = Resistor('V3', 'GND') self.pcb.add(r1, r2, r3, r4) width = 20.0 height = 20.0 print 'Defining the board edge' self.pcb.edge = [ Point(0, 0), Point(width, 0), Point(width, height), Point(0, height), Point(0, 0) ] print 'Compiling PCB' self.pcb.compile(json_file=self.json_fname)
def inst_ldo(self): # Barrel jack for 7-12V supply jack_pos = Point(-75, self.top - 475, 'mils') jack = BarrelJack('PWRIN', 'GND', position=jack_pos, mode='UL') diode = Diode('PWRIN', 'VIN') self.pcb.add(jack, diode) # 5.0V LDO ldo_5v0 = LDO_5v0(vin='VIN', gnd='GND', vout='VCC') self.pcb.add(ldo_5v0) self.add_dcap(ldo_5v0.get_pin('IN')) self.add_dcap(ldo_5v0.get_pin('IN'), value=47e-6) self.add_dcap(ldo_5v0.get_pin('OUT')) self.add_dcap(ldo_5v0.get_pin('OUT'), value=47e-6)
def __init__(self, coord, layer_pair, diameter, drill, board=None): self._obj = pcbnew.VIA(board and board.native_obj) self.diameter = diameter coord_point = Point.build_from(coord) self._obj.SetEnd(coord_point.native_obj) self._obj.SetStart(coord_point.native_obj) if board: self._obj.SetLayerPair(board.get_layer(layer_pair[0]), board.get_layer(layer_pair[1])) else: self._obj.SetLayerPair(layer.get_std_layer(layer_pair[0]), layer.get_std_layer(layer_pair[1])) self.drill = drill
def __init__(self, coord, layer_pair, size, drill, board=None): self._via = pcbnew.VIA(board and board.native_obj) self._via.SetWidth(int(size * units.DEFAULT_UNIT_IUS)) coord_point = Point.build_from(coord) self._via.SetEnd(coord_point.native_obj) self._via.SetStart(coord_point.native_obj) if board: self._via.SetLayerPair(board.get_layer(layer_pair[0]), board.get_layer(layer_pair[1])) else: self._via.SetLayerPair(layer.get_std_layer(layer_pair[0]), layer.get_std_layer(layer_pair[1])) self._via.SetDrill(int(drill * units.DEFAULT_UNIT_IUS))
def inst_usb(self): # USB B connector usb_pos = Point(-250, self.top - 1725, 'mils') usb = UsbConnB(vdd='XUSB', dm='D-', dp='D+', gnd='GND', shield='GND', position=usb_pos, rotation=pi, mode='UL') self.pcb.add(usb) # Polyfuse to protect computer from shorts on the Freeduino board self.pcb.add(PTC('XUSB', 'USBVCC')) # USB bypass cap self.pcb.add(Capacitor('USBVCC', 'GND')) # Power header self.pcb.add(Header('USBVCC', '+5V', 'VCC', type='male'))
def center(self): return Point.wrap(self._obj.GetCenter())
def center(self): """Via center""" return Point.wrap(self._obj.GetCenter())
def main(): # load command-line arguments parser = argparse.ArgumentParser() parser.add_argument('--json') parser.add_argument('--pcb') parser.add_argument('--fill_top', default='GND') parser.add_argument('--fill_bot', default='GND') parser.add_argument('--bufx', type=float, default=0.5) parser.add_argument('--bufy', type=float, default=0.5) args = parser.parse_args() # read board placement from SMT-PCB with open(args.json, 'r') as f: json_dict = json.load(f) # get the board edge board_edge = json_dict['board_edge'] board_ul = Point(*BoardTools.get_board_ul(board_edge)) # compute board center cx, cy = BoardTools.get_board_center(board_edge) edge = [] for idx, (x, y) in enumerate(board_edge): if x < cx: px = x - args.bufx else: px = x + args.bufx if y < cy: py = y - args.bufy else: py = y + args.bufy board_edge[idx] = (px, py) # write board edge back with open(args.json, 'w') as f: json.dump(json_dict, f, indent=2, sort_keys=True) # create the new board edge edge = [Point(x, y) + board_ul for x, y in board_edge] # create zone outline for copper pours minx = min([p.x for p in edge]) maxx = max([p.x for p in edge]) miny = min([p.y for p in edge]) maxy = max([p.y for p in edge]) ul = Point(minx, miny) ur = Point(maxx, miny) lr = Point(maxx, maxy) ll = Point(minx, maxy) outline = [ul, ur, lr, ll] # write changes to board pcb = Board.load(args.pcb) # write edge pcb.clearLayer('Edge.Cuts') pcb.add_polyline(edge, layer='Edge.Cuts') # write zones #clearance = max(args.bufx, args.bufy) #pcb.add_zone(outline, args.fill_top, 'F.Cu', clearance) #pcb.add_zone(outline, args.fill_bot, 'B.Cu', clearance) pcb.save()
def end(self): return Point.wrap(self._obj.GetEnd())
def start(self, value): self._obj.SetStart(Point.native_from(value))
def inst_headers(self): # Digital 10-pin header header_pos = Point(1640, self.top - 2000, 'mils') header_rot = 3.0 * pi / 2.0 self.pcb.add( Header( 'IO8', 'IO9', 'IO10', 'IO11', 'IO12', 'IO13', 'GND', 'AREF', 'AD4', 'AD5', type='female', position=header_pos, rotation=header_rot, mode='PIN1')) # Digital 8-pin header header_pos = Point(2500, self.top - 2000, 'mils') header_rot = 3.0 * pi / 2.0 self.pcb.add( Header( 'IO0', 'IO1', 'IO2', 'IO3', 'IO4', 'IO5', 'IO6', 'IO7', type='female', position=header_pos, rotation=header_rot, mode='PIN1')) # Analog 6-pin header header_pos = Point(2000, self.top - 100, 'mils') header_rot = pi / 2.0 self.pcb.add( Header( 'AD0', 'AD1', 'AD2', 'AD3', 'AD4', 'AD5', type='female', position=header_pos, rotation=header_rot, mode='PIN1')) # Power header header_pos = Point(1100, self.top - 100, 'mils') header_rot = pi / 2.0 self.pcb.add( Header( None, '+5V', 'RESET', '+3V3', '+5V', 'GND', 'GND', 'VIN', type='female', position=header_pos, rotation=header_rot, mode='PIN1'))
def position(self): return Point.wrap(self._obj.GetPosition())
def end(self, value): self._obj.SetArcEnd(Point.native_from(value))
def center(self, value): self._obj.SetCenter(Point.native_from(value))
def position(self, value): self._obj.SetPosition(Point.native_from(value))
def __init__(self, width, start, end, layer='F.Cu', board=None): self._obj = pcbnew.TRACK(board and board.native_obj) self._obj.SetWidth(int(width * units.DEFAULT_UNIT_IUS)) self.layer = layer self._obj.SetStart(Point.native_from(start)) self._obj.SetEnd(Point.native_from(end))
def start(self): return Point.wrap(self._obj.GetStart())
def define_edge(self): # create list of points representing the board edge points = [(0, 0), (0, 2100), (2540, 2100), (2600, 2040), (2600, 1590), (2700, 1490), (2700, 200), (2600, 100), (2600, 0), (0, 0)] points = [Point(x, self.top - y, 'mils') for x, y in points] self.pcb.edge = points
def inst_mounting_holes(self): coords = [(600, 2000), (550, 100), (2600, 1400), (2600, 300)] for coord in coords: hole_pos = Point(coord[0], self.top - coord[1], 'mils') hole = MountingHole(position=hole_pos, mode='CENTER') self.pcb.add(hole)