Skip to content

2024

Why on earth did you create a new language? 🫣

It's a good question! Making people learn something new is a huge barrier to entry, ignores the wealth of community support from existing languages and can be a bit of a pain to maintain.

This iteration of the project actually came after first working with and then modifying an awesome project called SKiDL (https://github.com/devbisme/skidl). SKiDL takes the approach of using Python. Since it's procedural, turing complete and has a rich eco-system - people use to that and there aren't standard composable ways of designing things. Instead of describing your board, you (practically) write a script that generates your board. It entangles your targets with your source-code and can make it difficult to understand the ultimate outcome of what you've written.

We are trying to make it as readable and friendly as possible, our expectation is our users will likely have some experience with Python and perhaps a little C back in school, so making it clear and approachable is front of mind. Ideally some parts of code should "look" like the schematic, eg. power.vcc ~> resistor ~> led ~> power.gnd.

Units and tolerances are core to our language, the physical world is 'fuzzy' and having a good way to deal with those is pretty important. There's a few operators and first-class language features we wanted as well, (like units and tolerances eg. 3.3V +/- 100mV) that just aren't the same when embedded in a string, or class init method.

Additionally, since it's a potentially very long program, it was hard to write good language support around (a language server for VSCode, a schematic visualiser etc...) that were snappy, responsive and lent to examining modules as well as the whole program.

Worth noting; we're probably going to try make our language more like Python, than less over the coming little while.

Happy coding! 🚀

-- Matt

Make hardware flow

My dad taught me the technical details of everything for as long as I can remember. For my 7th Christmas, I got a lawn-mower - to tear the engine off and turn into a go-kart. I was absolutely stoked.

As Narayan and I grew up, we spent every weekend building things. We were always scheming about the next project, and we were always building something. We built a CNC machine, a liquid-fueled rocket motor, and a drone. We were always trying to make things better, faster, and more efficient. We were always trying to make things work better.

More than any of the individual projects, the thing that I always got most stoked about was new tools. We converted a milling machine to CNC an axis at a time by first 3D printing and then machining each of the axes brackets. We had to take a second pass at the first two axes because the 3D printed parts were sloppy enough that the machined brackets they created still had too much play for comfort. Man, that was a great project. And the endeavour landed us more offers for contract work (as ~17 year-olds) than we could handle.

One specific part of that project I wanted, and wanted for years, were low-cost tightly integrated servo drives. I wanted to make a PCB with 4 servo controllers on it that meant I would only need to run cables out to the motors and I could control the whole system form a single PCB - similar to 3D printer controllers. We're finally getting close! https://github.com/atopile/spin-servo-drive

My subsequent decade through university and industry made me consciously realise why people kept trying to pay us - it's far too hard and slow to make hardware fast enough to stay in a flow state and learn fast enough that failing is acceptable.

atopile will make high-quality hardware engineering flow the same way great software development does - and make engineers everywhere feel like how our scrappy younger selves did.

Trivial mistakes are expensive 🤑

Continuous integration / continuous deployment (CI/CD) is does things in software like running tests and deploying code automatically.

We've unfortunately been a little too responsible for some pretty expensive trivial mistakes in the past, so it's a key thing we wanted to focus on in atopile.

Instead of all shaking hands and totally agreeing that this local export named "pcb-final-final-final" is what we're going to spend serious money on - we can generate the manufacturing files on a trusted server

... and stamp them with the precise version of the source-code used to create them!

githash

No more export mistakes 👌. Plus, it makes ordering boards super easy!

Matt

✨ Layout Reuse ✨

Huge shout out to @nickkrstevski for this awesome new feature!

You can now reuse parts placement across designs. This is a huge time saver for designs - particularly those with a lot of common modules.

OMG, How?

Usage of the ato CLI will automatically install the hook for the atopile plugin to KiCAD. All you need to do is hit the sync 🔄 button to group the components into the modules that have layouts associated, then hit pull ⬇️ to use that layout. If you want to save a layout to a module, you can do so with the push ⬆️ button.

Happy designing! 🎉

Matt

Cloud Components

I am pretty excited about this one. In our latest release 0.2.5, we are introducing 'Cloud Components' - a way to parametrically define and select components from a server.

How it works

First step is defining the requirements of the component, much like you would in a digikey search. Currently our library has support for resistors, capacitors, inductors, diodes, and FETs. Here's an example of how you would define a few components:

resistor = new Resistor
resistor.value = 10kohm +/- 20%
resistor.package = "0603"

cap = new Capacitor
cap.value = 1uF +/- 10%
cap.package = "0603"

fet = new NFET
fet.current_a = 30A to 100A
fet.drain_source_voltage_v = 30V to 100V

inductor = new Inductor
inductor.inductance = 1uH to 10uH
inductor.current = 3A to 5A

diode = new Diode
diode.forward_voltage = 7V to 9V
diode.impedance = 1ohm to 10ohm
diode.power_dissipation = 5W to 60W
At build time, we take the requirements and send them to our component server, which filters parts in our library for the specified requirements. The server then sorts the parts by price and availability, and returns the best matches. These components are then downloaded and added to your BOM and netlist.

BOM output

Footprints

This was a bit of a pain. This is pretty simple for things like resistors and caps, but becomes a little more complex for devices like mosfets that might have three pins on some parts and eight on others. Our current solution, which admittedly is a bit of a hack, stores a muated footprint in the server for each part, downloads it and adds it to your library.

For example, here is a multi-pin mosfet, you can see that the pin names have been mutated to their corresponding signals:

Example Image

Why this is a big deal

The way circuits are defined today requires us as designers to be explicit as to which part number each component will have, in the process loosing information about why you chose that component. If a design at your company has a component shortage and you are assigned the task to find a replacement, how do you know which part to choose, what are the requirements? If you are luck there might be a design document or confluence page you can scroll through to reverse engineer the design and check new parts against it. If you are unlucky, the guy who designed it left the company and only took paper notes.

By capturing the requirements in your source code, the information is preserved and can be used even years later to find a suitable part. I imagine a future where automated systems can track component pricing and inventory, automatically finding cost down opportunities, or alerting you when a part is going end of life and proposing a replacement.

More immediately, as a designer making a quick turn board, I don't want to spend time browsing digikey, seeing what is available, checking if we have it in our companies component library, only to hear back from the vendor that the component is now out of stock and they need me to pick a new one. Thats enough to make a grown man cry, some days. Instead, we can have the tool generate a list of alternatives that meet the requirements and allow the vendor to pick from that list.

What is next?

I believe that a fundamental transformation of how we capture circuit information is needed to enable the next generation of tools. In order to make our tools truly smart, we need to come up with ways to communicate design intent, not just one explicit implementation. Concretely, we are working on:

  • Adding more component types to the server
  • Adding support for project level requirements and constraints: AECQ100, Environmental conditions, etc
  • Component traits - how to generically describe complex components (blog post coming soon)

Stay tuned for more updates!

Narayan

From Weekend Projects to Reinventing Hardware Design

Early Days: Can we build a predator drone?

Matt and I met at camp when we were thirteen and quickly became mates. We chatted the whole twelve hour bus ride home, scheming about the enormous drone we were going to build, looking back at it, we were a bit ambitious.

The next decade of weekend weekends Matt and I spent together stand out. They weren't filled with typical childhood pastimes; instead, we immersed ourselves in building and creating. Our projects were modest – from simple drones to CNC machines. I'll never forget our attempt at a liquid-fueled rocket motor. Igniting it was a disaster, but everything else from the servo-controlled throttling to the large blast shield worked quite the treat - not bad, for about a week's worth of evenings after work!

Stepping into the Professional World

Our first proper tech jobs were at Tesla and Lilium. We were eager to translate our weekend tinkering to the real world. At these companies, we learned a lot about manufacturing and bringing products to market. The technology and talent were inspiring, but we noticed the pace of innovation was slower and more traditional than we expected.

Facing Industry Realities

Eventually, we both ended up at Tesla together, during which time we met Tim. We quickly found common ground in our experiences. Even though we were part of some exciting projects, the reality of day-to-day work often meant dealing with a lot of repetition and slow-moving processes. The job started to feel less about innovation and more about navigating through routine procedures. It wasn't the dynamic environment we had dreamed of, it was becoming just a job.

A Shift in Perspective: The Seed of an Idea

Continuing the trend of the CNC machines we built growing up - our personal projects often revolved around making things to make things. It was clear there must be a better way to describe hardware. Mulling this led to pivotal realization: What if we could streamline hardware design using language-based descriptions? In my day job, our team was managing 10+ designs each disconnected from the other, meaning it could take us years to roll out improvements across all of them. The idea of simply making a PR for each to update that particular module sounded too good to be true.

Our Vision: A Humble Hope for Change

We’re not claiming to have all the answers or to revolutionize the industry overnight, but we do have a vision: a future where tools keep engineers in their flow state - whether working on teams small or large, no matter how complex the project. We believe this will make the design process significantly faster and less costly, bringing us closer to the agility and joy of those weekend projects from our youth.

An Invitation to Join Our Journey

This journey is just beginning, and there’s a long road ahead. We’re sharing our story not just to talk about our idea, but to invite collaboration, feedback, and shared learning. Together, we can explore ways to bring a new level of dynamism and creativity to hardware design. We’re excited about the future and we hope you’ll join us in this endeavor.

Narayan

Composable Electronics

How do we make designing electronics more like playing with legos? We need to standardize the building blocks, how they can be connected together and publish 'instruction manuals' that describe how to connect them up to make something useful.

The blocks

How do you describe what a component is? Today we rely on a language description in a datasheet and a clever human to interpret it. The information is not easily interpretable by a computer, which makes it hard to automate or augment the design process.

We need a way to embed key information into the source files.

What are the functional blocks inside the chip?

Here is a simple example of a buck converter IC. Example Image Lets try simplify this into a few functional blocks. Lets say the 'controller' is a block that takes in a voltage outputs a switching node, with a feedback pin. We can just use a NFET component for the fet. So in ato code we could define this as:

component LM2841:
    controller = new BuckController
    nfet = new NFET

Connecting and configuring the blocks

To more completely describe the internals of the IC, we need to define how the blocks are connected and what their properties are. Below we are connecting the NFET to the controller, connecting the blocks to the outputs and configuring the voltage and current limits.

# connect blocks to pins
controller.feedback ~ fb
controller.power_in.vcc ~ vin
controller.power_out.gnd ~ gnd
nfet.drain ~ sw
We will also need to add in any specifics required by this particular IC, like a bootstrap capacitor and a pull-up on the enable pin that ill leave out of this example.

The Instruction Manual

Following through with our buck converter example, lets build a description of how to connect the blocks together to make a buck converter. Example Image

To start, lets make a new 'topology' and instantiate the required blocks.

topology Buck:
    # Define external interfaces
    power_in = new Power
    power_out = new Power

    # Define blocks
    inductor = new Inductor
    output_cap = new Capacitor
    input_cap = new Capacitor
    diode = new Diode
    controller = new BuckController
    nfet = new NFET
    feedback_divider = new VDiv

Next, lets connect the blocks together.

    # Connect internal components
    controller.drive ~ nfet.gate
    # Method to chain dipole components (feedback welcome)
    power_in.vcc ~ nfet ~ inductor ~ power_out.vcc
    diode.anode ~ gnd
    diode.cathode ~ inductor.1

    # Feedback divider (input is a power interface)
    feedback_divider.input ~ power_out
    feedback_divider.output ~ controller.feedback


    # Connect bypass capacitors
    power_in ~ input_cap
    power_out ~ output_cap

    # We might want to define some equations to make the buck more intuitive to use
    eqn: power_out.voltage = feedback_divider.input.voltage
    eqn: controller.feedback.voltage = feedback_divider.output.voltage

Finally, we need a way to relate the two. Let now create a specific instance of the topology and define the parameters.

buck = new Buck
ic = new LM2841

# Map the IC to the topology using the replacement operator
buck.controller -> ic.controller
buck.nfet -> ic.nfet

# Configure the buck components
buck.inductor.inductance = 10uH +/- 20%
input_cap.capacitance = 10uF +/- 20%
output_cap.capacitance = 10uF +/- 20%

# Configure output voltage
buck.power_out.voltage = 5V +/- 5%

That might all feel like alot of work, until you realize that the topologies and components are reusable and only need to be defined once. You can design a buck converter using just that last block of code and a few imports.

If you are interested in checking out the full example, you can find it here

We have a few language features in the pipeline that will enable this type of workflow in the near future.

Narayan