Skip to main content Microfire 







Atopile

A big bridge

Create a schematic with code!


Head over to atopile

to read more about what they are creating. In their words:


atopile is a language and toolchain to describe electronic circuit boards with code. By replacing the point and click schematic interface with code, we introduce software development workflows like reuse, validation and automation to the world of electronics. Join us in this adventure!


And since a demonstration is probably the easiest way to understand it, here is some atopile code.

1
import Resistor from "generics/resistors.ato"
2

3
module VoltageDivider:
4
	signal top
5
	signal out
6
	signal bottom
7

8
	r_top = new Resistor
9
	r_top.footprint = "R0402"
10
	r_top.value = 100kohm +/- 10%
11

12
	r_bottom = new Resistor
13
	r_bottom.footprint = "R0402"
14
	r_bottom.value = 200kohm +/- 10%
15

16
	top ~ r_top.p1
17
	r_top.p2 ~ out
18
	out ~ r_bottom.p1
19
	r_bottom.p2 ~ bottom


  • it vaguely looks like JavaScript
  • it creates two resistors that have a 0402 footprint and are 100 Kohm and 200 Kohm, both with a tolerance of 10%
  • ~ connects things


That's interesting, right? Next, you use their toolchain and it will:

  • Search JLC/LSCS for a matching part (you can also specify exactly what part you want there)
  • download a footprint and convert it to KiCAD format
  • turn that code into a KiCAD netlist file
  • create a BOM


After you get your netlist, you open KiCAD, import it into the PCB Editor and lay out the board.


Why?


First, I would say why not? But really, there are some pros and cons to this approach


pros


  • automates several steps like part searching, symbol creation isn't needed, and footprint import is done for you
  • you can split up sections of the schematic into separate files
  • you can create abstractions, like the voltage divider code above or an I2C bus
  • it is code


cons


  • there are some benefits to a visual approach: you can see all the pins
  • it is a niche tool and you're not likely to see this in a company
  • it is code


Making a small board


To really get an idea of how it works, I made a small board and tried to use most of the features. One thing to note is this is a very early-stage tool. The latest version is 0.2 and there are bugs. One notable bug is it doesn't work on Windows.


Installing it in Linux went fine, just a simple pip install. I wanted to recreate a carrier board for a Mod-EC . The documentation describe how to create your own components, and use your own KiCAD footprints and it all worked quite easily.


The equivalent of a schematic symbol is (in a way), called a component in atopile. It is where you let the compiler know what to call each of the pins, what footprint to use, and what to call it.

1
import Power from "generics/interfaces.ato"
2
import I2C from "generics/interfaces.ato"
3
import Analog from "generics/interfaces.ato"
4
			
5
component Microfire_Mod_EC:
6
	mpn = 'none'
7
	footprint = "MICROFIRE_MOD"
8
	power = new Power
9
	i2c = new I2C
10
	analog = new Analog
11

12
	signal gnd ~ pin 12
13
	signal vcc ~ pin 11
14
	signal sda ~ pin 10
15
	signal scl ~ pin 9
16
	signal probe_1 ~ pin 1
17
	signal probe_2 ~ pin 2
18

19
	power.gnd ~ gnd
20
	power.vcc ~ vcc
21
	i2c.scl ~ scl
22
	i2c.sda ~ sda
23
	analog.io ~ probe_1
24
	analog.gnd ~ probe_2
Notice how you can specify power pins, I2C pins, and analog pins here? Those are called interfaces and they'll come in quite handy soon.


Now to use the new component import Microfire_Mod_EC from "Microfire_Mod-EC.ato it into the main .ato file, and ec_sensor = new Microfire_Mod_EC to make an instance of it. I quickly did the same for Mod-ISO and all the others.


I needed a few more components like an SMA connector and a block terminal. In KiCAD, I might have just placed a generic `CONN` symbol, and then searched for a specific component to ensure the footprint is correct. In atopile, you do it backwards: search JLCPCB Parts for the component you want, then enter ato install --jlcpcb Cxxxxxx where Cxxxxxx is the JLCPCB Part # from their parametric search page. atopile then downloads the footprint, creates a component file for you and you're set to use it. When you open KiCAD, you'll find the footprint ready to go. If you don't/can't use JLC for parts, you can use any KiCAD footprint, although I think you'll need to make your own component file.


