SKiDL Documentation

repository·master·Indexed 23 days ago

https://github.com/devbisme/skidl

A Python-based 'infrastructure as code' tool for electronic circuit design. SKiDL allows developers to programmatically describe circuits, perform Electrical Rules Checking (ERC), and generate netlists for PCB layout tools like KiCad. Key features include topology-based and pin-based connections, hierarchical subcircuits via decorators or classes, and support for part templates and custom library paths.

Tokens
32.6K
Snippets
93
Records
179
Agent score
81%

What's inside SKiDL

  1. New features in SKiDL 2.0.0

    master

    SKiDL 2.0.0 introduces several improvements and new capabilities:

    • Library Exporting: Additional Part attributes can now be specified during library export.
    • Interface I/O: Interface objects now include an expanded unexpio dictionary, which allows for accessing I/O (without buses) that have been expanded into individual nets.
    • Interface Interconnection: You can now interconnect Interface objects directly using the connect() method or the __iadd__() operator (e.g., interface1 += interface2).
    • Performance: Part libraries are now pickled upon their first load to ensure faster access during subsequent loads. The storage directory for these pickled files is configurable via the SKiDL configuration file.
    • KiCad Support: The KICAD tool identifier now points to KICAD8.
  2. Generate a SKiDL library from a design

    master
    Whenever you call generate_netlist(), SKiDL automatically creates a SKiDL library containing all the parts used in your design. If your script is my_design.py, the resulting library will be named my_design_sklib.py. This is useful for sharing designs, as the recipient only needs the script and the generated .sklib.py file to run the design.
  3. Use pin names instead of pin numbers for better portability

    master

    When connecting components in SKiDL, prefer using pin names (e.g., 'OSC1') rather than pin numbers (e.g., 9).

    Using pin names makes your circuit descriptions portable across different packages of the same device. For example, if you switch a microcontroller from an SSOP package to a QFN package, the pin numbers for specific functions (like OSC1) will likely change, but the names will remain the same. By using names, you can swap the Part definition (name and footprint) without needing to update any of your connection logic.

  4. Support both Common-Cathode and Common-Anode configurations

    master

    You can create a flexible module that supports both configurations by accepting two inputs (anodes and cathodes).

    • Common-Anode: Pass a single net (width 1) to anodes and a bus to cathodes.
    • Common-Cathode: Pass a single net (width 1) to cathodes and a bus to anodes.

    By using max(anodes.width, cathodes.width), the module determines the total number of LEDs required based on the larger of the two inputs.

    def leds(anodes, cathodes):
        width = max(anodes.width, cathodes.width)
    
        leds = width * Part("Device", 'LED', footprint='KiCad/LEDs.pretty:LED_0603', dest=TEMPLATE)
        rs = width * Part("Device", 'R', value='330', footprint='KiCad/Resistors_SMD.pretty:R_0603', dest=TEMPLATE)
    
        for led, r in zip(leds, rs):
            led['K'] += r[1]
    
        anodes += [led['A'] for led in leds]
        cathodes += [r[2] for r in rs]
  5. Manage multiple Circuit objects

    master

    While SKiDL uses a default_circuit globally, you can instantiate multiple Circuit objects to manage independent designs or hierarchical structures.

    Ways to add elements to a specific Circuit:

    1. Using the circuit parameter: Pass the circuit instance directly to the constructor of a Part, Net, or Bus.
    2. Using a context manager: Use with my_circuit: to make my_circuit the default_circuit for all elements created within that block.
    3. Using operators/methods: Use += with add_parts, add_nets, or add_buses on the circuit object.

    Note: You cannot connect elements (parts, nets, or buses) that reside in different Circuit objects. Once an element is connected within a circuit, it cannot be moved to a different one.

    >>> my_circuit = Circuit()
    >>> my_circuit += Part("Device",'R')  # Add a resistor to the circuit.
    >>> my_circuit += Net('GND')          # Add a net.
    >>> my_circuit += Bus('byte_bus', 8)  # Add a bus.
    >>> my_circuit = Circuit()
    >>> p = Part("Device", 'R', circuit = my_circuit)
    >>> n = Net('GND', circuit = my_circuit)
    >>> b = Bus('byte_bus', 8, circuit = my_circuit)
    my_circuit = Circuit()
    with my_circuit:
        p = Part('Device', 'R')
        n = Net('GND')
        b = Bus('byte_bus', 8)
  6. Define reusable subcircuits with @SubCircuit

    master

    The @SubCircuit decorator allows you to define a function that encapsulates a complex circuit design. This function can take nets or buses as arguments, making the circuit design generalized and reusable across different projects. Inside the function, you can perform logic (like calculating resistor values based on bus width) to automatically configure the subcircuit.

    Example structure:

    @SubCircuit
    def my_subcircuit(input_bus, output_net, gnd):
        # ... complex logic and part instantiations ...
        # Connect inputs to outputs
        ... 
    @SubCircuit
    def vga_port(red, grn, blu, hsync, vsync, gnd, logic_lvl=3.3):
        """Generate analog RGB VGA port driven by red, grn, blu digital color buses."""
        # ... implementation ...
  7. Manage design constraints with Part and Net Classes

    master

    SKiDL uses PartClass and NetClass to apply attributes (like manufacturing requirements, electrical characteristics, or trace widths) to groups of components and nets.

    • Priority: Classes have a priority attribute. Higher priority classes take precedence over lower priority ones.
    • Assignment: You can assign classes to individual parts/nets during instantiation or later via the .partclasses or .netclasses attributes.
    • Inheritance: Classes assigned to a SubCircuit are inherited by all parts and nets within that hierarchy.
    from skidl import *
    
    # Create part classes
    passive_parts = PartClass("passive_parts", priority=1, tolerance="5%")
    power_parts = PartClass("power_parts", priority=10, tolerance="1%", temp_rating="125C")
    
    # Create net classes
    high_speed = NetClass("high_speed", priority=2, width="0.1mm", impedance="50ohm")
    
    # Assign to parts
    resistor = Part("Device", "R", value="1K", partclasses=(passive_parts))
    
    # Assign to nets
    vcc_5v = Net("VCC_5V", netclasses=power_nets)
  8. How to connect circuit elements in SKiDL

    master

    SKiDL provides two primary ways to establish electrical connections:

    1. Topology-based connection: Use the & operator to chain components and nets together. This is highly readable for simple paths. vin & r1 & vout

    2. Pin-based connection: Use the += operator to connect specific pins to nets or other pins. This is useful for complex components or precise wiring. vin += r1[1] vout += r1[2], r2[1] gnd += r2[2]