The end result looks like this:

1
import Power from "generics/interfaces.ato"
2
import Analog from "generics/interfaces.ato"
3
import Resistor from "generics/resistors.ato"
4

5
import Microfire_Mod_EC from "Microfire_Mod-EC.ato"
6
import Microfire_Mod_ISO from "Microfire_Mod-ISO.ato"
7
import SMA_KWE902 from "SMA-KWE902.ato"
8
import XY308_2_54_6P from "XY308-2.54-6P.ato"
9
import I2C_Bus from "I2C_Bus.ato"
10

11
# import { Power, Analog, I2C } from "generics/interfaces.ato"
12

13
module Board:
14
	SMA = new SMA_KWE902
15
	iso = new Microfire_Mod_ISO
16
	ec_sensor = new Microfire_Mod_EC
17
	terminal = new XY308_2_54_6P
18
	power = new Power
19
	analog = new Analog
20
	i2c_bus = new I2C_Bus
21

22
	# terminal block
23
	terminal.value = "TERMINAL"
24
	terminal.power ~ power
25
	terminal.i2c ~ i2c_bus.i2c
26
	terminal._5 ~ iso.en
27

28
	# i2c pullups
29
	i2c_bus.power ~ power
30
	
31
	# iso
32
	iso.value = "Mod-ISO"
33
	power ~ iso.power
34
	i2c_bus.i2c ~ iso.i2c
35

36
	# ec sensor
37
	ec_sensor.value = "Mod-EC"
38
	ec_sensor.power ~ iso.iso_power
39
	ec_sensor.i2c ~ iso.iso_i2c
40

41
	# sma probe
42
	SMA.value = "SMA"
43
	SMA.analog ~ ec_sensor.analog
44
			
45
			


I decided to use some more of the features of the language and tried making a component that provided I2C pullup resistors. It looks like this:

1
import Resistor from "generics/resistors.ato"
2
import Power from "generics/interfaces.ato"
3
import I2C from "generics/interfaces.ato"
4

5
module I2C_Bus:
6
	power = new Power
7
	i2c = new I2C
8
	r_sda = new Resistor
9
	r_scl = new Resistor
10

11
	# define and connect I2C pullup resistors
12
	r_sda.footprint = "R0603"
13
	r_sda.value = 4.7kohm +/- 10%
14
	r_scl.footprint = "R0603"
15
	r_scl.value = 4.7kohm +/- 10%
16
	r_scl.p1 ~ power.vcc
17
	r_scl.p2 ~ i2c.scl
18
	r_sda.p1 ~ power.vcc
19
	r_sda.p2 ~ i2c.sda
I was motived to create the smallest code footprint as possible in the main ato file. While I was trying that, I began to wonder what the best practice for schematics-as-code might be. Is it best to silo as many things as possible, or put everything together? The urge to turn everything into a class is strong for me, but I found out fairly quickly the language doesn't support this sort of abstraction. Components still must be created explicitly.


There are definite benefits to this approach I think. Aside from personal preference, it is quicker to create things. You don't need to spend any time at all creating schematic symbols for parts, aside from creating the component. This actually has a benefit as well though, because you can create extra information to the component, providing interfaces, primarily.


One thing I found to be a downside to schematics-as-code, is some information is more efficiently displayed visually. Looking at a schematic symbol lets me see all the pins and what they are connected to. You'll need to be familiar with the project file structure to get that same information, checking the component file, looking through the signals, etc.


Last thoughts


Overall, I would say the downsides aren't necessarily downsides. They feel like it, but that's only because I've spent years and years doing it one way, and moving to a code-only method is a blank slate. I don't know what the best practices might be or what ways might be easier, but lead to problems down the road. There's also the need to learn another language, although to be fair, it is quite simple at this point. The developers are talking about adding features to the langue and it is being quickly developed from the looks of it.